From adc46de59a2e14f4ea58ba1b54ffdd73dd58009d Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 16 Nov 2022 18:15:33 +0100 Subject: [PATCH 001/187] Update prettier and re-format text --- CHANGELOG.md | 4 ++-- devtools/format_md.sh | 2 +- devtools/format_yml.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8847ec6ffb..fffd4fe228 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,8 +23,8 @@ and this project adheres to - all: Bump a few dependency versions to make the codebase compile with `-Zminimal-versions` ([#1465]). -- cosmwasm-profiler: Package was removed 🪦. It served its job showing us that we - cannot properly measure different runtimes for differet Wasm opcodes. +- cosmwasm-profiler: Package was removed 🪦. It served its job showing us that + we cannot properly measure different runtimes for differet Wasm opcodes. - cosmwasm-schema: schema generation is now locked to produce strictly `draft-07` schemas - cosmwasm-schema: `QueryResponses` derive now sets the `JsonSchema` trait bound diff --git a/devtools/format_md.sh b/devtools/format_md.sh index 1ad0f38f34..f45b8c6907 100755 --- a/devtools/format_md.sh +++ b/devtools/format_md.sh @@ -11,4 +11,4 @@ while getopts c option; do esac done -npx prettier@2.2.1 --$op "./**/*.md" +npx prettier@2.7.1 --$op "./**/*.md" diff --git a/devtools/format_yml.sh b/devtools/format_yml.sh index 36d684bf59..142ca7a43b 100755 --- a/devtools/format_yml.sh +++ b/devtools/format_yml.sh @@ -11,4 +11,4 @@ while getopts c option; do esac done -npx prettier@2.2.1 --$op "./**/*.yml" +npx prettier@2.7.1 --$op "./**/*.yml" From 889062fd4f25aadd2f2470d350e4b097f990f947 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 21 Nov 2022 14:10:14 +0100 Subject: [PATCH 002/187] Add CI job for testing cosmwasm-vm on Windows --- .circleci/config.yml | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 01ce7296d3..cd8159bc5b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,6 +2,7 @@ version: 2.1 orbs: codecov: codecov/codecov@3.2.0 + win: circleci/windows@5.0 workflows: test: @@ -15,6 +16,7 @@ workflows: - package_std - package_storage - package_vm + - package_vm_windows - contract_burner - contract_crypto_verify - contract_cyberpunk @@ -376,6 +378,49 @@ jobs: - target/debug/deps key: cargocache-v2-package_vm-rust:1.59.0-{{ checksum "Cargo.lock" }} + package_vm_windows: + executor: + name: win/default + shell: bash.exe + steps: + - run: + name: Enable symlinks for the checkout + command: git config --global core.symlinks true + - checkout + - run: + name: Reset git config set by CircleCI to make Cargo work + command: git config --global --unset url.ssh://git@github.com.insteadof + - run: + name: Install Rust + command: | + set -o errexit + curl -sS --output rustup-init.exe https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe + ./rustup-init.exe --default-toolchain 1.65.0 -y + echo 'export PATH="$PATH;$USERPROFILE/.cargo/bin"' >> "$BASH_ENV" + - run: + name: Version information + command: | + set -o errexit + rustc --version; cargo --version; rustup --version; rustup target list --installed + - restore_cache: + keys: + - cargocache-v2-package_vm_windows-rust:1.65.0-{{ checksum "Cargo.lock" }} + - run: + name: Test + working_directory: ~/project/packages/vm + command: cargo test --locked + - run: + name: Test with all features + working_directory: ~/project/packages/vm + command: cargo test --locked --features allow_interface_version_7,iterator,staking,stargate + - save_cache: + paths: + - /usr/local/cargo/registry + - target/debug/.fingerprint + - target/debug/build + - target/debug/deps + key: cargocache-v2-package_vm_windows-rust:1.65.0-{{ checksum "Cargo.lock" }} + contract_burner: docker: - image: rust:1.59.0 From 0b39abee2f06d0c24510c34f1f29ab6ed923e149 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 30 Aug 2022 16:41:43 +0200 Subject: [PATCH 003/187] Change filesystem errors to be consistent across operating systems --- packages/vm/src/cache.rs | 17 +++---- packages/vm/src/filesystem.rs | 43 ++++++++++++++++++ packages/vm/src/lib.rs | 1 + packages/vm/src/modules/file_system_cache.rs | 47 ++++++++++++-------- packages/vm/src/modules/mod.rs | 2 +- 5 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 packages/vm/src/filesystem.rs diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs index 6310f3ca40..16e9bfea72 100644 --- a/packages/vm/src/cache.rs +++ b/packages/vm/src/cache.rs @@ -1,5 +1,5 @@ use std::collections::HashSet; -use std::fs::{create_dir_all, File, OpenOptions}; +use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; use std::marker::PhantomData; use std::path::{Path, PathBuf}; @@ -10,6 +10,7 @@ use crate::capabilities::required_capabilities_from_module; use crate::checksum::Checksum; use crate::compatibility::check_wasm; use crate::errors::{VmError, VmResult}; +use crate::filesystem::mkdir_p; use crate::instance::{Instance, InstanceOptions}; use crate::modules::{FileSystemCache, InMemoryCache, PinnedMemoryCache}; use crate::size::Size; @@ -108,15 +109,9 @@ where let wasm_path = state_path.join(WASM_DIR); // Ensure all the needed directories exist on disk. - for path in [&state_path, &cache_path, &wasm_path].iter() { - create_dir_all(path).map_err(|e| { - VmError::cache_err(format!( - "Error creating directory {}: {}", - path.display(), - e - )) - })?; - } + mkdir_p(&state_path).map_err(|_e| VmError::cache_err("Error creating state directory"))?; + mkdir_p(&cache_path).map_err(|_e| VmError::cache_err("Error creating cache directory"))?; + mkdir_p(&wasm_path).map_err(|_e| VmError::cache_err("Error creating wasm directory"))?; let fs_cache = FileSystemCache::new(cache_path.join(MODULES_DIR)) .map_err(|e| VmError::cache_err(format!("Error file system cache: {}", e)))?; @@ -373,7 +368,7 @@ mod tests { use crate::errors::VmError; use crate::testing::{mock_backend, mock_env, mock_info, MockApi, MockQuerier, MockStorage}; use cosmwasm_std::{coins, Empty}; - use std::fs::OpenOptions; + use std::fs::{create_dir_all, OpenOptions}; use std::io::Write; use tempfile::TempDir; diff --git a/packages/vm/src/filesystem.rs b/packages/vm/src/filesystem.rs new file mode 100644 index 0000000000..45a60f435f --- /dev/null +++ b/packages/vm/src/filesystem.rs @@ -0,0 +1,43 @@ +use std::{fs::create_dir_all, path::Path}; + +#[derive(Debug)] +pub struct MkdirPFailure; + +/// An implementation for `mkdir -p`. +/// +/// This is a thin wrapper around fs::create_dir_all that +/// hides all OS specific error messages to ensure they don't end up +/// breaking consensus. +pub fn mkdir_p(path: &Path) -> Result<(), MkdirPFailure> { + create_dir_all(path).map_err(|_e| MkdirPFailure) +} + +#[cfg(test)] +mod tests { + use tempfile::TempDir; + + use super::*; + + #[test] + fn mkdir_p_works() { + let tmp_root = TempDir::new().unwrap(); + + // Can create + let path = tmp_root.path().join("something"); + assert!(!path.is_dir()); + mkdir_p(&path).unwrap(); + assert!(path.is_dir()); + + // Can be called on existing dir + let path = tmp_root.path().join("something else"); + assert!(!path.is_dir()); + mkdir_p(&path).unwrap(); + assert!(path.is_dir()); + mkdir_p(&path).unwrap(); // no-op + assert!(path.is_dir()); + + // Fails for dir with null + let path = tmp_root.path().join("something\0with NULL"); + mkdir_p(&path).unwrap_err(); + } +} diff --git a/packages/vm/src/lib.rs b/packages/vm/src/lib.rs index 37713763fa..986275853b 100644 --- a/packages/vm/src/lib.rs +++ b/packages/vm/src/lib.rs @@ -9,6 +9,7 @@ mod compatibility; mod conversion; mod environment; mod errors; +mod filesystem; mod imports; mod instance; mod limited; diff --git a/packages/vm/src/modules/file_system_cache.rs b/packages/vm/src/modules/file_system_cache.rs index 0488ca7635..406a0ebcc3 100644 --- a/packages/vm/src/modules/file_system_cache.rs +++ b/packages/vm/src/modules/file_system_cache.rs @@ -1,12 +1,13 @@ -use std::fs; use std::io; use std::path::PathBuf; +use thiserror::Error; use wasmer::{DeserializeError, Module, Store}; use crate::checksum::Checksum; use crate::errors::{VmError, VmResult}; +use crate::filesystem::mkdir_p; use crate::modules::current_wasmer_module_version; /// Bump this version whenever the module system changes in a way @@ -47,6 +48,20 @@ pub struct FileSystemCache { wasmer_module_version: u32, } +/// An error type that hides system specific error information +/// to ensure deterministic errors across operating systems. +#[derive(Error, Debug)] +pub enum NewFileSystemCacheError { + #[error("Could not get metadata of cache path")] + CouldntGetMetadata, + #[error("The supplied path is readonly")] + ReadonlyPath, + #[error("The supplied path already exists but is no directory")] + ExistsButNoDirectory, + #[error("Could not create cache path")] + CouldntCreatePath, +} + impl FileSystemCache { /// Construct a new `FileSystemCache` around the specified directory. /// The contents of the cache are stored in sub-versioned directories. @@ -55,12 +70,14 @@ impl FileSystemCache { /// /// This method is unsafe because there's no way to ensure the artifacts /// stored in this cache haven't been corrupted or tampered with. - pub unsafe fn new(path: impl Into) -> io::Result { + pub unsafe fn new(path: impl Into) -> Result { let wasmer_module_version = current_wasmer_module_version(); let path: PathBuf = path.into(); if path.exists() { - let metadata = path.metadata()?; + let metadata = path + .metadata() + .map_err(|_e| NewFileSystemCacheError::CouldntGetMetadata)?; if metadata.is_dir() { if !metadata.permissions().readonly() { Ok(Self { @@ -68,25 +85,14 @@ impl FileSystemCache { wasmer_module_version, }) } else { - // This directory is readonly. - Err(io::Error::new( - io::ErrorKind::PermissionDenied, - format!("the supplied path is readonly: {}", path.display()), - )) + Err(NewFileSystemCacheError::ReadonlyPath) } } else { - // This path points to a file. - Err(io::Error::new( - io::ErrorKind::PermissionDenied, - format!( - "the supplied path already points to a file: {}", - path.display() - ), - )) + Err(NewFileSystemCacheError::ExistsButNoDirectory) } } else { // Create the directory and any parent directories if they don't yet exist. - fs::create_dir_all(&path)?; + mkdir_p(&path).map_err(|_e| NewFileSystemCacheError::CouldntCreatePath)?; Ok(Self { base_path: path, wasmer_module_version, @@ -120,8 +126,9 @@ impl FileSystemCache { /// Stores a serialized module to the file system. Returns the size of the serialized module. pub fn store(&mut self, checksum: &Checksum, module: &Module) -> VmResult<()> { let modules_dir = self.latest_modules_path(); - fs::create_dir_all(&modules_dir) - .map_err(|e| VmError::cache_err(format!("Error creating directory: {}", e)))?; + mkdir_p(&modules_dir) + .map_err(|_e| VmError::cache_err("Error creating modules directory"))?; + let filename = checksum.to_hex(); let path = modules_dir.join(filename); module @@ -142,6 +149,8 @@ impl FileSystemCache { #[cfg(test)] mod tests { + use std::fs; + use super::*; use crate::size::Size; use crate::wasm_backend::{compile, make_runtime_store}; diff --git a/packages/vm/src/modules/mod.rs b/packages/vm/src/modules/mod.rs index c00ebae121..daa0adef11 100644 --- a/packages/vm/src/modules/mod.rs +++ b/packages/vm/src/modules/mod.rs @@ -4,7 +4,7 @@ mod pinned_memory_cache; mod sized_module; mod versioning; -pub use file_system_cache::FileSystemCache; +pub use file_system_cache::{FileSystemCache, NewFileSystemCacheError}; pub use in_memory_cache::InMemoryCache; pub use pinned_memory_cache::PinnedMemoryCache; pub use versioning::current_wasmer_module_version; From 530c979eb0447a8dbfa0254a3710bd41f85f321b Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 30 Aug 2022 16:55:06 +0200 Subject: [PATCH 004/187] Remove system specific detail from error message --- packages/vm/src/cache.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs index 16e9bfea72..b08b9c7c97 100644 --- a/packages/vm/src/cache.rs +++ b/packages/vm/src/cache.rs @@ -351,12 +351,12 @@ fn save_wasm_to_disk(dir: impl Into, wasm: &[u8]) -> VmResult fn load_wasm_from_disk(dir: impl Into, checksum: &Checksum) -> VmResult> { // this requires the directory and file to exist let path = dir.into().join(checksum.to_hex()); - let mut file = File::open(path) - .map_err(|e| VmError::cache_err(format!("Error opening Wasm file for reading: {}", e)))?; + let mut file = + File::open(path).map_err(|_e| VmError::cache_err("Error opening Wasm file for reading"))?; let mut wasm = Vec::::new(); file.read_to_end(&mut wasm) - .map_err(|e| VmError::cache_err(format!("Error reading Wasm file: {}", e)))?; + .map_err(|_e| VmError::cache_err("Error reading Wasm file"))?; Ok(wasm) } @@ -518,8 +518,7 @@ mod tests { match cache.load_wasm(&checksum).unwrap_err() { VmError::CacheErr { msg, .. } => { - assert!(msg - .starts_with("Error opening Wasm file for reading: No such file or directory")) + assert_eq!(msg, "Error opening Wasm file for reading") } e => panic!("Unexpected error: {:?}", e), } From b4316bfa8d36898366bd7ac742a222ca5481e0d8 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 21 Nov 2022 17:23:19 +0100 Subject: [PATCH 005/187] Add CHANGELOG entry --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fffd4fe228..4c6ad45371 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ and this project adheres to ## [Unreleased] +### Changed + +- cosmwasm-vm: Avoid exposing OS specific file system errors in order to test + cosmwasm-vm on Windows. This gives us confidence for integrating cosmwasm-vm + in a libwasmvm build on Windows. This change is likely to be consensus + breaking as error messages change. ([#1406]) + +[#1406]: https://github.com/CosmWasm/cosmwasm/pull/1406 + ## [1.1.6] - 2022-11-16 ### Added From 3c26a3d77c4f5e717f9cb33f191af3f1a2031f1a Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 8 Nov 2022 16:10:14 +0100 Subject: [PATCH 006/187] Add `cosmwasm_1_2 feature` --- packages/std/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 0c792c491e..ee6d84597a 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -36,6 +36,9 @@ ibc3 = ["stargate"] # This feature makes `BankQuery::Supply` available for the contract to call, but requires # the host blockchain to run CosmWasm `1.1.0` or higher. cosmwasm_1_1 = [] +# This feature makes `GovMsg::VoteWeighted` available for the contract to call, but requires +# the host blockchain to run CosmWasm `1.2.0` or higher. +cosmwasm_1_2 = [] [dependencies] base64 = "0.13.0" From 869072e6e8f8fdd277c7d5708d68ed626457da37 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 8 Nov 2022 16:41:27 +0100 Subject: [PATCH 007/187] Add `GovMsg::VoteWeighted` --- packages/std/src/lib.rs | 2 ++ packages/std/src/results/cosmos_msg.rs | 15 +++++++++++++++ packages/std/src/results/mod.rs | 2 ++ 3 files changed, 19 insertions(+) diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 1f37bed1d6..26445f4b55 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -63,6 +63,8 @@ pub use crate::query::{ pub use crate::query::{ChannelResponse, IbcQuery, ListChannelsResponse, PortIdResponse}; #[allow(deprecated)] pub use crate::results::SubMsgExecutionResponse; +#[cfg(all(feature = "stargate", feature = "cosmwasm_1_2"))] +pub use crate::results::WeightedVoteOption; pub use crate::results::{ attr, wasm_execute, wasm_instantiate, Attribute, BankMsg, ContractResult, CosmosMsg, CustomMsg, Empty, Event, QueryResponse, Reply, ReplyOn, Response, SubMsg, SubMsgResponse, SubMsgResult, diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index d72f98ddda..2761ac280b 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -9,6 +9,8 @@ use crate::errors::StdResult; #[cfg(feature = "stargate")] use crate::ibc::IbcMsg; use crate::serde::to_binary; +#[cfg(all(feature = "stargate", feature = "cosmwasm_1_2"))] +use crate::Decimal; use super::Empty; @@ -183,6 +185,12 @@ pub enum WasmMsg { pub enum GovMsg { /// This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address. Vote { proposal_id: u64, vote: VoteOption }, + /// This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address. + #[cfg(feature = "cosmwasm_1_2")] + VoteWeighted { + proposal_id: u64, + vote: WeightedVoteOption, + }, } #[cfg(feature = "stargate")] @@ -195,6 +203,13 @@ pub enum VoteOption { NoWithVeto, } +#[cfg(all(feature = "stargate", feature = "cosmwasm_1_2"))] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct WeightedVoteOption { + option: VoteOption, + weight: Decimal, +} + /// Shortcut helper as the construction of WasmMsg::Instantiate can be quite verbose in contract code. /// /// When using this, `admin` is always unset. If you need more flexibility, create the message directly. diff --git a/packages/std/src/results/mod.rs b/packages/std/src/results/mod.rs index 95dd1dd8ef..90b8879746 100644 --- a/packages/std/src/results/mod.rs +++ b/packages/std/src/results/mod.rs @@ -10,6 +10,8 @@ mod submessages; mod system_result; pub use contract_result::ContractResult; +#[cfg(all(feature = "stargate", feature = "cosmwasm_1_2"))] +pub use cosmos_msg::WeightedVoteOption; pub use cosmos_msg::{wasm_execute, wasm_instantiate, BankMsg, CosmosMsg, CustomMsg, WasmMsg}; #[cfg(feature = "staking")] pub use cosmos_msg::{DistributionMsg, StakingMsg}; From 9a46fe97576cb38a6ba77103f2afb861eef2858b Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 8 Nov 2022 16:47:43 +0100 Subject: [PATCH 008/187] Update CHANGELOG --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c6ad45371..e106965a72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,8 +25,13 @@ and this project adheres to `CanonicalAddr` ([#1463]). - cosmwasm-std: Implement `PartialEq` between `CanonicalAddr` and `HexBinary`/`Binary` ([#1463]). +- cosmwasm-std: Add `GovMsg::VoteWeighted`. In order to use this in a contract, + the `cosmwasm_1_2` feature needs to be enabled for the `cosmwasm_std` + dependency. This makes the contract incompatible with chains running versions + of CosmWasm earlier than 1.2.0 ([#1481]). [#1463]: https://github.com/CosmWasm/cosmwasm/pull/1463 +[#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 ### Changed From e59234e6b27aef17441bfe849293ecb4924a04ef Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 21 Nov 2022 18:01:33 +0100 Subject: [PATCH 009/187] update CHANGELOG --- CHANGELOG.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e106965a72..47cc8557eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ and this project adheres to ## [Unreleased] +### Added + +- cosmwasm-std: Add `GovMsg::VoteWeighted`. In order to use this in a contract, + the `cosmwasm_1_2` feature needs to be enabled for the `cosmwasm_std` + dependency. This makes the contract incompatible with chains running versions + of CosmWasm earlier than 1.2.0 ([#1481]). + +[#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 + ### Changed - cosmwasm-vm: Avoid exposing OS specific file system errors in order to test @@ -25,13 +34,8 @@ and this project adheres to `CanonicalAddr` ([#1463]). - cosmwasm-std: Implement `PartialEq` between `CanonicalAddr` and `HexBinary`/`Binary` ([#1463]). -- cosmwasm-std: Add `GovMsg::VoteWeighted`. In order to use this in a contract, - the `cosmwasm_1_2` feature needs to be enabled for the `cosmwasm_std` - dependency. This makes the contract incompatible with chains running versions - of CosmWasm earlier than 1.2.0 ([#1481]). [#1463]: https://github.com/CosmWasm/cosmwasm/pull/1463 -[#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 ### Changed From 7e117a38fc3bc7084fb7162945b2666d342354b0 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 21 Nov 2022 18:58:56 +0100 Subject: [PATCH 010/187] Add the `cosmwasm_1_2` export --- packages/std/src/exports.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs index a2c986806f..5b4b30925c 100644 --- a/packages/std/src/exports.rs +++ b/packages/std/src/exports.rs @@ -45,6 +45,10 @@ extern "C" fn requires_stargate() -> () {} #[no_mangle] extern "C" fn requires_cosmwasm_1_1() -> () {} +#[cfg(feature = "cosmwasm_1_2")] +#[no_mangle] +extern "C" fn requires_cosmwasm_1_2() -> () {} + /// interface_version_* exports mark which Wasm VM interface level this contract is compiled for. /// They can be checked by cosmwasm_vm. /// Update this whenever the Wasm VM interface breaks. From 2a5951cf88892bc405662dee396781d9eeaf1179 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 7 Nov 2022 20:57:05 +0100 Subject: [PATCH 011/187] schema: Add option to generate separate JSON schema files --- packages/schema-derive/src/generate_api.rs | 37 +++++++++++++++---- packages/schema/src/idl.rs | 42 ++++++++++++++++++++++ 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/packages/schema-derive/src/generate_api.rs b/packages/schema-derive/src/generate_api.rs index f3f8bbcaa8..33064df1de 100644 --- a/packages/schema-derive/src/generate_api.rs +++ b/packages/schema-derive/src/generate_api.rs @@ -15,23 +15,46 @@ pub fn write_api_impl(input: Options) -> Block { { #[cfg(target_arch = "wasm32")] compile_error!("can't compile schema generator for the `wasm32` arch\nhint: are you trying to compile a smart contract without specifying `--lib`?"); - use ::std::env::current_dir; + use ::std::env; use ::std::fs::{create_dir_all, write}; use ::cosmwasm_schema::{remove_schemas, Api, QueryResponses}; - let mut out_dir = current_dir().unwrap(); + if env::args().find(|arg| arg == "--help").is_some() { + println!("USAGE:"); + println!(" cargo schema [OPTIONS]"); + println!(); + println!("FLAGS:"); + println!(" --basic"); + println!(" Generate pure JSON schema files rather than the \"unified\" format."); + println!(" --help"); + println!(" Print this helpfile."); + return; + } + + let basic = env::args().find(|arg| arg == "--basic").is_some(); + + let mut out_dir = env::current_dir().unwrap(); out_dir.push("schema"); create_dir_all(&out_dir).unwrap(); remove_schemas(&out_dir).unwrap(); - let path = out_dir.join(concat!(#name, ".json")); - let api = #api_object.render(); - let json = api.to_string().unwrap(); - write(&path, json + "\n").unwrap(); - println!("Exported the full API as {}", path.to_str().unwrap()); + if basic { + for (filename, json) in api.to_schema_files().unwrap() { + let path = out_dir.join(filename); + + write(&path, json + "\n").unwrap(); + println!("Exported {}", path.to_str().unwrap()); + } + } else { + let path = out_dir.join(concat!(#name, ".json")); + + let json = api.to_string().unwrap(); + write(&path, json + "\n").unwrap(); + println!("Exported the full API as {}", path.to_str().unwrap()); + } } } } diff --git a/packages/schema/src/idl.rs b/packages/schema/src/idl.rs index 8297d6f191..ec2c5478aa 100644 --- a/packages/schema/src/idl.rs +++ b/packages/schema/src/idl.rs @@ -85,6 +85,48 @@ impl JsonApi { serde_json::to_string_pretty(&self).map_err(Into::into) } + pub fn to_schema_files(&self) -> Result, EncodeError> { + let mut result = vec![( + "instantiate.json".to_string(), + serde_json::to_string_pretty(&self.instantiate)?, + )]; + + if let Some(execute) = &self.execute { + result.push(( + "execute.json".to_string(), + serde_json::to_string_pretty(&execute)?, + )); + } + if let Some(query) = &self.execute { + result.push(( + "query.json".to_string(), + serde_json::to_string_pretty(&query)?, + )); + } + if let Some(migrate) = &self.execute { + result.push(( + "migrate.json".to_string(), + serde_json::to_string_pretty(&migrate)?, + )); + } + if let Some(sudo) = &self.execute { + result.push(( + "sudo.json".to_string(), + serde_json::to_string_pretty(&sudo)?, + )); + } + if let Some(responses) = &self.responses { + for (name, response) in responses { + result.push(( + format!("response_to_{}.json", name), + serde_json::to_string_pretty(&response)?, + )); + } + } + + Ok(result) + } + pub fn to_writer(&self, writer: impl std::io::Write) -> Result<(), EncodeError> { serde_json::to_writer_pretty(writer, self).map_err(Into::into) } From c15d57dc2d6a92b8edb1aa792035e4ecd40f862f Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 8 Nov 2022 12:12:28 +0100 Subject: [PATCH 012/187] CHANGELOG update --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47cc8557eb..7b1f062f2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,9 @@ and this project adheres to `CanonicalAddr` ([#1463]). - cosmwasm-std: Implement `PartialEq` between `CanonicalAddr` and `HexBinary`/`Binary` ([#1463]). +- cosmwasm-schema: In contracts, `cosmwasm schema` now accepts the `--basic` + flag. This will output a separate JSON Schema file for each entrypoint, + similar to the old way. No unified file is produced this way. [#1463]: https://github.com/CosmWasm/cosmwasm/pull/1463 From afc2a7e184120027da420ae65e3efd6e4b520fd8 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 22 Nov 2022 00:32:34 +0100 Subject: [PATCH 013/187] make schema gen export raw schemas by default --- CHANGELOG.md | 5 +- contracts/burner/schema/raw/instantiate.json | 7 + .../crypto-verify/schema/raw/instantiate.json | 6 + ...response_to_list_verification_schemes.json | 17 + .../response_to_verify_cosmos_signature.json | 14 + .../raw/response_to_verify_ethereum_text.json | 14 + ...sponse_to_verify_ethereum_transaction.json | 14 + .../response_to_verify_tendermint_batch.json | 14 + ...sponse_to_verify_tendermint_signature.json | 14 + contracts/cyberpunk/schema/raw/execute.json | 52 ++ .../cyberpunk/schema/raw/instantiate.json | 6 + contracts/cyberpunk/schema/raw/migrate.json | 52 ++ contracts/cyberpunk/schema/raw/query.json | 52 ++ .../schema/raw/response_to_mirror_env.json | 98 ++ contracts/cyberpunk/schema/raw/sudo.json | 52 ++ contracts/floaty/schema/raw/execute.json | 20 + contracts/floaty/schema/raw/instantiate.json | 18 + contracts/floaty/schema/raw/migrate.json | 20 + contracts/floaty/schema/raw/query.json | 20 + .../schema/raw/response_to_other_balance.json | 38 + .../schema/raw/response_to_verifier.json | 14 + contracts/floaty/schema/raw/sudo.json | 20 + contracts/hackatom/schema/raw/execute.json | 128 +++ .../hackatom/schema/raw/instantiate.json | 18 + contracts/hackatom/schema/raw/migrate.json | 128 +++ contracts/hackatom/schema/raw/query.json | 128 +++ .../schema/raw/response_to_get_int.json | 16 + .../schema/raw/response_to_other_balance.json | 38 + .../schema/raw/response_to_recurse.json | 25 + .../schema/raw/response_to_verifier.json | 14 + contracts/hackatom/schema/raw/sudo.json | 128 +++ .../ibc-reflect-send/schema/raw/execute.json | 817 +++++++++++++++++ .../schema/raw/instantiate.json | 7 + .../ibc-reflect-send/schema/raw/migrate.json | 817 +++++++++++++++++ .../ibc-reflect-send/schema/raw/query.json | 817 +++++++++++++++++ .../schema/raw/response_to_account.json | 70 ++ .../schema/raw/response_to_admin.json | 14 + .../schema/raw/response_to_list_accounts.json | 85 ++ .../ibc-reflect-send/schema/raw/sudo.json | 817 +++++++++++++++++ .../ibc-reflect/schema/raw/instantiate.json | 17 + .../schema/raw/response_to_account.json | 14 + .../schema/raw/response_to_list_accounts.json | 35 + contracts/queue/schema/raw/execute.json | 41 + contracts/queue/schema/raw/instantiate.json | 6 + contracts/queue/schema/raw/migrate.json | 41 + contracts/queue/schema/raw/query.json | 41 + .../queue/schema/raw/response_to_count.json | 16 + .../queue/schema/raw/response_to_list.json | 40 + .../raw/response_to_open_iterators.json | 6 + .../queue/schema/raw/response_to_reducer.json | 29 + .../queue/schema/raw/response_to_sum.json | 15 + contracts/queue/schema/raw/sudo.json | 41 + contracts/reflect/schema/raw/execute.json | 854 ++++++++++++++++++ contracts/reflect/schema/raw/instantiate.json | 6 + contracts/reflect/schema/raw/migrate.json | 854 ++++++++++++++++++ contracts/reflect/schema/raw/query.json | 854 ++++++++++++++++++ .../schema/raw/response_to_capitalized.json | 14 + .../reflect/schema/raw/response_to_chain.json | 20 + .../reflect/schema/raw/response_to_owner.json | 14 + .../reflect/schema/raw/response_to_raw.json | 25 + .../raw/response_to_sub_msg_result.json | 119 +++ contracts/reflect/schema/raw/sudo.json | 854 ++++++++++++++++++ contracts/staking/schema/raw/execute.json | 116 +++ contracts/staking/schema/raw/instantiate.json | 60 ++ contracts/staking/schema/raw/migrate.json | 116 +++ contracts/staking/schema/raw/query.json | 116 +++ .../schema/raw/response_to_balance.json | 20 + .../schema/raw/response_to_claims.json | 20 + .../schema/raw/response_to_investment.json | 75 ++ .../schema/raw/response_to_token_info.json | 28 + contracts/staking/schema/raw/sudo.json | 116 +++ packages/schema-derive/src/generate_api.rs | 36 +- 72 files changed, 9266 insertions(+), 27 deletions(-) create mode 100644 contracts/burner/schema/raw/instantiate.json create mode 100644 contracts/crypto-verify/schema/raw/instantiate.json create mode 100644 contracts/crypto-verify/schema/raw/response_to_list_verification_schemes.json create mode 100644 contracts/crypto-verify/schema/raw/response_to_verify_cosmos_signature.json create mode 100644 contracts/crypto-verify/schema/raw/response_to_verify_ethereum_text.json create mode 100644 contracts/crypto-verify/schema/raw/response_to_verify_ethereum_transaction.json create mode 100644 contracts/crypto-verify/schema/raw/response_to_verify_tendermint_batch.json create mode 100644 contracts/crypto-verify/schema/raw/response_to_verify_tendermint_signature.json create mode 100644 contracts/cyberpunk/schema/raw/execute.json create mode 100644 contracts/cyberpunk/schema/raw/instantiate.json create mode 100644 contracts/cyberpunk/schema/raw/migrate.json create mode 100644 contracts/cyberpunk/schema/raw/query.json create mode 100644 contracts/cyberpunk/schema/raw/response_to_mirror_env.json create mode 100644 contracts/cyberpunk/schema/raw/sudo.json create mode 100644 contracts/floaty/schema/raw/execute.json create mode 100644 contracts/floaty/schema/raw/instantiate.json create mode 100644 contracts/floaty/schema/raw/migrate.json create mode 100644 contracts/floaty/schema/raw/query.json create mode 100644 contracts/floaty/schema/raw/response_to_other_balance.json create mode 100644 contracts/floaty/schema/raw/response_to_verifier.json create mode 100644 contracts/floaty/schema/raw/sudo.json create mode 100644 contracts/hackatom/schema/raw/execute.json create mode 100644 contracts/hackatom/schema/raw/instantiate.json create mode 100644 contracts/hackatom/schema/raw/migrate.json create mode 100644 contracts/hackatom/schema/raw/query.json create mode 100644 contracts/hackatom/schema/raw/response_to_get_int.json create mode 100644 contracts/hackatom/schema/raw/response_to_other_balance.json create mode 100644 contracts/hackatom/schema/raw/response_to_recurse.json create mode 100644 contracts/hackatom/schema/raw/response_to_verifier.json create mode 100644 contracts/hackatom/schema/raw/sudo.json create mode 100644 contracts/ibc-reflect-send/schema/raw/execute.json create mode 100644 contracts/ibc-reflect-send/schema/raw/instantiate.json create mode 100644 contracts/ibc-reflect-send/schema/raw/migrate.json create mode 100644 contracts/ibc-reflect-send/schema/raw/query.json create mode 100644 contracts/ibc-reflect-send/schema/raw/response_to_account.json create mode 100644 contracts/ibc-reflect-send/schema/raw/response_to_admin.json create mode 100644 contracts/ibc-reflect-send/schema/raw/response_to_list_accounts.json create mode 100644 contracts/ibc-reflect-send/schema/raw/sudo.json create mode 100644 contracts/ibc-reflect/schema/raw/instantiate.json create mode 100644 contracts/ibc-reflect/schema/raw/response_to_account.json create mode 100644 contracts/ibc-reflect/schema/raw/response_to_list_accounts.json create mode 100644 contracts/queue/schema/raw/execute.json create mode 100644 contracts/queue/schema/raw/instantiate.json create mode 100644 contracts/queue/schema/raw/migrate.json create mode 100644 contracts/queue/schema/raw/query.json create mode 100644 contracts/queue/schema/raw/response_to_count.json create mode 100644 contracts/queue/schema/raw/response_to_list.json create mode 100644 contracts/queue/schema/raw/response_to_open_iterators.json create mode 100644 contracts/queue/schema/raw/response_to_reducer.json create mode 100644 contracts/queue/schema/raw/response_to_sum.json create mode 100644 contracts/queue/schema/raw/sudo.json create mode 100644 contracts/reflect/schema/raw/execute.json create mode 100644 contracts/reflect/schema/raw/instantiate.json create mode 100644 contracts/reflect/schema/raw/migrate.json create mode 100644 contracts/reflect/schema/raw/query.json create mode 100644 contracts/reflect/schema/raw/response_to_capitalized.json create mode 100644 contracts/reflect/schema/raw/response_to_chain.json create mode 100644 contracts/reflect/schema/raw/response_to_owner.json create mode 100644 contracts/reflect/schema/raw/response_to_raw.json create mode 100644 contracts/reflect/schema/raw/response_to_sub_msg_result.json create mode 100644 contracts/reflect/schema/raw/sudo.json create mode 100644 contracts/staking/schema/raw/execute.json create mode 100644 contracts/staking/schema/raw/instantiate.json create mode 100644 contracts/staking/schema/raw/migrate.json create mode 100644 contracts/staking/schema/raw/query.json create mode 100644 contracts/staking/schema/raw/response_to_balance.json create mode 100644 contracts/staking/schema/raw/response_to_claims.json create mode 100644 contracts/staking/schema/raw/response_to_investment.json create mode 100644 contracts/staking/schema/raw/response_to_token_info.json create mode 100644 contracts/staking/schema/raw/sudo.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b1f062f2f..1c28ed4589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to the `cosmwasm_1_2` feature needs to be enabled for the `cosmwasm_std` dependency. This makes the contract incompatible with chains running versions of CosmWasm earlier than 1.2.0 ([#1481]). +- cosmwasm-schema: In contracts, `cosmwasm schema` will now output a separate + JSON Schema file for each entrypoint in the `raw` subdirectory. [#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 @@ -34,9 +36,6 @@ and this project adheres to `CanonicalAddr` ([#1463]). - cosmwasm-std: Implement `PartialEq` between `CanonicalAddr` and `HexBinary`/`Binary` ([#1463]). -- cosmwasm-schema: In contracts, `cosmwasm schema` now accepts the `--basic` - flag. This will output a separate JSON Schema file for each entrypoint, - similar to the old way. No unified file is produced this way. [#1463]: https://github.com/CosmWasm/cosmwasm/pull/1463 diff --git a/contracts/burner/schema/raw/instantiate.json b/contracts/burner/schema/raw/instantiate.json new file mode 100644 index 0000000000..b055cda393 --- /dev/null +++ b/contracts/burner/schema/raw/instantiate.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "description": "A placeholder where we don't take any input", + "type": "object", + "additionalProperties": false +} diff --git a/contracts/crypto-verify/schema/raw/instantiate.json b/contracts/crypto-verify/schema/raw/instantiate.json new file mode 100644 index 0000000000..1352613d57 --- /dev/null +++ b/contracts/crypto-verify/schema/raw/instantiate.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "additionalProperties": false +} diff --git a/contracts/crypto-verify/schema/raw/response_to_list_verification_schemes.json b/contracts/crypto-verify/schema/raw/response_to_list_verification_schemes.json new file mode 100644 index 0000000000..26fa42ab41 --- /dev/null +++ b/contracts/crypto-verify/schema/raw/response_to_list_verification_schemes.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ListVerificationsResponse", + "type": "object", + "required": [ + "verification_schemes" + ], + "properties": { + "verification_schemes": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false +} diff --git a/contracts/crypto-verify/schema/raw/response_to_verify_cosmos_signature.json b/contracts/crypto-verify/schema/raw/response_to_verify_cosmos_signature.json new file mode 100644 index 0000000000..a2cdc3461c --- /dev/null +++ b/contracts/crypto-verify/schema/raw/response_to_verify_cosmos_signature.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VerifyResponse", + "type": "object", + "required": [ + "verifies" + ], + "properties": { + "verifies": { + "type": "boolean" + } + }, + "additionalProperties": false +} diff --git a/contracts/crypto-verify/schema/raw/response_to_verify_ethereum_text.json b/contracts/crypto-verify/schema/raw/response_to_verify_ethereum_text.json new file mode 100644 index 0000000000..a2cdc3461c --- /dev/null +++ b/contracts/crypto-verify/schema/raw/response_to_verify_ethereum_text.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VerifyResponse", + "type": "object", + "required": [ + "verifies" + ], + "properties": { + "verifies": { + "type": "boolean" + } + }, + "additionalProperties": false +} diff --git a/contracts/crypto-verify/schema/raw/response_to_verify_ethereum_transaction.json b/contracts/crypto-verify/schema/raw/response_to_verify_ethereum_transaction.json new file mode 100644 index 0000000000..a2cdc3461c --- /dev/null +++ b/contracts/crypto-verify/schema/raw/response_to_verify_ethereum_transaction.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VerifyResponse", + "type": "object", + "required": [ + "verifies" + ], + "properties": { + "verifies": { + "type": "boolean" + } + }, + "additionalProperties": false +} diff --git a/contracts/crypto-verify/schema/raw/response_to_verify_tendermint_batch.json b/contracts/crypto-verify/schema/raw/response_to_verify_tendermint_batch.json new file mode 100644 index 0000000000..a2cdc3461c --- /dev/null +++ b/contracts/crypto-verify/schema/raw/response_to_verify_tendermint_batch.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VerifyResponse", + "type": "object", + "required": [ + "verifies" + ], + "properties": { + "verifies": { + "type": "boolean" + } + }, + "additionalProperties": false +} diff --git a/contracts/crypto-verify/schema/raw/response_to_verify_tendermint_signature.json b/contracts/crypto-verify/schema/raw/response_to_verify_tendermint_signature.json new file mode 100644 index 0000000000..a2cdc3461c --- /dev/null +++ b/contracts/crypto-verify/schema/raw/response_to_verify_tendermint_signature.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VerifyResponse", + "type": "object", + "required": [ + "verifies" + ], + "properties": { + "verifies": { + "type": "boolean" + } + }, + "additionalProperties": false +} diff --git a/contracts/cyberpunk/schema/raw/execute.json b/contracts/cyberpunk/schema/raw/execute.json new file mode 100644 index 0000000000..8e7af5fe3c --- /dev/null +++ b/contracts/cyberpunk/schema/raw/execute.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Hashes some data. Uses CPU and memory, but no external calls.", + "type": "object", + "required": [ + "argon2" + ], + "properties": { + "argon2": { + "type": "object", + "required": [ + "mem_cost", + "time_cost" + ], + "properties": { + "mem_cost": { + "description": "The amount of memory requested (KB).", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "time_cost": { + "description": "The number of passes.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns the env for testing", + "type": "object", + "required": [ + "mirror_env" + ], + "properties": { + "mirror_env": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/cyberpunk/schema/raw/instantiate.json b/contracts/cyberpunk/schema/raw/instantiate.json new file mode 100644 index 0000000000..5f6dfaf43c --- /dev/null +++ b/contracts/cyberpunk/schema/raw/instantiate.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" +} diff --git a/contracts/cyberpunk/schema/raw/migrate.json b/contracts/cyberpunk/schema/raw/migrate.json new file mode 100644 index 0000000000..8e7af5fe3c --- /dev/null +++ b/contracts/cyberpunk/schema/raw/migrate.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Hashes some data. Uses CPU and memory, but no external calls.", + "type": "object", + "required": [ + "argon2" + ], + "properties": { + "argon2": { + "type": "object", + "required": [ + "mem_cost", + "time_cost" + ], + "properties": { + "mem_cost": { + "description": "The amount of memory requested (KB).", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "time_cost": { + "description": "The number of passes.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns the env for testing", + "type": "object", + "required": [ + "mirror_env" + ], + "properties": { + "mirror_env": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/cyberpunk/schema/raw/query.json b/contracts/cyberpunk/schema/raw/query.json new file mode 100644 index 0000000000..8e7af5fe3c --- /dev/null +++ b/contracts/cyberpunk/schema/raw/query.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Hashes some data. Uses CPU and memory, but no external calls.", + "type": "object", + "required": [ + "argon2" + ], + "properties": { + "argon2": { + "type": "object", + "required": [ + "mem_cost", + "time_cost" + ], + "properties": { + "mem_cost": { + "description": "The amount of memory requested (KB).", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "time_cost": { + "description": "The number of passes.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns the env for testing", + "type": "object", + "required": [ + "mirror_env" + ], + "properties": { + "mirror_env": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/cyberpunk/schema/raw/response_to_mirror_env.json b/contracts/cyberpunk/schema/raw/response_to_mirror_env.json new file mode 100644 index 0000000000..a14d618225 --- /dev/null +++ b/contracts/cyberpunk/schema/raw/response_to_mirror_env.json @@ -0,0 +1,98 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Env", + "type": "object", + "required": [ + "block", + "contract" + ], + "properties": { + "block": { + "$ref": "#/definitions/BlockInfo" + }, + "contract": { + "$ref": "#/definitions/ContractInfo" + }, + "transaction": { + "description": "Information on the transaction this message was executed in. The field is unset when the `MsgExecuteContract`/`MsgInstantiateContract`/`MsgMigrateContract` is not executed as part of a transaction.", + "anyOf": [ + { + "$ref": "#/definitions/TransactionInfo" + }, + { + "type": "null" + } + ] + } + }, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + }, + "BlockInfo": { + "type": "object", + "required": [ + "chain_id", + "height", + "time" + ], + "properties": { + "chain_id": { + "type": "string" + }, + "height": { + "description": "The height of a block is the number of blocks preceding it in the blockchain.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "time": { + "description": "Absolute time of the block creation in seconds since the UNIX epoch (00:00:00 on 1970-01-01 UTC).\n\nThe source of this is the [BFT Time in Tendermint](https://github.com/tendermint/tendermint/blob/58dc1726/spec/consensus/bft-time.md), which has the same nanosecond precision as the `Timestamp` type.\n\n# Examples\n\nUsing chrono:\n\n``` # use cosmwasm_std::{Addr, BlockInfo, ContractInfo, Env, MessageInfo, Timestamp, TransactionInfo}; # let env = Env { # block: BlockInfo { # height: 12_345, # time: Timestamp::from_nanos(1_571_797_419_879_305_533), # chain_id: \"cosmos-testnet-14002\".to_string(), # }, # transaction: Some(TransactionInfo { index: 3 }), # contract: ContractInfo { # address: Addr::unchecked(\"contract\"), # }, # }; # extern crate chrono; use chrono::NaiveDateTime; let seconds = env.block.time.seconds(); let nsecs = env.block.time.subsec_nanos(); let dt = NaiveDateTime::from_timestamp(seconds as i64, nsecs as u32); ```\n\nCreating a simple millisecond-precision timestamp (as used in JavaScript):\n\n``` # use cosmwasm_std::{Addr, BlockInfo, ContractInfo, Env, MessageInfo, Timestamp, TransactionInfo}; # let env = Env { # block: BlockInfo { # height: 12_345, # time: Timestamp::from_nanos(1_571_797_419_879_305_533), # chain_id: \"cosmos-testnet-14002\".to_string(), # }, # transaction: Some(TransactionInfo { index: 3 }), # contract: ContractInfo { # address: Addr::unchecked(\"contract\"), # }, # }; let millis = env.block.time.nanos() / 1_000_000; ```", + "allOf": [ + { + "$ref": "#/definitions/Timestamp" + } + ] + } + } + }, + "ContractInfo": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "$ref": "#/definitions/Addr" + } + } + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "TransactionInfo": { + "type": "object", + "required": [ + "index" + ], + "properties": { + "index": { + "description": "The position of this transaction in the block. The first transaction has index 0.\n\nThis allows you to get a unique transaction indentifier in this chain using the pair (`env.block.height`, `env.transaction.index`).", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/cyberpunk/schema/raw/sudo.json b/contracts/cyberpunk/schema/raw/sudo.json new file mode 100644 index 0000000000..8e7af5fe3c --- /dev/null +++ b/contracts/cyberpunk/schema/raw/sudo.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Hashes some data. Uses CPU and memory, but no external calls.", + "type": "object", + "required": [ + "argon2" + ], + "properties": { + "argon2": { + "type": "object", + "required": [ + "mem_cost", + "time_cost" + ], + "properties": { + "mem_cost": { + "description": "The amount of memory requested (KB).", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "time_cost": { + "description": "The number of passes.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns the env for testing", + "type": "object", + "required": [ + "mirror_env" + ], + "properties": { + "mirror_env": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/floaty/schema/raw/execute.json b/contracts/floaty/schema/raw/execute.json new file mode 100644 index 0000000000..76967fd17b --- /dev/null +++ b/contracts/floaty/schema/raw/execute.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "type": "object", + "required": [ + "release" + ], + "properties": { + "release": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/floaty/schema/raw/instantiate.json b/contracts/floaty/schema/raw/instantiate.json new file mode 100644 index 0000000000..8639103d34 --- /dev/null +++ b/contracts/floaty/schema/raw/instantiate.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "required": [ + "beneficiary", + "verifier" + ], + "properties": { + "beneficiary": { + "type": "string" + }, + "verifier": { + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/floaty/schema/raw/migrate.json b/contracts/floaty/schema/raw/migrate.json new file mode 100644 index 0000000000..76967fd17b --- /dev/null +++ b/contracts/floaty/schema/raw/migrate.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "type": "object", + "required": [ + "release" + ], + "properties": { + "release": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/floaty/schema/raw/query.json b/contracts/floaty/schema/raw/query.json new file mode 100644 index 0000000000..76967fd17b --- /dev/null +++ b/contracts/floaty/schema/raw/query.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "type": "object", + "required": [ + "release" + ], + "properties": { + "release": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/floaty/schema/raw/response_to_other_balance.json b/contracts/floaty/schema/raw/response_to_other_balance.json new file mode 100644 index 0000000000..20f0a47f1c --- /dev/null +++ b/contracts/floaty/schema/raw/response_to_other_balance.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AllBalanceResponse", + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "description": "Returns all non-zero coins held by this account.", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + }, + "definitions": { + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/floaty/schema/raw/response_to_verifier.json b/contracts/floaty/schema/raw/response_to_verifier.json new file mode 100644 index 0000000000..fb04c86d67 --- /dev/null +++ b/contracts/floaty/schema/raw/response_to_verifier.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VerifierResponse", + "type": "object", + "required": [ + "verifier" + ], + "properties": { + "verifier": { + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/floaty/schema/raw/sudo.json b/contracts/floaty/schema/raw/sudo.json new file mode 100644 index 0000000000..76967fd17b --- /dev/null +++ b/contracts/floaty/schema/raw/sudo.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "type": "object", + "required": [ + "release" + ], + "properties": { + "release": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/hackatom/schema/raw/execute.json b/contracts/hackatom/schema/raw/execute.json new file mode 100644 index 0000000000..a82fdeef2d --- /dev/null +++ b/contracts/hackatom/schema/raw/execute.json @@ -0,0 +1,128 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "type": "object", + "required": [ + "release" + ], + "properties": { + "release": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)", + "type": "object", + "required": [ + "cpu_loop" + ], + "properties": { + "cpu_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop making storage calls (to test when their limit hits)", + "type": "object", + "required": [ + "storage_loop" + ], + "properties": { + "storage_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop reading and writing memory", + "type": "object", + "required": [ + "memory_loop" + ], + "properties": { + "memory_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop sending message to itself", + "type": "object", + "required": [ + "message_loop" + ], + "properties": { + "message_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Allocate large amounts of memory without consuming much gas", + "type": "object", + "required": [ + "allocate_large_memory" + ], + "properties": { + "allocate_large_memory": { + "type": "object", + "required": [ + "pages" + ], + "properties": { + "pages": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Trigger a panic to ensure framework handles gracefully", + "type": "object", + "required": [ + "panic" + ], + "properties": { + "panic": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Starting with CosmWasm 0.10, some API calls return user errors back to the contract. This triggers such user errors, ensuring the transaction does not fail in the backend.", + "type": "object", + "required": [ + "user_errors_in_api_calls" + ], + "properties": { + "user_errors_in_api_calls": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/hackatom/schema/raw/instantiate.json b/contracts/hackatom/schema/raw/instantiate.json new file mode 100644 index 0000000000..8639103d34 --- /dev/null +++ b/contracts/hackatom/schema/raw/instantiate.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "required": [ + "beneficiary", + "verifier" + ], + "properties": { + "beneficiary": { + "type": "string" + }, + "verifier": { + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/hackatom/schema/raw/migrate.json b/contracts/hackatom/schema/raw/migrate.json new file mode 100644 index 0000000000..a82fdeef2d --- /dev/null +++ b/contracts/hackatom/schema/raw/migrate.json @@ -0,0 +1,128 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "type": "object", + "required": [ + "release" + ], + "properties": { + "release": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)", + "type": "object", + "required": [ + "cpu_loop" + ], + "properties": { + "cpu_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop making storage calls (to test when their limit hits)", + "type": "object", + "required": [ + "storage_loop" + ], + "properties": { + "storage_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop reading and writing memory", + "type": "object", + "required": [ + "memory_loop" + ], + "properties": { + "memory_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop sending message to itself", + "type": "object", + "required": [ + "message_loop" + ], + "properties": { + "message_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Allocate large amounts of memory without consuming much gas", + "type": "object", + "required": [ + "allocate_large_memory" + ], + "properties": { + "allocate_large_memory": { + "type": "object", + "required": [ + "pages" + ], + "properties": { + "pages": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Trigger a panic to ensure framework handles gracefully", + "type": "object", + "required": [ + "panic" + ], + "properties": { + "panic": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Starting with CosmWasm 0.10, some API calls return user errors back to the contract. This triggers such user errors, ensuring the transaction does not fail in the backend.", + "type": "object", + "required": [ + "user_errors_in_api_calls" + ], + "properties": { + "user_errors_in_api_calls": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/hackatom/schema/raw/query.json b/contracts/hackatom/schema/raw/query.json new file mode 100644 index 0000000000..a82fdeef2d --- /dev/null +++ b/contracts/hackatom/schema/raw/query.json @@ -0,0 +1,128 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "type": "object", + "required": [ + "release" + ], + "properties": { + "release": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)", + "type": "object", + "required": [ + "cpu_loop" + ], + "properties": { + "cpu_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop making storage calls (to test when their limit hits)", + "type": "object", + "required": [ + "storage_loop" + ], + "properties": { + "storage_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop reading and writing memory", + "type": "object", + "required": [ + "memory_loop" + ], + "properties": { + "memory_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop sending message to itself", + "type": "object", + "required": [ + "message_loop" + ], + "properties": { + "message_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Allocate large amounts of memory without consuming much gas", + "type": "object", + "required": [ + "allocate_large_memory" + ], + "properties": { + "allocate_large_memory": { + "type": "object", + "required": [ + "pages" + ], + "properties": { + "pages": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Trigger a panic to ensure framework handles gracefully", + "type": "object", + "required": [ + "panic" + ], + "properties": { + "panic": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Starting with CosmWasm 0.10, some API calls return user errors back to the contract. This triggers such user errors, ensuring the transaction does not fail in the backend.", + "type": "object", + "required": [ + "user_errors_in_api_calls" + ], + "properties": { + "user_errors_in_api_calls": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/hackatom/schema/raw/response_to_get_int.json b/contracts/hackatom/schema/raw/response_to_get_int.json new file mode 100644 index 0000000000..018fd695e1 --- /dev/null +++ b/contracts/hackatom/schema/raw/response_to_get_int.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "IntResponse", + "type": "object", + "required": [ + "int" + ], + "properties": { + "int": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false +} diff --git a/contracts/hackatom/schema/raw/response_to_other_balance.json b/contracts/hackatom/schema/raw/response_to_other_balance.json new file mode 100644 index 0000000000..20f0a47f1c --- /dev/null +++ b/contracts/hackatom/schema/raw/response_to_other_balance.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AllBalanceResponse", + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "description": "Returns all non-zero coins held by this account.", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + }, + "definitions": { + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/hackatom/schema/raw/response_to_recurse.json b/contracts/hackatom/schema/raw/response_to_recurse.json new file mode 100644 index 0000000000..3d50847ef9 --- /dev/null +++ b/contracts/hackatom/schema/raw/response_to_recurse.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "RecurseResponse", + "type": "object", + "required": [ + "hashed" + ], + "properties": { + "hashed": { + "description": "hashed is the result of running sha256 \"work+1\" times on the contract's human address", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + } + } +} diff --git a/contracts/hackatom/schema/raw/response_to_verifier.json b/contracts/hackatom/schema/raw/response_to_verifier.json new file mode 100644 index 0000000000..fb04c86d67 --- /dev/null +++ b/contracts/hackatom/schema/raw/response_to_verifier.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VerifierResponse", + "type": "object", + "required": [ + "verifier" + ], + "properties": { + "verifier": { + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/hackatom/schema/raw/sudo.json b/contracts/hackatom/schema/raw/sudo.json new file mode 100644 index 0000000000..a82fdeef2d --- /dev/null +++ b/contracts/hackatom/schema/raw/sudo.json @@ -0,0 +1,128 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "type": "object", + "required": [ + "release" + ], + "properties": { + "release": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)", + "type": "object", + "required": [ + "cpu_loop" + ], + "properties": { + "cpu_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop making storage calls (to test when their limit hits)", + "type": "object", + "required": [ + "storage_loop" + ], + "properties": { + "storage_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop reading and writing memory", + "type": "object", + "required": [ + "memory_loop" + ], + "properties": { + "memory_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop sending message to itself", + "type": "object", + "required": [ + "message_loop" + ], + "properties": { + "message_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Allocate large amounts of memory without consuming much gas", + "type": "object", + "required": [ + "allocate_large_memory" + ], + "properties": { + "allocate_large_memory": { + "type": "object", + "required": [ + "pages" + ], + "properties": { + "pages": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Trigger a panic to ensure framework handles gracefully", + "type": "object", + "required": [ + "panic" + ], + "properties": { + "panic": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Starting with CosmWasm 0.10, some API calls return user errors back to the contract. This triggers such user errors, ensuring the transaction does not fail in the backend.", + "type": "object", + "required": [ + "user_errors_in_api_calls" + ], + "properties": { + "user_errors_in_api_calls": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/ibc-reflect-send/schema/raw/execute.json b/contracts/ibc-reflect-send/schema/raw/execute.json new file mode 100644 index 0000000000..e08109d489 --- /dev/null +++ b/contracts/ibc-reflect-send/schema/raw/execute.json @@ -0,0 +1,817 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Changes the admin", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "send_msgs" + ], + "properties": { + "send_msgs": { + "type": "object", + "required": [ + "channel_id", + "msgs" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/CosmosMsg_for_Empty" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "check_remote_balance" + ], + "properties": { + "check_remote_balance": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "If you sent funds to this contract, it will attempt to ibc transfer them to the account on the remote side of this channel. If we don't have the address yet, this fails.", + "type": "object", + "required": [ + "send_funds" + ], + "properties": { + "send_funds": { + "type": "object", + "required": [ + "reflect_channel_id", + "transfer_channel_id" + ], + "properties": { + "reflect_channel_id": { + "description": "The channel id we use above to talk with the reflect contract", + "type": "string" + }, + "transfer_channel_id": { + "description": "The channel to use for ibctransfer. This is bound to a different port and handled by a different module. It should connect to the same chain as the reflect_channel_id does", + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "BankMsg": { + "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "oneOf": [ + { + "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "to_address" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "to_address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "CosmosMsg_for_Empty": { + "oneOf": [ + { + "type": "object", + "required": [ + "bank" + ], + "properties": { + "bank": { + "$ref": "#/definitions/BankMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "$ref": "#/definitions/Empty" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "staking" + ], + "properties": { + "staking": { + "$ref": "#/definitions/StakingMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "distribution" + ], + "properties": { + "distribution": { + "$ref": "#/definitions/DistributionMsg" + } + }, + "additionalProperties": false + }, + { + "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", + "type": "object", + "required": [ + "stargate" + ], + "properties": { + "stargate": { + "type": "object", + "required": [ + "type_url", + "value" + ], + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "ibc" + ], + "properties": { + "ibc": { + "$ref": "#/definitions/IbcMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "wasm" + ], + "properties": { + "wasm": { + "$ref": "#/definitions/WasmMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "gov" + ], + "properties": { + "gov": { + "$ref": "#/definitions/GovMsg" + } + }, + "additionalProperties": false + } + ] + }, + "DistributionMsg": { + "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "set_withdraw_address" + ], + "properties": { + "set_withdraw_address": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The `withdraw_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "withdraw_delegator_reward" + ], + "properties": { + "withdraw_delegator_reward": { + "type": "object", + "required": [ + "validator" + ], + "properties": { + "validator": { + "description": "The `validator_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Empty": { + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + }, + "GovMsg": { + "oneOf": [ + { + "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "vote" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vote": { + "$ref": "#/definitions/VoteOption" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcMsg": { + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "oneOf": [ + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "channel_id", + "timeout", + "to_address" + ], + "properties": { + "amount": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + }, + "channel_id": { + "description": "exisiting channel to send the tokens over", + "type": "string" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", + "type": "object", + "required": [ + "send_packet" + ], + "properties": { + "send_packet": { + "type": "object", + "required": [ + "channel_id", + "data", + "timeout" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/Binary" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", + "type": "object", + "required": [ + "close_channel" + ], + "properties": { + "close_channel": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "StakingMsg": { + "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "undelegate" + ], + "properties": { + "undelegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "redelegate" + ], + "properties": { + "redelegate": { + "type": "object", + "required": [ + "amount", + "dst_validator", + "src_validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "dst_validator": { + "type": "string" + }, + "src_validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + }, + "VoteOption": { + "type": "string", + "enum": [ + "yes", + "no", + "abstain", + "no_with_veto" + ] + }, + "WasmMsg": { + "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", + "oneOf": [ + { + "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "contract_addr", + "funds", + "msg" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "msg": { + "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "instantiate" + ], + "properties": { + "instantiate": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readbale label for the contract", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "migrate" + ], + "properties": { + "migrate": { + "type": "object", + "required": [ + "contract_addr", + "msg", + "new_code_id" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "msg": { + "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "new_code_id": { + "description": "the code_id of the new logic to place in the given contract", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin", + "contract_addr" + ], + "properties": { + "admin": { + "type": "string" + }, + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "clear_admin" + ], + "properties": { + "clear_admin": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/ibc-reflect-send/schema/raw/instantiate.json b/contracts/ibc-reflect-send/schema/raw/instantiate.json new file mode 100644 index 0000000000..4eb2ede310 --- /dev/null +++ b/contracts/ibc-reflect-send/schema/raw/instantiate.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "description": "This needs no info. Owner of the contract is whoever signed the InstantiateMsg.", + "type": "object", + "additionalProperties": false +} diff --git a/contracts/ibc-reflect-send/schema/raw/migrate.json b/contracts/ibc-reflect-send/schema/raw/migrate.json new file mode 100644 index 0000000000..e08109d489 --- /dev/null +++ b/contracts/ibc-reflect-send/schema/raw/migrate.json @@ -0,0 +1,817 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Changes the admin", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "send_msgs" + ], + "properties": { + "send_msgs": { + "type": "object", + "required": [ + "channel_id", + "msgs" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/CosmosMsg_for_Empty" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "check_remote_balance" + ], + "properties": { + "check_remote_balance": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "If you sent funds to this contract, it will attempt to ibc transfer them to the account on the remote side of this channel. If we don't have the address yet, this fails.", + "type": "object", + "required": [ + "send_funds" + ], + "properties": { + "send_funds": { + "type": "object", + "required": [ + "reflect_channel_id", + "transfer_channel_id" + ], + "properties": { + "reflect_channel_id": { + "description": "The channel id we use above to talk with the reflect contract", + "type": "string" + }, + "transfer_channel_id": { + "description": "The channel to use for ibctransfer. This is bound to a different port and handled by a different module. It should connect to the same chain as the reflect_channel_id does", + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "BankMsg": { + "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "oneOf": [ + { + "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "to_address" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "to_address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "CosmosMsg_for_Empty": { + "oneOf": [ + { + "type": "object", + "required": [ + "bank" + ], + "properties": { + "bank": { + "$ref": "#/definitions/BankMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "$ref": "#/definitions/Empty" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "staking" + ], + "properties": { + "staking": { + "$ref": "#/definitions/StakingMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "distribution" + ], + "properties": { + "distribution": { + "$ref": "#/definitions/DistributionMsg" + } + }, + "additionalProperties": false + }, + { + "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", + "type": "object", + "required": [ + "stargate" + ], + "properties": { + "stargate": { + "type": "object", + "required": [ + "type_url", + "value" + ], + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "ibc" + ], + "properties": { + "ibc": { + "$ref": "#/definitions/IbcMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "wasm" + ], + "properties": { + "wasm": { + "$ref": "#/definitions/WasmMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "gov" + ], + "properties": { + "gov": { + "$ref": "#/definitions/GovMsg" + } + }, + "additionalProperties": false + } + ] + }, + "DistributionMsg": { + "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "set_withdraw_address" + ], + "properties": { + "set_withdraw_address": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The `withdraw_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "withdraw_delegator_reward" + ], + "properties": { + "withdraw_delegator_reward": { + "type": "object", + "required": [ + "validator" + ], + "properties": { + "validator": { + "description": "The `validator_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Empty": { + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + }, + "GovMsg": { + "oneOf": [ + { + "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "vote" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vote": { + "$ref": "#/definitions/VoteOption" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcMsg": { + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "oneOf": [ + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "channel_id", + "timeout", + "to_address" + ], + "properties": { + "amount": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + }, + "channel_id": { + "description": "exisiting channel to send the tokens over", + "type": "string" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", + "type": "object", + "required": [ + "send_packet" + ], + "properties": { + "send_packet": { + "type": "object", + "required": [ + "channel_id", + "data", + "timeout" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/Binary" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", + "type": "object", + "required": [ + "close_channel" + ], + "properties": { + "close_channel": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "StakingMsg": { + "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "undelegate" + ], + "properties": { + "undelegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "redelegate" + ], + "properties": { + "redelegate": { + "type": "object", + "required": [ + "amount", + "dst_validator", + "src_validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "dst_validator": { + "type": "string" + }, + "src_validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + }, + "VoteOption": { + "type": "string", + "enum": [ + "yes", + "no", + "abstain", + "no_with_veto" + ] + }, + "WasmMsg": { + "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", + "oneOf": [ + { + "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "contract_addr", + "funds", + "msg" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "msg": { + "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "instantiate" + ], + "properties": { + "instantiate": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readbale label for the contract", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "migrate" + ], + "properties": { + "migrate": { + "type": "object", + "required": [ + "contract_addr", + "msg", + "new_code_id" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "msg": { + "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "new_code_id": { + "description": "the code_id of the new logic to place in the given contract", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin", + "contract_addr" + ], + "properties": { + "admin": { + "type": "string" + }, + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "clear_admin" + ], + "properties": { + "clear_admin": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/ibc-reflect-send/schema/raw/query.json b/contracts/ibc-reflect-send/schema/raw/query.json new file mode 100644 index 0000000000..e08109d489 --- /dev/null +++ b/contracts/ibc-reflect-send/schema/raw/query.json @@ -0,0 +1,817 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Changes the admin", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "send_msgs" + ], + "properties": { + "send_msgs": { + "type": "object", + "required": [ + "channel_id", + "msgs" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/CosmosMsg_for_Empty" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "check_remote_balance" + ], + "properties": { + "check_remote_balance": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "If you sent funds to this contract, it will attempt to ibc transfer them to the account on the remote side of this channel. If we don't have the address yet, this fails.", + "type": "object", + "required": [ + "send_funds" + ], + "properties": { + "send_funds": { + "type": "object", + "required": [ + "reflect_channel_id", + "transfer_channel_id" + ], + "properties": { + "reflect_channel_id": { + "description": "The channel id we use above to talk with the reflect contract", + "type": "string" + }, + "transfer_channel_id": { + "description": "The channel to use for ibctransfer. This is bound to a different port and handled by a different module. It should connect to the same chain as the reflect_channel_id does", + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "BankMsg": { + "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "oneOf": [ + { + "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "to_address" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "to_address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "CosmosMsg_for_Empty": { + "oneOf": [ + { + "type": "object", + "required": [ + "bank" + ], + "properties": { + "bank": { + "$ref": "#/definitions/BankMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "$ref": "#/definitions/Empty" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "staking" + ], + "properties": { + "staking": { + "$ref": "#/definitions/StakingMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "distribution" + ], + "properties": { + "distribution": { + "$ref": "#/definitions/DistributionMsg" + } + }, + "additionalProperties": false + }, + { + "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", + "type": "object", + "required": [ + "stargate" + ], + "properties": { + "stargate": { + "type": "object", + "required": [ + "type_url", + "value" + ], + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "ibc" + ], + "properties": { + "ibc": { + "$ref": "#/definitions/IbcMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "wasm" + ], + "properties": { + "wasm": { + "$ref": "#/definitions/WasmMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "gov" + ], + "properties": { + "gov": { + "$ref": "#/definitions/GovMsg" + } + }, + "additionalProperties": false + } + ] + }, + "DistributionMsg": { + "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "set_withdraw_address" + ], + "properties": { + "set_withdraw_address": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The `withdraw_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "withdraw_delegator_reward" + ], + "properties": { + "withdraw_delegator_reward": { + "type": "object", + "required": [ + "validator" + ], + "properties": { + "validator": { + "description": "The `validator_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Empty": { + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + }, + "GovMsg": { + "oneOf": [ + { + "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "vote" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vote": { + "$ref": "#/definitions/VoteOption" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcMsg": { + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "oneOf": [ + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "channel_id", + "timeout", + "to_address" + ], + "properties": { + "amount": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + }, + "channel_id": { + "description": "exisiting channel to send the tokens over", + "type": "string" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", + "type": "object", + "required": [ + "send_packet" + ], + "properties": { + "send_packet": { + "type": "object", + "required": [ + "channel_id", + "data", + "timeout" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/Binary" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", + "type": "object", + "required": [ + "close_channel" + ], + "properties": { + "close_channel": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "StakingMsg": { + "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "undelegate" + ], + "properties": { + "undelegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "redelegate" + ], + "properties": { + "redelegate": { + "type": "object", + "required": [ + "amount", + "dst_validator", + "src_validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "dst_validator": { + "type": "string" + }, + "src_validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + }, + "VoteOption": { + "type": "string", + "enum": [ + "yes", + "no", + "abstain", + "no_with_veto" + ] + }, + "WasmMsg": { + "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", + "oneOf": [ + { + "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "contract_addr", + "funds", + "msg" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "msg": { + "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "instantiate" + ], + "properties": { + "instantiate": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readbale label for the contract", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "migrate" + ], + "properties": { + "migrate": { + "type": "object", + "required": [ + "contract_addr", + "msg", + "new_code_id" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "msg": { + "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "new_code_id": { + "description": "the code_id of the new logic to place in the given contract", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin", + "contract_addr" + ], + "properties": { + "admin": { + "type": "string" + }, + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "clear_admin" + ], + "properties": { + "clear_admin": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/ibc-reflect-send/schema/raw/response_to_account.json b/contracts/ibc-reflect-send/schema/raw/response_to_account.json new file mode 100644 index 0000000000..3b022b2f57 --- /dev/null +++ b/contracts/ibc-reflect-send/schema/raw/response_to_account.json @@ -0,0 +1,70 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AccountInfo", + "type": "object", + "required": [ + "channel_id", + "last_update_time", + "remote_balance" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "last_update_time": { + "description": "last block balance was updated (0 is never)", + "allOf": [ + { + "$ref": "#/definitions/Timestamp" + } + ] + }, + "remote_addr": { + "description": "in normal cases, it should be set, but there is a delay between binding the channel and making a query and in that time it is empty", + "type": [ + "string", + "null" + ] + }, + "remote_balance": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + }, + "additionalProperties": false, + "definitions": { + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/ibc-reflect-send/schema/raw/response_to_admin.json b/contracts/ibc-reflect-send/schema/raw/response_to_admin.json new file mode 100644 index 0000000000..627be7a025 --- /dev/null +++ b/contracts/ibc-reflect-send/schema/raw/response_to_admin.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AdminResponse", + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/ibc-reflect-send/schema/raw/response_to_list_accounts.json b/contracts/ibc-reflect-send/schema/raw/response_to_list_accounts.json new file mode 100644 index 0000000000..bb03b416b9 --- /dev/null +++ b/contracts/ibc-reflect-send/schema/raw/response_to_list_accounts.json @@ -0,0 +1,85 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ListAccountsResponse", + "type": "object", + "required": [ + "accounts" + ], + "properties": { + "accounts": { + "type": "array", + "items": { + "$ref": "#/definitions/AccountInfo" + } + } + }, + "additionalProperties": false, + "definitions": { + "AccountInfo": { + "type": "object", + "required": [ + "channel_id", + "last_update_time", + "remote_balance" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "last_update_time": { + "description": "last block balance was updated (0 is never)", + "allOf": [ + { + "$ref": "#/definitions/Timestamp" + } + ] + }, + "remote_addr": { + "description": "in normal cases, it should be set, but there is a delay between binding the channel and making a query and in that time it is empty", + "type": [ + "string", + "null" + ] + }, + "remote_balance": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + }, + "additionalProperties": false + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/ibc-reflect-send/schema/raw/sudo.json b/contracts/ibc-reflect-send/schema/raw/sudo.json new file mode 100644 index 0000000000..e08109d489 --- /dev/null +++ b/contracts/ibc-reflect-send/schema/raw/sudo.json @@ -0,0 +1,817 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Changes the admin", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin" + ], + "properties": { + "admin": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "send_msgs" + ], + "properties": { + "send_msgs": { + "type": "object", + "required": [ + "channel_id", + "msgs" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/CosmosMsg_for_Empty" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "check_remote_balance" + ], + "properties": { + "check_remote_balance": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "If you sent funds to this contract, it will attempt to ibc transfer them to the account on the remote side of this channel. If we don't have the address yet, this fails.", + "type": "object", + "required": [ + "send_funds" + ], + "properties": { + "send_funds": { + "type": "object", + "required": [ + "reflect_channel_id", + "transfer_channel_id" + ], + "properties": { + "reflect_channel_id": { + "description": "The channel id we use above to talk with the reflect contract", + "type": "string" + }, + "transfer_channel_id": { + "description": "The channel to use for ibctransfer. This is bound to a different port and handled by a different module. It should connect to the same chain as the reflect_channel_id does", + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "BankMsg": { + "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "oneOf": [ + { + "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "to_address" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "to_address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "CosmosMsg_for_Empty": { + "oneOf": [ + { + "type": "object", + "required": [ + "bank" + ], + "properties": { + "bank": { + "$ref": "#/definitions/BankMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "$ref": "#/definitions/Empty" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "staking" + ], + "properties": { + "staking": { + "$ref": "#/definitions/StakingMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "distribution" + ], + "properties": { + "distribution": { + "$ref": "#/definitions/DistributionMsg" + } + }, + "additionalProperties": false + }, + { + "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", + "type": "object", + "required": [ + "stargate" + ], + "properties": { + "stargate": { + "type": "object", + "required": [ + "type_url", + "value" + ], + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "ibc" + ], + "properties": { + "ibc": { + "$ref": "#/definitions/IbcMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "wasm" + ], + "properties": { + "wasm": { + "$ref": "#/definitions/WasmMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "gov" + ], + "properties": { + "gov": { + "$ref": "#/definitions/GovMsg" + } + }, + "additionalProperties": false + } + ] + }, + "DistributionMsg": { + "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "set_withdraw_address" + ], + "properties": { + "set_withdraw_address": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The `withdraw_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "withdraw_delegator_reward" + ], + "properties": { + "withdraw_delegator_reward": { + "type": "object", + "required": [ + "validator" + ], + "properties": { + "validator": { + "description": "The `validator_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Empty": { + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" + }, + "GovMsg": { + "oneOf": [ + { + "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "vote" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vote": { + "$ref": "#/definitions/VoteOption" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcMsg": { + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "oneOf": [ + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "channel_id", + "timeout", + "to_address" + ], + "properties": { + "amount": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + }, + "channel_id": { + "description": "exisiting channel to send the tokens over", + "type": "string" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", + "type": "object", + "required": [ + "send_packet" + ], + "properties": { + "send_packet": { + "type": "object", + "required": [ + "channel_id", + "data", + "timeout" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/Binary" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", + "type": "object", + "required": [ + "close_channel" + ], + "properties": { + "close_channel": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "StakingMsg": { + "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "undelegate" + ], + "properties": { + "undelegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "redelegate" + ], + "properties": { + "redelegate": { + "type": "object", + "required": [ + "amount", + "dst_validator", + "src_validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "dst_validator": { + "type": "string" + }, + "src_validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + }, + "VoteOption": { + "type": "string", + "enum": [ + "yes", + "no", + "abstain", + "no_with_veto" + ] + }, + "WasmMsg": { + "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", + "oneOf": [ + { + "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "contract_addr", + "funds", + "msg" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "msg": { + "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "instantiate" + ], + "properties": { + "instantiate": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readbale label for the contract", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "migrate" + ], + "properties": { + "migrate": { + "type": "object", + "required": [ + "contract_addr", + "msg", + "new_code_id" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "msg": { + "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "new_code_id": { + "description": "the code_id of the new logic to place in the given contract", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin", + "contract_addr" + ], + "properties": { + "admin": { + "type": "string" + }, + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "clear_admin" + ], + "properties": { + "clear_admin": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/ibc-reflect/schema/raw/instantiate.json b/contracts/ibc-reflect/schema/raw/instantiate.json new file mode 100644 index 0000000000..1320f1a0b9 --- /dev/null +++ b/contracts/ibc-reflect/schema/raw/instantiate.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "description": "Just needs to know the code_id of a reflect contract to spawn sub-accounts", + "type": "object", + "required": [ + "reflect_code_id" + ], + "properties": { + "reflect_code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false +} diff --git a/contracts/ibc-reflect/schema/raw/response_to_account.json b/contracts/ibc-reflect/schema/raw/response_to_account.json new file mode 100644 index 0000000000..84edc87b94 --- /dev/null +++ b/contracts/ibc-reflect/schema/raw/response_to_account.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AccountResponse", + "type": "object", + "properties": { + "account": { + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false +} diff --git a/contracts/ibc-reflect/schema/raw/response_to_list_accounts.json b/contracts/ibc-reflect/schema/raw/response_to_list_accounts.json new file mode 100644 index 0000000000..22591bd068 --- /dev/null +++ b/contracts/ibc-reflect/schema/raw/response_to_list_accounts.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ListAccountsResponse", + "type": "object", + "required": [ + "accounts" + ], + "properties": { + "accounts": { + "type": "array", + "items": { + "$ref": "#/definitions/AccountInfo" + } + } + }, + "additionalProperties": false, + "definitions": { + "AccountInfo": { + "type": "object", + "required": [ + "account", + "channel_id" + ], + "properties": { + "account": { + "type": "string" + }, + "channel_id": { + "type": "string" + } + }, + "additionalProperties": false + } + } +} diff --git a/contracts/queue/schema/raw/execute.json b/contracts/queue/schema/raw/execute.json new file mode 100644 index 0000000000..1877209732 --- /dev/null +++ b/contracts/queue/schema/raw/execute.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "enqueue" + ], + "properties": { + "enqueue": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "dequeue" + ], + "properties": { + "dequeue": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/queue/schema/raw/instantiate.json b/contracts/queue/schema/raw/instantiate.json new file mode 100644 index 0000000000..1352613d57 --- /dev/null +++ b/contracts/queue/schema/raw/instantiate.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "additionalProperties": false +} diff --git a/contracts/queue/schema/raw/migrate.json b/contracts/queue/schema/raw/migrate.json new file mode 100644 index 0000000000..1877209732 --- /dev/null +++ b/contracts/queue/schema/raw/migrate.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "enqueue" + ], + "properties": { + "enqueue": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "dequeue" + ], + "properties": { + "dequeue": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/queue/schema/raw/query.json b/contracts/queue/schema/raw/query.json new file mode 100644 index 0000000000..1877209732 --- /dev/null +++ b/contracts/queue/schema/raw/query.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "enqueue" + ], + "properties": { + "enqueue": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "dequeue" + ], + "properties": { + "dequeue": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/queue/schema/raw/response_to_count.json b/contracts/queue/schema/raw/response_to_count.json new file mode 100644 index 0000000000..cf6f1c3cdd --- /dev/null +++ b/contracts/queue/schema/raw/response_to_count.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CountResponse", + "type": "object", + "required": [ + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false +} diff --git a/contracts/queue/schema/raw/response_to_list.json b/contracts/queue/schema/raw/response_to_list.json new file mode 100644 index 0000000000..e4da637795 --- /dev/null +++ b/contracts/queue/schema/raw/response_to_list.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ListResponse", + "type": "object", + "required": [ + "early", + "empty", + "late" + ], + "properties": { + "early": { + "description": "List all IDs lower than 0x20", + "type": "array", + "items": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "empty": { + "description": "List an empty range, both bounded", + "type": "array", + "items": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "late": { + "description": "List all IDs starting from 0x20", + "type": "array", + "items": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + "additionalProperties": false +} diff --git a/contracts/queue/schema/raw/response_to_open_iterators.json b/contracts/queue/schema/raw/response_to_open_iterators.json new file mode 100644 index 0000000000..ad4ff226d4 --- /dev/null +++ b/contracts/queue/schema/raw/response_to_open_iterators.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Empty", + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" +} diff --git a/contracts/queue/schema/raw/response_to_reducer.json b/contracts/queue/schema/raw/response_to_reducer.json new file mode 100644 index 0000000000..612b4029a8 --- /dev/null +++ b/contracts/queue/schema/raw/response_to_reducer.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ReducerResponse", + "type": "object", + "required": [ + "counters" + ], + "properties": { + "counters": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "integer", + "format": "int32" + } + ], + "maxItems": 2, + "minItems": 2 + } + } + }, + "additionalProperties": false +} diff --git a/contracts/queue/schema/raw/response_to_sum.json b/contracts/queue/schema/raw/response_to_sum.json new file mode 100644 index 0000000000..c8133fe4e0 --- /dev/null +++ b/contracts/queue/schema/raw/response_to_sum.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "SumResponse", + "type": "object", + "required": [ + "sum" + ], + "properties": { + "sum": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false +} diff --git a/contracts/queue/schema/raw/sudo.json b/contracts/queue/schema/raw/sudo.json new file mode 100644 index 0000000000..1877209732 --- /dev/null +++ b/contracts/queue/schema/raw/sudo.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "enqueue" + ], + "properties": { + "enqueue": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "dequeue" + ], + "properties": { + "dequeue": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/reflect/schema/raw/execute.json b/contracts/reflect/schema/raw/execute.json new file mode 100644 index 0000000000..e0db5ae603 --- /dev/null +++ b/contracts/reflect/schema/raw/execute.json @@ -0,0 +1,854 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "reflect_msg" + ], + "properties": { + "reflect_msg": { + "type": "object", + "required": [ + "msgs" + ], + "properties": { + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/CosmosMsg_for_CustomMsg" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "reflect_sub_msg" + ], + "properties": { + "reflect_sub_msg": { + "type": "object", + "required": [ + "msgs" + ], + "properties": { + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/SubMsg_for_CustomMsg" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "change_owner" + ], + "properties": { + "change_owner": { + "type": "object", + "required": [ + "owner" + ], + "properties": { + "owner": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "BankMsg": { + "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "oneOf": [ + { + "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "to_address" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "to_address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "CosmosMsg_for_CustomMsg": { + "oneOf": [ + { + "type": "object", + "required": [ + "bank" + ], + "properties": { + "bank": { + "$ref": "#/definitions/BankMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "$ref": "#/definitions/CustomMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "staking" + ], + "properties": { + "staking": { + "$ref": "#/definitions/StakingMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "distribution" + ], + "properties": { + "distribution": { + "$ref": "#/definitions/DistributionMsg" + } + }, + "additionalProperties": false + }, + { + "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", + "type": "object", + "required": [ + "stargate" + ], + "properties": { + "stargate": { + "type": "object", + "required": [ + "type_url", + "value" + ], + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "ibc" + ], + "properties": { + "ibc": { + "$ref": "#/definitions/IbcMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "wasm" + ], + "properties": { + "wasm": { + "$ref": "#/definitions/WasmMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "gov" + ], + "properties": { + "gov": { + "$ref": "#/definitions/GovMsg" + } + }, + "additionalProperties": false + } + ] + }, + "CustomMsg": { + "description": "CustomMsg is an override of CosmosMsg::Custom to show this works and can be extended in the contract", + "oneOf": [ + { + "type": "object", + "required": [ + "debug" + ], + "properties": { + "debug": { + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "raw" + ], + "properties": { + "raw": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + } + ] + }, + "DistributionMsg": { + "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "set_withdraw_address" + ], + "properties": { + "set_withdraw_address": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The `withdraw_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "withdraw_delegator_reward" + ], + "properties": { + "withdraw_delegator_reward": { + "type": "object", + "required": [ + "validator" + ], + "properties": { + "validator": { + "description": "The `validator_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "GovMsg": { + "oneOf": [ + { + "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "vote" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vote": { + "$ref": "#/definitions/VoteOption" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcMsg": { + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "oneOf": [ + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "channel_id", + "timeout", + "to_address" + ], + "properties": { + "amount": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + }, + "channel_id": { + "description": "exisiting channel to send the tokens over", + "type": "string" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", + "type": "object", + "required": [ + "send_packet" + ], + "properties": { + "send_packet": { + "type": "object", + "required": [ + "channel_id", + "data", + "timeout" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/Binary" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", + "type": "object", + "required": [ + "close_channel" + ], + "properties": { + "close_channel": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "ReplyOn": { + "description": "Use this to define when the contract gets a response callback. If you only need it for errors or success you can select just those in order to save gas.", + "type": "string", + "enum": [ + "always", + "error", + "success", + "never" + ] + }, + "StakingMsg": { + "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "undelegate" + ], + "properties": { + "undelegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "redelegate" + ], + "properties": { + "redelegate": { + "type": "object", + "required": [ + "amount", + "dst_validator", + "src_validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "dst_validator": { + "type": "string" + }, + "src_validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "SubMsg_for_CustomMsg": { + "description": "A submessage that will guarantee a `reply` call on success or error, depending on the `reply_on` setting. If you do not need to process the result, use regular messages instead.\n\nNote: On error the submessage execution will revert any partial state changes due to this message, but not revert any state changes in the calling contract. If this is required, it must be done manually in the `reply` entry point.", + "type": "object", + "required": [ + "id", + "msg", + "reply_on" + ], + "properties": { + "gas_limit": { + "description": "Gas limit measured in [Cosmos SDK gas](https://github.com/CosmWasm/cosmwasm/blob/main/docs/GAS.md).", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "id": { + "description": "An arbitrary ID chosen by the contract. This is typically used to match `Reply`s in the `reply` entry point to the submessage.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "msg": { + "$ref": "#/definitions/CosmosMsg_for_CustomMsg" + }, + "reply_on": { + "$ref": "#/definitions/ReplyOn" + } + } + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + }, + "VoteOption": { + "type": "string", + "enum": [ + "yes", + "no", + "abstain", + "no_with_veto" + ] + }, + "WasmMsg": { + "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", + "oneOf": [ + { + "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "contract_addr", + "funds", + "msg" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "msg": { + "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "instantiate" + ], + "properties": { + "instantiate": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readbale label for the contract", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "migrate" + ], + "properties": { + "migrate": { + "type": "object", + "required": [ + "contract_addr", + "msg", + "new_code_id" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "msg": { + "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "new_code_id": { + "description": "the code_id of the new logic to place in the given contract", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin", + "contract_addr" + ], + "properties": { + "admin": { + "type": "string" + }, + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "clear_admin" + ], + "properties": { + "clear_admin": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/reflect/schema/raw/instantiate.json b/contracts/reflect/schema/raw/instantiate.json new file mode 100644 index 0000000000..1352613d57 --- /dev/null +++ b/contracts/reflect/schema/raw/instantiate.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "additionalProperties": false +} diff --git a/contracts/reflect/schema/raw/migrate.json b/contracts/reflect/schema/raw/migrate.json new file mode 100644 index 0000000000..e0db5ae603 --- /dev/null +++ b/contracts/reflect/schema/raw/migrate.json @@ -0,0 +1,854 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "reflect_msg" + ], + "properties": { + "reflect_msg": { + "type": "object", + "required": [ + "msgs" + ], + "properties": { + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/CosmosMsg_for_CustomMsg" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "reflect_sub_msg" + ], + "properties": { + "reflect_sub_msg": { + "type": "object", + "required": [ + "msgs" + ], + "properties": { + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/SubMsg_for_CustomMsg" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "change_owner" + ], + "properties": { + "change_owner": { + "type": "object", + "required": [ + "owner" + ], + "properties": { + "owner": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "BankMsg": { + "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "oneOf": [ + { + "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "to_address" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "to_address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "CosmosMsg_for_CustomMsg": { + "oneOf": [ + { + "type": "object", + "required": [ + "bank" + ], + "properties": { + "bank": { + "$ref": "#/definitions/BankMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "$ref": "#/definitions/CustomMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "staking" + ], + "properties": { + "staking": { + "$ref": "#/definitions/StakingMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "distribution" + ], + "properties": { + "distribution": { + "$ref": "#/definitions/DistributionMsg" + } + }, + "additionalProperties": false + }, + { + "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", + "type": "object", + "required": [ + "stargate" + ], + "properties": { + "stargate": { + "type": "object", + "required": [ + "type_url", + "value" + ], + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "ibc" + ], + "properties": { + "ibc": { + "$ref": "#/definitions/IbcMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "wasm" + ], + "properties": { + "wasm": { + "$ref": "#/definitions/WasmMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "gov" + ], + "properties": { + "gov": { + "$ref": "#/definitions/GovMsg" + } + }, + "additionalProperties": false + } + ] + }, + "CustomMsg": { + "description": "CustomMsg is an override of CosmosMsg::Custom to show this works and can be extended in the contract", + "oneOf": [ + { + "type": "object", + "required": [ + "debug" + ], + "properties": { + "debug": { + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "raw" + ], + "properties": { + "raw": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + } + ] + }, + "DistributionMsg": { + "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "set_withdraw_address" + ], + "properties": { + "set_withdraw_address": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The `withdraw_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "withdraw_delegator_reward" + ], + "properties": { + "withdraw_delegator_reward": { + "type": "object", + "required": [ + "validator" + ], + "properties": { + "validator": { + "description": "The `validator_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "GovMsg": { + "oneOf": [ + { + "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "vote" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vote": { + "$ref": "#/definitions/VoteOption" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcMsg": { + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "oneOf": [ + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "channel_id", + "timeout", + "to_address" + ], + "properties": { + "amount": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + }, + "channel_id": { + "description": "exisiting channel to send the tokens over", + "type": "string" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", + "type": "object", + "required": [ + "send_packet" + ], + "properties": { + "send_packet": { + "type": "object", + "required": [ + "channel_id", + "data", + "timeout" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/Binary" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", + "type": "object", + "required": [ + "close_channel" + ], + "properties": { + "close_channel": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "ReplyOn": { + "description": "Use this to define when the contract gets a response callback. If you only need it for errors or success you can select just those in order to save gas.", + "type": "string", + "enum": [ + "always", + "error", + "success", + "never" + ] + }, + "StakingMsg": { + "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "undelegate" + ], + "properties": { + "undelegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "redelegate" + ], + "properties": { + "redelegate": { + "type": "object", + "required": [ + "amount", + "dst_validator", + "src_validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "dst_validator": { + "type": "string" + }, + "src_validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "SubMsg_for_CustomMsg": { + "description": "A submessage that will guarantee a `reply` call on success or error, depending on the `reply_on` setting. If you do not need to process the result, use regular messages instead.\n\nNote: On error the submessage execution will revert any partial state changes due to this message, but not revert any state changes in the calling contract. If this is required, it must be done manually in the `reply` entry point.", + "type": "object", + "required": [ + "id", + "msg", + "reply_on" + ], + "properties": { + "gas_limit": { + "description": "Gas limit measured in [Cosmos SDK gas](https://github.com/CosmWasm/cosmwasm/blob/main/docs/GAS.md).", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "id": { + "description": "An arbitrary ID chosen by the contract. This is typically used to match `Reply`s in the `reply` entry point to the submessage.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "msg": { + "$ref": "#/definitions/CosmosMsg_for_CustomMsg" + }, + "reply_on": { + "$ref": "#/definitions/ReplyOn" + } + } + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + }, + "VoteOption": { + "type": "string", + "enum": [ + "yes", + "no", + "abstain", + "no_with_veto" + ] + }, + "WasmMsg": { + "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", + "oneOf": [ + { + "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "contract_addr", + "funds", + "msg" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "msg": { + "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "instantiate" + ], + "properties": { + "instantiate": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readbale label for the contract", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "migrate" + ], + "properties": { + "migrate": { + "type": "object", + "required": [ + "contract_addr", + "msg", + "new_code_id" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "msg": { + "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "new_code_id": { + "description": "the code_id of the new logic to place in the given contract", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin", + "contract_addr" + ], + "properties": { + "admin": { + "type": "string" + }, + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "clear_admin" + ], + "properties": { + "clear_admin": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/reflect/schema/raw/query.json b/contracts/reflect/schema/raw/query.json new file mode 100644 index 0000000000..e0db5ae603 --- /dev/null +++ b/contracts/reflect/schema/raw/query.json @@ -0,0 +1,854 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "reflect_msg" + ], + "properties": { + "reflect_msg": { + "type": "object", + "required": [ + "msgs" + ], + "properties": { + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/CosmosMsg_for_CustomMsg" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "reflect_sub_msg" + ], + "properties": { + "reflect_sub_msg": { + "type": "object", + "required": [ + "msgs" + ], + "properties": { + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/SubMsg_for_CustomMsg" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "change_owner" + ], + "properties": { + "change_owner": { + "type": "object", + "required": [ + "owner" + ], + "properties": { + "owner": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "BankMsg": { + "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "oneOf": [ + { + "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "to_address" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "to_address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "CosmosMsg_for_CustomMsg": { + "oneOf": [ + { + "type": "object", + "required": [ + "bank" + ], + "properties": { + "bank": { + "$ref": "#/definitions/BankMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "$ref": "#/definitions/CustomMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "staking" + ], + "properties": { + "staking": { + "$ref": "#/definitions/StakingMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "distribution" + ], + "properties": { + "distribution": { + "$ref": "#/definitions/DistributionMsg" + } + }, + "additionalProperties": false + }, + { + "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", + "type": "object", + "required": [ + "stargate" + ], + "properties": { + "stargate": { + "type": "object", + "required": [ + "type_url", + "value" + ], + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "ibc" + ], + "properties": { + "ibc": { + "$ref": "#/definitions/IbcMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "wasm" + ], + "properties": { + "wasm": { + "$ref": "#/definitions/WasmMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "gov" + ], + "properties": { + "gov": { + "$ref": "#/definitions/GovMsg" + } + }, + "additionalProperties": false + } + ] + }, + "CustomMsg": { + "description": "CustomMsg is an override of CosmosMsg::Custom to show this works and can be extended in the contract", + "oneOf": [ + { + "type": "object", + "required": [ + "debug" + ], + "properties": { + "debug": { + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "raw" + ], + "properties": { + "raw": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + } + ] + }, + "DistributionMsg": { + "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "set_withdraw_address" + ], + "properties": { + "set_withdraw_address": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The `withdraw_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "withdraw_delegator_reward" + ], + "properties": { + "withdraw_delegator_reward": { + "type": "object", + "required": [ + "validator" + ], + "properties": { + "validator": { + "description": "The `validator_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "GovMsg": { + "oneOf": [ + { + "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "vote" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vote": { + "$ref": "#/definitions/VoteOption" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcMsg": { + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "oneOf": [ + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "channel_id", + "timeout", + "to_address" + ], + "properties": { + "amount": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + }, + "channel_id": { + "description": "exisiting channel to send the tokens over", + "type": "string" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", + "type": "object", + "required": [ + "send_packet" + ], + "properties": { + "send_packet": { + "type": "object", + "required": [ + "channel_id", + "data", + "timeout" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/Binary" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", + "type": "object", + "required": [ + "close_channel" + ], + "properties": { + "close_channel": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "ReplyOn": { + "description": "Use this to define when the contract gets a response callback. If you only need it for errors or success you can select just those in order to save gas.", + "type": "string", + "enum": [ + "always", + "error", + "success", + "never" + ] + }, + "StakingMsg": { + "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "undelegate" + ], + "properties": { + "undelegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "redelegate" + ], + "properties": { + "redelegate": { + "type": "object", + "required": [ + "amount", + "dst_validator", + "src_validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "dst_validator": { + "type": "string" + }, + "src_validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "SubMsg_for_CustomMsg": { + "description": "A submessage that will guarantee a `reply` call on success or error, depending on the `reply_on` setting. If you do not need to process the result, use regular messages instead.\n\nNote: On error the submessage execution will revert any partial state changes due to this message, but not revert any state changes in the calling contract. If this is required, it must be done manually in the `reply` entry point.", + "type": "object", + "required": [ + "id", + "msg", + "reply_on" + ], + "properties": { + "gas_limit": { + "description": "Gas limit measured in [Cosmos SDK gas](https://github.com/CosmWasm/cosmwasm/blob/main/docs/GAS.md).", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "id": { + "description": "An arbitrary ID chosen by the contract. This is typically used to match `Reply`s in the `reply` entry point to the submessage.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "msg": { + "$ref": "#/definitions/CosmosMsg_for_CustomMsg" + }, + "reply_on": { + "$ref": "#/definitions/ReplyOn" + } + } + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + }, + "VoteOption": { + "type": "string", + "enum": [ + "yes", + "no", + "abstain", + "no_with_veto" + ] + }, + "WasmMsg": { + "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", + "oneOf": [ + { + "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "contract_addr", + "funds", + "msg" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "msg": { + "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "instantiate" + ], + "properties": { + "instantiate": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readbale label for the contract", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "migrate" + ], + "properties": { + "migrate": { + "type": "object", + "required": [ + "contract_addr", + "msg", + "new_code_id" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "msg": { + "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "new_code_id": { + "description": "the code_id of the new logic to place in the given contract", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin", + "contract_addr" + ], + "properties": { + "admin": { + "type": "string" + }, + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "clear_admin" + ], + "properties": { + "clear_admin": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/reflect/schema/raw/response_to_capitalized.json b/contracts/reflect/schema/raw/response_to_capitalized.json new file mode 100644 index 0000000000..543a4fa4c4 --- /dev/null +++ b/contracts/reflect/schema/raw/response_to_capitalized.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CapitalizedResponse", + "type": "object", + "required": [ + "text" + ], + "properties": { + "text": { + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/reflect/schema/raw/response_to_chain.json b/contracts/reflect/schema/raw/response_to_chain.json new file mode 100644 index 0000000000..aa0adb0fc6 --- /dev/null +++ b/contracts/reflect/schema/raw/response_to_chain.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ChainResponse", + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false, + "definitions": { + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + } + } +} diff --git a/contracts/reflect/schema/raw/response_to_owner.json b/contracts/reflect/schema/raw/response_to_owner.json new file mode 100644 index 0000000000..d91dde1494 --- /dev/null +++ b/contracts/reflect/schema/raw/response_to_owner.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "OwnerResponse", + "type": "object", + "required": [ + "owner" + ], + "properties": { + "owner": { + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/reflect/schema/raw/response_to_raw.json b/contracts/reflect/schema/raw/response_to_raw.json new file mode 100644 index 0000000000..85774defd5 --- /dev/null +++ b/contracts/reflect/schema/raw/response_to_raw.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "RawResponse", + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "description": "The returned value of the raw query. Empty data can be the result of a non-existent key or an empty value. We cannot differentiate those two cases in cross contract queries.", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + } + } +} diff --git a/contracts/reflect/schema/raw/response_to_sub_msg_result.json b/contracts/reflect/schema/raw/response_to_sub_msg_result.json new file mode 100644 index 0000000000..e7a26e26fb --- /dev/null +++ b/contracts/reflect/schema/raw/response_to_sub_msg_result.json @@ -0,0 +1,119 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Reply", + "description": "The result object returned to `reply`. We always get the ID from the submessage back and then must handle success and error cases ourselves.", + "type": "object", + "required": [ + "id", + "result" + ], + "properties": { + "id": { + "description": "The ID that the contract set when emitting the `SubMsg`. Use this to identify which submessage triggered the `reply`.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "result": { + "$ref": "#/definitions/SubMsgResult" + } + }, + "definitions": { + "Attribute": { + "description": "An key value pair that is used in the context of event attributes in logs", + "type": "object", + "required": [ + "key", + "value" + ], + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Event": { + "description": "A full [*Cosmos SDK* event].\n\nThis version uses string attributes (similar to [*Cosmos SDK* StringEvent]), which then get magically converted to bytes for Tendermint somewhere between the Rust-Go interface, JSON deserialization and the `NewEvent` call in Cosmos SDK.\n\n[*Cosmos SDK* event]: https://docs.cosmos.network/main/core/events.html [*Cosmos SDK* StringEvent]: https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/base/abci/v1beta1/abci.proto#L56-L70", + "type": "object", + "required": [ + "attributes", + "type" + ], + "properties": { + "attributes": { + "description": "The attributes to be included in the event.\n\nYou can learn more about these from [*Cosmos SDK* docs].\n\n[*Cosmos SDK* docs]: https://docs.cosmos.network/main/core/events.html", + "type": "array", + "items": { + "$ref": "#/definitions/Attribute" + } + }, + "type": { + "description": "The event type. This is renamed to \"ty\" because \"type\" is reserved in Rust. This sucks, we know.", + "type": "string" + } + } + }, + "SubMsgResponse": { + "description": "The information we get back from a successful sub message execution, with full Cosmos SDK events.", + "type": "object", + "required": [ + "events" + ], + "properties": { + "data": { + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + }, + "events": { + "type": "array", + "items": { + "$ref": "#/definitions/Event" + } + } + } + }, + "SubMsgResult": { + "description": "This is the result type that is returned from a sub message execution.\n\nWe use a custom type here instead of Rust's Result because we want to be able to define the serialization, which is a public interface. Every language that compiles to Wasm and runs in the ComsWasm VM needs to create the same JSON representation.\n\nUntil version 1.0.0-beta5, `ContractResult` was used instead of this type. Once serialized, the two types are the same. However, in the Rust type system we want different types for clarity and documenation reasons.\n\n# Examples\n\nSuccess:\n\n``` # use cosmwasm_std::{to_vec, Binary, Event, SubMsgResponse, SubMsgResult}; let response = SubMsgResponse { data: Some(Binary::from_base64(\"MTIzCg==\").unwrap()), events: vec![Event::new(\"wasm\").add_attribute(\"fo\", \"ba\")], }; let result: SubMsgResult = SubMsgResult::Ok(response); assert_eq!(to_vec(&result).unwrap(), br#\"{\"ok\":{\"events\":[{\"type\":\"wasm\",\"attributes\":[{\"key\":\"fo\",\"value\":\"ba\"}]}],\"data\":\"MTIzCg==\"}}\"#); ```\n\nFailure:\n\n``` # use cosmwasm_std::{to_vec, SubMsgResult, Response}; let error_msg = String::from(\"Something went wrong\"); let result = SubMsgResult::Err(error_msg); assert_eq!(to_vec(&result).unwrap(), br#\"{\"error\":\"Something went wrong\"}\"#); ```", + "oneOf": [ + { + "type": "object", + "required": [ + "ok" + ], + "properties": { + "ok": { + "$ref": "#/definitions/SubMsgResponse" + } + }, + "additionalProperties": false + }, + { + "description": "An error type that every custom error created by contract developers can be converted to. This could potientially have more structure, but String is the easiest.", + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/reflect/schema/raw/sudo.json b/contracts/reflect/schema/raw/sudo.json new file mode 100644 index 0000000000..e0db5ae603 --- /dev/null +++ b/contracts/reflect/schema/raw/sudo.json @@ -0,0 +1,854 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "reflect_msg" + ], + "properties": { + "reflect_msg": { + "type": "object", + "required": [ + "msgs" + ], + "properties": { + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/CosmosMsg_for_CustomMsg" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "reflect_sub_msg" + ], + "properties": { + "reflect_sub_msg": { + "type": "object", + "required": [ + "msgs" + ], + "properties": { + "msgs": { + "type": "array", + "items": { + "$ref": "#/definitions/SubMsg_for_CustomMsg" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "change_owner" + ], + "properties": { + "change_owner": { + "type": "object", + "required": [ + "owner" + ], + "properties": { + "owner": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "BankMsg": { + "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "oneOf": [ + { + "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "send" + ], + "properties": { + "send": { + "type": "object", + "required": [ + "amount", + "to_address" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "to_address": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + } + }, + "additionalProperties": false + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "CosmosMsg_for_CustomMsg": { + "oneOf": [ + { + "type": "object", + "required": [ + "bank" + ], + "properties": { + "bank": { + "$ref": "#/definitions/BankMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "custom" + ], + "properties": { + "custom": { + "$ref": "#/definitions/CustomMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "staking" + ], + "properties": { + "staking": { + "$ref": "#/definitions/StakingMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "distribution" + ], + "properties": { + "distribution": { + "$ref": "#/definitions/DistributionMsg" + } + }, + "additionalProperties": false + }, + { + "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", + "type": "object", + "required": [ + "stargate" + ], + "properties": { + "stargate": { + "type": "object", + "required": [ + "type_url", + "value" + ], + "properties": { + "type_url": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Binary" + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "ibc" + ], + "properties": { + "ibc": { + "$ref": "#/definitions/IbcMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "wasm" + ], + "properties": { + "wasm": { + "$ref": "#/definitions/WasmMsg" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "gov" + ], + "properties": { + "gov": { + "$ref": "#/definitions/GovMsg" + } + }, + "additionalProperties": false + } + ] + }, + "CustomMsg": { + "description": "CustomMsg is an override of CosmosMsg::Custom to show this works and can be extended in the contract", + "oneOf": [ + { + "type": "object", + "required": [ + "debug" + ], + "properties": { + "debug": { + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "raw" + ], + "properties": { + "raw": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + } + ] + }, + "DistributionMsg": { + "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "set_withdraw_address" + ], + "properties": { + "set_withdraw_address": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "description": "The `withdraw_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "withdraw_delegator_reward" + ], + "properties": { + "withdraw_delegator_reward": { + "type": "object", + "required": [ + "validator" + ], + "properties": { + "validator": { + "description": "The `validator_address`", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "GovMsg": { + "oneOf": [ + { + "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", + "type": "object", + "required": [ + "vote" + ], + "properties": { + "vote": { + "type": "object", + "required": [ + "proposal_id", + "vote" + ], + "properties": { + "proposal_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "vote": { + "$ref": "#/definitions/VoteOption" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcMsg": { + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "oneOf": [ + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "channel_id", + "timeout", + "to_address" + ], + "properties": { + "amount": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "allOf": [ + { + "$ref": "#/definitions/Coin" + } + ] + }, + "channel_id": { + "description": "exisiting channel to send the tokens over", + "type": "string" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", + "type": "object", + "required": [ + "send_packet" + ], + "properties": { + "send_packet": { + "type": "object", + "required": [ + "channel_id", + "data", + "timeout" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/Binary" + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", + "type": "object", + "required": [ + "close_channel" + ], + "properties": { + "close_channel": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "IbcTimeout": { + "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", + "type": "object", + "properties": { + "block": { + "anyOf": [ + { + "$ref": "#/definitions/IbcTimeoutBlock" + }, + { + "type": "null" + } + ] + }, + "timestamp": { + "anyOf": [ + { + "$ref": "#/definitions/Timestamp" + }, + { + "type": "null" + } + ] + } + } + }, + "IbcTimeoutBlock": { + "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", + "type": "object", + "required": [ + "height", + "revision" + ], + "properties": { + "height": { + "description": "block height after which the packet times out. the height within the given revision", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "revision": { + "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + }, + "ReplyOn": { + "description": "Use this to define when the contract gets a response callback. If you only need it for errors or success you can select just those in order to save gas.", + "type": "string", + "enum": [ + "always", + "error", + "success", + "never" + ] + }, + "StakingMsg": { + "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", + "oneOf": [ + { + "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "undelegate" + ], + "properties": { + "undelegate": { + "type": "object", + "required": [ + "amount", + "validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "redelegate" + ], + "properties": { + "redelegate": { + "type": "object", + "required": [ + "amount", + "dst_validator", + "src_validator" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Coin" + }, + "dst_validator": { + "type": "string" + }, + "src_validator": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + }, + "SubMsg_for_CustomMsg": { + "description": "A submessage that will guarantee a `reply` call on success or error, depending on the `reply_on` setting. If you do not need to process the result, use regular messages instead.\n\nNote: On error the submessage execution will revert any partial state changes due to this message, but not revert any state changes in the calling contract. If this is required, it must be done manually in the `reply` entry point.", + "type": "object", + "required": [ + "id", + "msg", + "reply_on" + ], + "properties": { + "gas_limit": { + "description": "Gas limit measured in [Cosmos SDK gas](https://github.com/CosmWasm/cosmwasm/blob/main/docs/GAS.md).", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + }, + "id": { + "description": "An arbitrary ID chosen by the contract. This is typically used to match `Reply`s in the `reply` entry point to the submessage.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "msg": { + "$ref": "#/definitions/CosmosMsg_for_CustomMsg" + }, + "reply_on": { + "$ref": "#/definitions/ReplyOn" + } + } + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + }, + "VoteOption": { + "type": "string", + "enum": [ + "yes", + "no", + "abstain", + "no_with_veto" + ] + }, + "WasmMsg": { + "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", + "oneOf": [ + { + "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "execute" + ], + "properties": { + "execute": { + "type": "object", + "required": [ + "contract_addr", + "funds", + "msg" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "msg": { + "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "instantiate" + ], + "properties": { + "instantiate": { + "type": "object", + "required": [ + "code_id", + "funds", + "label", + "msg" + ], + "properties": { + "admin": { + "type": [ + "string", + "null" + ] + }, + "code_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "funds": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "label": { + "description": "A human-readbale label for the contract", + "type": "string" + }, + "msg": { + "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "type": "object", + "required": [ + "migrate" + ], + "properties": { + "migrate": { + "type": "object", + "required": [ + "contract_addr", + "msg", + "new_code_id" + ], + "properties": { + "contract_addr": { + "type": "string" + }, + "msg": { + "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "new_code_id": { + "description": "the code_id of the new logic to place in the given contract", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "update_admin" + ], + "properties": { + "update_admin": { + "type": "object", + "required": [ + "admin", + "contract_addr" + ], + "properties": { + "admin": { + "type": "string" + }, + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "type": "object", + "required": [ + "clear_admin" + ], + "properties": { + "clear_admin": { + "type": "object", + "required": [ + "contract_addr" + ], + "properties": { + "contract_addr": { + "type": "string" + } + } + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/staking/schema/raw/execute.json b/contracts/staking/schema/raw/execute.json new file mode 100644 index 0000000000..159d67cd90 --- /dev/null +++ b/contracts/staking/schema/raw/execute.json @@ -0,0 +1,116 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Transfer moves the derivative token", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "recipient" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "recipient": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Bond will bond all staking tokens sent with the message and release derivative tokens", + "type": "object", + "required": [ + "bond" + ], + "properties": { + "bond": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Unbond will \"burn\" the given amount of derivative tokens and send the unbonded staking tokens to the message sender (after exit tax is deducted)", + "type": "object", + "required": [ + "unbond" + ], + "properties": { + "unbond": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Claim is used to claim your native tokens that you previously \"unbonded\" after the chain-defined waiting period (eg. 3 weeks)", + "type": "object", + "required": [ + "claim" + ], + "properties": { + "claim": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Reinvest will check for all accumulated rewards, withdraw them, and re-bond them to the same validator. Anyone can call this, which updates the value of the token (how much under custody).", + "type": "object", + "required": [ + "reinvest" + ], + "properties": { + "reinvest": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "_BondAllTokens can only be called by the contract itself, after all rewards have been withdrawn. This is an example of using \"callbacks\" in message flows. This can only be invoked by the contract itself as a return from Reinvest", + "type": "object", + "required": [ + "__bond_all_tokens" + ], + "properties": { + "__bond_all_tokens": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/staking/schema/raw/instantiate.json b/contracts/staking/schema/raw/instantiate.json new file mode 100644 index 0000000000..dd25457114 --- /dev/null +++ b/contracts/staking/schema/raw/instantiate.json @@ -0,0 +1,60 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "required": [ + "decimals", + "exit_tax", + "min_withdrawal", + "name", + "symbol", + "validator" + ], + "properties": { + "decimals": { + "description": "decimal places of the derivative token (for UI) TODO: does this make sense? Do we need to normalize on this? We don't even know the decimals of the native token", + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "exit_tax": { + "description": "this is how much the owner takes as a cut when someone unbonds TODO", + "allOf": [ + { + "$ref": "#/definitions/Decimal" + } + ] + }, + "min_withdrawal": { + "description": "This is the minimum amount we will pull out to reinvest, as well as a minumum that can be unbonded (to avoid needless staking tx)", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "name": { + "description": "name of the derivative token (FIXME: auto-generate?)", + "type": "string" + }, + "symbol": { + "description": "symbol / ticker of the derivative token", + "type": "string" + }, + "validator": { + "description": "This is the validator that all tokens will be bonded to", + "type": "string" + } + }, + "additionalProperties": false, + "definitions": { + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/staking/schema/raw/migrate.json b/contracts/staking/schema/raw/migrate.json new file mode 100644 index 0000000000..159d67cd90 --- /dev/null +++ b/contracts/staking/schema/raw/migrate.json @@ -0,0 +1,116 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Transfer moves the derivative token", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "recipient" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "recipient": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Bond will bond all staking tokens sent with the message and release derivative tokens", + "type": "object", + "required": [ + "bond" + ], + "properties": { + "bond": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Unbond will \"burn\" the given amount of derivative tokens and send the unbonded staking tokens to the message sender (after exit tax is deducted)", + "type": "object", + "required": [ + "unbond" + ], + "properties": { + "unbond": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Claim is used to claim your native tokens that you previously \"unbonded\" after the chain-defined waiting period (eg. 3 weeks)", + "type": "object", + "required": [ + "claim" + ], + "properties": { + "claim": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Reinvest will check for all accumulated rewards, withdraw them, and re-bond them to the same validator. Anyone can call this, which updates the value of the token (how much under custody).", + "type": "object", + "required": [ + "reinvest" + ], + "properties": { + "reinvest": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "_BondAllTokens can only be called by the contract itself, after all rewards have been withdrawn. This is an example of using \"callbacks\" in message flows. This can only be invoked by the contract itself as a return from Reinvest", + "type": "object", + "required": [ + "__bond_all_tokens" + ], + "properties": { + "__bond_all_tokens": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/staking/schema/raw/query.json b/contracts/staking/schema/raw/query.json new file mode 100644 index 0000000000..159d67cd90 --- /dev/null +++ b/contracts/staking/schema/raw/query.json @@ -0,0 +1,116 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Transfer moves the derivative token", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "recipient" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "recipient": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Bond will bond all staking tokens sent with the message and release derivative tokens", + "type": "object", + "required": [ + "bond" + ], + "properties": { + "bond": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Unbond will \"burn\" the given amount of derivative tokens and send the unbonded staking tokens to the message sender (after exit tax is deducted)", + "type": "object", + "required": [ + "unbond" + ], + "properties": { + "unbond": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Claim is used to claim your native tokens that you previously \"unbonded\" after the chain-defined waiting period (eg. 3 weeks)", + "type": "object", + "required": [ + "claim" + ], + "properties": { + "claim": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Reinvest will check for all accumulated rewards, withdraw them, and re-bond them to the same validator. Anyone can call this, which updates the value of the token (how much under custody).", + "type": "object", + "required": [ + "reinvest" + ], + "properties": { + "reinvest": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "_BondAllTokens can only be called by the contract itself, after all rewards have been withdrawn. This is an example of using \"callbacks\" in message flows. This can only be invoked by the contract itself as a return from Reinvest", + "type": "object", + "required": [ + "__bond_all_tokens" + ], + "properties": { + "__bond_all_tokens": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/staking/schema/raw/response_to_balance.json b/contracts/staking/schema/raw/response_to_balance.json new file mode 100644 index 0000000000..7dcf4d4a51 --- /dev/null +++ b/contracts/staking/schema/raw/response_to_balance.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "BalanceResponse", + "type": "object", + "required": [ + "balance" + ], + "properties": { + "balance": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false, + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/staking/schema/raw/response_to_claims.json b/contracts/staking/schema/raw/response_to_claims.json new file mode 100644 index 0000000000..b393e85853 --- /dev/null +++ b/contracts/staking/schema/raw/response_to_claims.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ClaimsResponse", + "type": "object", + "required": [ + "claims" + ], + "properties": { + "claims": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false, + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/staking/schema/raw/response_to_investment.json b/contracts/staking/schema/raw/response_to_investment.json new file mode 100644 index 0000000000..ffa5b81226 --- /dev/null +++ b/contracts/staking/schema/raw/response_to_investment.json @@ -0,0 +1,75 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InvestmentResponse", + "type": "object", + "required": [ + "exit_tax", + "min_withdrawal", + "nominal_value", + "owner", + "staked_tokens", + "token_supply", + "validator" + ], + "properties": { + "exit_tax": { + "description": "this is how much the owner takes as a cut when someone unbonds", + "allOf": [ + { + "$ref": "#/definitions/Decimal" + } + ] + }, + "min_withdrawal": { + "description": "This is the minimum amount we will pull out to reinvest, as well as a minumum that can be unbonded (to avoid needless staking tx)", + "allOf": [ + { + "$ref": "#/definitions/Uint128" + } + ] + }, + "nominal_value": { + "$ref": "#/definitions/Decimal" + }, + "owner": { + "description": "owner created the contract and takes a cut", + "type": "string" + }, + "staked_tokens": { + "$ref": "#/definitions/Coin" + }, + "token_supply": { + "$ref": "#/definitions/Uint128" + }, + "validator": { + "description": "All tokens are bonded to this validator", + "type": "string" + } + }, + "additionalProperties": false, + "definitions": { + "Coin": { + "type": "object", + "required": [ + "amount", + "denom" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" + } + } + }, + "Decimal": { + "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", + "type": "string" + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/staking/schema/raw/response_to_token_info.json b/contracts/staking/schema/raw/response_to_token_info.json new file mode 100644 index 0000000000..76b139ecf9 --- /dev/null +++ b/contracts/staking/schema/raw/response_to_token_info.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "TokenInfoResponse", + "description": "TokenInfoResponse is info to display the derivative token in a UI", + "type": "object", + "required": [ + "decimals", + "name", + "symbol" + ], + "properties": { + "decimals": { + "description": "decimal places of the derivative token (for UI)", + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "name": { + "description": "name of the derivative token", + "type": "string" + }, + "symbol": { + "description": "symbol / ticker of the derivative token", + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/staking/schema/raw/sudo.json b/contracts/staking/schema/raw/sudo.json new file mode 100644 index 0000000000..159d67cd90 --- /dev/null +++ b/contracts/staking/schema/raw/sudo.json @@ -0,0 +1,116 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "description": "Transfer moves the derivative token", + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "recipient" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "recipient": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Bond will bond all staking tokens sent with the message and release derivative tokens", + "type": "object", + "required": [ + "bond" + ], + "properties": { + "bond": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Unbond will \"burn\" the given amount of derivative tokens and send the unbonded staking tokens to the message sender (after exit tax is deducted)", + "type": "object", + "required": [ + "unbond" + ], + "properties": { + "unbond": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Claim is used to claim your native tokens that you previously \"unbonded\" after the chain-defined waiting period (eg. 3 weeks)", + "type": "object", + "required": [ + "claim" + ], + "properties": { + "claim": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Reinvest will check for all accumulated rewards, withdraw them, and re-bond them to the same validator. Anyone can call this, which updates the value of the token (how much under custody).", + "type": "object", + "required": [ + "reinvest" + ], + "properties": { + "reinvest": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "_BondAllTokens can only be called by the contract itself, after all rewards have been withdrawn. This is an example of using \"callbacks\" in message flows. This can only be invoked by the contract itself as a return from Reinvest", + "type": "object", + "required": [ + "__bond_all_tokens" + ], + "properties": { + "__bond_all_tokens": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/packages/schema-derive/src/generate_api.rs b/packages/schema-derive/src/generate_api.rs index 33064df1de..f67ac94318 100644 --- a/packages/schema-derive/src/generate_api.rs +++ b/packages/schema-derive/src/generate_api.rs @@ -20,20 +20,6 @@ pub fn write_api_impl(input: Options) -> Block { use ::cosmwasm_schema::{remove_schemas, Api, QueryResponses}; - if env::args().find(|arg| arg == "--help").is_some() { - println!("USAGE:"); - println!(" cargo schema [OPTIONS]"); - println!(); - println!("FLAGS:"); - println!(" --basic"); - println!(" Generate pure JSON schema files rather than the \"unified\" format."); - println!(" --help"); - println!(" Print this helpfile."); - return; - } - - let basic = env::args().find(|arg| arg == "--basic").is_some(); - let mut out_dir = env::current_dir().unwrap(); out_dir.push("schema"); create_dir_all(&out_dir).unwrap(); @@ -41,19 +27,21 @@ pub fn write_api_impl(input: Options) -> Block { let api = #api_object.render(); - if basic { - for (filename, json) in api.to_schema_files().unwrap() { - let path = out_dir.join(filename); - write(&path, json + "\n").unwrap(); - println!("Exported {}", path.to_str().unwrap()); - } - } else { - let path = out_dir.join(concat!(#name, ".json")); + let path = out_dir.join(concat!(#name, ".json")); + + let json = api.to_string().unwrap(); + write(&path, json + "\n").unwrap(); + println!("Exported the full API as {}", path.to_str().unwrap()); + + let raw_dir = out_dir.join("raw"); + create_dir_all(&raw_dir).unwrap(); + + for (filename, json) in api.to_schema_files().unwrap() { + let path = raw_dir.join(filename); - let json = api.to_string().unwrap(); write(&path, json + "\n").unwrap(); - println!("Exported the full API as {}", path.to_str().unwrap()); + println!("Exported {}", path.to_str().unwrap()); } } } From d52f9777d90643974831dd90fcaf5c9989554677 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 21 Nov 2022 17:59:37 +0100 Subject: [PATCH 014/187] Add initial instantiate2_address implementation --- Cargo.lock | 1 + contracts/burner/Cargo.lock | 1 + contracts/crypto-verify/Cargo.lock | 1 + contracts/cyberpunk/Cargo.lock | 1 + contracts/floaty/Cargo.lock | 1 + contracts/hackatom/Cargo.lock | 1 + contracts/ibc-reflect-send/Cargo.lock | 1 + contracts/ibc-reflect/Cargo.lock | 1 + contracts/queue/Cargo.lock | 1 + contracts/reflect/Cargo.lock | 1 + contracts/staking/Cargo.lock | 1 + packages/std/Cargo.toml | 1 + packages/std/src/addresses.rs | 151 ++++++++++++++++++++++++++ packages/std/src/lib.rs | 2 +- 14 files changed, 164 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index a0c1c8f276..3409fe6398 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,6 +321,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index aab6e4eb26..8ce9fa5f8b 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -223,6 +223,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index 70e33e0629..45b1e80a9c 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -218,6 +218,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index 0b83be8a3d..b62dcbdf63 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -241,6 +241,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index 500aa21fdc..1f2c2202d3 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -212,6 +212,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index 8390c799d5..9cc29d7b9e 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -212,6 +212,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index 5049396e67..fd280678ff 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -212,6 +212,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index 98831f4271..198d980637 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -212,6 +212,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index cd65a4253e..bdc63c558c 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -212,6 +212,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index 881705e2ac..f1005dd6fc 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -212,6 +212,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index 4e52d9f26d..db94696e4c 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -212,6 +212,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "sha2 0.10.3", "thiserror", "uint", ] diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index ee6d84597a..fe71667207 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -47,6 +47,7 @@ derivative = "2" forward_ref = "1" hex = "0.4" schemars = "0.8.3" +sha2 = "0.10.3" serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } serde-json-wasm = { version = "0.4.1" } thiserror = "1.0.13" diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index ef03d5ab60..4fa4cb19bd 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -1,5 +1,9 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use sha2::{ + digest::{Digest, Update}, + Sha256, +}; use std::borrow::Cow; use std::fmt; use std::ops::Deref; @@ -271,9 +275,95 @@ impl fmt::Display for CanonicalAddr { } } +#[derive(Debug)] +pub enum Instantiate2AddressError { + /// Checksum must be 32 bytes + InvalidChecksumLength, + /// Salt must be between 1 and 64 bytes + InvalidSaltLength, +} + +/// Creates a contract address using the predictable address format introduced with +/// wasmd 0.29. When using instantiate2, this is a way to precompute the address. +/// Then using instantiate, the contract address will use a different algorithm and +/// cannot be pre-computed as it contains inputs from the chain's state at the time of +/// message execution. +/// +/// The predicable address format of instantiate2 is stable. But bear in mind this is +/// a powerful tool that requires multiple software components to work together smoothly. +/// It should be used carefully and tested thoroughly to avoid the loss of funds. +/// +/// This method operates on [`CanonicalAddr`] to be implemented without chain interaction. +/// The typical usage looks like this: +/// +/// ``` +/// # use cosmwasm_std::{ +/// # HexBinary, +/// # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, +/// # Response, QueryResponse, +/// # }; +/// # type ExecuteMsg = (); +/// use cosmwasm_std::instantiate2_address; +/// +/// #[entry_point] +/// pub fn execute( +/// deps: DepsMut, +/// env: Env, +/// info: MessageInfo, +/// msg: ExecuteMsg, +/// ) -> Result { +/// let canonical_creator = deps.api.addr_canonicalize(env.contract.address.as_str())?; +/// let checksum = HexBinary::from_hex("9af782a3a1bcbcd22dbb6a45c751551d9af782a3a1bcbcd22dbb6a45c751551d")?; +/// let salt = b"instance 1231"; +/// let canonical_addr = instantiate2_address(&checksum, &canonical_creator, salt, None) +/// .map_err(|_| StdError::generic_err("Could not calculate addr"))?; +/// let addr = deps.api.addr_humanize(&canonical_addr)?; +/// +/// # Ok(Default::default()) +/// } +/// ``` +pub fn instantiate2_address( + checksum: &[u8], + creator: &CanonicalAddr, + salt: &[u8], + msg: Option<&[u8]>, +) -> Result { + if checksum.len() != 32 { + return Err(Instantiate2AddressError::InvalidChecksumLength); + } + + if salt.is_empty() || salt.len() > 64 { + return Err(Instantiate2AddressError::InvalidSaltLength); + }; + + let msg = msg.unwrap_or_default(); + + let mut key = Vec::::new(); + key.extend_from_slice(b"wasm\0"); + key.extend_from_slice(&(checksum.len() as u64).to_be_bytes()); + key.extend_from_slice(checksum); + key.extend_from_slice(&(creator.len() as u64).to_be_bytes()); + key.extend_from_slice(creator); + key.extend_from_slice(&(salt.len() as u64).to_be_bytes()); + key.extend_from_slice(salt); + key.extend_from_slice(&(msg.len() as u64).to_be_bytes()); + key.extend_from_slice(msg); + let address_data = hash("module", &key); + Ok(address_data.into()) +} + +/// The "Basic Address" Hash from +/// https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/docs/architecture/adr-028-public-key-addresses.md +fn hash(ty: &str, key: &[u8]) -> Vec { + let inner = Sha256::digest(ty.as_bytes()); + Sha256::new().chain(inner).chain(key).finalize().to_vec() +} + #[cfg(test)] mod tests { use super::*; + use crate::HexBinary; + use hex_literal::hex; use std::collections::hash_map::DefaultHasher; use std::collections::HashSet; use std::hash::{Hash, Hasher}; @@ -567,4 +657,65 @@ mod tests { // pass by value assert_eq!(value, &flexible(addr)); } + + #[test] + fn instantiate2_address_works() { + let checksum1 = + HexBinary::from_hex("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5") + .unwrap(); + let creator1 = CanonicalAddr::from(hex!("9999999999aaaaaaaaaabbbbbbbbbbcccccccccc")); + let salt1 = hex!("61"); + let salt2 = hex!("aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae"); + let msg1: Option<&[u8]> = None; + let msg2: Option<&[u8]> = Some(b"{}"); + let msg3: Option<&[u8]> = Some(b"{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"); + + // No msg + let expected = CanonicalAddr::from(hex!( + "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847" + )); + assert_eq!( + instantiate2_address(&checksum1, &creator1, &salt1, msg1).unwrap(), + expected + ); + + // With msg + let expected = CanonicalAddr::from(hex!( + "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835" + )); + assert_eq!( + instantiate2_address(&checksum1, &creator1, &salt1, msg2).unwrap(), + expected + ); + + // Long msg + let expected = CanonicalAddr::from(hex!( + "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167" + )); + assert_eq!( + instantiate2_address(&checksum1, &creator1, &salt1, msg3).unwrap(), + expected + ); + + // Long salt + let expected = CanonicalAddr::from(hex!( + "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564" + )); + assert_eq!( + instantiate2_address(&checksum1, &creator1, &salt2, None).unwrap(), + expected + ); + + // Salt too short or too long + let empty = Vec::::new(); + assert!(matches!( + instantiate2_address(&checksum1, &creator1, &empty, None).unwrap_err(), + Instantiate2AddressError::InvalidSaltLength + )); + let too_long = vec![0x11; 65]; + assert!(matches!( + instantiate2_address(&checksum1, &creator1, &too_long, None).unwrap_err(), + Instantiate2AddressError::InvalidSaltLength + )); + } } diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 26445f4b55..4a03d3025a 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -25,7 +25,7 @@ mod timestamp; mod traits; mod types; -pub use crate::addresses::{Addr, CanonicalAddr}; +pub use crate::addresses::{instantiate2_address, Addr, CanonicalAddr}; pub use crate::binary::Binary; pub use crate::coin::{coin, coins, has_coins, Coin}; pub use crate::deps::{Deps, DepsMut, OwnedDeps}; From f5b007a39714d2a41493f5ffa637b8310ae838ab Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 18 Oct 2022 11:39:38 +0200 Subject: [PATCH 015/187] Test invalid checksum lengths --- packages/std/src/addresses.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 4fa4cb19bd..0220f93dc3 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -717,5 +717,22 @@ mod tests { instantiate2_address(&checksum1, &creator1, &too_long, None).unwrap_err(), Instantiate2AddressError::InvalidSaltLength )); + + // invalid checksum length + let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2"); + assert!(matches!( + instantiate2_address(&broken_cs, &creator1, &salt1, None).unwrap_err(), + Instantiate2AddressError::InvalidChecksumLength + )); + let broken_cs = hex!(""); + assert!(matches!( + instantiate2_address(&broken_cs, &creator1, &salt1, None).unwrap_err(), + Instantiate2AddressError::InvalidChecksumLength + )); + let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2aaaa"); + assert!(matches!( + instantiate2_address(&broken_cs, &creator1, &salt1, None).unwrap_err(), + Instantiate2AddressError::InvalidChecksumLength + )); } } From c5ddc3d0ac00049eabc7b9d71939f4807f5c96db Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 18 Oct 2022 16:13:10 +0200 Subject: [PATCH 016/187] Test instantiate2_address against test vectors --- Cargo.lock | 1 + packages/std/Cargo.toml | 1 + packages/std/src/addresses.rs | 69 ++++ .../std/testdata/instantiate2_addresses.json | 386 ++++++++++++++++++ 4 files changed, 457 insertions(+) create mode 100644 packages/std/testdata/instantiate2_addresses.json diff --git a/Cargo.lock b/Cargo.lock index 3409fe6398..d43b7d1b6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,6 +321,7 @@ dependencies = [ "schemars", "serde", "serde-json-wasm", + "serde_json", "sha2 0.10.3", "thiserror", "uint", diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index fe71667207..5d7475d060 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -61,3 +61,4 @@ cosmwasm-schema = { path = "../schema" } # The chrono dependency is only used in an example, which Rust compiles for us. If this causes trouble, remove it. chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] } hex-literal = "0.3.1" +serde_json = "1.0.81" diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 0220f93dc3..8b1d0102b4 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -735,4 +735,73 @@ mod tests { Instantiate2AddressError::InvalidChecksumLength )); } + + #[test] + fn instantiate2_address_works_for_cosmjs_testvectors() { + // Test data from https://github.com/cosmos/cosmjs/pull/1253 + const COSMOS_ED25519_TESTS_JSON: &str = "./testdata/instantiate2_addresses.json"; + + #[derive(Deserialize, Debug)] + #[serde(rename_all = "camelCase")] + #[allow(dead_code)] + struct In { + checksum: HexBinary, + creator: String, + creator_data: HexBinary, + salt: HexBinary, + msg: Option, + } + + #[derive(Deserialize, Debug)] + #[serde(rename_all = "camelCase")] + #[allow(dead_code)] + struct Intermediate { + key: HexBinary, + address_data: HexBinary, + } + + #[derive(Deserialize, Debug)] + #[serde(rename_all = "camelCase")] + #[allow(dead_code)] + struct Out { + address: String, + } + + #[derive(Deserialize, Debug)] + #[allow(dead_code)] + struct Row { + #[serde(rename = "in")] + input: In, + intermediate: Intermediate, + out: Out, + } + + fn read_tests() -> Vec { + use std::fs::File; + use std::io::BufReader; + + // Open the file in read-only mode with buffer. + let file = File::open(COSMOS_ED25519_TESTS_JSON).unwrap(); + let reader = BufReader::new(file); + + serde_json::from_reader(reader).unwrap() + } + + for Row { + input, + intermediate, + out: _, + } in read_tests() + { + let msg = input.msg.map(|msg| msg.into_bytes()); + let addr = instantiate2_address( + &input.checksum, + &input.creator_data.into(), + &input.salt, + msg.as_deref(), + ) + .unwrap(); + assert_eq!(addr, intermediate.address_data); + } + } } diff --git a/packages/std/testdata/instantiate2_addresses.json b/packages/std/testdata/instantiate2_addresses.json new file mode 100644 index 0000000000..a12ad69521 --- /dev/null +++ b/packages/std/testdata/instantiate2_addresses.json @@ -0,0 +1,386 @@ +[ + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000", + "addressData": "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847" + }, + "out": { + "address": "purple1t6r960j945lfv8mhl4mage2rg97w63xeynwrupum2s2l7em4lprs9ce5hk" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d", + "addressData": "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835" + }, + "out": { + "address": "purple1px25n9sgj3a99q0zcl4awx7my6s6mxqegmdd2lmvf5lwxh080q6suttktr" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167" + }, + "out": { + "address": "purple1svexu428ywc4htrxfn4tezjcsl38qqata8aany4033auafr529ns4v254c" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564" + }, + "out": { + "address": "purple1jwzvvfyvpwchrccxl476pxf7c83qawsqv3f2820q0zyrav6eg4jqdcq7gc" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "9a8d5f98fb186825401a26206158e7a1213311a9b6a87944469913655af52ffb" + }, + "out": { + "address": "purple1n2x4lx8mrp5z2sq6ycsxzk885ysnxydfk658j3zxnyfk2kh49lasesxf6j" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "932f07bc53f7d0b0b43cb5a54ac3e245b205e6ae6f7c1d991dc6af4a2ff9ac18" + }, + "out": { + "address": "purple1jvhs00zn7lgtpdpukkj54slzgkeqte4wda7pmxgac6h55tle4svq8cmp60" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000", + "addressData": "9725e94f528d8b78d33c25f3dfcd60e6142d8be60ab36f6a5b59036fd51560db" + }, + "out": { + "address": "purple1juj7jn6j3k9h35euyhealntquc2zmzlxp2ek76jmtypkl4g4vrdsfwmwxk" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d", + "addressData": "b056e539bbaf447ba18f3f13b792970111fc78933eb6700f4d227b5216d63658" + }, + "out": { + "address": "purple1kptw2wdm4az8hgv08ufm0y5hqyglc7yn86m8qr6dyfa4y9kkxevqmkm9q3" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "6c98434180f052294ff89fb6d2dae34f9f4468b0b8e6e7c002b2a44adee39abd" + }, + "out": { + "address": "purple1djvyxsvq7pfzjnlcn7md9khrf705g69shrnw0sqzk2jy4hhrn27sjh2ysy" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "0aaf1c31c5d529d21d898775bc35b3416f47bfd99188c334c6c716102cbd3101" + }, + "out": { + "address": "purple1p2h3cvw9655ay8vfsa6mcddng9h5007ejxyvxdxxcutpqt9axyqsagmmay" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "36fe6ab732187cdfed46290b448b32eb7f4798e7a4968b0537de8a842cbf030e" + }, + "out": { + "address": "purple1xmlx4dejrp7dlm2x9y95fzejadl50x885jtgkpfhm69ggt9lqv8qk3vn4f" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "a0d0c942adac6f3e5e7c23116c4c42a24e96e0ab75f53690ec2d3de16067c751" + }, + "out": { + "address": "purple15rgvjs4d43hnuhnuyvgkcnzz5f8fdc9twh6ndy8v9577zcr8cags40l9dt" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000", + "addressData": "b95c467218d408a0f93046f227b6ece7fe18133ff30113db4d2a7becdfeca141" + }, + "out": { + "address": "purple1h9wyvusc6sy2p7fsgmez0dhvullpsyel7vq38k6d9fa7ehlv59qsvnyh36" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d", + "addressData": "23fe45dbbd45dc6cd25244a74b6e99e7a65bf0bac2f2842a05049d37555a3ae6" + }, + "out": { + "address": "purple1y0lytkaaghwxe5jjgjn5km5eu7n9hu96ctegg2s9qjwnw4268tnqxhg60a" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "6faea261ed63baa65b05726269e83b217fa6205dc7d9fb74f9667d004a69c082" + }, + "out": { + "address": "purple1d7h2yc0dvwa2vkc9wf3xn6pmy9l6vgzaclvlka8eve7sqjnfczpqqsdnwu" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "67a3ab6384729925fdb144574628ce96836fe098d2c6be4e84ac106b2728d96c" + }, + "out": { + "address": "purple1v736kcuyw2vjtld3g3t5v2xwj6pklcyc6trtun5y4sgxkfegm9kq7vgpnt" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "23a121263bfce05c144f4af86f3d8a9f87dc56f9dc48dbcffc8c5a614da4c661" + }, + "out": { + "address": "purple1ywsjzf3mlns9c9z0ftux70v2n7rac4hem3ydhnlu33dxzndycesssc7x2m" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "dd90dba6d6fcd5fb9c9c8f536314eb1bb29cb5aa084b633c5806b926a5636b58" + }, + "out": { + "address": "purple1mkgdhfkkln2lh8yu3afkx98trwefedd2pp9kx0zcq6ujdftrddvq50esay" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000", + "addressData": "547a743022f4f1af05b102f57bf1c1c7d7ee81bae427dc20d36b2c4ec57612ae" + }, + "out": { + "address": "purple123a8gvpz7nc67pd3qt6hhuwpclt7aqd6usnacgxndvkya3tkz2hq5hz38f" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d", + "addressData": "416e169110e4b411bc53162d7503b2bbf14d6b36b1413a4f4c9af622696e9665" + }, + "out": { + "address": "purple1g9hpdygsuj6pr0znzckh2qajh0c566ekk9qn5n6vntmzy6twjejsrl9alk" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "619a0988b92d8796cea91dea63cbb1f1aefa4a6b6ee5c5d1e937007252697220" + }, + "out": { + "address": "purple1vxdqnz9e9kredn4frh4x8ja37xh05jntdmjut50fxuq8y5nfwgsquu9mxh" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "d8af856a6a04852d19b647ad6d4336eb26e077f740aef1a0331db34d299a885a" + }, + "out": { + "address": "purple1mzhc26n2qjzj6xdkg7kk6sekavnwqalhgzh0rgpnrke562v63pdq8grp8q" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "c7fb7bea96daab23e416c4fcf328215303005e1d0d5424257335568e5381e33c" + }, + "out": { + "address": "purple1clahh65km24j8eqkcn70x2pp2vpsqhsap42zgftnx4tgu5upuv7q9ywjws" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "ccdf9dea141a6c2475870529ab38fae9dec30df28e005894fe6578b66133ab4a" + }, + "out": { + "address": "purple1en0em6s5rfkzgav8q556kw86a80vxr0j3cq93987v4utvcfn4d9q0tql4w" + } + } +] From e05b74e82c3e16a94de64984ccaf3e47885cadc8 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 21 Nov 2022 19:16:11 +0100 Subject: [PATCH 017/187] Test Basic Address hash --- packages/std/src/addresses.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 8b1d0102b4..9112fac447 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -804,4 +804,14 @@ mod tests { assert_eq!(addr, intermediate.address_data); } } + + #[test] + fn hash_works() { + // Test case from https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-alpha1/types/address/hash_test.go#L19-L24 + let expected = [ + 195, 235, 23, 251, 9, 99, 177, 195, 81, 122, 182, 124, 36, 113, 245, 156, 76, 188, 221, + 83, 181, 192, 227, 82, 100, 177, 161, 133, 240, 160, 5, 25, + ]; + assert_eq!(hash("1", &[1]), expected); + } } From b1215387410c33c778d86ba9e642b410bdcaaf19 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 21 Nov 2022 19:16:30 +0100 Subject: [PATCH 018/187] Fix doc text --- packages/std/src/addresses.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 9112fac447..93248e0018 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -285,7 +285,7 @@ pub enum Instantiate2AddressError { /// Creates a contract address using the predictable address format introduced with /// wasmd 0.29. When using instantiate2, this is a way to precompute the address. -/// Then using instantiate, the contract address will use a different algorithm and +/// When using instantiate, the contract address will use a different algorithm and /// cannot be pre-computed as it contains inputs from the chain's state at the time of /// message execution. /// From 4e844177a936656ba1c3c981c759d4cdb24fc7b3 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 22 Nov 2022 11:10:00 +0100 Subject: [PATCH 019/187] Add CHANGELOG entry for instantiate2_address --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c28ed4589..1b19dd6701 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,12 @@ and this project adheres to the `cosmwasm_1_2` feature needs to be enabled for the `cosmwasm_std` dependency. This makes the contract incompatible with chains running versions of CosmWasm earlier than 1.2.0 ([#1481]). +- cosmwasm-std: Add `instantiate2_address` which allows calculating the + predictable addresses for `MsgInstantiateContract2` ([#1437]). - cosmwasm-schema: In contracts, `cosmwasm schema` will now output a separate JSON Schema file for each entrypoint in the `raw` subdirectory. +[#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 [#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 ### Changed From b54c8ed0d6c139120737767fdab989d74159a479 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 22 Nov 2022 14:43:19 +0100 Subject: [PATCH 020/187] docs: provide a list of all built-in capabilities --- docs/CAPABILITIES-BUILT-IN.md | 17 +++++++++++++++++ docs/CAPABILITIES.md | 11 +---------- 2 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 docs/CAPABILITIES-BUILT-IN.md diff --git a/docs/CAPABILITIES-BUILT-IN.md b/docs/CAPABILITIES-BUILT-IN.md new file mode 100644 index 0000000000..c3e425e554 --- /dev/null +++ b/docs/CAPABILITIES-BUILT-IN.md @@ -0,0 +1,17 @@ +# Built-in capabilities + +Since capabilities can be created between contract and environment, we don't +know them all in the VM. This is a list of all built-in capabilities, but chains +might define others. + +- `iterator` is for storage backends that allow range queries. Not all types of + databases do that. There are trees that don't allow it and Secret Network does + not support iterators for other technical reasons. +- `stargate` is for messages and queries that came with the Cosmos SDK upgrade + "Stargate". It primarily includes protobuf messages and IBC support. +- `staking` is for chains with the Cosmos SDK staking module. There are Cosmos + chains that don't use this (e.g. Tgrade). +- `cosmwasm_1_1` enables the `BankQuery::Supply` query. Only chains running + CosmWasm `1.1.0` or higher support this query. +- `cosmwasm_1_2` enables the `GovMsg::VoteWeighted` message. Only chains running + CosmWasm `1.2.0` or higher support this query. diff --git a/docs/CAPABILITIES.md b/docs/CAPABILITIES.md index 2679f5dd7c..0886d15b64 100644 --- a/docs/CAPABILITIES.md +++ b/docs/CAPABILITIES.md @@ -83,16 +83,7 @@ underscores. ## Common capabilities -Here is a list of capabilities created in the past. Since capabilities can be -created between contract and environment, we don't know them all in the VM. - -- `iterator` is for storage backends that allow range queries. Not all types of - databases do that. There are trees that don't allow it and Secret Network does - not support iterators for other technical reasons. -- `stargate` is for messages and queries that came with the Cosmos SDK upgrade - "Stargate". It primarily includes protobuf messages and IBC support. -- `staking` is for chains with the Cosmos SDK staking module. There are Cosmos - chains that don't use this (e.g. Tgrade). +Here is a list of all [built-in capabilities](CAPABILITIES-BUILT-IN.md). ## What's a good capability? From 46350b89c750c4fbbd4aaa5b974bf63c5c2dca06 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 22 Nov 2022 14:45:19 +0100 Subject: [PATCH 021/187] Revert "docs: provide a list of all built-in capabilities" This reverts commit b54c8ed0d6c139120737767fdab989d74159a479. --- docs/CAPABILITIES-BUILT-IN.md | 17 ----------------- docs/CAPABILITIES.md | 11 ++++++++++- 2 files changed, 10 insertions(+), 18 deletions(-) delete mode 100644 docs/CAPABILITIES-BUILT-IN.md diff --git a/docs/CAPABILITIES-BUILT-IN.md b/docs/CAPABILITIES-BUILT-IN.md deleted file mode 100644 index c3e425e554..0000000000 --- a/docs/CAPABILITIES-BUILT-IN.md +++ /dev/null @@ -1,17 +0,0 @@ -# Built-in capabilities - -Since capabilities can be created between contract and environment, we don't -know them all in the VM. This is a list of all built-in capabilities, but chains -might define others. - -- `iterator` is for storage backends that allow range queries. Not all types of - databases do that. There are trees that don't allow it and Secret Network does - not support iterators for other technical reasons. -- `stargate` is for messages and queries that came with the Cosmos SDK upgrade - "Stargate". It primarily includes protobuf messages and IBC support. -- `staking` is for chains with the Cosmos SDK staking module. There are Cosmos - chains that don't use this (e.g. Tgrade). -- `cosmwasm_1_1` enables the `BankQuery::Supply` query. Only chains running - CosmWasm `1.1.0` or higher support this query. -- `cosmwasm_1_2` enables the `GovMsg::VoteWeighted` message. Only chains running - CosmWasm `1.2.0` or higher support this query. diff --git a/docs/CAPABILITIES.md b/docs/CAPABILITIES.md index 0886d15b64..2679f5dd7c 100644 --- a/docs/CAPABILITIES.md +++ b/docs/CAPABILITIES.md @@ -83,7 +83,16 @@ underscores. ## Common capabilities -Here is a list of all [built-in capabilities](CAPABILITIES-BUILT-IN.md). +Here is a list of capabilities created in the past. Since capabilities can be +created between contract and environment, we don't know them all in the VM. + +- `iterator` is for storage backends that allow range queries. Not all types of + databases do that. There are trees that don't allow it and Secret Network does + not support iterators for other technical reasons. +- `stargate` is for messages and queries that came with the Cosmos SDK upgrade + "Stargate". It primarily includes protobuf messages and IBC support. +- `staking` is for chains with the Cosmos SDK staking module. There are Cosmos + chains that don't use this (e.g. Tgrade). ## What's a good capability? From 9fd98903ecbe02d892dfd86ede20ec55203fe434 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 22 Nov 2022 14:46:34 +0100 Subject: [PATCH 022/187] docs: provide a list of all built-in capabilities --- docs/CAPABILITIES-BUILT-IN.md | 17 +++++++++++++++++ docs/CAPABILITIES.md | 11 +---------- 2 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 docs/CAPABILITIES-BUILT-IN.md diff --git a/docs/CAPABILITIES-BUILT-IN.md b/docs/CAPABILITIES-BUILT-IN.md new file mode 100644 index 0000000000..c3e425e554 --- /dev/null +++ b/docs/CAPABILITIES-BUILT-IN.md @@ -0,0 +1,17 @@ +# Built-in capabilities + +Since capabilities can be created between contract and environment, we don't +know them all in the VM. This is a list of all built-in capabilities, but chains +might define others. + +- `iterator` is for storage backends that allow range queries. Not all types of + databases do that. There are trees that don't allow it and Secret Network does + not support iterators for other technical reasons. +- `stargate` is for messages and queries that came with the Cosmos SDK upgrade + "Stargate". It primarily includes protobuf messages and IBC support. +- `staking` is for chains with the Cosmos SDK staking module. There are Cosmos + chains that don't use this (e.g. Tgrade). +- `cosmwasm_1_1` enables the `BankQuery::Supply` query. Only chains running + CosmWasm `1.1.0` or higher support this query. +- `cosmwasm_1_2` enables the `GovMsg::VoteWeighted` message. Only chains running + CosmWasm `1.2.0` or higher support this query. diff --git a/docs/CAPABILITIES.md b/docs/CAPABILITIES.md index 2679f5dd7c..0886d15b64 100644 --- a/docs/CAPABILITIES.md +++ b/docs/CAPABILITIES.md @@ -83,16 +83,7 @@ underscores. ## Common capabilities -Here is a list of capabilities created in the past. Since capabilities can be -created between contract and environment, we don't know them all in the VM. - -- `iterator` is for storage backends that allow range queries. Not all types of - databases do that. There are trees that don't allow it and Secret Network does - not support iterators for other technical reasons. -- `stargate` is for messages and queries that came with the Cosmos SDK upgrade - "Stargate". It primarily includes protobuf messages and IBC support. -- `staking` is for chains with the Cosmos SDK staking module. There are Cosmos - chains that don't use this (e.g. Tgrade). +Here is a list of all [built-in capabilities](CAPABILITIES-BUILT-IN.md). ## What's a good capability? From 6cbfcaa6d457862e19e4e227e031430db574ac82 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 22 Nov 2022 14:48:43 +0100 Subject: [PATCH 023/187] typo --- docs/CAPABILITIES-BUILT-IN.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CAPABILITIES-BUILT-IN.md b/docs/CAPABILITIES-BUILT-IN.md index c3e425e554..f0cabc280b 100644 --- a/docs/CAPABILITIES-BUILT-IN.md +++ b/docs/CAPABILITIES-BUILT-IN.md @@ -12,6 +12,6 @@ might define others. - `staking` is for chains with the Cosmos SDK staking module. There are Cosmos chains that don't use this (e.g. Tgrade). - `cosmwasm_1_1` enables the `BankQuery::Supply` query. Only chains running - CosmWasm `1.1.0` or higher support this query. + CosmWasm `1.1.0` or higher support this. - `cosmwasm_1_2` enables the `GovMsg::VoteWeighted` message. Only chains running - CosmWasm `1.2.0` or higher support this query. + CosmWasm `1.2.0` or higher support this. From 0f4468a3f153da726c42343fbf1722c857487c13 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 22 Nov 2022 15:16:54 +0100 Subject: [PATCH 024/187] Update docs/CAPABILITIES.md Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> --- docs/CAPABILITIES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CAPABILITIES.md b/docs/CAPABILITIES.md index 0886d15b64..e647274c85 100644 --- a/docs/CAPABILITIES.md +++ b/docs/CAPABILITIES.md @@ -81,7 +81,7 @@ function name in Rust and other CosmWasm smart contract languages such as Go. By convention, the name should be short and all lower ASCII alphanumerical plus underscores. -## Common capabilities +## Built-in capabilities Here is a list of all [built-in capabilities](CAPABILITIES-BUILT-IN.md). From 546cb4a6bd3d3005db18f729eb7531312bf0f6bb Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Nov 2022 18:30:08 +0100 Subject: [PATCH 025/187] Use Display representation for embedding Wasmer InstantiationErrors --- CHANGELOG.md | 3 +++ packages/vm/src/instance.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1953c0b3b..34c3b1682f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,8 +26,11 @@ and this project adheres to cosmwasm-vm on Windows. This gives us confidence for integrating cosmwasm-vm in a libwasmvm build on Windows. This change is likely to be consensus breaking as error messages change. ([#1406]) +- cosmwasm-vm: Use `Display` representation for embedding Wasmer + `InstantiationError`s ([#1508]). [#1406]: https://github.com/CosmWasm/cosmwasm/pull/1406 +[#1508]: https://github.com/CosmWasm/cosmwasm/issues/1508 ## [1.1.8] - 2022-11-22 diff --git a/packages/vm/src/instance.rs b/packages/vm/src/instance.rs index 66801435c7..706f261716 100644 --- a/packages/vm/src/instance.rs +++ b/packages/vm/src/instance.rs @@ -231,7 +231,7 @@ where WasmerInstance::new(module, &import_obj) } .map_err(|original| { - VmError::instantiation_err(format!("Error instantiating module: {:?}", original)) + VmError::instantiation_err(format!("Error instantiating module: {original}")) })?, ); From 52d26594c1089af05fd1d33dab0d4dae037b3278 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 23 Nov 2022 19:18:58 +0100 Subject: [PATCH 026/187] Fix link to cargo registry on Windows --- .circleci/config.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cd8159bc5b..3e32556e5c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -404,7 +404,7 @@ jobs: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-package_vm_windows-rust:1.65.0-{{ checksum "Cargo.lock" }} + - cachev3-package_vm_windows-rust:1.65.0-{{ checksum "Cargo.lock" }} - run: name: Test working_directory: ~/project/packages/vm @@ -415,11 +415,12 @@ jobs: command: cargo test --locked --features allow_interface_version_7,iterator,staking,stargate - save_cache: paths: - - /usr/local/cargo/registry + # ".." is the easiest way to get $HOME here (pwd is $HOME\project) + - ../.cargo/registry - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-package_vm_windows-rust:1.65.0-{{ checksum "Cargo.lock" }} + key: cachev3-package_vm_windows-rust:1.65.0-{{ checksum "Cargo.lock" }} contract_burner: docker: From 01f74b252393320749f2ceffe4de37e030e4a3a0 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 28 Nov 2022 10:42:41 +0100 Subject: [PATCH 027/187] Remove check_contract implementation --- packages/vm/examples/check_contract.rs | 60 +++----------------------- 1 file changed, 6 insertions(+), 54 deletions(-) diff --git a/packages/vm/examples/check_contract.rs b/packages/vm/examples/check_contract.rs index 1d53b164ee..8b17dec808 100644 --- a/packages/vm/examples/check_contract.rs +++ b/packages/vm/examples/check_contract.rs @@ -1,57 +1,9 @@ -use std::fs::File; -use std::io::Read; - -use clap::{App, Arg}; - -use cosmwasm_vm::capabilities_from_csv; -use cosmwasm_vm::internals::{check_wasm, compile}; - -const DEFAULT_AVAILABLE_CAPABILITIES: &str = "iterator,staking,stargate,cosmwasm_1_1"; - pub fn main() { - eprintln!("`check_contract` will be removed from the next version of `cosmwasm-vm` - please use `cosmwasm-check` instead."); + eprintln!("`check_contract` has been removed from `cosmwasm-vm` examples - please use `cosmwasm-check` instead."); + eprintln!("See https://crates.io/crates/cosmwasm-check"); + eprintln!(); eprintln!("> cargo install cosmwasm-check"); - - let matches = App::new("Contract checking") - .version("0.1.0") - .long_about("Checks the given wasm file (memories, exports, imports, available capabilities, and non-determinism).") - .author("Mauro Lacy ") - .arg( - Arg::with_name("CAPABILITIES") - // `long` setting required to turn the position argument into an option 🤷 - .long("available-capabilities") - .aliases(&["FEATURES", "supported-features"]) // Old names - .value_name("CAPABILITIES") - .help("Sets the available capabilities that the desired target chain has") - .takes_value(true) - ) - .arg( - Arg::with_name("WASM") - .help("Wasm file to read and compile") - .required(true) - .index(1), - ) - .get_matches(); - - // Available capabilities - let available_capabilities_csv = matches - .value_of("CAPABILITIES") - .unwrap_or(DEFAULT_AVAILABLE_CAPABILITIES); - let available_capabilities = capabilities_from_csv(available_capabilities_csv); - println!("Available capabilities: {:?}", available_capabilities); - - // File - let path = matches.value_of("WASM").expect("Error parsing file name"); - let mut file = File::open(path).unwrap(); - - // Read wasm - let mut wasm = Vec::::new(); - file.read_to_end(&mut wasm).unwrap(); - - // Check wasm - check_wasm(&wasm, &available_capabilities).unwrap(); - - // Compile module - compile(&wasm, None, &[]).unwrap(); - println!("contract checks passed.") + eprintln!("> cosmwasm-check --help"); + eprintln!(); + std::process::exit(74); } From b2ad9ce2727af5516fdc3e2ef181a61e8481c9ae Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 28 Nov 2022 12:21:59 +0100 Subject: [PATCH 028/187] test nested QueryMsg with generics --- Cargo.lock | 56 +++++++++++++++--- packages/schema/Cargo.toml | 1 + packages/schema/tests/generics.rs | 4 ++ packages/schema/tests/idl.rs | 94 ++++++++++++++++++++----------- 4 files changed, 114 insertions(+), 41 deletions(-) create mode 100644 packages/schema/tests/generics.rs diff --git a/Cargo.lock b/Cargo.lock index 0c1203379c..858b9ddcf0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ "anyhow", "clap", "colored", - "cosmwasm-std", + "cosmwasm-std 1.1.8", "cosmwasm-vm", ] @@ -274,11 +274,33 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cosmwasm-crypto" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532d2ba11b7157e3b67114389925568af29ce3e452b582d6bdfe751cb2dadfb1" +dependencies = [ + "digest 0.10.3", + "ed25519-zebra", + "k256", + "rand_core 0.6.3", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.1.8" +dependencies = [ + "cosmwasm-std 1.1.8", + "syn", +] + [[package]] name = "cosmwasm-derive" version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8568b289cc366981319ab39edd85d666456456f7c126433ef065ebe5257f27b2" dependencies = [ - "cosmwasm-std", "syn", ] @@ -288,6 +310,7 @@ version = "1.1.8" dependencies = [ "anyhow", "cosmwasm-schema-derive", + "cosmwasm-std 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "schemars", "semver", "serde", @@ -311,8 +334,8 @@ version = "1.1.8" dependencies = [ "base64", "chrono", - "cosmwasm-crypto", - "cosmwasm-derive", + "cosmwasm-crypto 1.1.8", + "cosmwasm-derive 1.1.8", "cosmwasm-schema", "derivative", "forward_ref", @@ -327,11 +350,30 @@ dependencies = [ "uint", ] +[[package]] +name = "cosmwasm-std" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1ceebd520a10167e35080e4f55f6b0284bb8ea364dec0f22197da96acd9e64" +dependencies = [ + "base64", + "cosmwasm-crypto 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cosmwasm-derive 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "thiserror", + "uint", +] + [[package]] name = "cosmwasm-storage" version = "1.1.8" dependencies = [ - "cosmwasm-std", + "cosmwasm-std 1.1.8", "serde", ] @@ -343,8 +385,8 @@ dependencies = [ "bytecheck", "clap", "clru", - "cosmwasm-crypto", - "cosmwasm-std", + "cosmwasm-crypto 1.1.8", + "cosmwasm-std 1.1.8", "criterion", "enumset", "hex", diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index 543e9c460f..751c40b3c4 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -16,5 +16,6 @@ thiserror = "1.0.13" [dev-dependencies] anyhow = "1.0.57" +cosmwasm-std = "1.1.8" semver = "1" tempfile = "3" diff --git a/packages/schema/tests/generics.rs b/packages/schema/tests/generics.rs new file mode 100644 index 0000000000..aa1a62bbdc --- /dev/null +++ b/packages/schema/tests/generics.rs @@ -0,0 +1,4 @@ +use std::collections::HashMap; + +use cosmwasm_schema::{cw_serde, generate_api, QueryResponses, IDL_VERSION}; +use serde_json::Value; diff --git a/packages/schema/tests/idl.rs b/packages/schema/tests/idl.rs index 5f1f8b036d..16442fc328 100644 --- a/packages/schema/tests/idl.rs +++ b/packages/schema/tests/idl.rs @@ -1,36 +1,32 @@ use std::collections::HashMap; -use cosmwasm_schema::{generate_api, QueryResponses, IDL_VERSION}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; +use cosmwasm_schema::{cw_serde, generate_api, QueryResponses, IDL_VERSION}; use serde_json::Value; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[cw_serde] pub struct InstantiateMsg { pub admin: String, pub cap: u128, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] +#[cw_serde] pub enum ExecuteMsg { Mint { amount: u128 }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, QueryResponses)] -#[serde(rename_all = "snake_case")] +#[cw_serde] +#[derive(QueryResponses)] pub enum QueryMsg { #[returns(u128)] Balance { account: String }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] +#[cw_serde] pub enum SudoMsg { SetAdmin { new_admin: String }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[cw_serde] pub struct MigrateMsg { pub admin: String, pub cap: u128, @@ -107,15 +103,15 @@ fn test_query_responses() { api.get("responses").unwrap().get("balance").unwrap(); } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, QueryResponses)] -#[serde(rename_all = "snake_case")] +#[cw_serde] +#[derive(QueryResponses)] pub enum QueryMsgWithGenerics { #[returns(u128)] QueryData { data: T }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, QueryResponses)] -#[serde(rename_all = "snake_case")] +#[cw_serde] +#[derive(QueryResponses)] pub enum QueryMsgWithGenericsAndTraitBounds where T: PartialEq, @@ -124,8 +120,8 @@ where QueryData { data: T }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, QueryResponses)] -#[serde(rename_all = "snake_case")] +#[cw_serde] +#[derive(QueryResponses)] pub enum QueryMsgWithGenericsAndDefaultType { #[returns(u128)] QueryData { data: T }, @@ -191,7 +187,8 @@ fn test_query_responses_generics_and_trait_bounds() { api.get("responses").unwrap().get("query_data").unwrap(); } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, QueryResponses)] +#[cw_serde] +#[derive(QueryResponses)] #[serde(untagged)] #[query_responses(nested)] pub enum NestedQueryMsg { @@ -199,24 +196,15 @@ pub enum NestedQueryMsg { Sub(SubQueryMsg1), } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, QueryResponses)] -#[serde(rename_all = "snake_case")] +#[cw_serde] +#[derive(QueryResponses)] pub enum SubQueryMsg1 { #[returns(u128)] Variant1 { test: String }, } -#[test] -fn test_nested_query_responses() { - let api_str = generate_api! { - instantiate: InstantiateMsg, - query: NestedQueryMsg, - } - .render() - .to_string() - .unwrap(); - - let api: Value = serde_json::from_str(&api_str).unwrap(); +fn test_nested_query_responses_impl(api: &str) { + let api: Value = serde_json::from_str(api).unwrap(); let queries = api .get("query") .unwrap() @@ -274,14 +262,52 @@ fn test_nested_query_responses() { api.get("responses").unwrap().get("variant1").unwrap(); } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, QueryResponses)] -#[serde(rename_all = "snake_case")] +#[test] +fn test_nested_query_responses() { + let api_str = generate_api! { + instantiate: InstantiateMsg, + query: NestedQueryMsg, + } + .render() + .to_string() + .unwrap(); + + test_nested_query_responses_impl(&api_str); +} + +#[cw_serde] +#[derive(QueryResponses)] +#[serde(untagged)] +#[query_responses(nested)] +pub enum NestedQueryMsgGenerics { + /// A configuration message to a base implementation. + Query(T), + /// Custom query + Sub(U), +} + +#[test] +fn test_nested_query_responses_with_generics() { + let api_str = generate_api! { + instantiate: InstantiateMsg, + query: NestedQueryMsgGenerics, + } + .render() + .to_string() + .unwrap(); + + test_nested_query_responses_impl(&api_str); +} + +#[cw_serde] +#[derive(QueryResponses)] enum QueryMsg2 { #[returns(u128)] Balance {}, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, QueryResponses)] +#[cw_serde] +#[derive(QueryResponses)] #[query_responses(nested)] enum NestedNameCollision { Q1(QueryMsg), From 25ae6ebddff2f7418a96bdae8fa531c92b26adc3 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 28 Nov 2022 12:45:22 +0100 Subject: [PATCH 029/187] Support nested QueryMsg with generics --- packages/schema-derive/src/query_responses.rs | 19 +++++++++----- packages/schema/tests/generics.rs | 4 --- packages/schema/tests/idl.rs | 26 +++++++++---------- 3 files changed, 26 insertions(+), 23 deletions(-) delete mode 100644 packages/schema/tests/generics.rs diff --git a/packages/schema-derive/src/query_responses.rs b/packages/schema-derive/src/query_responses.rs index 195bb93d78..f3d9b755de 100644 --- a/packages/schema-derive/src/query_responses.rs +++ b/packages/schema-derive/src/query_responses.rs @@ -1,6 +1,8 @@ mod context; -use syn::{parse_quote, Expr, ExprTuple, Generics, ItemEnum, ItemImpl, Type, Variant}; +use syn::{ + parse_quote, Expr, ExprTuple, Generics, ItemEnum, ItemImpl, Type, TypeParamBound, Variant, +}; use self::context::Context; @@ -13,7 +15,11 @@ pub fn query_responses_derive_impl(input: ItemEnum) -> ItemImpl { // Handle generics if the type has any let (_, type_generics, where_clause) = input.generics.split_for_impl(); - let impl_generics = impl_generics(&ctx, &input.generics); + let impl_generics = impl_generics( + &ctx, + &input.generics, + &[parse_quote! {::cosmwasm_schema::QueryResponses}], + ); let subquery_len = subquery_calls.len(); parse_quote! { @@ -24,7 +30,7 @@ pub fn query_responses_derive_impl(input: ItemEnum) -> ItemImpl { let subqueries = [ #( #subquery_calls, )* ]; - ::cosmwasm_schema::combine_subqueries::<#subquery_len, #ident>(subqueries) + ::cosmwasm_schema::combine_subqueries::<#subquery_len, #ident #type_generics>(subqueries) } } } @@ -37,7 +43,7 @@ pub fn query_responses_derive_impl(input: ItemEnum) -> ItemImpl { // Handle generics if the type has any let (_, type_generics, where_clause) = input.generics.split_for_impl(); - let impl_generics = impl_generics(&ctx, &input.generics); + let impl_generics = impl_generics(&ctx, &input.generics, &[]); parse_quote! { #[automatically_derived] @@ -55,7 +61,7 @@ pub fn query_responses_derive_impl(input: ItemEnum) -> ItemImpl { /// Takes a list of generics from the type definition and produces a list of generics /// for the expanded `impl` block, adding trait bounds like `JsonSchema` as appropriate. -fn impl_generics(ctx: &Context, generics: &Generics) -> Generics { +fn impl_generics(ctx: &Context, generics: &Generics, bounds: &[TypeParamBound]) -> Generics { let mut impl_generics = generics.to_owned(); for param in impl_generics.type_params_mut() { // remove the default type if present, as those are invalid in @@ -65,7 +71,8 @@ fn impl_generics(ctx: &Context, generics: &Generics) -> Generics { if !ctx.no_bounds_for.contains(¶m.ident) { param .bounds - .push(parse_quote! {::cosmwasm_schema::schemars::JsonSchema}) + .push(parse_quote! {::cosmwasm_schema::schemars::JsonSchema}); + param.bounds.extend(bounds.to_owned()); } } diff --git a/packages/schema/tests/generics.rs b/packages/schema/tests/generics.rs deleted file mode 100644 index aa1a62bbdc..0000000000 --- a/packages/schema/tests/generics.rs +++ /dev/null @@ -1,4 +0,0 @@ -use std::collections::HashMap; - -use cosmwasm_schema::{cw_serde, generate_api, QueryResponses, IDL_VERSION}; -use serde_json::Value; diff --git a/packages/schema/tests/idl.rs b/packages/schema/tests/idl.rs index 16442fc328..0ef92a826b 100644 --- a/packages/schema/tests/idl.rs +++ b/packages/schema/tests/idl.rs @@ -279,25 +279,25 @@ fn test_nested_query_responses() { #[derive(QueryResponses)] #[serde(untagged)] #[query_responses(nested)] -pub enum NestedQueryMsgGenerics { +pub enum NestedQueryMsgGenerics { /// A configuration message to a base implementation. Query(T), /// Custom query Sub(U), } -#[test] -fn test_nested_query_responses_with_generics() { - let api_str = generate_api! { - instantiate: InstantiateMsg, - query: NestedQueryMsgGenerics, - } - .render() - .to_string() - .unwrap(); - - test_nested_query_responses_impl(&api_str); -} +// #[test] +// fn test_nested_query_responses_with_generics() { +// let api_str = generate_api! { +// instantiate: InstantiateMsg, +// query: NestedQueryMsgGenerics, +// } +// .render() +// .to_string() +// .unwrap(); + +// test_nested_query_responses_impl(&api_str); +// } #[cw_serde] #[derive(QueryResponses)] From 72ab73400ac005d230e30553fcf6f6f89d79384c Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 28 Nov 2022 12:51:25 +0100 Subject: [PATCH 030/187] Update CHANGELOG --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c3b1682f..97bc9c80dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,13 @@ and this project adheres to [#1406]: https://github.com/CosmWasm/cosmwasm/pull/1406 [#1508]: https://github.com/CosmWasm/cosmwasm/issues/1508 +### Fixed + +- cosmwasm-schema: Nested QueryMsg with generics is now supported by the + QueryResponses macro ([#1516]). + +[#1516]: https://github.com/CosmWasm/cosmwasm/issues/1516 + ## [1.1.8] - 2022-11-22 ### Fixed From 5de0bf428a43e311e042539cf5063f29eb6db436 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 28 Nov 2022 17:42:58 +0100 Subject: [PATCH 031/187] Test nested QueryMsg w generics --- packages/schema/src/query_response.rs | 2 +- packages/schema/tests/idl.rs | 26 ++++++++++++-------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/schema/src/query_response.rs b/packages/schema/src/query_response.rs index 20cf84e261..3917470ec0 100644 --- a/packages/schema/src/query_response.rs +++ b/packages/schema/src/query_response.rs @@ -170,7 +170,7 @@ fn check_api_integrity( // If `any_of` exists, we assume schema is generated from untagged enum any_of .into_iter() - .map(|schema| dbg!(schema.into_object())) + .map(|schema| schema.into_object()) .filter_map(|obj| { if let Some(reference) = obj.reference { // Subschemas can be hidden behind references - we want to map them to proper diff --git a/packages/schema/tests/idl.rs b/packages/schema/tests/idl.rs index 0ef92a826b..2b35c7f8c6 100644 --- a/packages/schema/tests/idl.rs +++ b/packages/schema/tests/idl.rs @@ -280,24 +280,22 @@ fn test_nested_query_responses() { #[serde(untagged)] #[query_responses(nested)] pub enum NestedQueryMsgGenerics { - /// A configuration message to a base implementation. Query(T), - /// Custom query Sub(U), } -// #[test] -// fn test_nested_query_responses_with_generics() { -// let api_str = generate_api! { -// instantiate: InstantiateMsg, -// query: NestedQueryMsgGenerics, -// } -// .render() -// .to_string() -// .unwrap(); - -// test_nested_query_responses_impl(&api_str); -// } +#[test] +fn test_nested_query_responses_with_generics() { + let api_str = generate_api! { + instantiate: InstantiateMsg, + query: NestedQueryMsgGenerics, + } + .render() + .to_string() + .unwrap(); + + test_nested_query_responses_impl(&api_str); +} #[cw_serde] #[derive(QueryResponses)] From e4000df9d275c83a3242d4e81f9cb2367d1c498e Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 28 Nov 2022 20:26:23 +0100 Subject: [PATCH 032/187] Fix nested QueryMsg with doc comments errors --- CHANGELOG.md | 2 + packages/schema/src/query_response.rs | 136 +------------------------- packages/schema/tests/idl.rs | 68 +------------ 3 files changed, 6 insertions(+), 200 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97bc9c80dd..1d780adf87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,8 @@ and this project adheres to - cosmwasm-schema: Nested QueryMsg with generics is now supported by the QueryResponses macro ([#1516]). +- cosmwasm-schema: A nested QueryMsg no longer causes runtime errors if it + contains doc comments. [#1516]: https://github.com/CosmWasm/cosmwasm/issues/1516 diff --git a/packages/schema/src/query_response.rs b/packages/schema/src/query_response.rs index 3917470ec0..85ecc7f3b2 100644 --- a/packages/schema/src/query_response.rs +++ b/packages/schema/src/query_response.rs @@ -1,9 +1,6 @@ use std::collections::{BTreeMap, BTreeSet}; -use schemars::{ - schema::{InstanceType, RootSchema, SingleOrVec, SubschemaValidation}, - JsonSchema, -}; +use schemars::{schema::RootSchema, JsonSchema}; use thiserror::Error; pub use cosmwasm_schema_derive::QueryResponses; @@ -69,10 +66,6 @@ pub trait QueryResponses: JsonSchema { fn response_schemas() -> Result, IntegrityError> { let response_schemas = Self::response_schemas_impl(); - let queries: BTreeSet<_> = response_schemas.keys().cloned().collect(); - - check_api_integrity::(queries)?; - Ok(response_schemas) } @@ -95,121 +88,6 @@ pub fn combine_subqueries( map } -/// Returns possible enum variants from `one_of` analysis -fn enum_variants( - subschemas: SubschemaValidation, -) -> Result>, IntegrityError> { - let iter = subschemas - .one_of - .ok_or(IntegrityError::InvalidQueryMsgSchema)? - .into_iter() - .map(|s| { - let s = s.into_object(); - - if let Some(SingleOrVec::Single(ty)) = s.instance_type { - match *ty { - // We'll have an object if the Rust enum variant was C-like or tuple-like - InstanceType::Object => s - .object - .ok_or(IntegrityError::InvalidQueryMsgSchema)? - .required - .into_iter() - .next() - .ok_or(IntegrityError::InvalidQueryMsgSchema), - // We might have a string here if the Rust enum variant was unit-like - InstanceType::String => { - let values = s.enum_values.ok_or(IntegrityError::InvalidQueryMsgSchema)?; - - if values.len() != 1 { - return Err(IntegrityError::InvalidQueryMsgSchema); - } - - values[0] - .as_str() - .map(String::from) - .ok_or(IntegrityError::InvalidQueryMsgSchema) - } - _ => Err(IntegrityError::InvalidQueryMsgSchema), - } - } else { - Err(IntegrityError::InvalidQueryMsgSchema) - } - }); - - Ok(iter) -} - -fn verify_queries( - query_msg: BTreeSet, - responses: BTreeSet, -) -> Result<(), IntegrityError> { - if query_msg != responses { - return Err(IntegrityError::InconsistentQueries { - query_msg, - responses, - }); - } - - Ok(()) -} - -/// `generated_queries` is expected to be a sorted slice here! -fn check_api_integrity( - generated_queries: BTreeSet, -) -> Result<(), IntegrityError> { - let schema = crate::schema_for!(T); - - let subschemas = if let Some(subschemas) = schema.schema.subschemas { - subschemas - } else { - // No subschemas - no resposnes are expected - return verify_queries(BTreeSet::new(), generated_queries); - }; - - let schema_queries = if let Some(any_of) = subschemas.any_of { - // If `any_of` exists, we assume schema is generated from untagged enum - any_of - .into_iter() - .map(|schema| schema.into_object()) - .filter_map(|obj| { - if let Some(reference) = obj.reference { - // Subschemas can be hidden behind references - we want to map them to proper - // subschemas in such case - - // Only references to definitions are supported - let reference = match reference.strip_prefix("#/definitions/") { - Some(reference) => reference, - None => { - return Some(Err(IntegrityError::ExternalReference { - reference: reference.to_owned(), - })) - } - }; - - let schema = match schema.definitions.get(reference) { - Some(schema) => schema.clone(), - None => return Some(Err(IntegrityError::InvalidQueryMsgSchema)), - }; - - Ok(schema.into_object().subschemas).transpose() - } else { - Ok(obj.subschemas).transpose() - } - }) - .map(|subschema| enum_variants(*subschema?)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect::>()? - } else { - // If `any_of` is not present, there was no untagged enum on top, we expect normal enum at - // this point - enum_variants(*subschemas)?.collect::>()? - }; - - verify_queries(schema_queries, generated_queries) -} - #[derive(Debug, Error, PartialEq, Eq)] pub enum IntegrityError { #[error("the structure of the QueryMsg schema was unexpected")] @@ -299,18 +177,6 @@ mod tests { } } - #[test] - fn bad_msg_fails() { - let err = BadMsg::response_schemas().unwrap_err(); - assert_eq!( - err, - IntegrityError::InconsistentQueries { - query_msg: BTreeSet::from(["balance-for".to_string()]), - responses: BTreeSet::from(["balance_for".to_string()]) - } - ); - } - #[derive(Debug, JsonSchema)] #[serde(rename_all = "snake_case")] #[allow(dead_code)] diff --git a/packages/schema/tests/idl.rs b/packages/schema/tests/idl.rs index 2b35c7f8c6..b8701d4231 100644 --- a/packages/schema/tests/idl.rs +++ b/packages/schema/tests/idl.rs @@ -203,76 +203,15 @@ pub enum SubQueryMsg1 { Variant1 { test: String }, } -fn test_nested_query_responses_impl(api: &str) { - let api: Value = serde_json::from_str(api).unwrap(); - let queries = api - .get("query") - .unwrap() - .get("anyOf") - .unwrap() - .as_array() - .unwrap(); - let definitions = api.get("query").unwrap().get("definitions").unwrap(); - - // Find the subqueries - assert_eq!(queries.len(), 2); - assert_eq!( - queries[0].get("$ref").unwrap().as_str().unwrap(), - "#/definitions/QueryMsg" - ); - assert_eq!( - queries[1].get("$ref").unwrap().as_str().unwrap(), - "#/definitions/SubQueryMsg1" - ); - let query_msg_queries = definitions - .get("QueryMsg") - .unwrap() - .get("oneOf") - .unwrap() - .as_array() - .unwrap(); - let sub_query_msg_queries = definitions - .get("SubQueryMsg1") - .unwrap() - .get("oneOf") - .unwrap() - .as_array() - .unwrap(); - - // Find "balance" and "variant1" queries in the query schema - assert_eq!( - query_msg_queries[0] - .get("required") - .unwrap() - .get(0) - .unwrap(), - "balance" - ); - assert_eq!( - sub_query_msg_queries[0] - .get("required") - .unwrap() - .get(0) - .unwrap(), - "variant1" - ); - - // Find "balance" and "variant1" queries in responses - api.get("responses").unwrap().get("balance").unwrap(); - api.get("responses").unwrap().get("variant1").unwrap(); -} - #[test] fn test_nested_query_responses() { - let api_str = generate_api! { + generate_api! { instantiate: InstantiateMsg, query: NestedQueryMsg, } .render() .to_string() .unwrap(); - - test_nested_query_responses_impl(&api_str); } #[cw_serde] @@ -280,21 +219,20 @@ fn test_nested_query_responses() { #[serde(untagged)] #[query_responses(nested)] pub enum NestedQueryMsgGenerics { + /// doc comment Query(T), Sub(U), } #[test] fn test_nested_query_responses_with_generics() { - let api_str = generate_api! { + generate_api! { instantiate: InstantiateMsg, query: NestedQueryMsgGenerics, } .render() .to_string() .unwrap(); - - test_nested_query_responses_impl(&api_str); } #[cw_serde] From 2333f19d2ed9146696ddc533fdd4b2345f35cd67 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 29 Nov 2022 15:34:24 +0100 Subject: [PATCH 033/187] fix schema dependencies --- Cargo.lock | 57 ++++++-------------------------------- packages/schema/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 858b9ddcf0..815caa2d27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,7 +251,7 @@ dependencies = [ "anyhow", "clap", "colored", - "cosmwasm-std 1.1.8", + "cosmwasm-std", "cosmwasm-vm", ] @@ -274,33 +274,11 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cosmwasm-crypto" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532d2ba11b7157e3b67114389925568af29ce3e452b582d6bdfe751cb2dadfb1" -dependencies = [ - "digest 0.10.3", - "ed25519-zebra", - "k256", - "rand_core 0.6.3", - "thiserror", -] - -[[package]] -name = "cosmwasm-derive" -version = "1.1.8" -dependencies = [ - "cosmwasm-std 1.1.8", - "syn", -] - [[package]] name = "cosmwasm-derive" version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8568b289cc366981319ab39edd85d666456456f7c126433ef065ebe5257f27b2" dependencies = [ + "cosmwasm-std", "syn", ] @@ -310,7 +288,7 @@ version = "1.1.8" dependencies = [ "anyhow", "cosmwasm-schema-derive", - "cosmwasm-std 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cosmwasm-std", "schemars", "semver", "serde", @@ -334,8 +312,8 @@ version = "1.1.8" dependencies = [ "base64", "chrono", - "cosmwasm-crypto 1.1.8", - "cosmwasm-derive 1.1.8", + "cosmwasm-crypto", + "cosmwasm-derive", "cosmwasm-schema", "derivative", "forward_ref", @@ -350,30 +328,11 @@ dependencies = [ "uint", ] -[[package]] -name = "cosmwasm-std" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1ceebd520a10167e35080e4f55f6b0284bb8ea364dec0f22197da96acd9e64" -dependencies = [ - "base64", - "cosmwasm-crypto 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "cosmwasm-derive 1.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "derivative", - "forward_ref", - "hex", - "schemars", - "serde", - "serde-json-wasm", - "thiserror", - "uint", -] - [[package]] name = "cosmwasm-storage" version = "1.1.8" dependencies = [ - "cosmwasm-std 1.1.8", + "cosmwasm-std", "serde", ] @@ -385,8 +344,8 @@ dependencies = [ "bytecheck", "clap", "clru", - "cosmwasm-crypto 1.1.8", - "cosmwasm-std 1.1.8", + "cosmwasm-crypto", + "cosmwasm-std", "criterion", "enumset", "hex", diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index 751c40b3c4..4e06a667fc 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -16,6 +16,6 @@ thiserror = "1.0.13" [dev-dependencies] anyhow = "1.0.57" -cosmwasm-std = "1.1.8" +cosmwasm-std = { version = "1.1.8", path = "../std" } semver = "1" tempfile = "3" From f853b546162f9970872e49a7e43d9221a31ee02f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 09:45:59 +0100 Subject: [PATCH 034/187] Add cache test new_base_dir_will_be_created --- packages/vm/src/cache.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs index b08b9c7c97..50ddc2f306 100644 --- a/packages/vm/src/cache.rs +++ b/packages/vm/src/cache.rs @@ -44,6 +44,10 @@ pub struct Metrics { #[derive(Clone, Debug)] pub struct CacheOptions { + /// The base directory of this cache. + /// + /// If this does not exist, it will be created. Not sure if this behaviour + /// is desired but wasmd relies on it. pub base_dir: PathBuf, pub available_capabilities: HashSet, pub memory_cache_size: Size, @@ -407,6 +411,20 @@ mod tests { } } + #[test] + fn new_base_dir_will_be_created() { + let dir = TempDir::new() + .unwrap() + .into_path() + .join("non-existent-sub-dir"); + let options = CacheOptions { + base_dir: dir.clone(), + ..make_testing_options() + }; + let _cache = unsafe { Cache::::new(options).unwrap() }; + assert!(dir.is_dir()); + } + #[test] fn save_wasm_works() { let cache: Cache = From e5de160432cbe9924b3d3c92760bbadc10163934 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 10:41:00 +0100 Subject: [PATCH 035/187] Check new base dir does not exist yet --- packages/vm/src/cache.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs index 50ddc2f306..ea56e30df4 100644 --- a/packages/vm/src/cache.rs +++ b/packages/vm/src/cache.rs @@ -413,16 +413,17 @@ mod tests { #[test] fn new_base_dir_will_be_created() { - let dir = TempDir::new() + let my_base_dir = TempDir::new() .unwrap() .into_path() .join("non-existent-sub-dir"); let options = CacheOptions { - base_dir: dir.clone(), + base_dir: my_base_dir.clone(), ..make_testing_options() }; + assert!(!my_base_dir.is_dir()); let _cache = unsafe { Cache::::new(options).unwrap() }; - assert!(dir.is_dir()); + assert!(my_base_dir.is_dir()); } #[test] From a474ae3fcc37fd49813b31bbe880f8ff7fae1fd7 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 11:30:07 +0100 Subject: [PATCH 036/187] Fix data in raw/{query,migrate,sudo}.json --- packages/schema/src/idl.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/schema/src/idl.rs b/packages/schema/src/idl.rs index ec2c5478aa..0cad4da9f0 100644 --- a/packages/schema/src/idl.rs +++ b/packages/schema/src/idl.rs @@ -97,19 +97,19 @@ impl JsonApi { serde_json::to_string_pretty(&execute)?, )); } - if let Some(query) = &self.execute { + if let Some(query) = &self.query { result.push(( "query.json".to_string(), serde_json::to_string_pretty(&query)?, )); } - if let Some(migrate) = &self.execute { + if let Some(migrate) = &self.migrate { result.push(( "migrate.json".to_string(), serde_json::to_string_pretty(&migrate)?, )); } - if let Some(sudo) = &self.execute { + if let Some(sudo) = &self.sudo { result.push(( "sudo.json".to_string(), serde_json::to_string_pretty(&sudo)?, From e10ea6fd2b0760e0609db9777789ffa0ada1022c Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 11:30:20 +0100 Subject: [PATCH 037/187] Regenerate contract schemas --- contracts/burner/schema/raw/migrate.json | 14 + contracts/crypto-verify/schema/raw/query.json | 268 ++++++ contracts/cyberpunk/schema/raw/query.json | 34 +- contracts/floaty/schema/raw/query.json | 30 +- contracts/hackatom/schema/raw/migrate.json | 135 +-- contracts/hackatom/schema/raw/query.json | 100 +-- contracts/hackatom/schema/raw/sudo.json | 132 +-- .../ibc-reflect-send/schema/raw/query.json | 780 +----------------- contracts/ibc-reflect/schema/raw/migrate.json | 6 + contracts/ibc-reflect/schema/raw/query.json | 42 + contracts/queue/schema/raw/migrate.json | 41 +- contracts/queue/schema/raw/query.json | 69 +- contracts/reflect/schema/raw/query.json | 721 +++++----------- contracts/staking/schema/raw/query.json | 76 +- 14 files changed, 732 insertions(+), 1716 deletions(-) create mode 100644 contracts/burner/schema/raw/migrate.json create mode 100644 contracts/crypto-verify/schema/raw/query.json create mode 100644 contracts/ibc-reflect/schema/raw/migrate.json create mode 100644 contracts/ibc-reflect/schema/raw/query.json diff --git a/contracts/burner/schema/raw/migrate.json b/contracts/burner/schema/raw/migrate.json new file mode 100644 index 0000000000..231a265325 --- /dev/null +++ b/contracts/burner/schema/raw/migrate.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MigrateMsg", + "type": "object", + "required": [ + "payout" + ], + "properties": { + "payout": { + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/contracts/crypto-verify/schema/raw/query.json b/contracts/crypto-verify/schema/raw/query.json new file mode 100644 index 0000000000..dbb6e99374 --- /dev/null +++ b/contracts/crypto-verify/schema/raw/query.json @@ -0,0 +1,268 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "oneOf": [ + { + "description": "Cosmos format (secp256k1 verification scheme).", + "type": "object", + "required": [ + "verify_cosmos_signature" + ], + "properties": { + "verify_cosmos_signature": { + "type": "object", + "required": [ + "message", + "public_key", + "signature" + ], + "properties": { + "message": { + "description": "Message to verify.", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "public_key": { + "description": "Serialized compressed (33 bytes) or uncompressed (65 bytes) public key.", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "signature": { + "description": "Serialized signature. Cosmos format (64 bytes).", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Ethereum text verification (compatible to the eth_sign RPC/web3 enpoint). This cannot be used to verify transaction.\n\nSee https://web3js.readthedocs.io/en/v1.2.0/web3-eth.html#sign", + "type": "object", + "required": [ + "verify_ethereum_text" + ], + "properties": { + "verify_ethereum_text": { + "type": "object", + "required": [ + "message", + "signature", + "signer_address" + ], + "properties": { + "message": { + "description": "Message to verify. This will be wrapped in the standard container `\"\\x19Ethereum Signed Message:\\n\" + len(message) + message` before verification.", + "type": "string" + }, + "signature": { + "description": "Serialized signature. Fixed length format (64 bytes `r` and `s` plus the one byte `v`).", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "signer_address": { + "description": "Signer address. This is matched case insensitive, so you can provide checksummed and non-checksummed addresses. Checksums are not validated.", + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "verify_ethereum_transaction" + ], + "properties": { + "verify_ethereum_transaction": { + "type": "object", + "required": [ + "chain_id", + "data", + "from", + "gas_limit", + "gas_price", + "nonce", + "r", + "s", + "to", + "v", + "value" + ], + "properties": { + "chain_id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "data": { + "$ref": "#/definitions/Binary" + }, + "from": { + "description": "Ethereum address in hex format (42 characters, starting with 0x)", + "type": "string" + }, + "gas_limit": { + "$ref": "#/definitions/Uint128" + }, + "gas_price": { + "$ref": "#/definitions/Uint128" + }, + "nonce": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "r": { + "$ref": "#/definitions/Binary" + }, + "s": { + "$ref": "#/definitions/Binary" + }, + "to": { + "description": "Ethereum address in hex format (42 characters, starting with 0x)", + "type": "string" + }, + "v": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "value": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Tendermint format (ed25519 verification scheme).", + "type": "object", + "required": [ + "verify_tendermint_signature" + ], + "properties": { + "verify_tendermint_signature": { + "type": "object", + "required": [ + "message", + "public_key", + "signature" + ], + "properties": { + "message": { + "description": "Message to verify.", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "public_key": { + "description": "Serialized public key. Tendermint format (32 bytes).", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "signature": { + "description": "Serialized signature. Tendermint format (64 bytes).", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Tendermint format (batch ed25519 verification scheme).", + "type": "object", + "required": [ + "verify_tendermint_batch" + ], + "properties": { + "verify_tendermint_batch": { + "type": "object", + "required": [ + "messages", + "public_keys", + "signatures" + ], + "properties": { + "messages": { + "description": "Messages to verify.", + "type": "array", + "items": { + "$ref": "#/definitions/Binary" + } + }, + "public_keys": { + "description": "Serialized public keys. Tendermint format (32 bytes).", + "type": "array", + "items": { + "$ref": "#/definitions/Binary" + } + }, + "signatures": { + "description": "Serialized signatures. Tendermint format (64 bytes).", + "type": "array", + "items": { + "$ref": "#/definitions/Binary" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns a list of supported verification schemes. No pagination - this is a short list.", + "type": "object", + "required": [ + "list_verification_schemes" + ], + "properties": { + "list_verification_schemes": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ], + "definitions": { + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/cyberpunk/schema/raw/query.json b/contracts/cyberpunk/schema/raw/query.json index 8e7af5fe3c..18c07a5622 100644 --- a/contracts/cyberpunk/schema/raw/query.json +++ b/contracts/cyberpunk/schema/raw/query.json @@ -1,39 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", + "title": "QueryMsg", "oneOf": [ - { - "description": "Hashes some data. Uses CPU and memory, but no external calls.", - "type": "object", - "required": [ - "argon2" - ], - "properties": { - "argon2": { - "type": "object", - "required": [ - "mem_cost", - "time_cost" - ], - "properties": { - "mem_cost": { - "description": "The amount of memory requested (KB).", - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "time_cost": { - "description": "The number of passes.", - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, { "description": "Returns the env for testing", "type": "object", diff --git a/contracts/floaty/schema/raw/query.json b/contracts/floaty/schema/raw/query.json index 76967fd17b..b96c3dfb8a 100644 --- a/contracts/floaty/schema/raw/query.json +++ b/contracts/floaty/schema/raw/query.json @@ -1,20 +1,42 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", + "title": "QueryMsg", "oneOf": [ { - "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "description": "returns a human-readable representation of the verifier use to ensure query path works in integration tests", "type": "object", "required": [ - "release" + "verifier" ], "properties": { - "release": { + "verifier": { "type": "object", "additionalProperties": false } }, "additionalProperties": false + }, + { + "description": "This returns cosmwasm_std::AllBalanceResponse to demo use of the querier", + "type": "object", + "required": [ + "other_balance" + ], + "properties": { + "other_balance": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } ] } diff --git a/contracts/hackatom/schema/raw/migrate.json b/contracts/hackatom/schema/raw/migrate.json index a82fdeef2d..2696e3ac26 100644 --- a/contracts/hackatom/schema/raw/migrate.json +++ b/contracts/hackatom/schema/raw/migrate.json @@ -1,128 +1,15 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", - "oneOf": [ - { - "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", - "type": "object", - "required": [ - "release" - ], - "properties": { - "release": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)", - "type": "object", - "required": [ - "cpu_loop" - ], - "properties": { - "cpu_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop making storage calls (to test when their limit hits)", - "type": "object", - "required": [ - "storage_loop" - ], - "properties": { - "storage_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop reading and writing memory", - "type": "object", - "required": [ - "memory_loop" - ], - "properties": { - "memory_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop sending message to itself", - "type": "object", - "required": [ - "message_loop" - ], - "properties": { - "message_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Allocate large amounts of memory without consuming much gas", - "type": "object", - "required": [ - "allocate_large_memory" - ], - "properties": { - "allocate_large_memory": { - "type": "object", - "required": [ - "pages" - ], - "properties": { - "pages": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Trigger a panic to ensure framework handles gracefully", - "type": "object", - "required": [ - "panic" - ], - "properties": { - "panic": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Starting with CosmWasm 0.10, some API calls return user errors back to the contract. This triggers such user errors, ensuring the transaction does not fail in the backend.", - "type": "object", - "required": [ - "user_errors_in_api_calls" - ], - "properties": { - "user_errors_in_api_calls": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false + "title": "MigrateMsg", + "description": "MigrateMsg allows a privileged contract administrator to run a migration on the contract. In this (demo) case it is just migrating from one hackatom code to the same code, but taking advantage of the migration step to set a new validator.\n\nNote that the contract doesn't enforce permissions here, this is done by blockchain logic (in the future by blockchain governance)", + "type": "object", + "required": [ + "verifier" + ], + "properties": { + "verifier": { + "type": "string" } - ] + }, + "additionalProperties": false } diff --git a/contracts/hackatom/schema/raw/query.json b/contracts/hackatom/schema/raw/query.json index a82fdeef2d..dfd58202b2 100644 --- a/contracts/hackatom/schema/raw/query.json +++ b/contracts/hackatom/schema/raw/query.json @@ -1,15 +1,15 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", + "title": "QueryMsg", "oneOf": [ { - "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", + "description": "returns a human-readable representation of the verifier use to ensure query path works in integration tests", "type": "object", "required": [ - "release" + "verifier" ], "properties": { - "release": { + "verifier": { "type": "object", "additionalProperties": false } @@ -17,75 +17,47 @@ "additionalProperties": false }, { - "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)", + "description": "This returns cosmwasm_std::AllBalanceResponse to demo use of the querier", "type": "object", "required": [ - "cpu_loop" + "other_balance" ], "properties": { - "cpu_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop making storage calls (to test when their limit hits)", - "type": "object", - "required": [ - "storage_loop" - ], - "properties": { - "storage_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop reading and writing memory", - "type": "object", - "required": [ - "memory_loop" - ], - "properties": { - "memory_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop sending message to itself", - "type": "object", - "required": [ - "message_loop" - ], - "properties": { - "message_loop": { + "other_balance": { "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string" + } + }, "additionalProperties": false } }, "additionalProperties": false }, { - "description": "Allocate large amounts of memory without consuming much gas", + "description": "Recurse will execute a query into itself up to depth-times and return Each step of the recursion may perform some extra work to test gas metering (`work` rounds of sha256 on contract). Now that we have Env, we can auto-calculate the address to recurse into", "type": "object", "required": [ - "allocate_large_memory" + "recurse" ], "properties": { - "allocate_large_memory": { + "recurse": { "type": "object", "required": [ - "pages" + "depth", + "work" ], "properties": { - "pages": { + "depth": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "work": { "type": "integer", "format": "uint32", "minimum": 0.0 @@ -97,27 +69,13 @@ "additionalProperties": false }, { - "description": "Trigger a panic to ensure framework handles gracefully", - "type": "object", - "required": [ - "panic" - ], - "properties": { - "panic": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Starting with CosmWasm 0.10, some API calls return user errors back to the contract. This triggers such user errors, ensuring the transaction does not fail in the backend.", + "description": "GetInt returns a hardcoded u32 value", "type": "object", "required": [ - "user_errors_in_api_calls" + "get_int" ], "properties": { - "user_errors_in_api_calls": { + "get_int": { "type": "object", "additionalProperties": false } diff --git a/contracts/hackatom/schema/raw/sudo.json b/contracts/hackatom/schema/raw/sudo.json index a82fdeef2d..d41253aeb0 100644 --- a/contracts/hackatom/schema/raw/sudo.json +++ b/contracts/hackatom/schema/raw/sudo.json @@ -1,128 +1,56 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", + "title": "SudoMsg", + "description": "SudoMsg is only exposed for internal Cosmos SDK modules to call. This is showing how we can expose \"admin\" functionality than can not be called by external users or contracts, but only trusted (native/Go) code in the blockchain", "oneOf": [ { - "description": "Releasing all funds in the contract to the beneficiary. This is the only \"proper\" action of this demo contract.", "type": "object", "required": [ - "release" + "steal_funds" ], "properties": { - "release": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)", - "type": "object", - "required": [ - "cpu_loop" - ], - "properties": { - "cpu_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop making storage calls (to test when their limit hits)", - "type": "object", - "required": [ - "storage_loop" - ], - "properties": { - "storage_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop reading and writing memory", - "type": "object", - "required": [ - "memory_loop" - ], - "properties": { - "memory_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Infinite loop sending message to itself", - "type": "object", - "required": [ - "message_loop" - ], - "properties": { - "message_loop": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Allocate large amounts of memory without consuming much gas", - "type": "object", - "required": [ - "allocate_large_memory" - ], - "properties": { - "allocate_large_memory": { + "steal_funds": { "type": "object", "required": [ - "pages" + "amount", + "recipient" ], "properties": { - "pages": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 + "amount": { + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "recipient": { + "type": "string" } }, "additionalProperties": false } }, "additionalProperties": false - }, - { - "description": "Trigger a panic to ensure framework handles gracefully", + } + ], + "definitions": { + "Coin": { "type": "object", "required": [ - "panic" + "amount", + "denom" ], "properties": { - "panic": { - "type": "object", - "additionalProperties": false + "amount": { + "$ref": "#/definitions/Uint128" + }, + "denom": { + "type": "string" } - }, - "additionalProperties": false + } }, - { - "description": "Starting with CosmWasm 0.10, some API calls return user errors back to the contract. This triggers such user errors, ensuring the transaction does not fail in the backend.", - "type": "object", - "required": [ - "user_errors_in_api_calls" - ], - "properties": { - "user_errors_in_api_calls": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" } - ] + } } diff --git a/contracts/ibc-reflect-send/schema/raw/query.json b/contracts/ibc-reflect-send/schema/raw/query.json index e08109d489..05a60cc1b8 100644 --- a/contracts/ibc-reflect-send/schema/raw/query.json +++ b/contracts/ibc-reflect-send/schema/raw/query.json @@ -1,24 +1,15 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", + "title": "QueryMsg", "oneOf": [ { - "description": "Changes the admin", "type": "object", "required": [ - "update_admin" + "admin" ], "properties": { - "update_admin": { + "admin": { "type": "object", - "required": [ - "admin" - ], - "properties": { - "admin": { - "type": "string" - } - }, "additionalProperties": false } }, @@ -27,26 +18,11 @@ { "type": "object", "required": [ - "send_msgs" + "list_accounts" ], "properties": { - "send_msgs": { + "list_accounts": { "type": "object", - "required": [ - "channel_id", - "msgs" - ], - "properties": { - "channel_id": { - "type": "string" - }, - "msgs": { - "type": "array", - "items": { - "$ref": "#/definitions/CosmosMsg_for_Empty" - } - } - }, "additionalProperties": false } }, @@ -55,10 +31,10 @@ { "type": "object", "required": [ - "check_remote_balance" + "account" ], "properties": { - "check_remote_balance": { + "account": { "type": "object", "required": [ "channel_id" @@ -72,746 +48,6 @@ } }, "additionalProperties": false - }, - { - "description": "If you sent funds to this contract, it will attempt to ibc transfer them to the account on the remote side of this channel. If we don't have the address yet, this fails.", - "type": "object", - "required": [ - "send_funds" - ], - "properties": { - "send_funds": { - "type": "object", - "required": [ - "reflect_channel_id", - "transfer_channel_id" - ], - "properties": { - "reflect_channel_id": { - "description": "The channel id we use above to talk with the reflect contract", - "type": "string" - }, - "transfer_channel_id": { - "description": "The channel to use for ibctransfer. This is bound to a different port and handled by a different module. It should connect to the same chain as the reflect_channel_id does", - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - } - ], - "definitions": { - "BankMsg": { - "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", - "oneOf": [ - { - "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "send" - ], - "properties": { - "send": { - "type": "object", - "required": [ - "amount", - "to_address" - ], - "properties": { - "amount": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "to_address": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", - "type": "object", - "required": [ - "burn" - ], - "properties": { - "burn": { - "type": "object", - "required": [ - "amount" - ], - "properties": { - "amount": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - } - } - } - }, - "additionalProperties": false - } - ] - }, - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", - "type": "string" - }, - "Coin": { - "type": "object", - "required": [ - "amount", - "denom" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "denom": { - "type": "string" - } - } - }, - "CosmosMsg_for_Empty": { - "oneOf": [ - { - "type": "object", - "required": [ - "bank" - ], - "properties": { - "bank": { - "$ref": "#/definitions/BankMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "custom" - ], - "properties": { - "custom": { - "$ref": "#/definitions/Empty" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "staking" - ], - "properties": { - "staking": { - "$ref": "#/definitions/StakingMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "distribution" - ], - "properties": { - "distribution": { - "$ref": "#/definitions/DistributionMsg" - } - }, - "additionalProperties": false - }, - { - "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", - "type": "object", - "required": [ - "stargate" - ], - "properties": { - "stargate": { - "type": "object", - "required": [ - "type_url", - "value" - ], - "properties": { - "type_url": { - "type": "string" - }, - "value": { - "$ref": "#/definitions/Binary" - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "ibc" - ], - "properties": { - "ibc": { - "$ref": "#/definitions/IbcMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "wasm" - ], - "properties": { - "wasm": { - "$ref": "#/definitions/WasmMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "gov" - ], - "properties": { - "gov": { - "$ref": "#/definitions/GovMsg" - } - }, - "additionalProperties": false - } - ] - }, - "DistributionMsg": { - "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", - "oneOf": [ - { - "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "set_withdraw_address" - ], - "properties": { - "set_withdraw_address": { - "type": "object", - "required": [ - "address" - ], - "properties": { - "address": { - "description": "The `withdraw_address`", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "withdraw_delegator_reward" - ], - "properties": { - "withdraw_delegator_reward": { - "type": "object", - "required": [ - "validator" - ], - "properties": { - "validator": { - "description": "The `validator_address`", - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - }, - "GovMsg": { - "oneOf": [ - { - "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", - "type": "object", - "required": [ - "vote" - ], - "properties": { - "vote": { - "type": "object", - "required": [ - "proposal_id", - "vote" - ], - "properties": { - "proposal_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "vote": { - "$ref": "#/definitions/VoteOption" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", - "oneOf": [ - { - "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", - "type": "object", - "required": [ - "transfer" - ], - "properties": { - "transfer": { - "type": "object", - "required": [ - "amount", - "channel_id", - "timeout", - "to_address" - ], - "properties": { - "amount": { - "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", - "allOf": [ - { - "$ref": "#/definitions/Coin" - } - ] - }, - "channel_id": { - "description": "exisiting channel to send the tokens over", - "type": "string" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] - }, - "to_address": { - "description": "address on the remote chain to receive these tokens", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", - "type": "object", - "required": [ - "send_packet" - ], - "properties": { - "send_packet": { - "type": "object", - "required": [ - "channel_id", - "data", - "timeout" - ], - "properties": { - "channel_id": { - "type": "string" - }, - "data": { - "$ref": "#/definitions/Binary" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", - "type": "object", - "required": [ - "close_channel" - ], - "properties": { - "close_channel": { - "type": "object", - "required": [ - "channel_id" - ], - "properties": { - "channel_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "IbcTimeout": { - "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", - "type": "object", - "properties": { - "block": { - "anyOf": [ - { - "$ref": "#/definitions/IbcTimeoutBlock" - }, - { - "type": "null" - } - ] - }, - "timestamp": { - "anyOf": [ - { - "$ref": "#/definitions/Timestamp" - }, - { - "type": "null" - } - ] - } - } - }, - "IbcTimeoutBlock": { - "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", - "type": "object", - "required": [ - "height", - "revision" - ], - "properties": { - "height": { - "description": "block height after which the packet times out. the height within the given revision", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "revision": { - "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "StakingMsg": { - "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", - "oneOf": [ - { - "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "delegate" - ], - "properties": { - "delegate": { - "type": "object", - "required": [ - "amount", - "validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "validator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "undelegate" - ], - "properties": { - "undelegate": { - "type": "object", - "required": [ - "amount", - "validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "validator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "redelegate" - ], - "properties": { - "redelegate": { - "type": "object", - "required": [ - "amount", - "dst_validator", - "src_validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "dst_validator": { - "type": "string" - }, - "src_validator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - }, - "VoteOption": { - "type": "string", - "enum": [ - "yes", - "no", - "abstain", - "no_with_veto" - ] - }, - "WasmMsg": { - "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", - "oneOf": [ - { - "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "execute" - ], - "properties": { - "execute": { - "type": "object", - "required": [ - "contract_addr", - "funds", - "msg" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "funds": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "msg": { - "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "instantiate" - ], - "properties": { - "instantiate": { - "type": "object", - "required": [ - "code_id", - "funds", - "label", - "msg" - ], - "properties": { - "admin": { - "type": [ - "string", - "null" - ] - }, - "code_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "funds": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "label": { - "description": "A human-readbale label for the contract", - "type": "string" - }, - "msg": { - "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "migrate" - ], - "properties": { - "migrate": { - "type": "object", - "required": [ - "contract_addr", - "msg", - "new_code_id" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "msg": { - "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - }, - "new_code_id": { - "description": "the code_id of the new logic to place in the given contract", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", - "type": "object", - "required": [ - "update_admin" - ], - "properties": { - "update_admin": { - "type": "object", - "required": [ - "admin", - "contract_addr" - ], - "properties": { - "admin": { - "type": "string" - }, - "contract_addr": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", - "type": "object", - "required": [ - "clear_admin" - ], - "properties": { - "clear_admin": { - "type": "object", - "required": [ - "contract_addr" - ], - "properties": { - "contract_addr": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] } - } + ] } diff --git a/contracts/ibc-reflect/schema/raw/migrate.json b/contracts/ibc-reflect/schema/raw/migrate.json new file mode 100644 index 0000000000..2bba958247 --- /dev/null +++ b/contracts/ibc-reflect/schema/raw/migrate.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MigrateMsg", + "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", + "type": "object" +} diff --git a/contracts/ibc-reflect/schema/raw/query.json b/contracts/ibc-reflect/schema/raw/query.json new file mode 100644 index 0000000000..2fb7b34e6f --- /dev/null +++ b/contracts/ibc-reflect/schema/raw/query.json @@ -0,0 +1,42 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "QueryMsg", + "oneOf": [ + { + "description": "Returns (reflect) account that is attached to this channel, or none.", + "type": "object", + "required": [ + "account" + ], + "properties": { + "account": { + "type": "object", + "required": [ + "channel_id" + ], + "properties": { + "channel_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Returns all (channel, reflect_account) pairs. No pagination - this is a test contract", + "type": "object", + "required": [ + "list_accounts" + ], + "properties": { + "list_accounts": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/queue/schema/raw/migrate.json b/contracts/queue/schema/raw/migrate.json index 1877209732..7fbe8c5708 100644 --- a/contracts/queue/schema/raw/migrate.json +++ b/contracts/queue/schema/raw/migrate.json @@ -1,41 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", - "oneOf": [ - { - "type": "object", - "required": [ - "enqueue" - ], - "properties": { - "enqueue": { - "type": "object", - "required": [ - "value" - ], - "properties": { - "value": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "dequeue" - ], - "properties": { - "dequeue": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ] + "title": "MigrateMsg", + "type": "object", + "additionalProperties": false } diff --git a/contracts/queue/schema/raw/query.json b/contracts/queue/schema/raw/query.json index 1877209732..3c61d5fc57 100644 --- a/contracts/queue/schema/raw/query.json +++ b/contracts/queue/schema/raw/query.json @@ -1,24 +1,15 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", + "title": "QueryMsg", "oneOf": [ { "type": "object", "required": [ - "enqueue" + "count" ], "properties": { - "enqueue": { + "count": { "type": "object", - "required": [ - "value" - ], - "properties": { - "value": { - "type": "integer", - "format": "int32" - } - }, "additionalProperties": false } }, @@ -27,15 +18,65 @@ { "type": "object", "required": [ - "dequeue" + "sum" ], "properties": { - "dequeue": { + "sum": { "type": "object", "additionalProperties": false } }, "additionalProperties": false + }, + { + "type": "object", + "required": [ + "reducer" + ], + "properties": { + "reducer": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "list" + ], + "properties": { + "list": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Opens the given number of iterators for no reason other than testing. Returns and `Empty` response.", + "type": "object", + "required": [ + "open_iterators" + ], + "properties": { + "open_iterators": { + "type": "object", + "required": [ + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } ] } diff --git a/contracts/reflect/schema/raw/query.json b/contracts/reflect/schema/raw/query.json index e0db5ae603..04512e6f3f 100644 --- a/contracts/reflect/schema/raw/query.json +++ b/contracts/reflect/schema/raw/query.json @@ -1,24 +1,35 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", + "title": "QueryMsg", "oneOf": [ { "type": "object", "required": [ - "reflect_msg" + "owner" ], "properties": { - "reflect_msg": { + "owner": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "This will call out to SpecialQuery::Capitalized", + "type": "object", + "required": [ + "capitalized" + ], + "properties": { + "capitalized": { "type": "object", "required": [ - "msgs" + "text" ], "properties": { - "msgs": { - "type": "array", - "items": { - "$ref": "#/definitions/CosmosMsg_for_CustomMsg" - } + "text": { + "type": "string" } }, "additionalProperties": false @@ -27,22 +38,20 @@ "additionalProperties": false }, { + "description": "Queries the blockchain and returns the result untouched", "type": "object", "required": [ - "reflect_sub_msg" + "chain" ], "properties": { - "reflect_sub_msg": { + "chain": { "type": "object", "required": [ - "msgs" + "request" ], "properties": { - "msgs": { - "type": "array", - "items": { - "$ref": "#/definitions/SubMsg_for_CustomMsg" - } + "request": { + "$ref": "#/definitions/QueryRequest_for_SpecialQuery" } }, "additionalProperties": false @@ -51,19 +60,48 @@ "additionalProperties": false }, { + "description": "Queries another contract and returns the data", "type": "object", "required": [ - "change_owner" + "raw" ], "properties": { - "change_owner": { + "raw": { "type": "object", "required": [ - "owner" + "contract", + "key" ], "properties": { - "owner": { + "contract": { "type": "string" + }, + "key": { + "$ref": "#/definitions/Binary" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "If there was a previous ReflectSubMsg with this ID, returns cosmwasm_std::Reply", + "type": "object", + "required": [ + "sub_msg_result" + ], + "properties": { + "sub_msg_result": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 } }, "additionalProperties": false @@ -73,30 +111,22 @@ } ], "definitions": { - "BankMsg": { - "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", + "BankQuery": { "oneOf": [ { - "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", + "description": "This calls into the native bank module for querying the total supply of one denomination. It does the same as the SupplyOf call in Cosmos SDK's RPC API. Return value is of type SupplyResponse.", "type": "object", "required": [ - "send" + "supply" ], "properties": { - "send": { + "supply": { "type": "object", "required": [ - "amount", - "to_address" + "denom" ], "properties": { - "amount": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "to_address": { + "denom": { "type": "string" } } @@ -105,133 +135,133 @@ "additionalProperties": false }, { - "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", + "description": "This calls into the native bank module for one denomination Return value is BalanceResponse", "type": "object", "required": [ - "burn" + "balance" ], "properties": { - "burn": { + "balance": { "type": "object", "required": [ - "amount" + "address", + "denom" ], "properties": { - "amount": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } + "address": { + "type": "string" + }, + "denom": { + "type": "string" } } } }, "additionalProperties": false - } - ] - }, - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", - "type": "string" - }, - "Coin": { - "type": "object", - "required": [ - "amount", - "denom" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" }, - "denom": { - "type": "string" - } - } - }, - "CosmosMsg_for_CustomMsg": { - "oneOf": [ { + "description": "This calls into the native bank module for all denominations. Note that this may be much more expensive than Balance and should be avoided if possible. Return value is AllBalanceResponse.", "type": "object", "required": [ - "bank" - ], - "properties": { - "bank": { - "$ref": "#/definitions/BankMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "custom" + "all_balances" ], "properties": { - "custom": { - "$ref": "#/definitions/CustomMsg" + "all_balances": { + "type": "object", + "required": [ + "address" + ], + "properties": { + "address": { + "type": "string" + } + } } }, "additionalProperties": false - }, + } + ] + }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "IbcQuery": { + "description": "These are queries to the various IBC modules to see the state of the contract's IBC connection. These will return errors if the contract is not \"ibc enabled\"", + "oneOf": [ { + "description": "Gets the Port ID the current contract is bound to.\n\nReturns a `PortIdResponse`.", "type": "object", "required": [ - "staking" + "port_id" ], "properties": { - "staking": { - "$ref": "#/definitions/StakingMsg" + "port_id": { + "type": "object" } }, "additionalProperties": false }, { + "description": "Lists all channels that are bound to a given port. If `port_id` is omitted, this list all channels bound to the contract's port.\n\nReturns a `ListChannelsResponse`.", "type": "object", "required": [ - "distribution" + "list_channels" ], "properties": { - "distribution": { - "$ref": "#/definitions/DistributionMsg" + "list_channels": { + "type": "object", + "properties": { + "port_id": { + "type": [ + "string", + "null" + ] + } + } } }, "additionalProperties": false }, { - "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", + "description": "Lists all information for a (portID, channelID) pair. If port_id is omitted, it will default to the contract's own channel. (To save a PortId{} call)\n\nReturns a `ChannelResponse`.", "type": "object", "required": [ - "stargate" + "channel" ], "properties": { - "stargate": { + "channel": { "type": "object", "required": [ - "type_url", - "value" + "channel_id" ], "properties": { - "type_url": { + "channel_id": { "type": "string" }, - "value": { - "$ref": "#/definitions/Binary" + "port_id": { + "type": [ + "string", + "null" + ] } } } }, "additionalProperties": false - }, + } + ] + }, + "QueryRequest_for_SpecialQuery": { + "oneOf": [ { "type": "object", "required": [ - "ibc" + "bank" ], "properties": { - "ibc": { - "$ref": "#/definitions/IbcMsg" + "bank": { + "$ref": "#/definitions/BankQuery" } }, "additionalProperties": false @@ -239,11 +269,11 @@ { "type": "object", "required": [ - "wasm" + "custom" ], "properties": { - "wasm": { - "$ref": "#/definitions/WasmMsg" + "custom": { + "$ref": "#/definitions/SpecialQuery" } }, "additionalProperties": false @@ -251,64 +281,39 @@ { "type": "object", "required": [ - "gov" - ], - "properties": { - "gov": { - "$ref": "#/definitions/GovMsg" - } - }, - "additionalProperties": false - } - ] - }, - "CustomMsg": { - "description": "CustomMsg is an override of CosmosMsg::Custom to show this works and can be extended in the contract", - "oneOf": [ - { - "type": "object", - "required": [ - "debug" + "staking" ], "properties": { - "debug": { - "type": "string" + "staking": { + "$ref": "#/definitions/StakingQuery" } }, "additionalProperties": false }, { + "description": "A Stargate query is encoded the same way as abci_query, with path and protobuf encoded request data. The format is defined in [ADR-21](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-021-protobuf-query-encoding.md). The response is protobuf encoded data directly without a JSON response wrapper. The caller is responsible for compiling the proper protobuf definitions for both requests and responses.", "type": "object", "required": [ - "raw" - ], - "properties": { - "raw": { - "$ref": "#/definitions/Binary" - } - }, - "additionalProperties": false - } - ] - }, - "DistributionMsg": { - "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", - "oneOf": [ - { - "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "set_withdraw_address" + "stargate" ], "properties": { - "set_withdraw_address": { + "stargate": { "type": "object", "required": [ - "address" + "data", + "path" ], "properties": { - "address": { - "description": "The `withdraw_address`", + "data": { + "description": "this is the expected protobuf message type (not any), binary encoded", + "allOf": [ + { + "$ref": "#/definitions/Binary" + } + ] + }, + "path": { + "description": "this is the fully qualified service path used for routing, eg. custom/cosmos_sdk.x.bank.v1.Query/QueryBalance", "type": "string" } } @@ -317,244 +322,99 @@ "additionalProperties": false }, { - "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", "type": "object", "required": [ - "withdraw_delegator_reward" + "ibc" ], "properties": { - "withdraw_delegator_reward": { - "type": "object", - "required": [ - "validator" - ], - "properties": { - "validator": { - "description": "The `validator_address`", - "type": "string" - } - } + "ibc": { + "$ref": "#/definitions/IbcQuery" } }, "additionalProperties": false - } - ] - }, - "GovMsg": { - "oneOf": [ + }, { - "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", "type": "object", "required": [ - "vote" + "wasm" ], "properties": { - "vote": { - "type": "object", - "required": [ - "proposal_id", - "vote" - ], - "properties": { - "proposal_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "vote": { - "$ref": "#/definitions/VoteOption" - } - } + "wasm": { + "$ref": "#/definitions/WasmQuery" } }, "additionalProperties": false } ] }, - "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "SpecialQuery": { + "description": "An implementation of QueryRequest::Custom to show this works and can be extended in the contract", "oneOf": [ { - "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", "type": "object", "required": [ - "transfer" + "ping" ], "properties": { - "transfer": { + "ping": { "type": "object", - "required": [ - "amount", - "channel_id", - "timeout", - "to_address" - ], - "properties": { - "amount": { - "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", - "allOf": [ - { - "$ref": "#/definitions/Coin" - } - ] - }, - "channel_id": { - "description": "exisiting channel to send the tokens over", - "type": "string" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] - }, - "to_address": { - "description": "address on the remote chain to receive these tokens", - "type": "string" - } - } + "additionalProperties": false } }, "additionalProperties": false }, { - "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", "type": "object", "required": [ - "send_packet" + "capitalized" ], "properties": { - "send_packet": { + "capitalized": { "type": "object", "required": [ - "channel_id", - "data", - "timeout" + "text" ], "properties": { - "channel_id": { + "text": { "type": "string" - }, - "data": { - "$ref": "#/definitions/Binary" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] } - } + }, + "additionalProperties": false } }, "additionalProperties": false - }, + } + ] + }, + "StakingQuery": { + "oneOf": [ { - "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", + "description": "Returns the denomination that can be bonded (if there are multiple native tokens on the chain)", "type": "object", "required": [ - "close_channel" + "bonded_denom" ], "properties": { - "close_channel": { - "type": "object", - "required": [ - "channel_id" - ], - "properties": { - "channel_id": { - "type": "string" - } - } + "bonded_denom": { + "type": "object" } }, "additionalProperties": false - } - ] - }, - "IbcTimeout": { - "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", - "type": "object", - "properties": { - "block": { - "anyOf": [ - { - "$ref": "#/definitions/IbcTimeoutBlock" - }, - { - "type": "null" - } - ] - }, - "timestamp": { - "anyOf": [ - { - "$ref": "#/definitions/Timestamp" - }, - { - "type": "null" - } - ] - } - } - }, - "IbcTimeoutBlock": { - "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", - "type": "object", - "required": [ - "height", - "revision" - ], - "properties": { - "height": { - "description": "block height after which the packet times out. the height within the given revision", - "type": "integer", - "format": "uint64", - "minimum": 0.0 }, - "revision": { - "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "ReplyOn": { - "description": "Use this to define when the contract gets a response callback. If you only need it for errors or success you can select just those in order to save gas.", - "type": "string", - "enum": [ - "always", - "error", - "success", - "never" - ] - }, - "StakingMsg": { - "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", - "oneOf": [ { - "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", + "description": "AllDelegations will return all delegations by the delegator", "type": "object", "required": [ - "delegate" + "all_delegations" ], "properties": { - "delegate": { + "all_delegations": { "type": "object", "required": [ - "amount", - "validator" + "delegator" ], "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "validator": { + "delegator": { "type": "string" } } @@ -563,21 +423,21 @@ "additionalProperties": false }, { - "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", + "description": "Delegation will return more detailed info on a particular delegation, defined by delegator/validator pair", "type": "object", "required": [ - "undelegate" + "delegation" ], "properties": { - "undelegate": { + "delegation": { "type": "object", "required": [ - "amount", + "delegator", "validator" ], "properties": { - "amount": { - "$ref": "#/definitions/Coin" + "delegator": { + "type": "string" }, "validator": { "type": "string" @@ -588,172 +448,63 @@ "additionalProperties": false }, { - "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", + "description": "Returns all validators in the currently active validator set.\n\nThe query response type is `AllValidatorsResponse`.", "type": "object", "required": [ - "redelegate" + "all_validators" ], "properties": { - "redelegate": { - "type": "object", - "required": [ - "amount", - "dst_validator", - "src_validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "dst_validator": { - "type": "string" - }, - "src_validator": { - "type": "string" - } - } + "all_validators": { + "type": "object" } }, "additionalProperties": false - } - ] - }, - "SubMsg_for_CustomMsg": { - "description": "A submessage that will guarantee a `reply` call on success or error, depending on the `reply_on` setting. If you do not need to process the result, use regular messages instead.\n\nNote: On error the submessage execution will revert any partial state changes due to this message, but not revert any state changes in the calling contract. If this is required, it must be done manually in the `reply` entry point.", - "type": "object", - "required": [ - "id", - "msg", - "reply_on" - ], - "properties": { - "gas_limit": { - "description": "Gas limit measured in [Cosmos SDK gas](https://github.com/CosmWasm/cosmwasm/blob/main/docs/GAS.md).", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "id": { - "description": "An arbitrary ID chosen by the contract. This is typically used to match `Reply`s in the `reply` entry point to the submessage.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "msg": { - "$ref": "#/definitions/CosmosMsg_for_CustomMsg" }, - "reply_on": { - "$ref": "#/definitions/ReplyOn" - } - } - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - }, - "VoteOption": { - "type": "string", - "enum": [ - "yes", - "no", - "abstain", - "no_with_veto" - ] - }, - "WasmMsg": { - "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", - "oneOf": [ - { - "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", + "description": "Returns the validator at the given address. Returns None if the validator is not part of the currently active validator set.\n\nThe query response type is `ValidatorResponse`.", "type": "object", "required": [ - "execute" + "validator" ], "properties": { - "execute": { + "validator": { "type": "object", "required": [ - "contract_addr", - "funds", - "msg" + "address" ], "properties": { - "contract_addr": { + "address": { + "description": "The validator's address (e.g. (e.g. cosmosvaloper1...))", "type": "string" - }, - "funds": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "msg": { - "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] } } } }, "additionalProperties": false - }, + } + ] + }, + "WasmQuery": { + "oneOf": [ { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "this queries the public API of another contract at a known address (with known ABI) Return value is whatever the contract returns (caller should know), wrapped in a ContractResult that is JSON encoded.", "type": "object", "required": [ - "instantiate" + "smart" ], "properties": { - "instantiate": { + "smart": { "type": "object", "required": [ - "code_id", - "funds", - "label", + "contract_addr", "msg" ], "properties": { - "admin": { - "type": [ - "string", - "null" - ] - }, - "code_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "funds": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "label": { - "description": "A human-readbale label for the contract", + "contract_addr": { "type": "string" }, "msg": { - "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", + "description": "msg is the json-encoded QueryMsg struct", "allOf": [ { "$ref": "#/definitions/Binary" @@ -766,61 +517,29 @@ "additionalProperties": false }, { - "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", + "description": "this queries the raw kv-store of the contract. returns the raw, unparsed data stored at that key, which may be an empty vector if not present", "type": "object", "required": [ - "migrate" + "raw" ], "properties": { - "migrate": { + "raw": { "type": "object", "required": [ "contract_addr", - "msg", - "new_code_id" + "key" ], "properties": { "contract_addr": { "type": "string" }, - "msg": { - "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", + "key": { + "description": "Key is the raw key used in the contracts Storage", "allOf": [ { "$ref": "#/definitions/Binary" } ] - }, - "new_code_id": { - "description": "the code_id of the new logic to place in the given contract", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", - "type": "object", - "required": [ - "update_admin" - ], - "properties": { - "update_admin": { - "type": "object", - "required": [ - "admin", - "contract_addr" - ], - "properties": { - "admin": { - "type": "string" - }, - "contract_addr": { - "type": "string" } } } @@ -828,13 +547,13 @@ "additionalProperties": false }, { - "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", + "description": "returns a ContractInfoResponse with metadata on the contract from the runtime", "type": "object", "required": [ - "clear_admin" + "contract_info" ], "properties": { - "clear_admin": { + "contract_info": { "type": "object", "required": [ "contract_addr" diff --git a/contracts/staking/schema/raw/query.json b/contracts/staking/schema/raw/query.json index 159d67cd90..6427a6bc87 100644 --- a/contracts/staking/schema/raw/query.json +++ b/contracts/staking/schema/raw/query.json @@ -1,25 +1,21 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", + "title": "QueryMsg", "oneOf": [ { - "description": "Transfer moves the derivative token", + "description": "Balance shows the number of staking derivatives", "type": "object", "required": [ - "transfer" + "balance" ], "properties": { - "transfer": { + "balance": { "type": "object", "required": [ - "amount", - "recipient" + "address" ], "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "recipient": { + "address": { "type": "string" } }, @@ -29,34 +25,20 @@ "additionalProperties": false }, { - "description": "Bond will bond all staking tokens sent with the message and release derivative tokens", + "description": "Claims shows the number of tokens this address can access when they are done unbonding", "type": "object", "required": [ - "bond" + "claims" ], "properties": { - "bond": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - }, - { - "description": "Unbond will \"burn\" the given amount of derivative tokens and send the unbonded staking tokens to the message sender (after exit tax is deducted)", - "type": "object", - "required": [ - "unbond" - ], - "properties": { - "unbond": { + "claims": { "type": "object", "required": [ - "amount" + "address" ], "properties": { - "amount": { - "$ref": "#/definitions/Uint128" + "address": { + "type": "string" } }, "additionalProperties": false @@ -65,13 +47,13 @@ "additionalProperties": false }, { - "description": "Claim is used to claim your native tokens that you previously \"unbonded\" after the chain-defined waiting period (eg. 3 weeks)", + "description": "TokenInfo shows the metadata of the token for UIs", "type": "object", "required": [ - "claim" + "token_info" ], "properties": { - "claim": { + "token_info": { "type": "object", "additionalProperties": false } @@ -79,38 +61,18 @@ "additionalProperties": false }, { - "description": "Reinvest will check for all accumulated rewards, withdraw them, and re-bond them to the same validator. Anyone can call this, which updates the value of the token (how much under custody).", + "description": "Investment shows info on total staking tokens under custody, with which validator, as well as how many derivative tokens are lists. It also shows with the exit tax.", "type": "object", "required": [ - "reinvest" + "investment" ], "properties": { - "reinvest": { + "investment": { "type": "object", "additionalProperties": false } }, "additionalProperties": false - }, - { - "description": "_BondAllTokens can only be called by the contract itself, after all rewards have been withdrawn. This is an example of using \"callbacks\" in message flows. This can only be invoked by the contract itself as a return from Reinvest", - "type": "object", - "required": [ - "__bond_all_tokens" - ], - "properties": { - "__bond_all_tokens": { - "type": "object", - "additionalProperties": false - } - }, - "additionalProperties": false - } - ], - "definitions": { - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" } - } + ] } From c939aff71fe2ca0e09926eccb62c7e99c0c8e809 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 11:45:52 +0100 Subject: [PATCH 038/187] Add PR links to raw JSON Schema directory change --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d780adf87..d6472e1d97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,10 +15,13 @@ and this project adheres to - cosmwasm-std: Add `instantiate2_address` which allows calculating the predictable addresses for `MsgInstantiateContract2` ([#1437]). - cosmwasm-schema: In contracts, `cosmwasm schema` will now output a separate - JSON Schema file for each entrypoint in the `raw` subdirectory. + JSON Schema file for each entrypoint in the `raw` subdirectory ([#1478], + [#1533]). [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 [#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 +[#1478]: https://github.com/CosmWasm/cosmwasm/pull/1478 +[#1533]: https://github.com/CosmWasm/cosmwasm/pull/1533 ### Changed From a82b4a9631852bab3cf7030615c6c61b54383cdc Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 10:46:37 +0100 Subject: [PATCH 039/187] Test cpu_loop --- contracts/cyberpunk/src/contract.rs | 11 +++++++++++ contracts/cyberpunk/src/msg.rs | 2 ++ packages/vm/README.md | 6 ++++++ packages/vm/src/calls.rs | 19 +++++++++++++++++++ packages/vm/testdata/cyberpunk.wasm | Bin 0 -> 160084 bytes 5 files changed, 38 insertions(+) create mode 100644 packages/vm/testdata/cyberpunk.wasm diff --git a/contracts/cyberpunk/src/contract.rs b/contracts/cyberpunk/src/contract.rs index 7ea42967ac..5b8a37015c 100644 --- a/contracts/cyberpunk/src/contract.rs +++ b/contracts/cyberpunk/src/contract.rs @@ -33,6 +33,7 @@ pub fn execute( mem_cost, time_cost, } => execute::argon2(mem_cost, time_cost), + CpuLoop {} => execute::cpu_loop(), MirrorEnv {} => execute::mirror_env(env), } } @@ -62,6 +63,16 @@ mod execute { //Ok(Response::new()) } + pub fn cpu_loop() -> Result { + let mut counter = 0u64; + loop { + counter += 1; + if counter >= 9_000_000_000 { + counter = 0; + } + } + } + pub fn mirror_env(env: Env) -> Result { Ok(Response::new().set_data(to_binary(&env)?)) } diff --git a/contracts/cyberpunk/src/msg.rs b/contracts/cyberpunk/src/msg.rs index 98a03b0b7b..83626ccd43 100644 --- a/contracts/cyberpunk/src/msg.rs +++ b/contracts/cyberpunk/src/msg.rs @@ -9,6 +9,8 @@ pub enum ExecuteMsg { /// The number of passes. time_cost: u32, }, + /// Infinite loop to burn cpu cycles (only run when metering is enabled) + CpuLoop {}, /// Returns the env for testing MirrorEnv {}, } diff --git a/packages/vm/README.md b/packages/vm/README.md index f3b0cc1bb5..2d85697bed 100644 --- a/packages/vm/README.md +++ b/packages/vm/README.md @@ -50,6 +50,12 @@ run through [rust-optimizer](https://github.com/CosmWasm/rust-optimizer). To rebuild the test contracts, go to the repo root and do ```sh +docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="devcontract_cache_cyberpunk",target=/code/contracts/cyberpunk/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer:0.12.10 ./contracts/cyberpunk \ + && cp artifacts/cyberpunk.wasm packages/vm/testdata/cyberpunk.wasm + docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_hackatom",target=/code/contracts/hackatom/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index 55ec230e5f..63b90922ff 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -595,6 +595,7 @@ mod tests { use cosmwasm_std::{coins, Empty}; static CONTRACT: &[u8] = include_bytes!("../testdata/hackatom.wasm"); + static CYBERPUNK: &[u8] = include_bytes!("../testdata/cyberpunk.wasm"); #[test] fn call_instantiate_works() { @@ -627,6 +628,24 @@ mod tests { .unwrap(); } + #[test] + fn call_execute_runs_out_of_gas() { + let mut instance = mock_instance(CYBERPUNK, &[]); + + // init + let info = mock_info("creator", &[]); + call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, br#"{}"#) + .unwrap() + .unwrap(); + + // execute + let info = mock_info("looper", &[]); + let msg = br#"{"cpu_loop":{}}"#; + let err = + call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap_err(); + assert!(matches!(err, VmError::GasDepletion {})); + } + #[test] fn call_migrate_works() { let mut instance = mock_instance(CONTRACT, &[]); diff --git a/packages/vm/testdata/cyberpunk.wasm b/packages/vm/testdata/cyberpunk.wasm new file mode 100644 index 0000000000000000000000000000000000000000..4fa2b7cbfeb193da0bb8123425df632ba3b166ed GIT binary patch literal 160084 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

7*vC(IQ~nsAsS4L;U=h_C+0Qo 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 f16hpv49awr$@p}_WstkW2n!JYfV1^88_NGLL Date: Tue, 6 Dec 2022 12:18:41 +0100 Subject: [PATCH 040/187] Update schemas for new cpu_loop type --- contracts/cyberpunk/schema/cyberpunk.json | 14 ++++++++++++++ contracts/cyberpunk/schema/raw/execute.json | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/contracts/cyberpunk/schema/cyberpunk.json b/contracts/cyberpunk/schema/cyberpunk.json index 9439d30556..2daf62f72e 100644 --- a/contracts/cyberpunk/schema/cyberpunk.json +++ b/contracts/cyberpunk/schema/cyberpunk.json @@ -44,6 +44,20 @@ }, "additionalProperties": false }, + { + "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)", + "type": "object", + "required": [ + "cpu_loop" + ], + "properties": { + "cpu_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Returns the env for testing", "type": "object", diff --git a/contracts/cyberpunk/schema/raw/execute.json b/contracts/cyberpunk/schema/raw/execute.json index 8e7af5fe3c..5e811f8e5d 100644 --- a/contracts/cyberpunk/schema/raw/execute.json +++ b/contracts/cyberpunk/schema/raw/execute.json @@ -34,6 +34,20 @@ }, "additionalProperties": false }, + { + "description": "Infinite loop to burn cpu cycles (only run when metering is enabled)", + "type": "object", + "required": [ + "cpu_loop" + ], + "properties": { + "cpu_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Returns the env for testing", "type": "object", From b3d136e87e3e91701fded2527200bfadeae51528 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 10:56:58 +0100 Subject: [PATCH 041/187] Add contract folders to arm64 caching --- .circleci/config.yml | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3e32556e5c..00aa2091c9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -94,7 +94,7 @@ jobs: command: rustup target add wasm32-unknown-unknown && rustup target list --installed - restore_cache: keys: - - cargocache-v2-arm64-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cachev3-arm64-rust:1.59.0-{{ checksum "Cargo.lock" }} - run: name: "contracts/crypto-verify: integration-test" working_directory: ~/project/contracts/crypto-verify @@ -134,7 +134,42 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-arm64-rust:1.59.0-{{ checksum "Cargo.lock" }} + # crypto-verify + - contracts/crypto-verify/target/debug/.fingerprint + - contracts/crypto-verify/target/debug/build + - contracts/crypto-verify/target/debug/deps + - contracts/crypto-verify/target/wasm32-unknown-unknown/release/.fingerprint + - contracts/crypto-verify/target/wasm32-unknown-unknown/release/build + - contracts/crypto-verify/target/wasm32-unknown-unknown/release/deps + # hackatom + - contracts/hackatom/target/debug/.fingerprint + - contracts/hackatom/target/debug/build + - contracts/hackatom/target/debug/deps + - contracts/hackatom/target/wasm32-unknown-unknown/release/.fingerprint + - contracts/hackatom/target/wasm32-unknown-unknown/release/build + - contracts/hackatom/target/wasm32-unknown-unknown/release/deps + # queue + - contracts/queue/target/debug/.fingerprint + - contracts/queue/target/debug/build + - contracts/queue/target/debug/deps + - contracts/queue/target/wasm32-unknown-unknown/release/.fingerprint + - contracts/queue/target/wasm32-unknown-unknown/release/build + - contracts/queue/target/wasm32-unknown-unknown/release/deps + # reflect + - contracts/reflect/target/debug/.fingerprint + - contracts/reflect/target/debug/build + - contracts/reflect/target/debug/deps + - contracts/reflect/target/wasm32-unknown-unknown/release/.fingerprint + - contracts/reflect/target/wasm32-unknown-unknown/release/build + - contracts/reflect/target/wasm32-unknown-unknown/release/deps + # staking + - contracts/staking/target/debug/.fingerprint + - contracts/staking/target/debug/build + - contracts/staking/target/debug/deps + - contracts/staking/target/wasm32-unknown-unknown/release/.fingerprint + - contracts/staking/target/wasm32-unknown-unknown/release/build + - contracts/staking/target/wasm32-unknown-unknown/release/deps + key: cachev3-arm64-rust:1.59.0-{{ checksum "Cargo.lock" }} package_crypto: docker: From 43d345a4f19ad20014aa34d8597bc712bc427a98 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 18:31:37 +0100 Subject: [PATCH 042/187] Split into two caches: v4-arm64-workspace-... and v4-arm64-contracts-... --- .circleci/config.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 00aa2091c9..851bcd8a04 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -94,7 +94,12 @@ jobs: command: rustup target add wasm32-unknown-unknown && rustup target list --installed - restore_cache: keys: - - cachev3-arm64-rust:1.59.0-{{ checksum "Cargo.lock" }} + - v4-arm64-workspace-rust:1.59.0-{{ checksum "Cargo.lock" }} + - v4-arm64-workspace-rust:1.59.0- + - restore_cache: + keys: + - v4-arm64-contracts-rust:1.59.0-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} + - v4-arm64-contracts-rust:1.59.0- - run: name: "contracts/crypto-verify: integration-test" working_directory: ~/project/contracts/crypto-verify @@ -129,11 +134,16 @@ jobs: # use all features command: cargo test --locked --features iterator,staking,stargate - save_cache: + key: v4-arm64-workspace-rust:1.59.0-{{ checksum "Cargo.lock" }} paths: - ~/.cargo/registry - target/debug/.fingerprint - target/debug/build - target/debug/deps + - save_cache: + key: v4-arm64-contracts-rust:1.59.0-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} + paths: + - ~/.cargo/registry # crypto-verify - contracts/crypto-verify/target/debug/.fingerprint - contracts/crypto-verify/target/debug/build @@ -169,7 +179,6 @@ jobs: - contracts/staking/target/wasm32-unknown-unknown/release/.fingerprint - contracts/staking/target/wasm32-unknown-unknown/release/build - contracts/staking/target/wasm32-unknown-unknown/release/deps - key: cachev3-arm64-rust:1.59.0-{{ checksum "Cargo.lock" }} package_crypto: docker: From b23b02067cf6b0c6b76f5e4d87353798a74d71e6 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 19:00:23 +0100 Subject: [PATCH 043/187] Use cache From 694875e3cde5aa255e96e34d6e0de6fe137dc9e2 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 6 Dec 2022 19:45:47 +0100 Subject: [PATCH 044/187] Upgrade serde-json-wasm to 0.5.0 --- CHANGELOG.md | 2 ++ Cargo.lock | 4 ++-- contracts/burner/Cargo.lock | 4 ++-- contracts/crypto-verify/Cargo.lock | 4 ++-- contracts/cyberpunk/Cargo.lock | 4 ++-- contracts/floaty/Cargo.lock | 4 ++-- contracts/hackatom/Cargo.lock | 4 ++-- contracts/ibc-reflect-send/Cargo.lock | 4 ++-- contracts/ibc-reflect/Cargo.lock | 4 ++-- contracts/queue/Cargo.lock | 4 ++-- contracts/reflect/Cargo.lock | 4 ++-- contracts/staking/Cargo.lock | 4 ++-- packages/std/Cargo.toml | 2 +- 13 files changed, 25 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8e3840168..b2b253cc22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to - cosmwasm-schema: In contracts, `cosmwasm schema` will now output a separate JSON Schema file for each entrypoint in the `raw` subdirectory ([#1478], [#1533]). +- cosmwasm-std: Upgrade `serde-json-wasm` dependency to 0.5.0 which adds map + support to `to_vec`/`to_binary` and friends. [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 [#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 diff --git a/Cargo.lock b/Cargo.lock index b468d26695..021ce07392 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1568,9 +1568,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index 47624e7fc9..9044ff718a 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -1282,9 +1282,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index 91b16b5216..4bebe371ca 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -1330,9 +1330,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index fa1b022caa..58b2b8dcf5 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -1332,9 +1332,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index b8f7d7347b..a91764061f 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -1292,9 +1292,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index b707cf2b96..a88a63914f 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -1293,9 +1293,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index fa5c44979e..eef33fcda3 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -1291,9 +1291,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index a664494d0e..2433c84e57 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -1291,9 +1291,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index 1bb95637c9..69ea329dbb 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -1282,9 +1282,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index 62fed006eb..7ffedc112b 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -1292,9 +1292,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index e23dfbfab0..0c4a548896 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -1285,9 +1285,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 993238c5ad..a960528f7b 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -49,7 +49,7 @@ hex = "0.4" schemars = "0.8.3" sha2 = "0.10.3" serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } -serde-json-wasm = { version = "0.4.1" } +serde-json-wasm = { version = "0.5.0" } thiserror = "1.0.13" uint = "0.9.3" From 368e93311983d25f160c36a8604dc63bfdc72b65 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 7 Dec 2022 12:40:58 +0100 Subject: [PATCH 045/187] Create introduction to the CosmWasm development contracts --- contracts/README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/contracts/README.md b/contracts/README.md index 30e1103c01..cb89fc0039 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -4,6 +4,39 @@ Those contracts are made for development purpose only. For more realistic example contracts, see [cosmwasm-examples](https://github.com/CosmWasm/cosmwasm-examples). +## The contracts + +Introducing the development contracts in the order they were created. + +1. **hackatom** is the very first development contract that was created at a + Cosmos Hackatom in Berlin in 2019, the event where CosmWasm was born. It is a + very basic escrow contract. During the years of CosmWasm development, many + more test cases were hacked into it. +2. **queue** shows and tests the newly added iterator support + ([#181](https://github.com/CosmWasm/cosmwasm/pull/181)). +3. **reflect** is an evolution of the + [mask contract](https://medium.com/cosmwasm/introducing-the-mask-41d11e51bccf), + which allows the user to send messages to the contract which are then emitted + with the contract as the sender. It later got support to handle sub messages + and replys ([#796](https://github.com/CosmWasm/cosmwasm/pull/796)). +4. **staking** is a staking derivates example showing how the contract itself + can be a delegator. +5. **burner** shows how contract migrations work, which were added in CosmWasm + 0.9 ([#413](https://github.com/CosmWasm/cosmwasm/pull/413)). It shuts down + the contract my clearing all state and sending all tokens to a given address. +6. **ibc-reflect**/**ibc-reflect-send** are inspired by the idea of Interchain + Accounts and demonstrate the power of contract to contract IBC. + ibc-reflect-send receives a message on chain A and sends it to an ibc-reflect + instance on chain B where the message is executed. +7. **crypto-verify** shows how to use the CosmWasm crypto APIs for signature + verification ([#783](https://github.com/CosmWasm/cosmwasm/pull/783)). +8. **floaty** emits float operations when compiled to Wasm and allows us to test + how tooling and the runtime deal with those operations + ([#970](https://github.com/CosmWasm/cosmwasm/pull/970)). +9. **cyberpunk** is an attempt to cleanup hackatom and make writing runtime + tests (cosmwasm-vm/wamsmvm) easier by avoid the need for the escrow setup + that hackatom has. + ## Optimized builds Those development contracts are used for testing in other repos, e.g. in From fb6b6080b8d13e8d1adfd278285396878cc835e1 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 7 Dec 2022 12:52:50 +0100 Subject: [PATCH 046/187] Add StorageLoop, MemoryLoop, MessageLoop, AllocateLargeMemory and Panic to cyberpunk --- contracts/cyberpunk/schema/cyberpunk.json | 80 +++++++++++ contracts/cyberpunk/schema/raw/execute.json | 80 +++++++++++ contracts/cyberpunk/src/contract.rs | 150 ++++++++++++++------ contracts/cyberpunk/src/msg.rs | 10 ++ 4 files changed, 276 insertions(+), 44 deletions(-) diff --git a/contracts/cyberpunk/schema/cyberpunk.json b/contracts/cyberpunk/schema/cyberpunk.json index 2daf62f72e..666e8042a7 100644 --- a/contracts/cyberpunk/schema/cyberpunk.json +++ b/contracts/cyberpunk/schema/cyberpunk.json @@ -58,6 +58,86 @@ }, "additionalProperties": false }, + { + "description": "Infinite loop making storage calls (to test when their limit hits)", + "type": "object", + "required": [ + "storage_loop" + ], + "properties": { + "storage_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop reading and writing memory", + "type": "object", + "required": [ + "memory_loop" + ], + "properties": { + "memory_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop sending message to itself", + "type": "object", + "required": [ + "message_loop" + ], + "properties": { + "message_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Allocate large amounts of memory without consuming much gas", + "type": "object", + "required": [ + "allocate_large_memory" + ], + "properties": { + "allocate_large_memory": { + "type": "object", + "required": [ + "pages" + ], + "properties": { + "pages": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Trigger a panic to ensure framework handles gracefully", + "type": "object", + "required": [ + "panic" + ], + "properties": { + "panic": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Returns the env for testing", "type": "object", diff --git a/contracts/cyberpunk/schema/raw/execute.json b/contracts/cyberpunk/schema/raw/execute.json index 5e811f8e5d..8ad4797118 100644 --- a/contracts/cyberpunk/schema/raw/execute.json +++ b/contracts/cyberpunk/schema/raw/execute.json @@ -48,6 +48,86 @@ }, "additionalProperties": false }, + { + "description": "Infinite loop making storage calls (to test when their limit hits)", + "type": "object", + "required": [ + "storage_loop" + ], + "properties": { + "storage_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop reading and writing memory", + "type": "object", + "required": [ + "memory_loop" + ], + "properties": { + "memory_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Infinite loop sending message to itself", + "type": "object", + "required": [ + "message_loop" + ], + "properties": { + "message_loop": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Allocate large amounts of memory without consuming much gas", + "type": "object", + "required": [ + "allocate_large_memory" + ], + "properties": { + "allocate_large_memory": { + "type": "object", + "required": [ + "pages" + ], + "properties": { + "pages": { + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Trigger a panic to ensure framework handles gracefully", + "type": "object", + "required": [ + "panic" + ], + "properties": { + "panic": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Returns the env for testing", "type": "object", diff --git a/contracts/cyberpunk/src/contract.rs b/contracts/cyberpunk/src/contract.rs index 5b8a37015c..1133dc3a63 100644 --- a/contracts/cyberpunk/src/contract.rs +++ b/contracts/cyberpunk/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ entry_point, to_binary, Deps, DepsMut, Empty, Env, MessageInfo, QueryResponse, Response, - StdError, StdResult, + StdError, StdResult, WasmMsg, }; use crate::errors::ContractError; @@ -21,7 +21,7 @@ pub fn instantiate( #[entry_point] pub fn execute( - _deps: DepsMut, + deps: DepsMut, env: Env, _info: MessageInfo, msg: ExecuteMsg, @@ -32,50 +32,116 @@ pub fn execute( Argon2 { mem_cost, time_cost, - } => execute::argon2(mem_cost, time_cost), - CpuLoop {} => execute::cpu_loop(), - MirrorEnv {} => execute::mirror_env(env), + } => execute_argon2(mem_cost, time_cost), + CpuLoop {} => execute_cpu_loop(), + StorageLoop {} => execute_storage_loop(deps), + MemoryLoop {} => execute_memory_loop(), + MessageLoop {} => execute_message_loop(env), + AllocateLargeMemory { pages } => execute_allocate_large_memory(pages), + Panic {} => execute_panic(), + MirrorEnv {} => execute_mirror_env(env), } } -mod execute { - use super::*; +fn execute_argon2(mem_cost: u32, time_cost: u32) -> Result { + let password = b"password"; + let salt = b"othersalt"; + let config = argon2::Config { + variant: argon2::Variant::Argon2i, + version: argon2::Version::Version13, + mem_cost, + time_cost, + lanes: 4, + thread_mode: argon2::ThreadMode::Sequential, + secret: &[], + ad: &[], + hash_length: 32, + }; + let hash = argon2::hash_encoded(password, salt, &config) + .map_err(|e| StdError::generic_err(format!("hash_encoded errored: {}", e)))?; + // let matches = argon2::verify_encoded(&hash, password).unwrap(); + // assert!(matches); + Ok(Response::new().set_data(hash.into_bytes())) + //Ok(Response::new()) +} - pub fn argon2(mem_cost: u32, time_cost: u32) -> Result { - let password = b"password"; - let salt = b"othersalt"; - let config = argon2::Config { - variant: argon2::Variant::Argon2i, - version: argon2::Version::Version13, - mem_cost, - time_cost, - lanes: 4, - thread_mode: argon2::ThreadMode::Sequential, - secret: &[], - ad: &[], - hash_length: 32, - }; - let hash = argon2::hash_encoded(password, salt, &config) - .map_err(|e| StdError::generic_err(format!("hash_encoded errored: {}", e)))?; - // let matches = argon2::verify_encoded(&hash, password).unwrap(); - // assert!(matches); - Ok(Response::new().set_data(hash.into_bytes())) - //Ok(Response::new()) +fn execute_cpu_loop() -> Result { + let mut counter = 0u64; + loop { + counter += 1; + if counter >= 9_000_000_000 { + counter = 0; + } } +} - pub fn cpu_loop() -> Result { - let mut counter = 0u64; - loop { - counter += 1; - if counter >= 9_000_000_000 { - counter = 0; - } - } +fn execute_storage_loop(deps: DepsMut) -> Result { + let mut test_case = 0u64; + loop { + deps.storage + .set(b"test.key", test_case.to_string().as_bytes()); + test_case += 1; } +} + +fn execute_memory_loop() -> Result { + let mut data = vec![1usize]; + loop { + // add one element + data.push((*data.last().expect("must not be empty")) + 1); + } +} + +fn execute_message_loop(env: Env) -> Result { + let resp = Response::new().add_message(WasmMsg::Execute { + contract_addr: env.contract.address.into(), + msg: to_binary(&ExecuteMsg::MessageLoop {})?, + funds: vec![], + }); + Ok(resp) +} - pub fn mirror_env(env: Env) -> Result { - Ok(Response::new().set_data(to_binary(&env)?)) +#[allow(unused_variables)] +fn execute_allocate_large_memory(pages: u32) -> Result { + // We create memory pages explicitely since Rust's default allocator seems to be clever enough + // to not grow memory for unused capacity like `Vec::::with_capacity(100 * 1024 * 1024)`. + // Even with std::alloc::alloc the memory did now grow beyond 1.5 MiB. + + #[cfg(target_arch = "wasm32")] + { + use core::arch::wasm32; + let old_size = wasm32::memory_grow(0, pages as usize); + if old_size == usize::max_value() { + return Err(StdError::generic_err("memory.grow failed").into()); + } + Ok(Response::new().set_data((old_size as u32).to_be_bytes())) } + + #[cfg(not(target_arch = "wasm32"))] + Err(StdError::generic_err("Unsupported architecture").into()) +} + +fn execute_panic() -> Result { + // Uncomment your favourite panic case + + // panicked at 'This page intentionally faulted', src/contract.rs:53:5 + panic!("This page intentionally faulted"); + + // panicked at 'oh no (a = 3)', src/contract.rs:56:5 + // let a = 3; + // panic!("oh no (a = {a})"); + + // panicked at 'attempt to subtract with overflow', src/contract.rs:59:13 + // #[allow(arithmetic_overflow)] + // let _ = 5u32 - 8u32; + + // panicked at 'no entry found for key', src/contract.rs:62:13 + // let map = std::collections::HashMap::::new(); + // let _ = map["foo"]; +} + +fn execute_mirror_env(env: Env) -> Result { + Ok(Response::new().set_data(to_binary(&env)?)) } #[entry_point] @@ -83,14 +149,10 @@ pub fn query(_deps: Deps, env: Env, msg: QueryMsg) -> StdResult { use QueryMsg::*; match msg { - MirrorEnv {} => to_binary(&query::mirror_env(env)), + MirrorEnv {} => to_binary(&query_mirror_env(env)), } } -mod query { - use super::*; - - pub fn mirror_env(env: Env) -> Env { - env - } +fn query_mirror_env(env: Env) -> Env { + env } diff --git a/contracts/cyberpunk/src/msg.rs b/contracts/cyberpunk/src/msg.rs index 83626ccd43..a671a11c34 100644 --- a/contracts/cyberpunk/src/msg.rs +++ b/contracts/cyberpunk/src/msg.rs @@ -11,6 +11,16 @@ pub enum ExecuteMsg { }, /// Infinite loop to burn cpu cycles (only run when metering is enabled) CpuLoop {}, + /// Infinite loop making storage calls (to test when their limit hits) + StorageLoop {}, + /// Infinite loop reading and writing memory + MemoryLoop {}, + /// Infinite loop sending message to itself + MessageLoop {}, + /// Allocate large amounts of memory without consuming much gas + AllocateLargeMemory { pages: u32 }, + /// Trigger a panic to ensure framework handles gracefully + Panic {}, /// Returns the env for testing MirrorEnv {}, } From 49cf319ec7ca26b0782d2bbd8fdb5af48c40173f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 7 Dec 2022 14:42:27 +0100 Subject: [PATCH 047/187] Add Unreachable message to cyberpunk contract --- contracts/cyberpunk/schema/cyberpunk.json | 14 ++++++++++++++ contracts/cyberpunk/schema/raw/execute.json | 14 ++++++++++++++ contracts/cyberpunk/src/contract.rs | 9 +++++++++ contracts/cyberpunk/src/msg.rs | 5 +++++ 4 files changed, 42 insertions(+) diff --git a/contracts/cyberpunk/schema/cyberpunk.json b/contracts/cyberpunk/schema/cyberpunk.json index 666e8042a7..1584ac900e 100644 --- a/contracts/cyberpunk/schema/cyberpunk.json +++ b/contracts/cyberpunk/schema/cyberpunk.json @@ -138,6 +138,20 @@ }, "additionalProperties": false }, + { + "description": "In contrast to Panic, this does not use the panic handler.\n\nFrom : \"Generates the unreachable instruction, which causes an unconditional trap.\"", + "type": "object", + "required": [ + "unreachable" + ], + "properties": { + "unreachable": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Returns the env for testing", "type": "object", diff --git a/contracts/cyberpunk/schema/raw/execute.json b/contracts/cyberpunk/schema/raw/execute.json index 8ad4797118..e096feab6f 100644 --- a/contracts/cyberpunk/schema/raw/execute.json +++ b/contracts/cyberpunk/schema/raw/execute.json @@ -128,6 +128,20 @@ }, "additionalProperties": false }, + { + "description": "In contrast to Panic, this does not use the panic handler.\n\nFrom : \"Generates the unreachable instruction, which causes an unconditional trap.\"", + "type": "object", + "required": [ + "unreachable" + ], + "properties": { + "unreachable": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Returns the env for testing", "type": "object", diff --git a/contracts/cyberpunk/src/contract.rs b/contracts/cyberpunk/src/contract.rs index 1133dc3a63..8edd2c6e1e 100644 --- a/contracts/cyberpunk/src/contract.rs +++ b/contracts/cyberpunk/src/contract.rs @@ -39,6 +39,7 @@ pub fn execute( MessageLoop {} => execute_message_loop(env), AllocateLargeMemory { pages } => execute_allocate_large_memory(pages), Panic {} => execute_panic(), + Unreachable {} => execute_unreachable(), MirrorEnv {} => execute_mirror_env(env), } } @@ -140,6 +141,14 @@ fn execute_panic() -> Result { // let _ = map["foo"]; } +fn execute_unreachable() -> Result { + #[cfg(target_arch = "wasm32")] + core::arch::wasm32::unreachable(); + + #[cfg(not(target_arch = "wasm32"))] + Err(StdError::generic_err("Unsupported architecture").into()) +} + fn execute_mirror_env(env: Env) -> Result { Ok(Response::new().set_data(to_binary(&env)?)) } diff --git a/contracts/cyberpunk/src/msg.rs b/contracts/cyberpunk/src/msg.rs index a671a11c34..33d73a51b1 100644 --- a/contracts/cyberpunk/src/msg.rs +++ b/contracts/cyberpunk/src/msg.rs @@ -21,6 +21,11 @@ pub enum ExecuteMsg { AllocateLargeMemory { pages: u32 }, /// Trigger a panic to ensure framework handles gracefully Panic {}, + /// In contrast to Panic, this does not use the panic handler. + /// + /// From : + /// "Generates the unreachable instruction, which causes an unconditional trap." + Unreachable {}, /// Returns the env for testing MirrorEnv {}, } From 7063e441936f42ae8825f47a3c236c328cc70559 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 7 Dec 2022 14:42:41 +0100 Subject: [PATCH 048/187] Cleanup cyberpunk unreachable --- contracts/cyberpunk/src/contract.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/contracts/cyberpunk/src/contract.rs b/contracts/cyberpunk/src/contract.rs index 8edd2c6e1e..f5f1b98655 100644 --- a/contracts/cyberpunk/src/contract.rs +++ b/contracts/cyberpunk/src/contract.rs @@ -8,15 +8,12 @@ use crate::msg::{ExecuteMsg, QueryMsg}; #[entry_point] pub fn instantiate( - deps: DepsMut, + _deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty, ) -> Result { - deps.api.debug("here we go 🚀"); - - // This adds some unrelated event attribute for testing purposes - Ok(Response::new().add_attribute("Let the", "hacking begin")) + Ok(Response::default()) } #[entry_point] From fbb75a6d8666ac024bf1bf240d9ebc75d48d187e Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 7 Dec 2022 14:43:25 +0100 Subject: [PATCH 049/187] Re-build cyberpunk.wasm --- packages/vm/testdata/cyberpunk.wasm | Bin 160084 -> 165993 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/vm/testdata/cyberpunk.wasm b/packages/vm/testdata/cyberpunk.wasm index 4fa2b7cbfeb193da0bb8123425df632ba3b166ed..982acad20c86b3607dd8c95d1b6a37f5b87ec6ee 100644 GIT binary patch delta 62749 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 R9|oW0!R5fUgZsiZ{|nX)waEYg delta 57182 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

PF7U|ohT%Qt&*Vc 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 From c7c5ba271123f4a9e228be0762e03ec30d2ab580 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 7 Dec 2022 14:43:33 +0100 Subject: [PATCH 050/187] Test panic and unreachable --- packages/vm/src/calls.rs | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index 63b90922ff..32c7eff3eb 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -646,6 +646,52 @@ mod tests { assert!(matches!(err, VmError::GasDepletion {})); } + #[test] + fn call_execute_handles_panic() { + let mut instance = mock_instance(CYBERPUNK, &[]); + + let info = mock_info("creator", &[]); + call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, br#"{}"#) + .unwrap() + .unwrap(); + + // execute + let info = mock_info("troll", &[]); + let msg = br#"{"panic":{}}"#; + let err = + call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap_err(); + match err { + VmError::RuntimeErr { msg } => { + assert!(msg.contains( + "RuntimeError: Aborted: panicked at 'This page intentionally faulted'" + )) + } + err => panic!("Unexpected error: {:?}", err), + } + } + + #[test] + fn call_execute_handles_unreachable() { + let mut instance = mock_instance(CYBERPUNK, &[]); + + let info = mock_info("creator", &[]); + call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, br#"{}"#) + .unwrap() + .unwrap(); + + // execute + let info = mock_info("troll", &[]); + let msg = br#"{"unreachable":{}}"#; + let err = + call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap_err(); + match err { + VmError::RuntimeErr { msg } => { + assert!(msg.contains("RuntimeError: unreachable")) + } + err => panic!("Unexpected error: {:?}", err), + } + } + #[test] fn call_migrate_works() { let mut instance = mock_instance(CONTRACT, &[]); From 364778f2ed7ffb647b6f6b27e5e929ea7584511f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 8 Dec 2022 14:58:35 +0100 Subject: [PATCH 051/187] Contracts: Move all schema.rs from examples to src/bin --- contracts/burner/.cargo/config | 6 +++--- contracts/burner/{examples => src/bin}/schema.rs | 0 contracts/crypto-verify/.cargo/config | 6 +++--- contracts/crypto-verify/{examples => src/bin}/schema.rs | 0 contracts/cyberpunk/.cargo/config | 6 +++--- contracts/cyberpunk/{examples => src/bin}/schema.rs | 0 contracts/floaty/.cargo/config | 6 +++--- contracts/floaty/{examples => src/bin}/schema.rs | 0 contracts/hackatom/.cargo/config | 6 +++--- contracts/hackatom/{examples => src/bin}/schema.rs | 0 contracts/ibc-reflect-send/.cargo/config | 6 +++--- contracts/ibc-reflect-send/{examples => src/bin}/schema.rs | 0 contracts/ibc-reflect/.cargo/config | 6 +++--- contracts/ibc-reflect/{examples => src/bin}/schema.rs | 0 contracts/queue/.cargo/config | 6 +++--- contracts/queue/{examples => src/bin}/schema.rs | 0 contracts/reflect/.cargo/config | 6 +++--- contracts/reflect/{examples => src/bin}/schema.rs | 0 contracts/staking/.cargo/config | 6 +++--- contracts/staking/{examples => src/bin}/schema.rs | 0 20 files changed, 30 insertions(+), 30 deletions(-) rename contracts/burner/{examples => src/bin}/schema.rs (100%) rename contracts/crypto-verify/{examples => src/bin}/schema.rs (100%) rename contracts/cyberpunk/{examples => src/bin}/schema.rs (100%) rename contracts/floaty/{examples => src/bin}/schema.rs (100%) rename contracts/hackatom/{examples => src/bin}/schema.rs (100%) rename contracts/ibc-reflect-send/{examples => src/bin}/schema.rs (100%) rename contracts/ibc-reflect/{examples => src/bin}/schema.rs (100%) rename contracts/queue/{examples => src/bin}/schema.rs (100%) rename contracts/reflect/{examples => src/bin}/schema.rs (100%) rename contracts/staking/{examples => src/bin}/schema.rs (100%) diff --git a/contracts/burner/.cargo/config b/contracts/burner/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/burner/.cargo/config +++ b/contracts/burner/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/burner/examples/schema.rs b/contracts/burner/src/bin/schema.rs similarity index 100% rename from contracts/burner/examples/schema.rs rename to contracts/burner/src/bin/schema.rs diff --git a/contracts/crypto-verify/.cargo/config b/contracts/crypto-verify/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/crypto-verify/.cargo/config +++ b/contracts/crypto-verify/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/crypto-verify/examples/schema.rs b/contracts/crypto-verify/src/bin/schema.rs similarity index 100% rename from contracts/crypto-verify/examples/schema.rs rename to contracts/crypto-verify/src/bin/schema.rs diff --git a/contracts/cyberpunk/.cargo/config b/contracts/cyberpunk/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/cyberpunk/.cargo/config +++ b/contracts/cyberpunk/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/cyberpunk/examples/schema.rs b/contracts/cyberpunk/src/bin/schema.rs similarity index 100% rename from contracts/cyberpunk/examples/schema.rs rename to contracts/cyberpunk/src/bin/schema.rs diff --git a/contracts/floaty/.cargo/config b/contracts/floaty/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/floaty/.cargo/config +++ b/contracts/floaty/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/floaty/examples/schema.rs b/contracts/floaty/src/bin/schema.rs similarity index 100% rename from contracts/floaty/examples/schema.rs rename to contracts/floaty/src/bin/schema.rs diff --git a/contracts/hackatom/.cargo/config b/contracts/hackatom/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/hackatom/.cargo/config +++ b/contracts/hackatom/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/hackatom/examples/schema.rs b/contracts/hackatom/src/bin/schema.rs similarity index 100% rename from contracts/hackatom/examples/schema.rs rename to contracts/hackatom/src/bin/schema.rs diff --git a/contracts/ibc-reflect-send/.cargo/config b/contracts/ibc-reflect-send/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/ibc-reflect-send/.cargo/config +++ b/contracts/ibc-reflect-send/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/ibc-reflect-send/examples/schema.rs b/contracts/ibc-reflect-send/src/bin/schema.rs similarity index 100% rename from contracts/ibc-reflect-send/examples/schema.rs rename to contracts/ibc-reflect-send/src/bin/schema.rs diff --git a/contracts/ibc-reflect/.cargo/config b/contracts/ibc-reflect/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/ibc-reflect/.cargo/config +++ b/contracts/ibc-reflect/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/ibc-reflect/examples/schema.rs b/contracts/ibc-reflect/src/bin/schema.rs similarity index 100% rename from contracts/ibc-reflect/examples/schema.rs rename to contracts/ibc-reflect/src/bin/schema.rs diff --git a/contracts/queue/.cargo/config b/contracts/queue/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/queue/.cargo/config +++ b/contracts/queue/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/queue/examples/schema.rs b/contracts/queue/src/bin/schema.rs similarity index 100% rename from contracts/queue/examples/schema.rs rename to contracts/queue/src/bin/schema.rs diff --git a/contracts/reflect/.cargo/config b/contracts/reflect/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/reflect/.cargo/config +++ b/contracts/reflect/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/reflect/examples/schema.rs b/contracts/reflect/src/bin/schema.rs similarity index 100% rename from contracts/reflect/examples/schema.rs rename to contracts/reflect/src/bin/schema.rs diff --git a/contracts/staking/.cargo/config b/contracts/staking/.cargo/config index 8d4bc738b1..f5174787c2 100644 --- a/contracts/staking/.cargo/config +++ b/contracts/staking/.cargo/config @@ -1,6 +1,6 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" integration-test = "test --test integration" -schema = "run --example schema" +schema = "run --bin schema" diff --git a/contracts/staking/examples/schema.rs b/contracts/staking/src/bin/schema.rs similarity index 100% rename from contracts/staking/examples/schema.rs rename to contracts/staking/src/bin/schema.rs From c5ee42a1a66223dfbd842ce25a20560446c2829b Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 8 Dec 2022 15:11:00 +0100 Subject: [PATCH 052/187] Remove poorly maintaned schema generator from cosmwasm-std --- .circleci/config.yml | 13 -- packages/std/.cargo/config | 5 +- packages/std/examples/schema.rs | 17 -- packages/std/schema/block_info.json | 43 ---- packages/std/schema/cosmos_msg.json | 303 ------------------------- packages/std/schema/query_request.json | 208 ----------------- packages/std/schema/timestamp.json | 16 -- 7 files changed, 2 insertions(+), 603 deletions(-) delete mode 100644 packages/std/examples/schema.rs delete mode 100644 packages/std/schema/block_info.json delete mode 100644 packages/std/schema/cosmos_msg.json delete mode 100644 packages/std/schema/query_request.json delete mode 100644 packages/std/schema/timestamp.json diff --git a/.circleci/config.yml b/.circleci/config.yml index 851bcd8a04..3e54ea7ac7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -329,19 +329,6 @@ jobs: name: Run unit tests (all features) working_directory: ~/project/packages/std command: cargo test --locked --features abort,iterator,staking,stargate,cosmwasm_1_1 - - run: - name: Build and run schema generator - working_directory: ~/project/packages/std - command: cargo schema --features cosmwasm_1_1 --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi - save_cache: paths: - /usr/local/cargo/registry diff --git a/packages/std/.cargo/config b/packages/std/.cargo/config index 7d1a066c82..b93207d67e 100644 --- a/packages/std/.cargo/config +++ b/packages/std/.cargo/config @@ -1,5 +1,4 @@ [alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" unit-test = "test --lib" -schema = "run --example schema" diff --git a/packages/std/examples/schema.rs b/packages/std/examples/schema.rs deleted file mode 100644 index 0fe2eac963..0000000000 --- a/packages/std/examples/schema.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::env::current_dir; -use std::fs::create_dir_all; - -use cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, schema_for}; -use cosmwasm_std::{BlockInfo, CosmosMsg, Empty, QueryRequest, Timestamp}; - -fn main() { - let mut out_dir = current_dir().unwrap(); - out_dir.push("schema"); - create_dir_all(&out_dir).unwrap(); - remove_schemas(&out_dir).unwrap(); - - export_schema(&schema_for!(BlockInfo), &out_dir); - export_schema(&schema_for!(Timestamp), &out_dir); - export_schema_with_title(&schema_for!(CosmosMsg), &out_dir, "CosmosMsg"); - export_schema_with_title(&schema_for!(QueryRequest), &out_dir, "QueryRequest"); -} diff --git a/packages/std/schema/block_info.json b/packages/std/schema/block_info.json deleted file mode 100644 index 2ddc87f0d3..0000000000 --- a/packages/std/schema/block_info.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "BlockInfo", - "type": "object", - "required": [ - "chain_id", - "height", - "time" - ], - "properties": { - "chain_id": { - "type": "string" - }, - "height": { - "description": "The height of a block is the number of blocks preceding it in the blockchain.", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "time": { - "description": "Absolute time of the block creation in seconds since the UNIX epoch (00:00:00 on 1970-01-01 UTC).\n\nThe source of this is the [BFT Time in Tendermint](https://github.com/tendermint/tendermint/blob/58dc1726/spec/consensus/bft-time.md), which has the same nanosecond precision as the `Timestamp` type.\n\n# Examples\n\nUsing chrono:\n\n``` # use cosmwasm_std::{Addr, BlockInfo, ContractInfo, Env, MessageInfo, Timestamp, TransactionInfo}; # let env = Env { # block: BlockInfo { # height: 12_345, # time: Timestamp::from_nanos(1_571_797_419_879_305_533), # chain_id: \"cosmos-testnet-14002\".to_string(), # }, # transaction: Some(TransactionInfo { index: 3 }), # contract: ContractInfo { # address: Addr::unchecked(\"contract\"), # }, # }; # extern crate chrono; use chrono::NaiveDateTime; let seconds = env.block.time.seconds(); let nsecs = env.block.time.subsec_nanos(); let dt = NaiveDateTime::from_timestamp(seconds as i64, nsecs as u32); ```\n\nCreating a simple millisecond-precision timestamp (as used in JavaScript):\n\n``` # use cosmwasm_std::{Addr, BlockInfo, ContractInfo, Env, MessageInfo, Timestamp, TransactionInfo}; # let env = Env { # block: BlockInfo { # height: 12_345, # time: Timestamp::from_nanos(1_571_797_419_879_305_533), # chain_id: \"cosmos-testnet-14002\".to_string(), # }, # transaction: Some(TransactionInfo { index: 3 }), # contract: ContractInfo { # address: Addr::unchecked(\"contract\"), # }, # }; let millis = env.block.time.nanos() / 1_000_000; ```", - "allOf": [ - { - "$ref": "#/definitions/Timestamp" - } - ] - } - }, - "definitions": { - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/packages/std/schema/cosmos_msg.json b/packages/std/schema/cosmos_msg.json deleted file mode 100644 index 8361702ac2..0000000000 --- a/packages/std/schema/cosmos_msg.json +++ /dev/null @@ -1,303 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "CosmosMsg", - "oneOf": [ - { - "type": "object", - "required": [ - "bank" - ], - "properties": { - "bank": { - "$ref": "#/definitions/BankMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "custom" - ], - "properties": { - "custom": { - "$ref": "#/definitions/Empty" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "wasm" - ], - "properties": { - "wasm": { - "$ref": "#/definitions/WasmMsg" - } - }, - "additionalProperties": false - } - ], - "definitions": { - "BankMsg": { - "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", - "oneOf": [ - { - "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "send" - ], - "properties": { - "send": { - "type": "object", - "required": [ - "amount", - "to_address" - ], - "properties": { - "amount": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "to_address": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", - "type": "object", - "required": [ - "burn" - ], - "properties": { - "burn": { - "type": "object", - "required": [ - "amount" - ], - "properties": { - "amount": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - } - } - } - }, - "additionalProperties": false - } - ] - }, - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", - "type": "string" - }, - "Coin": { - "type": "object", - "required": [ - "amount", - "denom" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "denom": { - "type": "string" - } - } - }, - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - }, - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - }, - "WasmMsg": { - "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", - "oneOf": [ - { - "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "execute" - ], - "properties": { - "execute": { - "type": "object", - "required": [ - "contract_addr", - "funds", - "msg" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "funds": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "msg": { - "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "instantiate" - ], - "properties": { - "instantiate": { - "type": "object", - "required": [ - "code_id", - "funds", - "label", - "msg" - ], - "properties": { - "admin": { - "type": [ - "string", - "null" - ] - }, - "code_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "funds": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "label": { - "description": "A human-readbale label for the contract", - "type": "string" - }, - "msg": { - "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "migrate" - ], - "properties": { - "migrate": { - "type": "object", - "required": [ - "contract_addr", - "msg", - "new_code_id" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "msg": { - "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - }, - "new_code_id": { - "description": "the code_id of the new logic to place in the given contract", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", - "type": "object", - "required": [ - "update_admin" - ], - "properties": { - "update_admin": { - "type": "object", - "required": [ - "admin", - "contract_addr" - ], - "properties": { - "admin": { - "type": "string" - }, - "contract_addr": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", - "type": "object", - "required": [ - "clear_admin" - ], - "properties": { - "clear_admin": { - "type": "object", - "required": [ - "contract_addr" - ], - "properties": { - "contract_addr": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - } - } -} diff --git a/packages/std/schema/query_request.json b/packages/std/schema/query_request.json deleted file mode 100644 index 5653739422..0000000000 --- a/packages/std/schema/query_request.json +++ /dev/null @@ -1,208 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "QueryRequest", - "oneOf": [ - { - "type": "object", - "required": [ - "bank" - ], - "properties": { - "bank": { - "$ref": "#/definitions/BankQuery" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "custom" - ], - "properties": { - "custom": { - "$ref": "#/definitions/Empty" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "wasm" - ], - "properties": { - "wasm": { - "$ref": "#/definitions/WasmQuery" - } - }, - "additionalProperties": false - } - ], - "definitions": { - "BankQuery": { - "oneOf": [ - { - "description": "This calls into the native bank module for querying the total supply of one denomination. It does the same as the SupplyOf call in Cosmos SDK's RPC API. Return value is of type SupplyResponse.", - "type": "object", - "required": [ - "supply" - ], - "properties": { - "supply": { - "type": "object", - "required": [ - "denom" - ], - "properties": { - "denom": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This calls into the native bank module for one denomination Return value is BalanceResponse", - "type": "object", - "required": [ - "balance" - ], - "properties": { - "balance": { - "type": "object", - "required": [ - "address", - "denom" - ], - "properties": { - "address": { - "type": "string" - }, - "denom": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This calls into the native bank module for all denominations. Note that this may be much more expensive than Balance and should be avoided if possible. Return value is AllBalanceResponse.", - "type": "object", - "required": [ - "all_balances" - ], - "properties": { - "all_balances": { - "type": "object", - "required": [ - "address" - ], - "properties": { - "address": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", - "type": "string" - }, - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - }, - "WasmQuery": { - "oneOf": [ - { - "description": "this queries the public API of another contract at a known address (with known ABI) Return value is whatever the contract returns (caller should know), wrapped in a ContractResult that is JSON encoded.", - "type": "object", - "required": [ - "smart" - ], - "properties": { - "smart": { - "type": "object", - "required": [ - "contract_addr", - "msg" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "msg": { - "description": "msg is the json-encoded QueryMsg struct", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "this queries the raw kv-store of the contract. returns the raw, unparsed data stored at that key, which may be an empty vector if not present", - "type": "object", - "required": [ - "raw" - ], - "properties": { - "raw": { - "type": "object", - "required": [ - "contract_addr", - "key" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "key": { - "description": "Key is the raw key used in the contracts Storage", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "returns a ContractInfoResponse with metadata on the contract from the runtime", - "type": "object", - "required": [ - "contract_info" - ], - "properties": { - "contract_info": { - "type": "object", - "required": [ - "contract_addr" - ], - "properties": { - "contract_addr": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - } - } -} diff --git a/packages/std/schema/timestamp.json b/packages/std/schema/timestamp.json deleted file mode 100644 index 6dd9971a14..0000000000 --- a/packages/std/schema/timestamp.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Timestamp", - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ], - "definitions": { - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} From e2cb4be7cc73629e3bf74de86e176b01df6eb528 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 11:59:58 +0100 Subject: [PATCH 053/187] Move riffle_shuffle insto its own file --- packages/std/src/testing/mock.rs | 96 +--------------------------- packages/std/src/testing/mod.rs | 4 +- packages/std/src/testing/shuffle.rs | 98 +++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 95 deletions(-) create mode 100644 packages/std/src/testing/shuffle.rs diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 8639d8c7b9..a8c4d2141b 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -34,6 +34,8 @@ use crate::traits::{Api, Querier, QuerierResult}; use crate::types::{BlockInfo, ContractInfo, Env, MessageInfo, TransactionInfo}; use crate::Attribute; +use super::riffle_shuffle; + pub const MOCK_CONTRACT_ADDR: &str = "cosmos2contract"; /// Creates all external requirements that can be injected for unit tests. @@ -728,68 +730,6 @@ impl StakingQuerier { } } -/// Performs a perfect shuffle (in shuffle) -/// -/// https://en.wikipedia.org/wiki/Riffle_shuffle_permutation#Perfect_shuffles -/// https://en.wikipedia.org/wiki/In_shuffle -/// -/// The number of shuffles required to restore the original order are listed in -/// https://oeis.org/A002326, e.g.: -/// -/// ```ignore -/// 2: 2 -/// 4: 4 -/// 6: 3 -/// 8: 6 -/// 10: 10 -/// 12: 12 -/// 14: 4 -/// 16: 8 -/// 18: 18 -/// 20: 6 -/// 22: 11 -/// 24: 20 -/// 26: 18 -/// 28: 28 -/// 30: 5 -/// 32: 10 -/// 34: 12 -/// 36: 36 -/// 38: 12 -/// 40: 20 -/// 42: 14 -/// 44: 12 -/// 46: 23 -/// 48: 21 -/// 50: 8 -/// 52: 52 -/// 54: 20 -/// 56: 18 -/// 58: 58 -/// 60: 60 -/// 62: 6 -/// 64: 12 -/// 66: 66 -/// 68: 22 -/// 70: 35 -/// 72: 9 -/// 74: 20 -/// ``` -pub fn riffle_shuffle(input: &[T]) -> Vec { - assert!( - input.len() % 2 == 0, - "Method only defined for even number of elements" - ); - let mid = input.len() / 2; - let (left, right) = input.split_at(mid); - let mut out = Vec::::with_capacity(input.len()); - for i in 0..mid { - out.push(right[i].clone()); - out.push(left[i].clone()); - } - out -} - pub fn digit_sum(input: &[u8]) -> usize { input.iter().fold(0, |sum, val| sum + (*val as usize)) } @@ -1569,38 +1509,6 @@ mod tests { } } - #[test] - fn riffle_shuffle_works() { - // Example from https://en.wikipedia.org/wiki/In_shuffle - let start = [0xA, 0x2, 0x3, 0x4, 0x5, 0x6]; - let round1 = riffle_shuffle(&start); - assert_eq!(round1, [0x4, 0xA, 0x5, 0x2, 0x6, 0x3]); - let round2 = riffle_shuffle(&round1); - assert_eq!(round2, [0x2, 0x4, 0x6, 0xA, 0x3, 0x5]); - let round3 = riffle_shuffle(&round2); - assert_eq!(round3, start); - - // For 14 elements, the original order is restored after 4 executions - // See https://en.wikipedia.org/wiki/In_shuffle#Mathematics and https://oeis.org/A002326 - let original = [12, 33, 76, 576, 0, 44, 1, 14, 78, 99, 871212, -7, 2, -1]; - let mut result = Vec::from(original); - for _ in 0..4 { - result = riffle_shuffle(&result); - } - assert_eq!(result, original); - - // For 24 elements, the original order is restored after 20 executions - let original = [ - 7, 4, 2, 4656, 23, 45, 23, 1, 12, 76, 576, 0, 12, 1, 14, 78, 99, 12, 1212, 444, 31, - 111, 424, 34, - ]; - let mut result = Vec::from(original); - for _ in 0..20 { - result = riffle_shuffle(&result); - } - assert_eq!(result, original); - } - #[test] fn digit_sum_works() { assert_eq!(digit_sum(&[]), 0); diff --git a/packages/std/src/testing/mod.rs b/packages/std/src/testing/mod.rs index b317d61c48..657aada5de 100644 --- a/packages/std/src/testing/mod.rs +++ b/packages/std/src/testing/mod.rs @@ -5,6 +5,7 @@ mod assertions; mod mock; +mod shuffle; pub use assertions::assert_approx_eq_impl; @@ -12,7 +13,7 @@ pub use assertions::assert_approx_eq_impl; pub use mock::StakingQuerier; pub use mock::{ digit_sum, mock_dependencies, mock_dependencies_with_balance, mock_dependencies_with_balances, - mock_env, mock_info, mock_wasmd_attr, riffle_shuffle, BankQuerier, MockApi, MockQuerier, + mock_env, mock_info, mock_wasmd_attr, BankQuerier, MockApi, MockQuerier, MockQuerierCustomHandlerResult, MockStorage, MOCK_CONTRACT_ADDR, }; #[cfg(feature = "stargate")] @@ -21,3 +22,4 @@ pub use mock::{ mock_ibc_channel_connect_ack, mock_ibc_channel_connect_confirm, mock_ibc_channel_open_init, mock_ibc_channel_open_try, mock_ibc_packet_ack, mock_ibc_packet_recv, mock_ibc_packet_timeout, }; +pub use shuffle::riffle_shuffle; diff --git a/packages/std/src/testing/shuffle.rs b/packages/std/src/testing/shuffle.rs new file mode 100644 index 0000000000..2ad949cb73 --- /dev/null +++ b/packages/std/src/testing/shuffle.rs @@ -0,0 +1,98 @@ +/// Performs a perfect shuffle (in shuffle) +/// +/// https://en.wikipedia.org/wiki/Riffle_shuffle_permutation#Perfect_shuffles +/// https://en.wikipedia.org/wiki/In_shuffle +/// +/// The number of shuffles required to restore the original order are listed in +/// https://oeis.org/A002326, e.g.: +/// +/// ```ignore +/// 2: 2 +/// 4: 4 +/// 6: 3 +/// 8: 6 +/// 10: 10 +/// 12: 12 +/// 14: 4 +/// 16: 8 +/// 18: 18 +/// 20: 6 +/// 22: 11 +/// 24: 20 +/// 26: 18 +/// 28: 28 +/// 30: 5 +/// 32: 10 +/// 34: 12 +/// 36: 36 +/// 38: 12 +/// 40: 20 +/// 42: 14 +/// 44: 12 +/// 46: 23 +/// 48: 21 +/// 50: 8 +/// 52: 52 +/// 54: 20 +/// 56: 18 +/// 58: 58 +/// 60: 60 +/// 62: 6 +/// 64: 12 +/// 66: 66 +/// 68: 22 +/// 70: 35 +/// 72: 9 +/// 74: 20 +/// ``` +pub fn riffle_shuffle(input: &[T]) -> Vec { + assert!( + input.len() % 2 == 0, + "Method only defined for even number of elements" + ); + let mid = input.len() / 2; + let (left, right) = input.split_at(mid); + let mut out = Vec::::with_capacity(input.len()); + for i in 0..mid { + out.push(right[i].clone()); + out.push(left[i].clone()); + } + out +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn riffle_shuffle_works() { + // Example from https://en.wikipedia.org/wiki/In_shuffle + let start = [0xA, 0x2, 0x3, 0x4, 0x5, 0x6]; + let round1 = riffle_shuffle(&start); + assert_eq!(round1, [0x4, 0xA, 0x5, 0x2, 0x6, 0x3]); + let round2 = riffle_shuffle(&round1); + assert_eq!(round2, [0x2, 0x4, 0x6, 0xA, 0x3, 0x5]); + let round3 = riffle_shuffle(&round2); + assert_eq!(round3, start); + + // For 14 elements, the original order is restored after 4 executions + // See https://en.wikipedia.org/wiki/In_shuffle#Mathematics and https://oeis.org/A002326 + let original = [12, 33, 76, 576, 0, 44, 1, 14, 78, 99, 871212, -7, 2, -1]; + let mut result = Vec::from(original); + for _ in 0..4 { + result = riffle_shuffle(&result); + } + assert_eq!(result, original); + + // For 24 elements, the original order is restored after 20 executions + let original = [ + 7, 4, 2, 4656, 23, 45, 23, 1, 12, 76, 576, 0, 12, 1, 14, 78, 99, 12, 1212, 444, 31, + 111, 424, 34, + ]; + let mut result = Vec::from(original); + for _ in 0..20 { + result = riffle_shuffle(&result); + } + assert_eq!(result, original); + } +} From 736aef5e6fb33b4b930f2db45405225b80ee65d2 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 12:00:15 +0100 Subject: [PATCH 054/187] Improve docs and testing --- packages/std/src/testing/mock.rs | 33 ++++++++++++------- packages/std/src/testing/shuffle.rs | 49 ++++++----------------------- packages/vm/src/testing/mock.rs | 8 +++-- 3 files changed, 37 insertions(+), 53 deletions(-) diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index a8c4d2141b..ffa4cf5a54 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -77,10 +77,15 @@ pub fn mock_dependencies_with_balances( // We can later make simplifications here if needed pub type MockStorage = MemoryStorage; -/// Length of canonical addresses created with this API. Contracts should not make any assumtions +/// Length of canonical addresses created with this API. Contracts should not make any assumptions /// what this value is. +/// +/// The mock API can only canonicalize and humanize addresses up to this length. So it must be +/// long enough to store common bech32 addresses. +/// /// The value here must be restorable with `SHUFFLES_ENCODE` + `SHUFFLES_DECODE` in-shuffles. -const CANONICAL_LENGTH: usize = 54; +/// See for a table of those values. +const CANONICAL_LENGTH: usize = 54; // n = 27 const SHUFFLES_ENCODE: usize = 18; const SHUFFLES_DECODE: usize = 2; @@ -90,7 +95,7 @@ const SHUFFLES_DECODE: usize = 2; // not really smart, but allows us to see a difference (and consistent length for canonical adddresses) #[derive(Copy, Clone)] pub struct MockApi { - /// Length of canonical addresses created with this API. Contracts should not make any assumtions + /// Length of canonical addresses created with this API. Contracts should not make any assumptions /// what this value is. canonical_length: usize, } @@ -118,14 +123,16 @@ impl Api for MockApi { fn addr_canonicalize(&self, input: &str) -> StdResult { // Dummy input validation. This is more sophisticated for formats like bech32, where format and checksum are validated. - if input.len() < 3 { + let min_length = 3; + let max_length = self.canonical_length; + if input.len() < min_length { return Err(StdError::generic_err( - "Invalid input: human address too short", + format!("Invalid input: human address too short for this mock implementation (must be >= {min_length})."), )); } - if input.len() > self.canonical_length { + if input.len() > max_length { return Err(StdError::generic_err( - "Invalid input: human address too long", + format!("Invalid input: human address too long for this mock implementation (must be <= {max_length})."), )); } @@ -822,20 +829,24 @@ mod tests { } #[test] - #[should_panic(expected = "address too short")] fn addr_canonicalize_min_input_length() { let api = MockApi::default(); let human = String::from("1"); - let _ = api.addr_canonicalize(&human).unwrap(); + let err = api.addr_canonicalize(&human).unwrap_err(); + assert!(err + .to_string() + .contains("human address too short for this mock implementation (must be >= 3)")); } #[test] - #[should_panic(expected = "address too long")] fn addr_canonicalize_max_input_length() { let api = MockApi::default(); let human = String::from("some-extremely-long-address-not-supported-by-this-api-longer-than-54"); - let _ = api.addr_canonicalize(&human).unwrap(); + let err = api.addr_canonicalize(&human).unwrap_err(); + assert!(err + .to_string() + .contains("human address too long for this mock implementation (must be <= 54)")); } #[test] diff --git a/packages/std/src/testing/shuffle.rs b/packages/std/src/testing/shuffle.rs index 2ad949cb73..aa04c17ff2 100644 --- a/packages/std/src/testing/shuffle.rs +++ b/packages/std/src/testing/shuffle.rs @@ -4,46 +4,17 @@ /// https://en.wikipedia.org/wiki/In_shuffle /// /// The number of shuffles required to restore the original order are listed in -/// https://oeis.org/A002326, e.g.: +/// and , e.g.: /// -/// ```ignore -/// 2: 2 -/// 4: 4 -/// 6: 3 -/// 8: 6 -/// 10: 10 -/// 12: 12 -/// 14: 4 -/// 16: 8 -/// 18: 18 -/// 20: 6 -/// 22: 11 -/// 24: 20 -/// 26: 18 -/// 28: 28 -/// 30: 5 -/// 32: 10 -/// 34: 12 -/// 36: 36 -/// 38: 12 -/// 40: 20 -/// 42: 14 -/// 44: 12 -/// 46: 23 -/// 48: 21 -/// 50: 8 -/// 52: 52 -/// 54: 20 -/// 56: 18 -/// 58: 58 -/// 60: 60 -/// 62: 6 -/// 64: 12 -/// 66: 66 -/// 68: 22 -/// 70: 35 -/// 72: 9 -/// 74: 20 +/// ```text +/// 2 (n=1): 2 +/// 4 (n=2): 4 +/// 6 (n=3): 3 +/// 8 (n=4): 6 +/// 10 (n=5): 10 +/// 12 (n=6): 12 +/// 14 (n=7): 4 +/// 16 (n=8): 8 /// ``` pub fn riffle_shuffle(input: &[T]) -> Vec { assert!( diff --git a/packages/vm/src/testing/mock.rs b/packages/vm/src/testing/mock.rs index 131a7c43a7..53c2a42093 100644 --- a/packages/vm/src/testing/mock.rs +++ b/packages/vm/src/testing/mock.rs @@ -33,10 +33,12 @@ pub fn mock_backend_with_balances( } } -/// Length of canonical addresses created with this API. Contracts should not make any assumtions +/// Length of canonical addresses created with this API. Contracts should not make any assumptions /// what this value is. +/// /// The value here must be restorable with `SHUFFLES_ENCODE` + `SHUFFLES_DECODE` in-shuffles. -const CANONICAL_LENGTH: usize = 54; +/// See for a table of those values. +const CANONICAL_LENGTH: usize = 54; // n = 27 const SHUFFLES_ENCODE: usize = 18; const SHUFFLES_DECODE: usize = 2; @@ -46,7 +48,7 @@ const SHUFFLES_DECODE: usize = 2; /// This is not really smart, but allows us to see a difference (and consistent length for canonical adddresses). #[derive(Copy, Clone)] pub struct MockApi { - /// Length of canonical addresses created with this API. Contracts should not make any assumtions + /// Length of canonical addresses created with this API. Contracts should not make any assumptions /// what this value is. canonical_length: usize, /// When set, all calls to the API fail with BackendError::Unknown containing this message From b7cd07277ade64e073b88d680c30c848da611fa4 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 13:02:36 +0100 Subject: [PATCH 055/187] Increate CANONICAL_LENGTH from 54 to 90 in MockApi --- packages/std/src/testing/mock.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index ffa4cf5a54..1417b93d1f 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -85,9 +85,9 @@ pub type MockStorage = MemoryStorage; /// /// The value here must be restorable with `SHUFFLES_ENCODE` + `SHUFFLES_DECODE` in-shuffles. /// See for a table of those values. -const CANONICAL_LENGTH: usize = 54; // n = 27 +const CANONICAL_LENGTH: usize = 90; // n = 45 -const SHUFFLES_ENCODE: usize = 18; +const SHUFFLES_ENCODE: usize = 10; const SHUFFLES_DECODE: usize = 2; // MockPrecompiles zero pads all human addresses to make them fit the canonical_length @@ -826,6 +826,13 @@ mod tests { let canonical = api.addr_canonicalize(&original).unwrap(); let recovered = api.addr_humanize(&canonical).unwrap(); assert_eq!(recovered, "cosmwasmchef"); + + // Long input (Juno contract address) + let original = + String::from("juno1v82su97skv6ucfqvuvswe0t5fph7pfsrtraxf0x33d8ylj5qnrysdvkc95"); + let canonical = api.addr_canonicalize(&original).unwrap(); + let recovered = api.addr_humanize(&canonical).unwrap(); + assert_eq!(recovered, original); } #[test] @@ -842,11 +849,11 @@ mod tests { fn addr_canonicalize_max_input_length() { let api = MockApi::default(); let human = - String::from("some-extremely-long-address-not-supported-by-this-api-longer-than-54"); + String::from("some-extremely-long-address-not-supported-by-this-api-longer-than-supported------------------------"); let err = api.addr_canonicalize(&human).unwrap_err(); assert!(err .to_string() - .contains("human address too long for this mock implementation (must be <= 54)")); + .contains("human address too long for this mock implementation (must be <= 90)")); } #[test] From 4792a97d92e05ea91453e361375aaa113d635413 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 13:06:07 +0100 Subject: [PATCH 056/187] Improve error messages for BackendApi length restrictions --- packages/vm/src/testing/mock.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/vm/src/testing/mock.rs b/packages/vm/src/testing/mock.rs index 53c2a42093..554ecf77f2 100644 --- a/packages/vm/src/testing/mock.rs +++ b/packages/vm/src/testing/mock.rs @@ -90,18 +90,20 @@ impl BackendApi for MockApi { } // Dummy input validation. This is more sophisticated for formats like bech32, where format and checksum are validated. - if normalized.len() < 3 { + let min_length = 3; + let max_length = self.canonical_length; + if normalized.len() < min_length { return ( Err(BackendError::user_err( - "Invalid input: human address too short", + format!("Invalid input: human address too short for this mock implementation (must be >= {min_length})."), )), gas_info, ); } - if normalized.len() > self.canonical_length { + if normalized.len() > max_length { return ( Err(BackendError::user_err( - "Invalid input: human address too long", + format!("Invalid input: human address too long for this mock implementation (must be <= {max_length})."), )), gas_info, ); @@ -249,7 +251,7 @@ mod tests { let api = MockApi::default(); let human = "1"; match api.canonical_address(human).0.unwrap_err() { - BackendError::UserErr { .. } => {} + BackendError::UserErr { msg } => assert!(msg.contains("too short")), err => panic!("Unexpected error: {:?}", err), } } @@ -259,7 +261,7 @@ mod tests { let api = MockApi::default(); let human = "longer-than-the-address-length-supported-by-this-api-longer-than-54"; match api.canonical_address(human).0.unwrap_err() { - BackendError::UserErr { .. } => {} + BackendError::UserErr { msg } => assert!(msg.contains("too long")), err => panic!("Unexpected error: {:?}", err), } } From a20595157290a864be57db8a74223a51d58a91de Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 13:19:09 +0100 Subject: [PATCH 057/187] Increase CANONICAL_LENGTH from 54 to 64 on backend MockApi --- packages/vm/src/imports.rs | 10 ++++++++-- packages/vm/src/testing/mock.rs | 11 +++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/vm/src/imports.rs b/packages/vm/src/imports.rs index d99e6b7ecc..357fbe024f 100644 --- a/packages/vm/src/imports.rs +++ b/packages/vm/src/imports.rs @@ -887,7 +887,10 @@ mod tests { let res = do_addr_validate(&env, source_ptr3).unwrap(); assert_ne!(res, 0); let err = String::from_utf8(force_read(&env, res)).unwrap(); - assert_eq!(err, "Invalid input: human address too long"); + assert_eq!( + err, + "Invalid input: human address too long for this mock implementation (must be <= 64)." + ); let res = do_addr_validate(&env, source_ptr4).unwrap(); assert_ne!(res, 0); @@ -982,7 +985,10 @@ mod tests { let res = do_addr_canonicalize(&env, source_ptr3, dest_ptr).unwrap(); assert_ne!(res, 0); let err = String::from_utf8(force_read(&env, res)).unwrap(); - assert_eq!(err, "Invalid input: human address too long"); + assert_eq!( + err, + "Invalid input: human address too long for this mock implementation (must be <= 64)." + ); } #[test] diff --git a/packages/vm/src/testing/mock.rs b/packages/vm/src/testing/mock.rs index 554ecf77f2..64bacb40cf 100644 --- a/packages/vm/src/testing/mock.rs +++ b/packages/vm/src/testing/mock.rs @@ -38,9 +38,9 @@ pub fn mock_backend_with_balances( /// /// The value here must be restorable with `SHUFFLES_ENCODE` + `SHUFFLES_DECODE` in-shuffles. /// See for a table of those values. -const CANONICAL_LENGTH: usize = 54; // n = 27 +const CANONICAL_LENGTH: usize = 64; // n = 32 -const SHUFFLES_ENCODE: usize = 18; +const SHUFFLES_ENCODE: usize = 10; const SHUFFLES_DECODE: usize = 2; /// Zero-pads all human addresses to make them fit the canonical_length and @@ -233,6 +233,13 @@ mod tests { let canonical = api.canonical_address(&original).0.unwrap(); let recovered = api.human_address(&canonical).0.unwrap(); assert_eq!(recovered, "cosmwasmchef"); + + // Long input (Juno contract address) + let original = + String::from("juno1v82su97skv6ucfqvuvswe0t5fph7pfsrtraxf0x33d8ylj5qnrysdvkc95"); + let canonical = api.canonical_address(&original).0.unwrap(); + let recovered = api.human_address(&canonical).0.unwrap(); + assert_eq!(recovered, original); } #[test] From a11e471bea3d08b0403b177c208d362a76735574 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 13:22:10 +0100 Subject: [PATCH 058/187] Add CHANGELOG entry: Increase length limit for address conversion --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2b253cc22..e6451e14d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,8 +43,11 @@ and this project adheres to QueryResponses macro ([#1516]). - cosmwasm-schema: A nested QueryMsg no longer causes runtime errors if it contains doc comments. +- cosmwasm-std/cosmwasm-vm: Increase length limit for address conversion in + `MockApi` to support addresses longer than 54 bytes ([#1529]). [#1516]: https://github.com/CosmWasm/cosmwasm/issues/1516 +[#1529]: https://github.com/CosmWasm/cosmwasm/issues/1529 ## [1.1.9] - 2022-12-06 From 87f396619aebcf0a9f858505346b5788400c9448 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 13:34:15 +0100 Subject: [PATCH 059/187] Hackatom: Change error case to too long and increase value to > 90 bytes --- contracts/hackatom/src/contract.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/hackatom/src/contract.rs b/contracts/hackatom/src/contract.rs index 8365b78b55..26ffed649a 100644 --- a/contracts/hackatom/src/contract.rs +++ b/contracts/hackatom/src/contract.rs @@ -196,9 +196,9 @@ fn do_user_errors_in_api_calls(api: &dyn Api) -> Result { } } - let invalid_bech32 = - "bn9hhssomeltvhzgvuqkwjkpwxojfuigltwedayzxljucefikuieillowaticksoistqoynmgcnj219a"; - match api.addr_canonicalize(invalid_bech32).unwrap_err() { + let too_long = + "bn9hhssomeltvhzgvuqkwjkpwxojfuigltwedayzxljucefikuieillowaticksoistqoynmgcnj219aewfwefwwegwg"; + match api.addr_canonicalize(too_long).unwrap_err() { StdError::GenericErr { .. } => {} err => { return Err(StdError::generic_err(format!( From c97f6636e2e8ef1678426afd04935b33accf2332 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 13:49:49 +0100 Subject: [PATCH 060/187] Sort contracts alphabetically --- .circleci/config.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3e54ea7ac7..b969e0c321 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1142,6 +1142,13 @@ jobs: mkdir -p target/wasm32-unknown-unknown/release touch target/wasm32-unknown-unknown/release/cyberpunk.wasm cargo clippy --all-targets -- -D warnings + - run: + name: Clippy linting on floaty + working_directory: ~/project/contracts/floaty + command: | + mkdir -p target/wasm32-unknown-unknown/release + touch target/wasm32-unknown-unknown/release/floaty.wasm + cargo clippy --all-targets -- -D warnings - run: name: Clippy linting on hackatom working_directory: ~/project/contracts/hackatom @@ -1163,13 +1170,6 @@ jobs: mkdir -p target/wasm32-unknown-unknown/release touch target/wasm32-unknown-unknown/release/ibc_reflect_send.wasm cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on floaty - working_directory: ~/project/contracts/floaty - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/floaty.wasm - cargo clippy --all-targets -- -D warnings - run: name: Clippy linting on queue working_directory: ~/project/contracts/queue From 1d7a94e15c05b23ef716c440be8a71a1d1f99c0f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 13:50:12 +0100 Subject: [PATCH 061/187] Add missing cyberpunk and floaty entries to clippy config --- .circleci/config.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b969e0c321..5172194814 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1071,7 +1071,8 @@ jobs: command: rustc --version && cargo --version - restore_cache: keys: - - cargocache-v2-clippy-rust:<< parameters.rust-version >>-{{ checksum "Cargo.lock" }}-{{ checksum "contracts/burner/Cargo.lock" }}-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect-send/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} + - v1-clippy-rust:<< parameters.rust-version >>-{{ checksum "Cargo.lock" }}-{{ checksum "contracts/burner/Cargo.lock" }}-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/cyberpunk/Cargo.lock" }}-{{ checksum "contracts/floaty/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect-send/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} + - v1-clippy-rust:<< parameters.rust-version >>- - run: name: Add clippy component command: rustup component add clippy @@ -1194,15 +1195,23 @@ jobs: - save_cache: paths: - /usr/local/cargo/registry + # Workspace - target/debug/.fingerprint - target/debug/build - target/debug/deps + # Contracts - contracts/burner/target/debug/.fingerprint - contracts/burner/target/debug/build - contracts/burner/target/debug/deps - contracts/crypto-verify/target/debug/.fingerprint - contracts/crypto-verify/target/debug/build - contracts/crypto-verify/target/debug/deps + - contracts/cyberpunk/target/debug/.fingerprint + - contracts/cyberpunk/target/debug/build + - contracts/cyberpunk/target/debug/deps + - contracts/floaty/target/debug/.fingerprint + - contracts/floaty/target/debug/build + - contracts/floaty/target/debug/deps - contracts/hackatom/target/debug/.fingerprint - contracts/hackatom/target/debug/build - contracts/hackatom/target/debug/deps @@ -1221,7 +1230,7 @@ jobs: - contracts/staking/target/debug/.fingerprint - contracts/staking/target/debug/build - contracts/staking/target/debug/deps - key: cargocache-v2-clippy-rust:<< parameters.rust-version >>-{{ checksum "Cargo.lock" }}-{{ checksum "contracts/burner/Cargo.lock" }}-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect-send/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} + key: v1-clippy-rust:<< parameters.rust-version >>-{{ checksum "Cargo.lock" }}-{{ checksum "contracts/burner/Cargo.lock" }}-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/cyberpunk/Cargo.lock" }}-{{ checksum "contracts/floaty/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect-send/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} benchmarking: docker: From 0b3db002e048dec4cb992479c2f34308a5f01b21 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 16:04:23 +0100 Subject: [PATCH 062/187] Fix check_workspace.sh [skip ci] --- devtools/check_workspace.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/devtools/check_workspace.sh b/devtools/check_workspace.sh index 9609054c4c..d24813c5ed 100755 --- a/devtools/check_workspace.sh +++ b/devtools/check_workspace.sh @@ -12,7 +12,6 @@ cargo fmt cargo wasm-debug cargo wasm-debug --features iterator,staking,stargate cargo clippy --all-targets --features iterator,staking,stargate -- -D warnings - cargo schema --features cosmwasm_1_1 ) (cd packages/storage && cargo build && cargo clippy --all-targets --features iterator -- -D warnings) (cd packages/schema && cargo build && cargo clippy --all-targets -- -D warnings) From 122d1d499fee0ea595e9cf0a9971ea93f50c3edc Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 16:32:27 +0100 Subject: [PATCH 063/187] Pull out check_contract CI command and check contract formatting there --- .circleci/config.yml | 316 +++++++------------------------------------ 1 file changed, 48 insertions(+), 268 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5172194814..6e864281b3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -4,6 +4,44 @@ orbs: codecov: codecov/codecov@3.2.0 win: circleci/windows@5.0 +commands: + check_contract: + steps: + - run: + name: Add wasm32 target + command: rustup target add wasm32-unknown-unknown && rustup target list --installed + - run: + name: Add clippy and rustfmt components + command: rustup component add clippy rustfmt + - run: + name: Check formatting + command: cargo fmt -- --check + - run: + name: Unit tests + command: cargo unit-test --locked + - run: + name: Build wasm binary + command: cargo wasm --locked + # After wasm build to ensure target/wasm32-unknown-unknown/release/.wasm exists + - run: + name: Clippy + command: cargo clippy --all-targets -- -D warnings + - run: + name: Integration tests (singlepass backend) + command: cargo integration-test --locked --no-default-features + - run: + name: Build and run schema generator + command: cargo schema --locked + - run: + name: Ensure schemas are up-to-date + command: | + CHANGES_IN_REPO=$(git status --porcelain) + if [[ -n "$CHANGES_IN_REPO" ]]; then + echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" + git status && git --no-pager diff + exit 1 + fi + workflows: test: # Keep those job names in sync with .mergify.yml @@ -468,30 +506,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_burner-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests (singlepass backend) - command: cargo integration-test --locked --no-default-features - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -518,30 +533,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_crypto_verify-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests (singlepass backend) - command: cargo integration-test --locked --no-default-features - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -568,30 +560,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_cyberpunk-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests (singlepass backend) - command: cargo integration-test --locked --no-default-features - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -618,30 +587,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_hackatom-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests - command: cargo integration-test --locked - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -668,30 +614,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_ibc_reflect-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests (singlepass backend) - command: cargo integration-test --locked --no-default-features - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -718,30 +641,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_ibc_reflect_send-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests (singlepass backend) - command: cargo integration-test --locked --no-default-features - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -768,30 +668,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_floaty-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests (singlepass backend) - command: cargo integration-test --locked --no-default-features - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -818,30 +695,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_queue-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests (singlepass backend) - command: cargo integration-test --locked --no-default-features - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -868,30 +722,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_reflect-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests (singlepass backend) - command: cargo integration-test --locked --no-default-features - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -918,30 +749,7 @@ jobs: - restore_cache: keys: - cargocache-v2-contract_staking-rust:1.59.0-{{ checksum "Cargo.lock" }} - - run: - name: Add wasm32 target - command: rustup target add wasm32-unknown-unknown && rustup target list --installed - - run: - name: Build wasm binary - command: cargo wasm --locked - - run: - name: Unit tests - command: cargo unit-test --locked - - run: - name: Integration tests (singlepass backend) - command: cargo integration-test --locked --no-default-features - - run: - name: Build and run schema generator - command: cargo schema --locked - - run: - name: Ensure schemas are up-to-date - command: | - CHANGES_IN_REPO=$(git status --porcelain) - if [[ -n "$CHANGES_IN_REPO" ]]; then - echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" - git status && git --no-pager diff - exit 1 - fi + - check_contract - save_cache: paths: - /usr/local/cargo/registry @@ -970,34 +778,6 @@ jobs: - run: name: Check formatting of workspace command: cargo fmt -- --check - - run: - name: Check formatting of contract burner - working_directory: ~/project/contracts/burner - command: cargo fmt -- --check - - run: - name: Check formatting of contract crypto-verify - working_directory: ~/project/contracts/crypto-verify - command: cargo fmt -- --check - - run: - name: Check formatting of contract hackatom - working_directory: ~/project/contracts/hackatom - command: cargo fmt -- --check - - run: - name: Check formatting of contract floaty - working_directory: ~/project/contracts/floaty - command: cargo fmt -- --check - - run: - name: Check formatting of contract reflect - working_directory: ~/project/contracts/reflect - command: cargo fmt -- --check - - run: - name: Check formatting of contract queue - working_directory: ~/project/contracts/queue - command: cargo fmt -- --check - - run: - name: Check formatting of contract staking - working_directory: ~/project/contracts/staking - command: cargo fmt -- --check - save_cache: paths: - /usr/local/cargo/registry From 09484ec489c948bb4631d90ed168d384becaa5b0 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 16:38:11 +0100 Subject: [PATCH 064/187] Remove contracts from clippy job --- .circleci/config.yml | 110 ++----------------------------------------- 1 file changed, 3 insertions(+), 107 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6e864281b3..f9f6afc4ea 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -851,8 +851,8 @@ jobs: command: rustc --version && cargo --version - restore_cache: keys: - - v1-clippy-rust:<< parameters.rust-version >>-{{ checksum "Cargo.lock" }}-{{ checksum "contracts/burner/Cargo.lock" }}-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/cyberpunk/Cargo.lock" }}-{{ checksum "contracts/floaty/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect-send/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} - - v1-clippy-rust:<< parameters.rust-version >>- + - v2-clippy-rust:<< parameters.rust-version >>-{{ checksum "Cargo.lock" }} + - v2-clippy-rust:<< parameters.rust-version >>- - run: name: Add clippy component command: rustup component add clippy @@ -899,79 +899,6 @@ jobs: name: Clippy linting on vm (all feature flags) working_directory: ~/project/packages/vm command: cargo clippy --all-targets --features iterator,staking,stargate -- -D warnings - # - # Contracts - # - - run: - name: Clippy linting on burner - working_directory: ~/project/contracts/burner - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/burner.wasm - cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on crypto-verify - working_directory: ~/project/contracts/crypto-verify - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/crypto_verify.wasm - cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on cyberpunk - working_directory: ~/project/contracts/cyberpunk - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/cyberpunk.wasm - cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on floaty - working_directory: ~/project/contracts/floaty - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/floaty.wasm - cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on hackatom - working_directory: ~/project/contracts/hackatom - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/hackatom.wasm - cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on ibc-reflect - working_directory: ~/project/contracts/ibc-reflect - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/ibc_reflect.wasm - cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on ibc-reflect-send - working_directory: ~/project/contracts/ibc-reflect-send - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/ibc_reflect_send.wasm - cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on queue - working_directory: ~/project/contracts/queue - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/queue.wasm - cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on reflect - working_directory: ~/project/contracts/reflect - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/reflect.wasm - cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on staking - working_directory: ~/project/contracts/staking - command: | - mkdir -p target/wasm32-unknown-unknown/release - touch target/wasm32-unknown-unknown/release/staking.wasm - cargo clippy --all-targets -- -D warnings - save_cache: paths: - /usr/local/cargo/registry @@ -979,38 +906,7 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - # Contracts - - contracts/burner/target/debug/.fingerprint - - contracts/burner/target/debug/build - - contracts/burner/target/debug/deps - - contracts/crypto-verify/target/debug/.fingerprint - - contracts/crypto-verify/target/debug/build - - contracts/crypto-verify/target/debug/deps - - contracts/cyberpunk/target/debug/.fingerprint - - contracts/cyberpunk/target/debug/build - - contracts/cyberpunk/target/debug/deps - - contracts/floaty/target/debug/.fingerprint - - contracts/floaty/target/debug/build - - contracts/floaty/target/debug/deps - - contracts/hackatom/target/debug/.fingerprint - - contracts/hackatom/target/debug/build - - contracts/hackatom/target/debug/deps - - contracts/ibc-reflect/target/debug/.fingerprint - - contracts/ibc-reflect/target/debug/build - - contracts/ibc-reflect/target/debug/deps - - contracts/ibc-reflect-send/target/debug/.fingerprint - - contracts/ibc-reflect-send/target/debug/build - - contracts/ibc-reflect-send/target/debug/deps - - contracts/queue/target/debug/.fingerprint - - contracts/queue/target/debug/build - - contracts/queue/target/debug/deps - - contracts/reflect/target/debug/.fingerprint - - contracts/reflect/target/debug/build - - contracts/reflect/target/debug/deps - - contracts/staking/target/debug/.fingerprint - - contracts/staking/target/debug/build - - contracts/staking/target/debug/deps - key: v1-clippy-rust:<< parameters.rust-version >>-{{ checksum "Cargo.lock" }}-{{ checksum "contracts/burner/Cargo.lock" }}-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/cyberpunk/Cargo.lock" }}-{{ checksum "contracts/floaty/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect/Cargo.lock" }}-{{ checksum "contracts/ibc-reflect-send/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} + key: v2-clippy-rust:<< parameters.rust-version >>-{{ checksum "Cargo.lock" }} benchmarking: docker: From 49ff9fb098f8915b14ba8044b2321423daf128c5 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 16:39:43 +0100 Subject: [PATCH 065/187] Bump min Rust to 1.60.0 --- .circleci/config.yml | 138 +++++++++++++++++++-------------------- .github/workflows/ci.yml | 2 +- 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f9f6afc4ea..01000ce3ac 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -71,7 +71,7 @@ workflows: matrix: parameters: # Run with MSRV and some modern stable Rust - rust-version: ["1.59.0", "1.65.0"] + rust-version: ["1.60.0", "1.65.0"] - benchmarking: requires: - package_vm @@ -123,7 +123,7 @@ jobs: command: | wget https://static.rust-lang.org/rustup/dist/aarch64-unknown-linux-gnu/rustup-init chmod +x rustup-init - ./rustup-init -y --default-toolchain 1.59.0 --profile minimal + ./rustup-init -y --default-toolchain 1.60.0 --profile minimal - run: name: Version information command: rustc --version; cargo --version; rustup --version; rustup target list --installed @@ -132,12 +132,12 @@ jobs: command: rustup target add wasm32-unknown-unknown && rustup target list --installed - restore_cache: keys: - - v4-arm64-workspace-rust:1.59.0-{{ checksum "Cargo.lock" }} - - v4-arm64-workspace-rust:1.59.0- + - v4-arm64-workspace-rust:1.60.0-{{ checksum "Cargo.lock" }} + - v4-arm64-workspace-rust:1.60.0- - restore_cache: keys: - - v4-arm64-contracts-rust:1.59.0-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} - - v4-arm64-contracts-rust:1.59.0- + - v4-arm64-contracts-rust:1.60.0-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} + - v4-arm64-contracts-rust:1.60.0- - run: name: "contracts/crypto-verify: integration-test" working_directory: ~/project/contracts/crypto-verify @@ -172,14 +172,14 @@ jobs: # use all features command: cargo test --locked --features iterator,staking,stargate - save_cache: - key: v4-arm64-workspace-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: v4-arm64-workspace-rust:1.60.0-{{ checksum "Cargo.lock" }} paths: - ~/.cargo/registry - target/debug/.fingerprint - target/debug/build - target/debug/deps - save_cache: - key: v4-arm64-contracts-rust:1.59.0-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} + key: v4-arm64-contracts-rust:1.60.0-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} paths: - ~/.cargo/registry # crypto-verify @@ -220,7 +220,7 @@ jobs: package_crypto: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 steps: - checkout - run: @@ -228,7 +228,7 @@ jobs: command: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-package_crypto-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-package_crypto-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Build working_directory: ~/project/packages/crypto @@ -243,11 +243,11 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-package_crypto-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-package_crypto-rust:1.60.0-{{ checksum "Cargo.lock" }} package_check: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 steps: - checkout - run: @@ -255,7 +255,7 @@ jobs: command: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-package_check-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-package_check-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Build working_directory: ~/project/packages/check @@ -270,11 +270,11 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-package_check-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-package_check-rust:1.60.0-{{ checksum "Cargo.lock" }} package_schema: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 steps: - checkout - run: @@ -282,7 +282,7 @@ jobs: command: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-package_schema-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-package_schema-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Build working_directory: ~/project/packages/schema @@ -297,11 +297,11 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-package_schema-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-package_schema-rust:1.60.0-{{ checksum "Cargo.lock" }} package_schema_derive: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 steps: - checkout - run: @@ -309,7 +309,7 @@ jobs: command: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-package_schema_derive-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-package_schema_derive-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Build working_directory: ~/project/packages/schema-derive @@ -324,11 +324,11 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-package_schema_derive-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-package_schema_derive-rust:1.60.0-{{ checksum "Cargo.lock" }} package_std: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: # Limit the number of parallel jobs to avoid OOM crashes during doc testing RUST_TEST_THREADS: 8 @@ -339,7 +339,7 @@ jobs: command: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-package_std-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-package_std-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Add wasm32 target command: rustup target add wasm32-unknown-unknown && rustup target list --installed @@ -373,11 +373,11 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-package_std-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-package_std-rust:1.60.0-{{ checksum "Cargo.lock" }} package_storage: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 steps: - checkout - run: @@ -385,7 +385,7 @@ jobs: command: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-package_storage-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-package_storage-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Build library for native target working_directory: ~/project/packages/storage @@ -404,11 +404,11 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-package_storage-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-package_storage-rust:1.60.0-{{ checksum "Cargo.lock" }} package_vm: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 steps: - checkout - run: @@ -416,7 +416,7 @@ jobs: command: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-package_vm-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-package_vm-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Build working_directory: ~/project/packages/vm @@ -445,7 +445,7 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-package_vm-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-package_vm-rust:1.60.0-{{ checksum "Cargo.lock" }} package_vm_windows: executor: @@ -493,7 +493,7 @@ jobs: contract_burner: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/burner @@ -505,7 +505,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_burner-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_burner-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -516,11 +516,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_burner-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_burner-rust:1.60.0-{{ checksum "Cargo.lock" }} contract_crypto_verify: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/crypto-verify @@ -532,7 +532,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_crypto_verify-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_crypto_verify-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -543,11 +543,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_crypto_verify-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_crypto_verify-rust:1.60.0-{{ checksum "Cargo.lock" }} contract_cyberpunk: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/cyberpunk @@ -559,7 +559,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_cyberpunk-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_cyberpunk-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -570,11 +570,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_cyberpunk-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_cyberpunk-rust:1.60.0-{{ checksum "Cargo.lock" }} contract_hackatom: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/hackatom @@ -586,7 +586,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_hackatom-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_hackatom-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -597,11 +597,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_hackatom-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_hackatom-rust:1.60.0-{{ checksum "Cargo.lock" }} contract_ibc_reflect: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/ibc-reflect @@ -613,7 +613,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_ibc_reflect-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_ibc_reflect-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -624,11 +624,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_ibc_reflect-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_ibc_reflect-rust:1.60.0-{{ checksum "Cargo.lock" }} contract_ibc_reflect_send: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/ibc-reflect-send @@ -640,7 +640,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_ibc_reflect_send-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_ibc_reflect_send-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -651,11 +651,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_ibc_reflect_send-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_ibc_reflect_send-rust:1.60.0-{{ checksum "Cargo.lock" }} contract_floaty: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/floaty @@ -667,7 +667,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_floaty-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_floaty-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -678,11 +678,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_floaty-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_floaty-rust:1.60.0-{{ checksum "Cargo.lock" }} contract_queue: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/queue @@ -694,7 +694,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_queue-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_queue-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -705,11 +705,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_queue-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_queue-rust:1.60.0-{{ checksum "Cargo.lock" }} contract_reflect: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/reflect @@ -721,7 +721,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_reflect-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_reflect-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -732,11 +732,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_reflect-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_reflect-rust:1.60.0-{{ checksum "Cargo.lock" }} contract_staking: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 working_directory: ~/cosmwasm/contracts/staking @@ -748,7 +748,7 @@ jobs: command: rustc --version; cargo --version; rustup --version - restore_cache: keys: - - cargocache-v2-contract_staking-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-contract_staking-rust:1.60.0-{{ checksum "Cargo.lock" }} - check_contract - save_cache: paths: @@ -759,11 +759,11 @@ jobs: - target/wasm32-unknown-unknown/release/.fingerprint - target/wasm32-unknown-unknown/release/build - target/wasm32-unknown-unknown/release/deps - key: cargocache-v2-contract_staking-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-contract_staking-rust:1.60.0-{{ checksum "Cargo.lock" }} fmt: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 steps: - checkout - run: @@ -771,7 +771,7 @@ jobs: command: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-fmt-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-fmt-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Add rustfmt component command: rustup component add rustfmt @@ -784,7 +784,7 @@ jobs: - target/debug/.fingerprint - target/debug/build - target/debug/deps - key: cargocache-v2-fmt-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-fmt-rust:1.60.0-{{ checksum "Cargo.lock" }} fmt_extra: docker: @@ -806,7 +806,7 @@ jobs: deadlinks: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 steps: - checkout - run: @@ -814,7 +814,7 @@ jobs: command: rustc --version; cargo --version; rustup --version; rustup target list --installed - restore_cache: keys: - - cargocache-v2-deadlinks-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-deadlinks-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Generate docs command: cargo doc @@ -834,7 +834,7 @@ jobs: - target/debug/build - target/debug/deps - /root/.cache/pip - key: cargocache-v2-deadlinks-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-deadlinks-rust:1.60.0-{{ checksum "Cargo.lock" }} clippy: parameters: @@ -910,7 +910,7 @@ jobs: benchmarking: docker: - - image: rust:1.59.0 + - image: rust:1.60.0 environment: RUST_BACKTRACE: 1 steps: @@ -920,7 +920,7 @@ jobs: command: rustc --version && cargo --version - restore_cache: keys: - - cargocache-v2-benchmarking-rust:1.59.0-{{ checksum "Cargo.lock" }} + - cargocache-v2-benchmarking-rust:1.60.0-{{ checksum "Cargo.lock" }} - run: name: Run vm benchmarks (Singlepass) working_directory: ~/project/packages/vm @@ -938,7 +938,7 @@ jobs: - target/release/.fingerprint - target/release/build - target/release/deps - key: cargocache-v2-benchmarking-rust:1.59.0-{{ checksum "Cargo.lock" }} + key: cargocache-v2-benchmarking-rust:1.60.0-{{ checksum "Cargo.lock" }} coverage: # https://circleci.com/developer/images?imageType=machine @@ -1005,7 +1005,7 @@ jobs: name: Check development contracts command: | echo "Checking all contracts under ./artifacts" - docker run --volumes-from with_code rust:1.59.0 \ + docker run --volumes-from with_code rust:1.60.0 \ /bin/bash -e -c 'export GLOBIGNORE="artifacts/floaty.wasm"; cd ./code; cargo run --bin cosmwasm-check artifacts/*.wasm' docker cp with_code:/code/artifacts . - run: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index def0099f59..1d50ccbda5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: - name: Install Rust uses: actions-rs/toolchain@v1 with: - toolchain: 1.59.0 + toolchain: 1.60.0 target: wasm32-unknown-unknown profile: minimal override: true From f14d30845c0e3067b42b843dfc58b70e6215a30d Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 18:14:08 +0100 Subject: [PATCH 066/187] Bump cosmwasm-std version to 1.1.9 in [dev-dependencies] [skip ci] --- packages/schema/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index ad891e54ea..747fcba35f 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -16,6 +16,6 @@ thiserror = "1.0.13" [dev-dependencies] anyhow = "1.0.57" -cosmwasm-std = { version = "1.1.8", path = "../std" } +cosmwasm-std = { version = "1.1.9", path = "../std" } semver = "1" tempfile = "3" From 4525f29fe0971ee0a8a044bfcdcda26444bb10a4 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 18:16:33 +0100 Subject: [PATCH 067/187] Set version: 1.2.0-beta.0 --- Cargo.lock | 16 ++++++++-------- contracts/burner/Cargo.lock | 12 ++++++------ contracts/crypto-verify/Cargo.lock | 14 +++++++------- contracts/cyberpunk/Cargo.lock | 14 +++++++------- contracts/floaty/Cargo.lock | 14 +++++++------- contracts/hackatom/Cargo.lock | 14 +++++++------- contracts/ibc-reflect-send/Cargo.lock | 14 +++++++------- contracts/ibc-reflect/Cargo.lock | 14 +++++++------- contracts/queue/Cargo.lock | 12 ++++++------ contracts/reflect/Cargo.lock | 14 +++++++------- contracts/staking/Cargo.lock | 14 +++++++------- packages/check/Cargo.toml | 6 +++--- packages/crypto/Cargo.toml | 2 +- packages/derive/Cargo.toml | 2 +- packages/schema-derive/Cargo.toml | 2 +- packages/schema/Cargo.toml | 6 +++--- packages/std/Cargo.toml | 6 +++--- packages/storage/Cargo.toml | 4 ++-- packages/vm/Cargo.toml | 6 +++--- 19 files changed, 93 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 021ce07392..c939cf06c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "cosmwasm-check" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "anyhow", "clap", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "criterion", @@ -276,7 +276,7 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "syn", @@ -284,7 +284,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "anyhow", "cosmwasm-schema-derive", @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "chrono", @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "serde", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index 9044ff718a..20129c0bbf 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -174,7 +174,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -185,14 +185,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -203,7 +203,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index 4bebe371ca..92ebf0a51e 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -169,7 +169,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -180,14 +180,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -198,7 +198,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -207,7 +207,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "serde", @@ -233,7 +233,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index 58b2b8dcf5..04d7002ab4 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -203,14 +203,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -221,7 +221,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "serde", @@ -256,7 +256,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index a91764061f..b1857e209a 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index a88a63914f..b46d6b0382 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index eef33fcda3..ec798a0102 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index 2433c84e57..a60ff962fb 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index 69ea329dbb..69f5ecff87 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index 7ffedc112b..d5ba929da6 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index 0c4a548896..ad437ec305 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" dependencies = [ "bitflags", "bytecheck", diff --git a/packages/check/Cargo.toml b/packages/check/Cargo.toml index 2d094890a7..a2d0cfe904 100644 --- a/packages/check/Cargo.toml +++ b/packages/check/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-check" -version = "1.1.9" +version = "1.2.0-beta.0" authors = ["Mauro Lacy "] edition = "2021" description = "A CLI tool for verifying CosmWasm smart contracts" @@ -11,5 +11,5 @@ license = "Apache-2.0" anyhow = "1.0.57" clap = "2" colored = "2" -cosmwasm-vm = { path = "../vm", version = "1.1.9" } -cosmwasm-std = { path = "../std", version = "1.1.9" } +cosmwasm-vm = { path = "../vm", version = "1.2.0-beta.0" } +cosmwasm-std = { path = "../std", version = "1.2.0-beta.0" } diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index c5b07db3ce..5b11b33ead 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.0-beta.0" authors = ["Mauro Lacy "] edition = "2021" description = "Crypto bindings for cosmwasm contracts" diff --git a/packages/derive/Cargo.toml b/packages/derive/Cargo.toml index 939cebab5d..2a1eea212e 100644 --- a/packages/derive/Cargo.toml +++ b/packages/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-derive" -version = "1.1.9" +version = "1.2.0-beta.0" authors = ["Simon Warta "] edition = "2021" description = "A package for auto-generated code used for CosmWasm contract development. This is shipped as part of cosmwasm-std. Do not use directly." diff --git a/packages/schema-derive/Cargo.toml b/packages/schema-derive/Cargo.toml index 7527b0442d..743ccb4a58 100644 --- a/packages/schema-derive/Cargo.toml +++ b/packages/schema-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.0-beta.0" authors = ["Tomasz Kurcz "] edition = "2021" description = "Derive macros for cosmwasm-schema" diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index 747fcba35f..eb96253d69 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.0-beta.0" authors = ["Simon Warta ", "Ethan Frey "] edition = "2021" description = "A dev-dependency for CosmWasm contracts to generate JSON Schema files." @@ -8,7 +8,7 @@ repository = "https://github.com/CosmWasm/cosmwasm/tree/main/packages/schema" license = "Apache-2.0" [dependencies] -cosmwasm-schema-derive = { version = "=1.1.9", path = "../schema-derive" } +cosmwasm-schema-derive = { version = "=1.2.0-beta.0", path = "../schema-derive" } schemars = "0.8.3" serde = "1.0" serde_json = "1.0.40" @@ -16,6 +16,6 @@ thiserror = "1.0.13" [dev-dependencies] anyhow = "1.0.57" -cosmwasm-std = { version = "1.1.9", path = "../std" } +cosmwasm-std = { version = "1.2.0-beta.0", path = "../std" } semver = "1" tempfile = "3" diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index a960528f7b..7ea7191bed 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.0-beta.0" authors = ["Ethan Frey "] edition = "2021" description = "Standard library for Wasm based smart contracts on Cosmos blockchains" @@ -42,7 +42,7 @@ cosmwasm_1_2 = [] [dependencies] base64 = "0.13.0" -cosmwasm-derive = { path = "../derive", version = "1.1.9" } +cosmwasm-derive = { path = "../derive", version = "1.2.0-beta.0" } derivative = "2" forward_ref = "1" hex = "0.4" @@ -54,7 +54,7 @@ thiserror = "1.0.13" uint = "0.9.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -cosmwasm-crypto = { path = "../crypto", version = "1.1.9" } +cosmwasm-crypto = { path = "../crypto", version = "1.2.0-beta.0" } [dev-dependencies] cosmwasm-schema = { path = "../schema" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index 07c778d2b5..b726c7d125 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.0-beta.0" authors = ["Ethan Frey "] edition = "2021" description = "CosmWasm library with useful helpers for Storage patterns" @@ -16,5 +16,5 @@ iterator = ["cosmwasm-std/iterator"] [dependencies] # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.1.9", default-features = false } +cosmwasm-std = { path = "../std", version = "1.2.0-beta.0", default-features = false } serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index 685474d650..b00693b1fa 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-vm" -version = "1.1.9" +version = "1.2.0-beta.0" authors = ["Ethan Frey "] edition = "2021" description = "VM bindings to run cosmwams contracts" @@ -41,8 +41,8 @@ required-features = ["iterator"] [dependencies] clru = "0.4.0" # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.1.9", default-features = false } -cosmwasm-crypto = { path = "../crypto", version = "1.1.9" } +cosmwasm-std = { path = "../std", version = "1.2.0-beta.0", default-features = false } +cosmwasm-crypto = { path = "../crypto", version = "1.2.0-beta.0" } hex = "0.4" parity-wasm = "0.42" schemars = "0.8.3" From da768196643beb50beeb7e4d4471ba1c3ee1dd07 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 20 Dec 2022 10:41:21 +0100 Subject: [PATCH 068/187] Organize From implementations --- packages/std/src/binary.rs | 17 +++++++++-------- packages/std/src/hex_binary.rs | 17 +++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/std/src/binary.rs b/packages/std/src/binary.rs index 4ee4b253fb..192d68fd6b 100644 --- a/packages/std/src/binary.rs +++ b/packages/std/src/binary.rs @@ -83,12 +83,6 @@ impl fmt::Debug for Binary { } } -impl From<&[u8]> for Binary { - fn from(binary: &[u8]) -> Self { - Self(binary.to_vec()) - } -} - /// Just like Vec, Binary is a smart pointer to [u8]. /// This implements `*binary` for us and allows us to /// do `&*binary`, returning a `&[u8]` from a `&Binary`. @@ -102,14 +96,21 @@ impl Deref for Binary { } } -// Reference +// Slice +impl From<&[u8]> for Binary { + fn from(binary: &[u8]) -> Self { + Self(binary.to_vec()) + } +} + +// Array reference impl From<&[u8; LENGTH]> for Binary { fn from(source: &[u8; LENGTH]) -> Self { Self(source.to_vec()) } } -// Owned +// Owned array impl From<[u8; LENGTH]> for Binary { fn from(source: [u8; LENGTH]) -> Self { Self(source.into()) diff --git a/packages/std/src/hex_binary.rs b/packages/std/src/hex_binary.rs index 4aa5f7cc8e..4cc8f45ee7 100644 --- a/packages/std/src/hex_binary.rs +++ b/packages/std/src/hex_binary.rs @@ -79,12 +79,6 @@ impl fmt::Debug for HexBinary { } } -impl From<&[u8]> for HexBinary { - fn from(binary: &[u8]) -> Self { - Self(binary.to_vec()) - } -} - /// Just like Vec, HexBinary is a smart pointer to [u8]. /// This implements `*data` for us and allows us to /// do `&*data`, returning a `&[u8]` from a `&HexBinary`. @@ -98,14 +92,21 @@ impl Deref for HexBinary { } } -// Reference +// Slice +impl From<&[u8]> for HexBinary { + fn from(binary: &[u8]) -> Self { + Self(binary.to_vec()) + } +} + +// Array reference impl From<&[u8; LENGTH]> for HexBinary { fn from(source: &[u8; LENGTH]) -> Self { Self(source.to_vec()) } } -// Owned +// Owned array impl From<[u8; LENGTH]> for HexBinary { fn from(source: [u8; LENGTH]) -> Self { Self(source.into()) From 3d8bfa05b81c4c22c2bcb452daf0e7e2bd5e0c92 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 20 Dec 2022 10:51:01 +0100 Subject: [PATCH 069/187] Implement AsRef<[u8]> for Binary and HexBinary --- CHANGELOG.md | 2 ++ packages/std/src/binary.rs | 34 ++++++++++++++++++++++++++++++++++ packages/std/src/hex_binary.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6451e14d0..d71e2f5465 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,11 +19,13 @@ and this project adheres to [#1533]). - cosmwasm-std: Upgrade `serde-json-wasm` dependency to 0.5.0 which adds map support to `to_vec`/`to_binary` and friends. +- cosmwasm-std: Implement `AsRef<[u8]>` for `Binary` and `HexBinary` ([#1550]). [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 [#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 [#1478]: https://github.com/CosmWasm/cosmwasm/pull/1478 [#1533]: https://github.com/CosmWasm/cosmwasm/pull/1533 +[#1550]: https://github.com/CosmWasm/cosmwasm/issues/1550 ### Changed diff --git a/packages/std/src/binary.rs b/packages/std/src/binary.rs index 192d68fd6b..4e69b0ff20 100644 --- a/packages/std/src/binary.rs +++ b/packages/std/src/binary.rs @@ -96,6 +96,12 @@ impl Deref for Binary { } } +impl AsRef<[u8]> for Binary { + fn as_ref(&self) -> &[u8] { + self.as_slice() + } +} + // Slice impl From<&[u8]> for Binary { fn from(binary: &[u8]) -> Self { @@ -497,6 +503,34 @@ mod tests { assert_eq!(binary_slice, &[7u8, 35, 49, 101, 0, 255]); } + #[test] + fn binary_implements_as_ref() { + // Can use as_ref (this we already get via the Deref implementation) + let data = Binary(vec![7u8, 35, 49, 101, 0, 255]); + assert_eq!(data.as_ref(), &[7u8, 35, 49, 101, 0, 255]); + + let data = Binary(vec![7u8, 35, 49, 101, 0, 255]); + let data_ref = &data; + assert_eq!(data_ref.as_ref(), &[7u8, 35, 49, 101, 0, 255]); + + // Implements as ref + + // This is a dummy function to mimic the signature of + // https://docs.rs/sha2/0.10.6/sha2/trait.Digest.html#tymethod.digest + fn hash(data: impl AsRef<[u8]>) -> u64 { + let mut hasher = DefaultHasher::new(); + data.as_ref().hash(&mut hasher); + hasher.finish() + } + + let data = Binary(vec![7u8, 35, 49, 101, 0, 255]); + hash(data); + + let data = Binary(vec![7u8, 35, 49, 101, 0, 255]); + let data_ref = &data; + hash(data_ref); + } + #[test] fn binary_implements_hash() { let a1 = Binary::from([0, 187, 61, 11, 250, 0]); diff --git a/packages/std/src/hex_binary.rs b/packages/std/src/hex_binary.rs index 4cc8f45ee7..fcbcc4c05b 100644 --- a/packages/std/src/hex_binary.rs +++ b/packages/std/src/hex_binary.rs @@ -92,6 +92,12 @@ impl Deref for HexBinary { } } +impl AsRef<[u8]> for HexBinary { + fn as_ref(&self) -> &[u8] { + self.as_slice() + } +} + // Slice impl From<&[u8]> for HexBinary { fn from(binary: &[u8]) -> Self { @@ -561,6 +567,34 @@ mod tests { assert_eq!(data_slice, &[7u8, 35, 49, 101, 0, 255]); } + #[test] + fn hex_binary_implements_as_ref() { + // Can use as_ref (this we already get via the Deref implementation) + let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]); + assert_eq!(data.as_ref(), &[7u8, 35, 49, 101, 0, 255]); + + let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]); + let data_ref = &data; + assert_eq!(data_ref.as_ref(), &[7u8, 35, 49, 101, 0, 255]); + + // Implements as ref + + // This is a dummy function to mimic the signature of + // https://docs.rs/sha2/0.10.6/sha2/trait.Digest.html#tymethod.digest + fn hash(data: impl AsRef<[u8]>) -> u64 { + let mut hasher = DefaultHasher::new(); + data.as_ref().hash(&mut hasher); + hasher.finish() + } + + let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]); + hash(data); + + let data = HexBinary(vec![7u8, 35, 49, 101, 0, 255]); + let data_ref = &data; + hash(data_ref); + } + #[test] fn hex_binary_implements_hash() { let a1 = HexBinary::from([0, 187, 61, 11, 250, 0]); From 3b352a921aa730e91f6cbf404e5cfc84178a3041 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 13:55:04 +0100 Subject: [PATCH 070/187] Add missing cosmwasm_1_2 features --- .circleci/config.yml | 8 ++++---- devtools/check_workspace.sh | 2 +- packages/check/src/main.rs | 2 +- packages/vm/src/testing/instance.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 01000ce3ac..926f083f3d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -358,15 +358,15 @@ jobs: - run: name: Build library for native target (all features) working_directory: ~/project/packages/std - command: cargo build --locked --features abort,iterator,staking,stargate,cosmwasm_1_1 + command: cargo build --locked --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 - run: name: Build library for wasm target (all features) working_directory: ~/project/packages/std - command: cargo wasm --locked --features abort,iterator,staking,stargate,cosmwasm_1_1 + command: cargo wasm --locked --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 - run: name: Run unit tests (all features) working_directory: ~/project/packages/std - command: cargo test --locked --features abort,iterator,staking,stargate,cosmwasm_1_1 + command: cargo test --locked --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 - save_cache: paths: - /usr/local/cargo/registry @@ -882,7 +882,7 @@ jobs: - run: name: Clippy linting on std (all feature flags) working_directory: ~/project/packages/std - command: cargo clippy --all-targets --features abort,iterator,staking,stargate -- -D warnings + command: cargo clippy --all-targets --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 -- -D warnings - run: name: Clippy linting on storage (no feature flags) working_directory: ~/project/packages/storage diff --git a/devtools/check_workspace.sh b/devtools/check_workspace.sh index d24813c5ed..a9969ae5f8 100755 --- a/devtools/check_workspace.sh +++ b/devtools/check_workspace.sh @@ -8,7 +8,7 @@ cargo fmt ( cd packages/std cargo check - cargo check --features iterator,staking,stargate + cargo check --features iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 cargo wasm-debug cargo wasm-debug --features iterator,staking,stargate cargo clippy --all-targets --features iterator,staking,stargate -- -D warnings diff --git a/packages/check/src/main.rs b/packages/check/src/main.rs index 1d4e6eb67d..c1f7da1784 100644 --- a/packages/check/src/main.rs +++ b/packages/check/src/main.rs @@ -10,7 +10,7 @@ use colored::Colorize; use cosmwasm_vm::capabilities_from_csv; use cosmwasm_vm::internals::{check_wasm, compile}; -const DEFAULT_AVAILABLE_CAPABILITIES: &str = "iterator,staking,stargate,cosmwasm_1_1"; +const DEFAULT_AVAILABLE_CAPABILITIES: &str = "iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2"; pub fn main() { let matches = App::new("Contract checking") diff --git a/packages/vm/src/testing/instance.rs b/packages/vm/src/testing/instance.rs index 6311c10a67..14b85cf7c9 100644 --- a/packages/vm/src/testing/instance.rs +++ b/packages/vm/src/testing/instance.rs @@ -98,7 +98,7 @@ pub struct MockInstanceOptions<'a> { impl MockInstanceOptions<'_> { fn default_capabilities() -> HashSet { #[allow(unused_mut)] - let mut out = capabilities_from_csv("iterator,staking,cosmwasm_1_1"); + let mut out = capabilities_from_csv("iterator,staking,cosmwasm_1_1,cosmwasm_1_2"); #[cfg(feature = "stargate")] out.insert("stargate".to_string()); out From 36146e7cc3e7aba6de333b0855eb850771ead43b Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 12 Dec 2022 13:59:47 +0100 Subject: [PATCH 071/187] Add WasmMsg::Instantiate2 --- CHANGELOG.md | 4 +++ .../schema/ibc-reflect-send.json | 2 +- .../ibc-reflect-send/schema/packet_msg.json | 2 +- .../ibc-reflect-send/schema/raw/execute.json | 2 +- .../ibc-reflect-send/schema/raw/migrate.json | 2 +- .../ibc-reflect-send/schema/raw/sudo.json | 2 +- contracts/ibc-reflect/schema/packet_msg.json | 2 +- contracts/reflect/schema/raw/execute.json | 2 +- contracts/reflect/schema/raw/migrate.json | 2 +- contracts/reflect/schema/raw/sudo.json | 2 +- contracts/reflect/schema/reflect.json | 2 +- docs/CAPABILITIES-BUILT-IN.md | 4 +-- packages/std/src/results/cosmos_msg.rs | 26 ++++++++++++++++++- 13 files changed, 41 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d71e2f5465..a329879f66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ and this project adheres to of CosmWasm earlier than 1.2.0 ([#1481]). - cosmwasm-std: Add `instantiate2_address` which allows calculating the predictable addresses for `MsgInstantiateContract2` ([#1437]). +- cosmwasm-std: Add `WasmMsg::Instantiate2` (requires `cosmwasm_1_2`, see + `GovMsg::VoteWeighted` above) to instantiate contracts at a predictable + address ([#1436]). - cosmwasm-schema: In contracts, `cosmwasm schema` will now output a separate JSON Schema file for each entrypoint in the `raw` subdirectory ([#1478], [#1533]). @@ -21,6 +24,7 @@ and this project adheres to support to `to_vec`/`to_binary` and friends. - cosmwasm-std: Implement `AsRef<[u8]>` for `Binary` and `HexBinary` ([#1550]). +[#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436 [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 [#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 [#1478]: https://github.com/CosmWasm/cosmwasm/pull/1478 diff --git a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json index 5f6fe80a2c..b42ac67e89 100644 --- a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json +++ b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json @@ -690,7 +690,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/contracts/ibc-reflect-send/schema/packet_msg.json b/contracts/ibc-reflect-send/schema/packet_msg.json index 1aeb3db835..7bc2a45e21 100644 --- a/contracts/ibc-reflect-send/schema/packet_msg.json +++ b/contracts/ibc-reflect-send/schema/packet_msg.json @@ -628,7 +628,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/contracts/ibc-reflect-send/schema/raw/execute.json b/contracts/ibc-reflect-send/schema/raw/execute.json index e08109d489..a382cb2aac 100644 --- a/contracts/ibc-reflect-send/schema/raw/execute.json +++ b/contracts/ibc-reflect-send/schema/raw/execute.json @@ -679,7 +679,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/contracts/ibc-reflect-send/schema/raw/migrate.json b/contracts/ibc-reflect-send/schema/raw/migrate.json index e08109d489..a382cb2aac 100644 --- a/contracts/ibc-reflect-send/schema/raw/migrate.json +++ b/contracts/ibc-reflect-send/schema/raw/migrate.json @@ -679,7 +679,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/contracts/ibc-reflect-send/schema/raw/sudo.json b/contracts/ibc-reflect-send/schema/raw/sudo.json index e08109d489..a382cb2aac 100644 --- a/contracts/ibc-reflect-send/schema/raw/sudo.json +++ b/contracts/ibc-reflect-send/schema/raw/sudo.json @@ -679,7 +679,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/contracts/ibc-reflect/schema/packet_msg.json b/contracts/ibc-reflect/schema/packet_msg.json index 11f1cb38eb..259c21b1bd 100644 --- a/contracts/ibc-reflect/schema/packet_msg.json +++ b/contracts/ibc-reflect/schema/packet_msg.json @@ -473,7 +473,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/contracts/reflect/schema/raw/execute.json b/contracts/reflect/schema/raw/execute.json index e0db5ae603..1ccfba3b0e 100644 --- a/contracts/reflect/schema/raw/execute.json +++ b/contracts/reflect/schema/raw/execute.json @@ -716,7 +716,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/contracts/reflect/schema/raw/migrate.json b/contracts/reflect/schema/raw/migrate.json index e0db5ae603..1ccfba3b0e 100644 --- a/contracts/reflect/schema/raw/migrate.json +++ b/contracts/reflect/schema/raw/migrate.json @@ -716,7 +716,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/contracts/reflect/schema/raw/sudo.json b/contracts/reflect/schema/raw/sudo.json index e0db5ae603..1ccfba3b0e 100644 --- a/contracts/reflect/schema/raw/sudo.json +++ b/contracts/reflect/schema/raw/sudo.json @@ -716,7 +716,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/contracts/reflect/schema/reflect.json b/contracts/reflect/schema/reflect.json index 515e97eac5..ab4e2c0cc6 100644 --- a/contracts/reflect/schema/reflect.json +++ b/contracts/reflect/schema/reflect.json @@ -726,7 +726,7 @@ "additionalProperties": false }, { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", + "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThe contract address is non-predictable. But it is guaranteed that when emitting the same Instantiate message multiple times, multiple instances on different addresses will be generated. See also Instantiate2.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). `sender` is automatically filled with the current contract's address.", "type": "object", "required": [ "instantiate" diff --git a/docs/CAPABILITIES-BUILT-IN.md b/docs/CAPABILITIES-BUILT-IN.md index f0cabc280b..8fdd679fe1 100644 --- a/docs/CAPABILITIES-BUILT-IN.md +++ b/docs/CAPABILITIES-BUILT-IN.md @@ -13,5 +13,5 @@ might define others. chains that don't use this (e.g. Tgrade). - `cosmwasm_1_1` enables the `BankQuery::Supply` query. Only chains running CosmWasm `1.1.0` or higher support this. -- `cosmwasm_1_2` enables the `GovMsg::VoteWeighted` message. Only chains running - CosmWasm `1.2.0` or higher support this. +- `cosmwasm_1_2` enables the `GovMsg::VoteWeighted` and `WasmMsg::Instantiate2` + messages. Only chains running CosmWasm `1.2.0` or higher support this. diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index 2761ac280b..e7c63418f4 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -141,7 +141,12 @@ pub enum WasmMsg { }, /// Instantiates a new contracts from previously uploaded Wasm code. /// - /// This is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). + /// The contract address is non-predictable. But it is guaranteed that + /// when emitting the same Instantiate message multiple times, + /// multiple instances on different addresses will be generated. See also + /// Instantiate2. + /// + /// This is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L53-L71). /// `sender` is automatically filled with the current contract's address. Instantiate { admin: Option, @@ -153,6 +158,25 @@ pub enum WasmMsg { /// A human-readbale label for the contract label: String, }, + /// Instantiates a new contracts from previously uploaded Wasm code + /// using a predictable address derivation algorithm implemented in + /// [`cosmwasm_std::instantiate2_address`]. + /// + /// This is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). + /// `sender` is automatically filled with the current contract's address. + #[cfg(feature = "cosmwasm_1_2")] + Instantiate2 { + admin: Option, + code_id: u64, + /// A human-readbale label for the contract + label: String, + /// msg is the JSON-encoded InstantiateMsg struct (as raw Binary) + #[derivative(Debug(format_with = "binary_to_string"))] + msg: Binary, + funds: Vec, + salt: Binary, + fix_msg: bool, + }, /// Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to /// customize behavior. /// From f59ee3dc04573b7e14670d3dfedddcbd7fa1fcea Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 20 Dec 2022 14:44:42 +0100 Subject: [PATCH 072/187] Remove msg argument from instantiate2_address --- packages/std/src/addresses.rs | 52 +++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 93248e0018..880e2171b7 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -315,7 +315,7 @@ pub enum Instantiate2AddressError { /// let canonical_creator = deps.api.addr_canonicalize(env.contract.address.as_str())?; /// let checksum = HexBinary::from_hex("9af782a3a1bcbcd22dbb6a45c751551d9af782a3a1bcbcd22dbb6a45c751551d")?; /// let salt = b"instance 1231"; -/// let canonical_addr = instantiate2_address(&checksum, &canonical_creator, salt, None) +/// let canonical_addr = instantiate2_address(&checksum, &canonical_creator, salt) /// .map_err(|_| StdError::generic_err("Could not calculate addr"))?; /// let addr = deps.api.addr_humanize(&canonical_addr)?; /// @@ -326,7 +326,19 @@ pub fn instantiate2_address( checksum: &[u8], creator: &CanonicalAddr, salt: &[u8], - msg: Option<&[u8]>, +) -> Result { + instantiate2_address_impl(checksum, creator, salt, b"") +} + +/// The instantiate2 address derivation implementation. This API is used for +/// testing puposes only. The `msg` field is discouraged and should not be used. +/// Use [`instantiate2_address`]. +#[doc(hidden)] +fn instantiate2_address_impl( + checksum: &[u8], + creator: &CanonicalAddr, + salt: &[u8], + msg: &[u8], ) -> Result { if checksum.len() != 32 { return Err(Instantiate2AddressError::InvalidChecksumLength); @@ -336,8 +348,6 @@ pub fn instantiate2_address( return Err(Instantiate2AddressError::InvalidSaltLength); }; - let msg = msg.unwrap_or_default(); - let mut key = Vec::::new(); key.extend_from_slice(b"wasm\0"); key.extend_from_slice(&(checksum.len() as u64).to_be_bytes()); @@ -659,23 +669,23 @@ mod tests { } #[test] - fn instantiate2_address_works() { + fn instantiate2_address_impl_works() { let checksum1 = HexBinary::from_hex("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5") .unwrap(); let creator1 = CanonicalAddr::from(hex!("9999999999aaaaaaaaaabbbbbbbbbbcccccccccc")); let salt1 = hex!("61"); let salt2 = hex!("aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae"); - let msg1: Option<&[u8]> = None; - let msg2: Option<&[u8]> = Some(b"{}"); - let msg3: Option<&[u8]> = Some(b"{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"); + let msg1: &[u8] = b""; + let msg2: &[u8] = b"{}"; + let msg3: &[u8] = b"{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"; // No msg let expected = CanonicalAddr::from(hex!( "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847" )); assert_eq!( - instantiate2_address(&checksum1, &creator1, &salt1, msg1).unwrap(), + instantiate2_address_impl(&checksum1, &creator1, &salt1, msg1).unwrap(), expected ); @@ -684,7 +694,7 @@ mod tests { "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835" )); assert_eq!( - instantiate2_address(&checksum1, &creator1, &salt1, msg2).unwrap(), + instantiate2_address_impl(&checksum1, &creator1, &salt1, msg2).unwrap(), expected ); @@ -693,7 +703,7 @@ mod tests { "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167" )); assert_eq!( - instantiate2_address(&checksum1, &creator1, &salt1, msg3).unwrap(), + instantiate2_address_impl(&checksum1, &creator1, &salt1, msg3).unwrap(), expected ); @@ -702,42 +712,42 @@ mod tests { "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564" )); assert_eq!( - instantiate2_address(&checksum1, &creator1, &salt2, None).unwrap(), + instantiate2_address_impl(&checksum1, &creator1, &salt2, b"").unwrap(), expected ); // Salt too short or too long let empty = Vec::::new(); assert!(matches!( - instantiate2_address(&checksum1, &creator1, &empty, None).unwrap_err(), + instantiate2_address_impl(&checksum1, &creator1, &empty, b"").unwrap_err(), Instantiate2AddressError::InvalidSaltLength )); let too_long = vec![0x11; 65]; assert!(matches!( - instantiate2_address(&checksum1, &creator1, &too_long, None).unwrap_err(), + instantiate2_address_impl(&checksum1, &creator1, &too_long, b"").unwrap_err(), Instantiate2AddressError::InvalidSaltLength )); // invalid checksum length let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2"); assert!(matches!( - instantiate2_address(&broken_cs, &creator1, &salt1, None).unwrap_err(), + instantiate2_address_impl(&broken_cs, &creator1, &salt1, b"").unwrap_err(), Instantiate2AddressError::InvalidChecksumLength )); let broken_cs = hex!(""); assert!(matches!( - instantiate2_address(&broken_cs, &creator1, &salt1, None).unwrap_err(), + instantiate2_address_impl(&broken_cs, &creator1, &salt1, b"").unwrap_err(), Instantiate2AddressError::InvalidChecksumLength )); let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2aaaa"); assert!(matches!( - instantiate2_address(&broken_cs, &creator1, &salt1, None).unwrap_err(), + instantiate2_address_impl(&broken_cs, &creator1, &salt1, b"").unwrap_err(), Instantiate2AddressError::InvalidChecksumLength )); } #[test] - fn instantiate2_address_works_for_cosmjs_testvectors() { + fn instantiate2_address_impl_works_for_cosmjs_testvectors() { // Test data from https://github.com/cosmos/cosmjs/pull/1253 const COSMOS_ED25519_TESTS_JSON: &str = "./testdata/instantiate2_addresses.json"; @@ -793,12 +803,12 @@ mod tests { out: _, } in read_tests() { - let msg = input.msg.map(|msg| msg.into_bytes()); - let addr = instantiate2_address( + let msg = input.msg.map(|msg| msg.into_bytes()).unwrap_or_default(); + let addr = instantiate2_address_impl( &input.checksum, &input.creator_data.into(), &input.salt, - msg.as_deref(), + &msg, ) .unwrap(); assert_eq!(addr, intermediate.address_data); From 93582b9029c9635a4d7f4c7f43b153c47a42c78a Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 20 Dec 2022 18:17:33 +0100 Subject: [PATCH 073/187] Link update PR #1554 to instantiate2_address/Instantiate2 CHANGELOGs --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a329879f66..806a673192 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,10 @@ and this project adheres to dependency. This makes the contract incompatible with chains running versions of CosmWasm earlier than 1.2.0 ([#1481]). - cosmwasm-std: Add `instantiate2_address` which allows calculating the - predictable addresses for `MsgInstantiateContract2` ([#1437]). + predictable addresses for `MsgInstantiateContract2` ([#1437], [#1554]). - cosmwasm-std: Add `WasmMsg::Instantiate2` (requires `cosmwasm_1_2`, see `GovMsg::VoteWeighted` above) to instantiate contracts at a predictable - address ([#1436]). + address ([#1436], [#1554])). - cosmwasm-schema: In contracts, `cosmwasm schema` will now output a separate JSON Schema file for each entrypoint in the `raw` subdirectory ([#1478], [#1533]). @@ -30,6 +30,7 @@ and this project adheres to [#1478]: https://github.com/CosmWasm/cosmwasm/pull/1478 [#1533]: https://github.com/CosmWasm/cosmwasm/pull/1533 [#1550]: https://github.com/CosmWasm/cosmwasm/issues/1550 +[#1554]: https://github.com/CosmWasm/cosmwasm/pull/1554 ### Changed From ccf3f08e5238064f173971ace03d5213654199a3 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 20 Dec 2022 18:22:24 +0100 Subject: [PATCH 074/187] Remove fix_msg argument from Instantiate2 --- packages/std/src/results/cosmos_msg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index e7c63418f4..cc24034322 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -164,6 +164,7 @@ pub enum WasmMsg { /// /// This is translated to a [MsgInstantiateContract2](https://github.com/CosmWasm/wasmd/blob/v0.29.2/proto/cosmwasm/wasm/v1/tx.proto#L73-L96). /// `sender` is automatically filled with the current contract's address. + /// `fix_msg` is automatically set to false. #[cfg(feature = "cosmwasm_1_2")] Instantiate2 { admin: Option, @@ -175,7 +176,6 @@ pub enum WasmMsg { msg: Binary, funds: Vec, salt: Binary, - fix_msg: bool, }, /// Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to /// customize behavior. From c8bfa9cf32efceb37f57afa4005eff8c1ffad764 Mon Sep 17 00:00:00 2001 From: 0xArb Date: Sun, 18 Dec 2022 13:45:00 +1300 Subject: [PATCH 075/187] supplyresponse::new --- packages/std/src/query/bank.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/std/src/query/bank.rs b/packages/std/src/query/bank.rs index 9656ea6138..373ba8fcd9 100644 --- a/packages/std/src/query/bank.rs +++ b/packages/std/src/query/bank.rs @@ -31,6 +31,16 @@ pub struct SupplyResponse { pub amount: Coin, } +#[cfg(feature = "cosmwasm_1_1")] +impl SupplyResponse { + pub fn new(amount: Coin) -> Self { + Self { + amount, + } + } +} + + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct BalanceResponse { From 6da0ab73364aa02638509846e2b919d79fa523de Mon Sep 17 00:00:00 2001 From: Simon Warta <2603011+webmaster128@users.noreply.github.com> Date: Wed, 21 Dec 2022 17:47:23 +0100 Subject: [PATCH 076/187] Format code --- packages/std/src/query/bank.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/std/src/query/bank.rs b/packages/std/src/query/bank.rs index 373ba8fcd9..d8d99d030e 100644 --- a/packages/std/src/query/bank.rs +++ b/packages/std/src/query/bank.rs @@ -34,13 +34,10 @@ pub struct SupplyResponse { #[cfg(feature = "cosmwasm_1_1")] impl SupplyResponse { pub fn new(amount: Coin) -> Self { - Self { - amount, - } + Self { amount } } } - #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct BalanceResponse { From ad62c70065e010675cebb59aa6b8ab77610b0550 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 21 Dec 2022 17:52:35 +0100 Subject: [PATCH 077/187] Improve documentation for query response constructors --- packages/std/src/query/bank.rs | 5 +++++ packages/std/src/query/wasm.rs | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/std/src/query/bank.rs b/packages/std/src/query/bank.rs index d8d99d030e..e53dbcc9b0 100644 --- a/packages/std/src/query/bank.rs +++ b/packages/std/src/query/bank.rs @@ -33,6 +33,11 @@ pub struct SupplyResponse { #[cfg(feature = "cosmwasm_1_1")] impl SupplyResponse { + /// Constructor for testing frameworks such as cw-multi-test. + /// This is required because query response types should be #[non_exhaustive]. + /// As a contract developer you should not need this constructor since + /// query responses are constructed for you via deserialization. + #[doc(hidden)] pub fn new(amount: Coin) -> Self { Self { amount } } diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index cbac899834..fee0334635 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -41,7 +41,10 @@ pub struct ContractInfoResponse { } impl ContractInfoResponse { - /// Convenience constructor for tests / mocks + /// Constructor for testing frameworks such as cw-multi-test. + /// This is required because query response types should be #[non_exhaustive]. + /// As a contract developer you should not need this constructor since + /// query responses are constructed for you via deserialization. #[doc(hidden)] pub fn new(code_id: u64, creator: impl Into) -> Self { Self { From 629aa722fc16721b0c82d394788baa0f00f3dd42 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 21 Dec 2022 17:56:36 +0100 Subject: [PATCH 078/187] Add CHANGELOG entry for SupplyResponse::new --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 806a673192..f8b77d714d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to - cosmwasm-std: Upgrade `serde-json-wasm` dependency to 0.5.0 which adds map support to `to_vec`/`to_binary` and friends. - cosmwasm-std: Implement `AsRef<[u8]>` for `Binary` and `HexBinary` ([#1550]). +- cosmwasm-std: Add constructor `SupplyResponse::new` ([#1552]). [#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436 [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 @@ -30,6 +31,7 @@ and this project adheres to [#1478]: https://github.com/CosmWasm/cosmwasm/pull/1478 [#1533]: https://github.com/CosmWasm/cosmwasm/pull/1533 [#1550]: https://github.com/CosmWasm/cosmwasm/issues/1550 +[#1552]: https://github.com/CosmWasm/cosmwasm/pull/1552 [#1554]: https://github.com/CosmWasm/cosmwasm/pull/1554 ### Changed From 25349990bf7b1adb90e39eca2b6849420fe5dd65 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Fri, 23 Dec 2022 14:13:53 +0100 Subject: [PATCH 079/187] Bump clippy to and fix some new warnings --- .circleci/config.yml | 2 +- contracts/crypto-verify/src/ethereum.rs | 2 +- packages/crypto/benches/main.rs | 2 +- packages/crypto/src/secp256k1.rs | 4 ++-- packages/vm/src/cache.rs | 4 ++-- packages/vm/src/imports.rs | 4 +++- packages/vm/src/modules/file_system_cache.rs | 2 +- packages/vm/src/modules/pinned_memory_cache.rs | 2 +- packages/vm/src/wasm_backend/gatekeeper.rs | 6 +++--- packages/vm/src/wasm_backend/store.rs | 2 +- 10 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 926f083f3d..0c248018e2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -71,7 +71,7 @@ workflows: matrix: parameters: # Run with MSRV and some modern stable Rust - rust-version: ["1.60.0", "1.65.0"] + rust-version: ["1.60.0", "1.66.0"] - benchmarking: requires: - package_vm diff --git a/contracts/crypto-verify/src/ethereum.rs b/contracts/crypto-verify/src/ethereum.rs index b47fe49335..bc6d8981dd 100644 --- a/contracts/crypto-verify/src/ethereum.rs +++ b/contracts/crypto-verify/src/ethereum.rs @@ -19,7 +19,7 @@ pub fn verify_transaction( ) -> StdResult { let sign_bytes = serialize_unsigned_transaction(to, nonce, gas, gas_price, value, data, chain_id); - let hash = Keccak256::digest(&sign_bytes); + let hash = Keccak256::digest(sign_bytes); let mut rs: Vec = Vec::with_capacity(64); rs.resize(32 - r.len(), 0); // Left pad r to 32 bytes rs.extend_from_slice(r); diff --git a/packages/crypto/benches/main.rs b/packages/crypto/benches/main.rs index 9135759c5f..e1efbfe2a3 100644 --- a/packages/crypto/benches/main.rs +++ b/packages/crypto/benches/main.rs @@ -78,7 +78,7 @@ fn bench_crypto(c: &mut Criterion) { group.bench_function("secp256k1_verify", |b| { let message = hex::decode(COSMOS_SECP256K1_MSG_HEX).unwrap(); - let message_hash = Sha256::digest(&message); + let message_hash = Sha256::digest(message); let signature = hex::decode(COSMOS_SECP256K1_SIGNATURE_HEX).unwrap(); let public_key = base64::decode(COSMOS_SECP256K1_PUBKEY_BASE64).unwrap(); b.iter(|| { diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index dda5ce2571..4783de67c9 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -253,7 +253,7 @@ mod tests { let signature = hex::decode(sig).unwrap(); // Explicit hash - let message_hash = Sha256::digest(&message); + let message_hash = Sha256::digest(message); // secp256k1_verify works assert!( @@ -290,7 +290,7 @@ mod tests { let message = hex::decode(&encoded.message).unwrap(); let hash = hex::decode(&encoded.message_hash).unwrap(); - let message_hash = Sha256::digest(&message); + let message_hash = Sha256::digest(message); assert_eq!(hash.as_slice(), message_hash.as_slice()); let signature = hex::decode(&encoded.signature).unwrap(); diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs index ea56e30df4..f971530ba9 100644 --- a/packages/vm/src/cache.rs +++ b/packages/vm/src/cache.rs @@ -336,7 +336,7 @@ fn save_wasm_to_disk(dir: impl Into, wasm: &[u8]) -> VmResult // calculate filename let checksum = Checksum::generate(wasm); let filename = checksum.to_hex(); - let filepath = dir.into().join(&filename); + let filepath = dir.into().join(filename); // write data to file // Since the same filename (a collision resistent hash) cannot be generated from two different byte codes @@ -561,7 +561,7 @@ mod tests { .path() .join(STATE_DIR) .join(WASM_DIR) - .join(&checksum.to_hex()); + .join(checksum.to_hex()); let mut file = OpenOptions::new().write(true).open(filepath).unwrap(); file.write_all(b"broken data").unwrap(); diff --git a/packages/vm/src/imports.rs b/packages/vm/src/imports.rs index 357fbe024f..4473282ce6 100644 --- a/packages/vm/src/imports.rs +++ b/packages/vm/src/imports.rs @@ -225,6 +225,7 @@ pub fn do_secp256k1_verify( let gas_info = GasInfo::with_cost(env.gas_config.secp256k1_verify_cost); process_gas_info::(env, gas_info)?; let result = secp256k1_verify(&hash, &signature, &pubkey); + #[allow(clippy::bool_to_int_with_if)] Ok(result.map_or_else( |err| match err { CryptoError::InvalidHashFormat { .. } @@ -285,6 +286,7 @@ pub fn do_ed25519_verify( let gas_info = GasInfo::with_cost(env.gas_config.ed25519_verify_cost); process_gas_info::(env, gas_info)?; let result = ed25519_verify(&message, &signature, &pubkey); + #[allow(clippy::bool_to_int_with_if)] Ok(result.map_or_else( |err| match err { CryptoError::InvalidPubkeyFormat { .. } @@ -588,7 +590,7 @@ mod tests { let result = do_db_read(&env, key_ptr); let value_ptr = result.unwrap(); assert!(value_ptr > 0); - assert_eq!(force_read(&env, value_ptr as u32), VALUE1); + assert_eq!(force_read(&env, value_ptr), VALUE1); } #[test] diff --git a/packages/vm/src/modules/file_system_cache.rs b/packages/vm/src/modules/file_system_cache.rs index 406a0ebcc3..a529e432de 100644 --- a/packages/vm/src/modules/file_system_cache.rs +++ b/packages/vm/src/modules/file_system_cache.rs @@ -106,7 +106,7 @@ impl FileSystemCache { let filename = checksum.to_hex(); let file_path = self.latest_modules_path().join(filename); - let result = unsafe { Module::deserialize_from_file(store, &file_path) }; + let result = unsafe { Module::deserialize_from_file(store, file_path) }; match result { Ok(module) => Ok(Some(module)), Err(DeserializeError::Io(err)) => match err.kind() { diff --git a/packages/vm/src/modules/pinned_memory_cache.rs b/packages/vm/src/modules/pinned_memory_cache.rs index 61ef8cc746..2f1a976d82 100644 --- a/packages/vm/src/modules/pinned_memory_cache.rs +++ b/packages/vm/src/modules/pinned_memory_cache.rs @@ -52,7 +52,7 @@ impl PinnedMemoryCache { /// This is based on the values provided with `store`. No actual /// memory size is measured here. pub fn size(&self) -> usize { - self.modules.iter().map(|(_, module)| module.size).sum() + self.modules.values().map(|module| module.size).sum() } } diff --git a/packages/vm/src/wasm_backend/gatekeeper.rs b/packages/vm/src/wasm_backend/gatekeeper.rs index c5c82efaff..897a500beb 100644 --- a/packages/vm/src/wasm_backend/gatekeeper.rs +++ b/packages/vm/src/wasm_backend/gatekeeper.rs @@ -711,7 +711,7 @@ mod tests { let mut compiler_config = Cranelift::default(); compiler_config.push_middleware(deterministic); let store = Store::new(&Universal::new(compiler_config).engine()); - let result = Module::new(&store, &wasm); + let result = Module::new(&store, wasm); assert!(result.is_ok()); } @@ -732,7 +732,7 @@ mod tests { let mut compiler_config = Cranelift::default(); compiler_config.push_middleware(deterministic); let store = Store::new(&Universal::new(compiler_config).engine()); - let result = Module::new(&store, &wasm); + let result = Module::new(&store, wasm); assert!(result .unwrap_err() .to_string() @@ -759,7 +759,7 @@ mod tests { let mut compiler_config = Cranelift::default(); compiler_config.push_middleware(deterministic); let store = Store::new(&Universal::new(compiler_config).engine()); - let result = Module::new(&store, &wasm); + let result = Module::new(&store, wasm); assert!(result .unwrap_err() .to_string() diff --git a/packages/vm/src/wasm_backend/store.rs b/packages/vm/src/wasm_backend/store.rs index 570692b590..1f98f6bd1c 100644 --- a/packages/vm/src/wasm_backend/store.rs +++ b/packages/vm/src/wasm_backend/store.rs @@ -171,7 +171,7 @@ mod tests { let serialized = { let wasm = wat::parse_str(EXPORTED_MEMORY_WAT).unwrap(); let store = make_compile_time_store(None, &[]); - let module = Module::new(&store, &wasm).unwrap(); + let module = Module::new(&store, wasm).unwrap(); module.serialize().unwrap() }; From e348516b88f8a90f5e564646210e1e1b92fe261e Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 2 Jan 2023 15:17:35 +0100 Subject: [PATCH 080/187] Create constants ED25519_VERIFY_CODE_{IN,}VALID and SECP256K1_VERIFY_CODE_{IN,}VALID --- packages/vm/src/imports.rs | 59 +++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/packages/vm/src/imports.rs b/packages/vm/src/imports.rs index 4473282ce6..7932887928 100644 --- a/packages/vm/src/imports.rs +++ b/packages/vm/src/imports.rs @@ -212,6 +212,12 @@ pub fn do_addr_humanize( } } +/// Return code (error code) for a valid signature +const SECP256K1_VERIFY_CODE_VALID: u32 = 0; + +/// Return code (error code) for an invalid signature +const SECP256K1_VERIFY_CODE_INVALID: u32 = 1; + pub fn do_secp256k1_verify( env: &Environment, hash_ptr: u32, @@ -225,9 +231,15 @@ pub fn do_secp256k1_verify( let gas_info = GasInfo::with_cost(env.gas_config.secp256k1_verify_cost); process_gas_info::(env, gas_info)?; let result = secp256k1_verify(&hash, &signature, &pubkey); - #[allow(clippy::bool_to_int_with_if)] - Ok(result.map_or_else( - |err| match err { + let code = match result { + Ok(valid) => { + if valid { + SECP256K1_VERIFY_CODE_VALID + } else { + SECP256K1_VERIFY_CODE_INVALID + } + } + Err(err) => match err { CryptoError::InvalidHashFormat { .. } | CryptoError::InvalidPubkeyFormat { .. } | CryptoError::InvalidSignatureFormat { .. } @@ -236,8 +248,8 @@ pub fn do_secp256k1_verify( panic!("Error must not happen for this call") } }, - |valid| if valid { 0 } else { 1 }, - )) + }; + Ok(code) } pub fn do_secp256k1_recover_pubkey( @@ -273,6 +285,12 @@ pub fn do_secp256k1_recover_pubkey( } } +/// Return code (error code) for a valid signature +const ED25519_VERIFY_CODE_VALID: u32 = 0; + +/// Return code (error code) for an invalid signature +const ED25519_VERIFY_CODE_INVALID: u32 = 1; + pub fn do_ed25519_verify( env: &Environment, message_ptr: u32, @@ -286,9 +304,15 @@ pub fn do_ed25519_verify( let gas_info = GasInfo::with_cost(env.gas_config.ed25519_verify_cost); process_gas_info::(env, gas_info)?; let result = ed25519_verify(&message, &signature, &pubkey); - #[allow(clippy::bool_to_int_with_if)] - Ok(result.map_or_else( - |err| match err { + let code = match result { + Ok(valid) => { + if valid { + ED25519_VERIFY_CODE_VALID + } else { + ED25519_VERIFY_CODE_INVALID + } + } + Err(err) => match err { CryptoError::InvalidPubkeyFormat { .. } | CryptoError::InvalidSignatureFormat { .. } | CryptoError::GenericErr { .. } => err.code(), @@ -298,8 +322,8 @@ pub fn do_ed25519_verify( panic!("Error must not happen for this call") } }, - |valid| if valid { 0 } else { 1 }, - )) + }; + Ok(code) } pub fn do_ed25519_batch_verify( @@ -336,8 +360,15 @@ pub fn do_ed25519_batch_verify( let gas_info = GasInfo::with_cost(max(gas_cost, env.gas_config.ed25519_verify_cost)); process_gas_info::(env, gas_info)?; let result = ed25519_batch_verify(&messages, &signatures, &public_keys); - Ok(result.map_or_else( - |err| match err { + let code = match result { + Ok(valid) => { + if valid { + ED25519_VERIFY_CODE_VALID + } else { + ED25519_VERIFY_CODE_INVALID + } + } + Err(err) => match err { CryptoError::BatchErr { .. } | CryptoError::InvalidPubkeyFormat { .. } | CryptoError::InvalidSignatureFormat { .. } @@ -346,8 +377,8 @@ pub fn do_ed25519_batch_verify( panic!("Error must not happen for this call") } }, - |valid| (!valid).into(), - )) + }; + Ok(code) } /// Prints a debug message to console. From a3f9ad780ee0da27deedcb8a3be518e018b96460 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 2 Jan 2023 14:52:36 +0100 Subject: [PATCH 081/187] Add QueryResponseType trait --- packages/std/src/query/bank.rs | 23 ++++++++++------------- packages/std/src/query/mod.rs | 1 + packages/std/src/query/query_response.rs | 16 ++++++++++++++++ packages/std/src/query/wasm.rs | 6 +++++- 4 files changed, 32 insertions(+), 14 deletions(-) create mode 100644 packages/std/src/query/query_response.rs diff --git a/packages/std/src/query/bank.rs b/packages/std/src/query/bank.rs index e53dbcc9b0..b3a43e11d5 100644 --- a/packages/std/src/query/bank.rs +++ b/packages/std/src/query/bank.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; use crate::Coin; +use super::query_response::QueryResponseType; + #[non_exhaustive] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -22,7 +24,7 @@ pub enum BankQuery { } #[cfg(feature = "cosmwasm_1_1")] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] #[non_exhaustive] pub struct SupplyResponse { @@ -32,18 +34,9 @@ pub struct SupplyResponse { } #[cfg(feature = "cosmwasm_1_1")] -impl SupplyResponse { - /// Constructor for testing frameworks such as cw-multi-test. - /// This is required because query response types should be #[non_exhaustive]. - /// As a contract developer you should not need this constructor since - /// query responses are constructed for you via deserialization. - #[doc(hidden)] - pub fn new(amount: Coin) -> Self { - Self { amount } - } -} +impl QueryResponseType for SupplyResponse {} -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct BalanceResponse { /// Always returns a Coin with the requested denom. @@ -51,9 +44,13 @@ pub struct BalanceResponse { pub amount: Coin, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +impl QueryResponseType for BalanceResponse {} + +#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct AllBalanceResponse { /// Returns all non-zero coins held by this account. pub amount: Vec, } + +impl QueryResponseType for AllBalanceResponse {} diff --git a/packages/std/src/query/mod.rs b/packages/std/src/query/mod.rs index 67a2fcdb0d..5ca17fe35b 100644 --- a/packages/std/src/query/mod.rs +++ b/packages/std/src/query/mod.rs @@ -7,6 +7,7 @@ use crate::Empty; mod bank; mod ibc; +mod query_response; mod staking; mod wasm; diff --git a/packages/std/src/query/query_response.rs b/packages/std/src/query/query_response.rs new file mode 100644 index 0000000000..dca2e766c9 --- /dev/null +++ b/packages/std/src/query/query_response.rs @@ -0,0 +1,16 @@ +use serde::de::DeserializeOwned; + +/// A marker trait for query response types. +/// +/// Those types have in common that they should be `#[non_exhaustive]` in order +/// to allow adding fields in a backwards compatible way. In contracts they are +/// only constructed through deserialization. We want to make it hard for +/// contract developers to construct those types themselves as this is most likely +/// not what they should do. +/// +/// In hosts they are constructed as follows: +/// - wasmvm: Go types with the same JSON layout +/// - multi-test/cw-sdk: create a default instance and mutate the fields +/// +/// This trait is crate-internal and can change any time. +pub(crate) trait QueryResponseType: Default + DeserializeOwned {} diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index fee0334635..09302d0563 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; use crate::Binary; +use super::query_response::QueryResponseType; + #[non_exhaustive] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -27,7 +29,7 @@ pub enum WasmQuery { } #[non_exhaustive] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, JsonSchema)] pub struct ContractInfoResponse { pub code_id: u64, /// address that instantiated this contract @@ -40,6 +42,8 @@ pub struct ContractInfoResponse { pub ibc_port: Option, } +impl QueryResponseType for ContractInfoResponse {} + impl ContractInfoResponse { /// Constructor for testing frameworks such as cw-multi-test. /// This is required because query response types should be #[non_exhaustive]. From 34f78d3613d17d9b72cc49a24ded2354b9eacd68 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 2 Jan 2023 14:55:28 +0100 Subject: [PATCH 082/187] Adapt CHANGELOG entry and add follow-up PR link --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8b77d714d..451055879c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,8 @@ and this project adheres to - cosmwasm-std: Upgrade `serde-json-wasm` dependency to 0.5.0 which adds map support to `to_vec`/`to_binary` and friends. - cosmwasm-std: Implement `AsRef<[u8]>` for `Binary` and `HexBinary` ([#1550]). -- cosmwasm-std: Add constructor `SupplyResponse::new` ([#1552]). +- cosmwasm-std: Allow constructing `SupplyResponse` via a `Default` + implementation ([#1552], [#1560]). [#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436 [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 @@ -33,6 +34,7 @@ and this project adheres to [#1550]: https://github.com/CosmWasm/cosmwasm/issues/1550 [#1552]: https://github.com/CosmWasm/cosmwasm/pull/1552 [#1554]: https://github.com/CosmWasm/cosmwasm/pull/1554 +[#1560]: https://github.com/CosmWasm/cosmwasm/pull/1560 ### Changed From 54dc68c8b316699b8662c592079d21d5634268b5 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 2 Jan 2023 15:00:05 +0100 Subject: [PATCH 083/187] Improve doc string of ContractInfo --- contracts/reflect/schema/raw/query.json | 2 +- contracts/reflect/schema/reflect.json | 2 +- packages/std/src/query/wasm.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/reflect/schema/raw/query.json b/contracts/reflect/schema/raw/query.json index 04512e6f3f..914555088d 100644 --- a/contracts/reflect/schema/raw/query.json +++ b/contracts/reflect/schema/raw/query.json @@ -547,7 +547,7 @@ "additionalProperties": false }, { - "description": "returns a ContractInfoResponse with metadata on the contract from the runtime", + "description": "Returns a [`ContractInfoResponse`] with metadata on the contract from the runtime", "type": "object", "required": [ "contract_info" diff --git a/contracts/reflect/schema/reflect.json b/contracts/reflect/schema/reflect.json index ab4e2c0cc6..603c401cd4 100644 --- a/contracts/reflect/schema/reflect.json +++ b/contracts/reflect/schema/reflect.json @@ -1411,7 +1411,7 @@ "additionalProperties": false }, { - "description": "returns a ContractInfoResponse with metadata on the contract from the runtime", + "description": "Returns a [`ContractInfoResponse`] with metadata on the contract from the runtime", "type": "object", "required": [ "contract_info" diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index 09302d0563..6bd52dde91 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -24,7 +24,7 @@ pub enum WasmQuery { /// Key is the raw key used in the contracts Storage key: Binary, }, - /// returns a ContractInfoResponse with metadata on the contract from the runtime + /// Returns a [`ContractInfoResponse`] with metadata on the contract from the runtime ContractInfo { contract_addr: String }, } From 71b1f5e129b6fc391d8d06dbb5fabeab7aec7ef5 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 2 Jan 2023 15:00:17 +0100 Subject: [PATCH 084/187] Deprecate ContractInfoResponse::new --- packages/std/src/query/wasm.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index 6bd52dde91..153b35f51c 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -50,13 +50,13 @@ impl ContractInfoResponse { /// As a contract developer you should not need this constructor since /// query responses are constructed for you via deserialization. #[doc(hidden)] + #[deprecated( + note = "Use ContractInfoResponse::default() and mutate the fields you want to set." + )] pub fn new(code_id: u64, creator: impl Into) -> Self { - Self { - code_id, - creator: creator.into(), - admin: None, - pinned: false, - ibc_port: None, - } + let mut out = ContractInfoResponse::default(); + out.code_id = code_id; + out.creator = creator.into(); + out } } From 03f803d8e17fba3e9a5539caafbd3243e9f9b8fd Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 2 Jan 2023 16:15:16 +0100 Subject: [PATCH 085/187] Make clippy happy --- packages/std/src/query/wasm.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index 153b35f51c..2be597ae65 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -54,9 +54,10 @@ impl ContractInfoResponse { note = "Use ContractInfoResponse::default() and mutate the fields you want to set." )] pub fn new(code_id: u64, creator: impl Into) -> Self { - let mut out = ContractInfoResponse::default(); - out.code_id = code_id; - out.creator = creator.into(); - out + ContractInfoResponse { + code_id, + creator: creator.into(), + ..Default::default() + } } } From 49ae7cf2b72e6f8cf4fe9ab1d860ce3d610d0276 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 3 Jan 2023 15:38:40 +0100 Subject: [PATCH 086/187] Enable cosmwasm_1_2 in coverage testing --- .circleci/config.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0c248018e2..f9de137824 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -956,8 +956,13 @@ jobs: mkdir -p reports/schema mkdir -p reports/std mkdir -p reports/storage + CRYPTO=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/crypto --packages cosmwasm-crypto" + DERIVE=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/derive --packages cosmwasm-derive" + SCHEMA=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/schema --packages cosmwasm-schema" + STD=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/std --packages cosmwasm-std --features cosmwasm_1_2" + STORAGE="cargo tarpaulin --skip-clean --out Xml --output-dir reports/storage --packages cosmwasm-storage" docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.21.0 \ - sh -c "cargo tarpaulin --skip-clean --out Xml --output-dir reports/crypto --packages cosmwasm-crypto && cargo tarpaulin --skip-clean --out Xml --output-dir reports/derive --packages cosmwasm-derive && cargo tarpaulin --skip-clean --out Xml --output-dir reports/schema --packages cosmwasm-schema && cargo tarpaulin --skip-clean --out Xml --output-dir reports/std --packages cosmwasm-std && cargo tarpaulin --skip-clean --out Xml --output-dir reports/storage --packages cosmwasm-storage" + sh -c "$CRYPTO && $DERIVE && $SCHEMA && $STD && $STORAGE" - codecov/upload: file: reports/crypto/cobertura.xml flags: cosmwasm-crypto From a4c54e40939075d7a6d04e7dd8fc33ce711375ee Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 3 Jan 2023 16:05:07 +0100 Subject: [PATCH 087/187] Add more features to coverage --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f9de137824..ad9fc54090 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -959,7 +959,7 @@ jobs: CRYPTO=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/crypto --packages cosmwasm-crypto" DERIVE=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/derive --packages cosmwasm-derive" SCHEMA=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/schema --packages cosmwasm-schema" - STD=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/std --packages cosmwasm-std --features cosmwasm_1_2" + STD=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/std --packages cosmwasm-std --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2" STORAGE="cargo tarpaulin --skip-clean --out Xml --output-dir reports/storage --packages cosmwasm-storage" docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.21.0 \ sh -c "$CRYPTO && $DERIVE && $SCHEMA && $STD && $STORAGE" From 358dc3eedfda57395718855c368017f109435173 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 3 Jan 2023 18:51:40 +0100 Subject: [PATCH 088/187] Bump min thiserror version to 1.0.26 for consistency --- contracts/cyberpunk/Cargo.toml | 2 +- contracts/floaty/Cargo.toml | 2 +- contracts/hackatom/Cargo.toml | 2 +- contracts/reflect/Cargo.toml | 2 +- packages/crypto/Cargo.toml | 2 +- packages/schema/Cargo.toml | 2 +- packages/std/Cargo.toml | 2 +- packages/vm/Cargo.toml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/contracts/cyberpunk/Cargo.toml b/contracts/cyberpunk/Cargo.toml index b4cdca0d35..32f43bf413 100644 --- a/contracts/cyberpunk/Cargo.toml +++ b/contracts/cyberpunk/Cargo.toml @@ -32,7 +32,7 @@ backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"] cosmwasm-schema = { path = "../../packages/schema" } cosmwasm-std = { path = "../../packages/std", default-features = false, features = ["abort"] } rust-argon2 = "0.8" -thiserror = "1.0" +thiserror = "1.0.26" [dev-dependencies] cosmwasm-storage = { path = "../../packages/storage", default-features = false } diff --git a/contracts/floaty/Cargo.toml b/contracts/floaty/Cargo.toml index e16a126438..b16a2c282b 100644 --- a/contracts/floaty/Cargo.toml +++ b/contracts/floaty/Cargo.toml @@ -35,7 +35,7 @@ cosmwasm-schema = { path = "../../packages/schema" } cosmwasm-std = { path = "../../packages/std" } schemars = "0.8.3" serde = { version = "1.0.103", default-features = false, features = ["derive"] } -thiserror = "1.0" +thiserror = "1.0.26" [dev-dependencies] cosmwasm-storage = { path = "../../packages/storage" } diff --git a/contracts/hackatom/Cargo.toml b/contracts/hackatom/Cargo.toml index 1a91f1100f..fa1b8ccf7d 100644 --- a/contracts/hackatom/Cargo.toml +++ b/contracts/hackatom/Cargo.toml @@ -36,7 +36,7 @@ cosmwasm-std = { path = "../../packages/std", default-features = false, features schemars = "0.8.3" serde = { version = "1.0.103", default-features = false, features = ["derive"] } sha2 = "0.10" -thiserror = "1.0" +thiserror = "1.0.26" [dev-dependencies] cosmwasm-storage = { path = "../../packages/storage", default-features = false } diff --git a/contracts/reflect/Cargo.toml b/contracts/reflect/Cargo.toml index eab872fe3e..c331845ac1 100644 --- a/contracts/reflect/Cargo.toml +++ b/contracts/reflect/Cargo.toml @@ -38,7 +38,7 @@ cosmwasm-std = { path = "../../packages/std", default-features = false, features cosmwasm-storage = { path = "../../packages/storage", default-features = false } schemars = "0.8.3" serde = { version = "=1.0.103", default-features = false, features = ["derive"] } -thiserror = "1.0" +thiserror = "1.0.26" [dev-dependencies] cosmwasm-vm = { path = "../../packages/vm", default-features = false, features = ["stargate"] } diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index 5b11b33ead..441efe5197 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -23,7 +23,7 @@ k256 = { version = "0.11.1", features = ["ecdsa"] } ed25519-zebra = "3" digest = "0.10" rand_core = { version = "0.6", features = ["getrandom"] } -thiserror = "1.0.13" +thiserror = "1.0.26" [dev-dependencies] criterion = "0.3" diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index eb96253d69..b883c13463 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -12,7 +12,7 @@ cosmwasm-schema-derive = { version = "=1.2.0-beta.0", path = "../schema-derive" schemars = "0.8.3" serde = "1.0" serde_json = "1.0.40" -thiserror = "1.0.13" +thiserror = "1.0.26" [dev-dependencies] anyhow = "1.0.57" diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 7ea7191bed..8a8c1f0615 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -50,7 +50,7 @@ schemars = "0.8.3" sha2 = "0.10.3" serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } serde-json-wasm = { version = "0.5.0" } -thiserror = "1.0.13" +thiserror = "1.0.26" uint = "0.9.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index b00693b1fa..fcfdcb8ac9 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -49,7 +49,7 @@ schemars = "0.8.3" serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } serde_json = "1.0.40" sha2 = "0.10.3" -thiserror = "1.0.13" +thiserror = "1.0.26" wasmer = { version = "=2.3.0", default-features = false, features = ["cranelift", "universal", "singlepass"] } wasmer-middlewares = "=2.3.0" loupe = "0.1.3" From 2c1035529140d9c06a912e6ee5fcc66d2bcec5a8 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 4 Jan 2023 10:20:06 +0100 Subject: [PATCH 089/187] Add Never type for to avoid ibc_packet_receive errors --- CHANGELOG.md | 3 ++ IBC.md | 52 +++++++++++++++------------ contracts/ibc-reflect-send/src/ibc.rs | 4 +-- contracts/ibc-reflect/src/contract.rs | 4 +-- packages/std/src/lib.rs | 2 ++ packages/std/src/never.rs | 21 +++++++++++ 6 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 packages/std/src/never.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 451055879c..3839dbc6c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ and this project adheres to - cosmwasm-std: Implement `AsRef<[u8]>` for `Binary` and `HexBinary` ([#1550]). - cosmwasm-std: Allow constructing `SupplyResponse` via a `Default` implementation ([#1552], [#1560]). +- cosmwasm-std: Add `Never` type which cannot be instantiated. This can be used + as the error type for the `ibc_packet_receive` to gain confidence that the + implementations never errors and the transaction does not get reverted. [#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436 [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 diff --git a/IBC.md b/IBC.md index 41497bdd48..fcefc92ffe 100644 --- a/IBC.md +++ b/IBC.md @@ -264,7 +264,9 @@ pub fn ibc_packet_receive( deps: DepsMut, env: Env, msg: IbcPacketReceiveMsg, -) -> StdResult { } +) -> Result { + // ... +} ``` This is a very special entry point as it has a unique workflow. (Please see the @@ -350,27 +352,33 @@ produced 3 suggestions on how to handle errors and rollbacks _inside [main dispatch loop in `ibc-reflect`](https://github.com/CosmWasm/cosmwasm/blob/cd784cd1148ee395574f3e564f102d0d7b5adcc3/contracts/ibc-reflect/src/contract.rs#L217-L248): ```rust - (|| { - // which local channel did this packet come on - let caller = packet.dest.channel_id; - let msg: PacketMsg = from_slice(&packet.data)?; - match msg { - PacketMsg::Dispatch { msgs } => receive_dispatch(deps, caller, msgs), - PacketMsg::WhoAmI {} => receive_who_am_i(deps, caller), - PacketMsg::Balances {} => receive_balances(deps, caller), - } - })() - .or_else(|e| { - // we try to capture all app-level errors and convert them into - // acknowledgement packets that contain an error code. - let acknowledgement = encode_ibc_error(format!("invalid packet: {}", e)); - Ok(IbcReceiveResponse { - acknowledgement, - submessages: vec![], - messages: vec![], - attributes: vec![], - }) - }) + pub fn ibc_packet_receive( + deps: DepsMut, + _env: Env, + msg: IbcPacketReceiveMsg, + ) -> Result { + (|| { + // which local channel did this packet come on + let caller = packet.dest.channel_id; + let msg: PacketMsg = from_slice(&packet.data)?; + match msg { + PacketMsg::Dispatch { msgs } => receive_dispatch(deps, caller, msgs), + PacketMsg::WhoAmI {} => receive_who_am_i(deps, caller), + PacketMsg::Balances {} => receive_balances(deps, caller), + } + })() + .or_else(|e| { + // we try to capture all app-level errors and convert them into + // acknowledgement packets that contain an error code. + let acknowledgement = encode_ibc_error(format!("invalid packet: {}", e)); + Ok(IbcReceiveResponse { + acknowledgement, + submessages: vec![], + messages: vec![], + attributes: vec![], + }) + }) + } ``` 2. If we modify state with an external call, we need to wrap it in a diff --git a/contracts/ibc-reflect-send/src/ibc.rs b/contracts/ibc-reflect-send/src/ibc.rs index dca8cbf78c..2284c48457 100644 --- a/contracts/ibc-reflect-send/src/ibc.rs +++ b/contracts/ibc-reflect-send/src/ibc.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{ entry_point, from_slice, to_binary, DepsMut, Env, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcMsg, IbcOrder, IbcPacketAckMsg, - IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, StdError, StdResult, + IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, Never, StdError, StdResult, }; use crate::ibc_msg::{ @@ -95,7 +95,7 @@ pub fn ibc_packet_receive( _deps: DepsMut, _env: Env, _packet: IbcPacketReceiveMsg, -) -> StdResult { +) -> Result { Ok(IbcReceiveResponse::new() .set_ack(b"{}") .add_attribute("action", "ibc_packet_ack")) diff --git a/contracts/ibc-reflect/src/contract.rs b/contracts/ibc-reflect/src/contract.rs index a43e581461..04750f00ec 100644 --- a/contracts/ibc-reflect/src/contract.rs +++ b/contracts/ibc-reflect/src/contract.rs @@ -2,7 +2,7 @@ use cosmwasm_std::{ entry_point, from_slice, to_binary, wasm_execute, BankMsg, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, Event, Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcOrder, IbcPacketAckMsg, - IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Order, + IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Never, Order, QueryResponse, Reply, Response, StdError, StdResult, SubMsg, SubMsgResponse, SubMsgResult, WasmMsg, }; @@ -233,7 +233,7 @@ pub fn ibc_packet_receive( deps: DepsMut, _env: Env, msg: IbcPacketReceiveMsg, -) -> StdResult { +) -> Result { // put this in a closure so we can convert all error responses into acknowledgements (|| { let packet = msg.packet; diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 4a03d3025a..809e87484f 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -15,6 +15,7 @@ mod import_helpers; #[cfg(feature = "iterator")] mod iterator; mod math; +mod never; mod panic; mod query; mod results; @@ -48,6 +49,7 @@ pub use crate::math::{ Decimal, Decimal256, Decimal256RangeExceeded, DecimalRangeExceeded, Fraction, Isqrt, Uint128, Uint256, Uint512, Uint64, }; +pub use crate::never::Never; #[cfg(feature = "cosmwasm_1_1")] pub use crate::query::SupplyResponse; pub use crate::query::{ diff --git a/packages/std/src/never.rs b/packages/std/src/never.rs new file mode 100644 index 0000000000..60b5861f85 --- /dev/null +++ b/packages/std/src/never.rs @@ -0,0 +1,21 @@ +/// Never can never be instantiated. This can be used in places +/// where we want to ensure that no error is returned, such as +/// the `ibc_packet_receive` entry point. +/// +/// Once the ! type is stable, this is not needed anymore. +/// See . +pub enum Never {} + +impl core::fmt::Debug for Never { + fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + // This is unreachable because no instance of Never can exist + unreachable!() + } +} + +impl core::fmt::Display for Never { + fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + // This is unreachable because no instance of Never can exist + unreachable!() + } +} From a570cc417d6d073134a23c12b1edc05f2220b718 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 24 Nov 2022 10:22:46 +0100 Subject: [PATCH 090/187] Improve Never documentation --- packages/std/src/never.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/std/src/never.rs b/packages/std/src/never.rs index 60b5861f85..fa30f18287 100644 --- a/packages/std/src/never.rs +++ b/packages/std/src/never.rs @@ -2,10 +2,14 @@ /// where we want to ensure that no error is returned, such as /// the `ibc_packet_receive` entry point. /// +/// In contrast to `Empty`, this does not have a JSON schema +/// and cannot be used for message and query types. +/// /// Once the ! type is stable, this is not needed anymore. /// See . pub enum Never {} +// The Debug implementation is needed to allow the use of `Result::unwrap`. impl core::fmt::Debug for Never { fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { // This is unreachable because no instance of Never can exist @@ -13,6 +17,8 @@ impl core::fmt::Debug for Never { } } +// The Display implementation is needed to fulfill the ToString requirement of +// entry point errors: `Result, E>` with `E: ToString`. impl core::fmt::Display for Never { fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { // This is unreachable because no instance of Never can exist From cd87530ca589c5c58cc9bd15bd2eb3678f7995e0 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 2 Jan 2023 17:08:11 +0100 Subject: [PATCH 091/187] Make unreachable implementation type-safe --- packages/std/src/never.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/std/src/never.rs b/packages/std/src/never.rs index fa30f18287..4b9f6c7b8a 100644 --- a/packages/std/src/never.rs +++ b/packages/std/src/never.rs @@ -12,8 +12,8 @@ pub enum Never {} // The Debug implementation is needed to allow the use of `Result::unwrap`. impl core::fmt::Debug for Never { fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - // This is unreachable because no instance of Never can exist - unreachable!() + // Unreachable because no instance of Never can exist + match *self {} } } @@ -21,7 +21,7 @@ impl core::fmt::Debug for Never { // entry point errors: `Result, E>` with `E: ToString`. impl core::fmt::Display for Never { fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - // This is unreachable because no instance of Never can exist - unreachable!() + // Unreachable because no instance of Never can exist + match *self {} } } From 2b8c55333d8c7077cd206691f416c4982e70f368 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 2 Jan 2023 17:13:17 +0100 Subject: [PATCH 092/187] Improve CHANGELOG --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3839dbc6c6..8292e9dfea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,13 +26,15 @@ and this project adheres to - cosmwasm-std: Allow constructing `SupplyResponse` via a `Default` implementation ([#1552], [#1560]). - cosmwasm-std: Add `Never` type which cannot be instantiated. This can be used - as the error type for the `ibc_packet_receive` to gain confidence that the - implementations never errors and the transaction does not get reverted. + as the error type for `ibc_packet_receive` or `ibc_packet_ack` to gain + confidence that the implementations never errors and the transaction does not + get reverted. ([#1513]) [#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436 [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 [#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 [#1478]: https://github.com/CosmWasm/cosmwasm/pull/1478 +[#1513]: https://github.com/CosmWasm/cosmwasm/pull/1513 [#1533]: https://github.com/CosmWasm/cosmwasm/pull/1533 [#1550]: https://github.com/CosmWasm/cosmwasm/issues/1550 [#1552]: https://github.com/CosmWasm/cosmwasm/pull/1552 From 5a6fec162b88cf46439d1319903bec55febc9e34 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 3 Jan 2023 14:26:34 +0100 Subject: [PATCH 093/187] Check workspace with different features --- devtools/check_workspace.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/devtools/check_workspace.sh b/devtools/check_workspace.sh index a9969ae5f8..7304866eed 100755 --- a/devtools/check_workspace.sh +++ b/devtools/check_workspace.sh @@ -7,8 +7,10 @@ cargo fmt (cd packages/derive && cargo check && cargo clippy --all-targets -- -D warnings) ( cd packages/std + # default, min, all cargo check - cargo check --features iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 + cargo check --no-default-features + cargo check --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 cargo wasm-debug cargo wasm-debug --features iterator,staking,stargate cargo clippy --all-targets --features iterator,staking,stargate -- -D warnings From e2814e55d9cc243f9bf600db5ef67f09031654c9 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 5 Jan 2023 16:00:29 +0100 Subject: [PATCH 094/187] Add new `WasmQuery::CodeInfo` --- CHANGELOG.md | 3 +++ packages/std/src/errors/system_error.rs | 6 ++++++ packages/std/src/lib.rs | 2 ++ packages/std/src/query/mod.rs | 2 ++ packages/std/src/query/wasm.rs | 23 +++++++++++++++++++++++ packages/std/src/testing/mock.rs | 23 ++++++++++++++++------- 6 files changed, 52 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8292e9dfea..5012273c5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ and this project adheres to as the error type for `ibc_packet_receive` or `ibc_packet_ack` to gain confidence that the implementations never errors and the transaction does not get reverted. ([#1513]) +- cosmwasm-std: Add new `WasmQuery::CodeInfo` to get the checksum of a code ID + ([#1561]). [#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436 [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 @@ -40,6 +42,7 @@ and this project adheres to [#1552]: https://github.com/CosmWasm/cosmwasm/pull/1552 [#1554]: https://github.com/CosmWasm/cosmwasm/pull/1554 [#1560]: https://github.com/CosmWasm/cosmwasm/pull/1560 +[#1561]: https://github.com/CosmWasm/cosmwasm/pull/1561 ### Changed diff --git a/packages/std/src/errors/system_error.rs b/packages/std/src/errors/system_error.rs index 27cd40f12e..97d7bba3cb 100644 --- a/packages/std/src/errors/system_error.rs +++ b/packages/std/src/errors/system_error.rs @@ -28,6 +28,11 @@ pub enum SystemError { /// The address that was attempted to query addr: String, }, + /// A Wasm code was not found. + NoSuchCode { + /// The code ID that is missing + code_id: u64, + }, Unknown {}, UnsupportedRequest { kind: String, @@ -52,6 +57,7 @@ impl std::fmt::Display for SystemError { String::from_utf8_lossy(response) ), SystemError::NoSuchContract { addr } => write!(f, "No such contract: {}", addr), + SystemError::NoSuchCode { code_id } => write!(f, "No such code: {}", code_id), SystemError::Unknown {} => write!(f, "Unknown system error"), SystemError::UnsupportedRequest { kind } => { write!(f, "Unsupported query type: {}", kind) diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 809e87484f..d40d25d68f 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -50,6 +50,8 @@ pub use crate::math::{ Uint256, Uint512, Uint64, }; pub use crate::never::Never; +#[cfg(feature = "cosmwasm_1_2")] +pub use crate::query::CodeInfoResponse; #[cfg(feature = "cosmwasm_1_1")] pub use crate::query::SupplyResponse; pub use crate::query::{ diff --git a/packages/std/src/query/mod.rs b/packages/std/src/query/mod.rs index 5ca17fe35b..50061df091 100644 --- a/packages/std/src/query/mod.rs +++ b/packages/std/src/query/mod.rs @@ -21,6 +21,8 @@ pub use staking::{ AllDelegationsResponse, AllValidatorsResponse, BondedDenomResponse, Delegation, DelegationResponse, FullDelegation, StakingQuery, Validator, ValidatorResponse, }; +#[cfg(feature = "cosmwasm_1_2")] +pub use wasm::CodeInfoResponse; pub use wasm::{ContractInfoResponse, WasmQuery}; #[non_exhaustive] diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index 2be597ae65..3cd5cb2378 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -26,6 +26,9 @@ pub enum WasmQuery { }, /// Returns a [`ContractInfoResponse`] with metadata on the contract from the runtime ContractInfo { contract_addr: String }, + /// Returns a [`CodeInfoResponse`] with metadata of the code + #[cfg(feature = "cosmwasm_1_2")] + CodeInfo { code_id: u64 }, } #[non_exhaustive] @@ -61,3 +64,23 @@ impl ContractInfoResponse { } } } + +/// The essential data from wasmd's [CodeInfo]/[CodeInfoResponse]. +/// +/// `code_hash`/`data_hash` was renamed to `checksum` to follow the CosmWasm +/// convention and naming in `instantiate2_address`. +/// +/// [CodeInfo]: https://github.com/CosmWasm/wasmd/blob/v0.30.0/proto/cosmwasm/wasm/v1/types.proto#L62-L72 +/// [CodeInfoResponse]: https://github.com/CosmWasm/wasmd/blob/v0.30.0/proto/cosmwasm/wasm/v1/query.proto#L184-L199 +#[non_exhaustive] +#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, JsonSchema)] +#[cfg(feature = "cosmwasm_1_2")] +pub struct CodeInfoResponse { + /// The address that initially stored the code + pub creator: String, + /// The hash of the Wasm blob + pub checksum: Binary, +} + +#[cfg(feature = "cosmwasm_1_2")] +impl QueryResponseType for CodeInfoResponse {} diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 1417b93d1f..41a64e0001 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -562,13 +562,22 @@ impl WasmQuerier { impl Default for WasmQuerier { fn default() -> Self { let handler = Box::from(|request: &WasmQuery| -> QuerierResult { - let addr = match request { - WasmQuery::Smart { contract_addr, .. } => contract_addr, - WasmQuery::Raw { contract_addr, .. } => contract_addr, - WasmQuery::ContractInfo { contract_addr, .. } => contract_addr, - } - .clone(); - SystemResult::Err(SystemError::NoSuchContract { addr }) + let err = match request { + WasmQuery::Smart { contract_addr, .. } => SystemError::NoSuchContract { + addr: contract_addr.clone(), + }, + WasmQuery::Raw { contract_addr, .. } => SystemError::NoSuchContract { + addr: contract_addr.clone(), + }, + WasmQuery::ContractInfo { contract_addr, .. } => SystemError::NoSuchContract { + addr: contract_addr.clone(), + }, + #[cfg(feature = "cosmwasm_1_2")] + WasmQuery::CodeInfo { code_id, .. } => { + SystemError::NoSuchCode { code_id: *code_id } + } + }; + SystemResult::Err(err) }); Self::new(handler) } From e92c8e506778b9c90185c703fbdade50e74fd67a Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 3 Jan 2023 14:57:41 +0100 Subject: [PATCH 095/187] Fix WasmQuery::CodeInfo testing code --- packages/std/src/testing/mock.rs | 48 ++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 41a64e0001..598881782b 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -1390,7 +1390,7 @@ mod tests { let any_addr = "foo".to_string(); - // Query WasmQuery::Raw + // By default, querier errors for WasmQuery::Raw let system_err = querier .query(&WasmQuery::Raw { contract_addr: any_addr.clone(), @@ -1402,7 +1402,7 @@ mod tests { err => panic!("Unexpected error: {:?}", err), } - // Query WasmQuery::Smart + // By default, querier errors for WasmQuery::Smart let system_err = querier .query(&WasmQuery::Smart { contract_addr: any_addr.clone(), @@ -1414,7 +1414,7 @@ mod tests { err => panic!("Unexpected error: {:?}", err), } - // Query WasmQuery::ContractInfo + // By default, querier errors for WasmQuery::ContractInfo let system_err = querier .query(&WasmQuery::ContractInfo { contract_addr: any_addr.clone(), @@ -1425,6 +1425,18 @@ mod tests { err => panic!("Unexpected error: {:?}", err), } + #[cfg(feature = "cosmwasm_1_2")] + { + // By default, querier errors for WasmQuery::CodeInfo + let system_err = querier + .query(&WasmQuery::CodeInfo { code_id: 4 }) + .unwrap_err(); + match system_err { + SystemError::NoSuchCode { code_id } => assert_eq!(code_id, 4), + err => panic!("Unexpected error: {:?}", err), + } + } + querier.update_handler(|request| { let constract1 = Addr::unchecked("contract1"); let mut storage1 = HashMap::::default(); @@ -1478,6 +1490,23 @@ mod tests { }) } } + #[cfg(feature = "cosmwasm_1_2")] + WasmQuery::CodeInfo { code_id } => { + let code_id = *code_id; + if code_id == 4 { + use crate::CodeInfoResponse; + let response = CodeInfoResponse { + creator: "lalala".into(), + checksum: Binary::from_base64( + "hM8ggQ/UKcr1iJjDIQ/LcXWaJ77N2uCNvehmjqL0cl0=", + ) + .unwrap(), + }; + SystemResult::Ok(ContractResult::Ok(to_binary(&response).unwrap())) + } else { + SystemResult::Err(SystemError::NoSuchCode { code_id }) + } + } } }); @@ -1534,6 +1563,19 @@ mod tests { ), res => panic!("Unexpected result: {:?}", res), } + + // WasmQuery::ContractInfo + #[cfg(feature = "cosmwasm_1_2")] + { + let result = querier.query(&WasmQuery::CodeInfo { code_id: 4 }); + match result { + SystemResult::Ok(ContractResult::Ok(value)) => assert_eq!( + value, + br#"{"creator":"lalala","checksum":"hM8ggQ/UKcr1iJjDIQ/LcXWaJ77N2uCNvehmjqL0cl0="}"# + ), + res => panic!("Unexpected result: {:?}", res), + } + } } #[test] From 910f85370eea58c705b9e59db56e438542c1d02d Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 3 Jan 2023 18:16:15 +0100 Subject: [PATCH 096/187] Add query_wasm_code_info to querier --- packages/std/src/traits.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/std/src/traits.rs b/packages/std/src/traits.rs index 57bd5d81b2..e3ba067b6e 100644 --- a/packages/std/src/traits.rs +++ b/packages/std/src/traits.rs @@ -8,6 +8,8 @@ use crate::coin::Coin; use crate::errors::{RecoverPubkeyError, StdError, StdResult, VerificationError}; #[cfg(feature = "iterator")] use crate::iterator::{Order, Record}; +#[cfg(feature = "cosmwasm_1_2")] +use crate::query::CodeInfoResponse; #[cfg(feature = "cosmwasm_1_1")] use crate::query::SupplyResponse; use crate::query::{ @@ -304,6 +306,13 @@ impl<'a, C: CustomQuery> QuerierWrapper<'a, C> { self.query(&request) } + /// Given a code ID, query information about that code. + #[cfg(feature = "cosmwasm_1_2")] + pub fn query_wasm_code_info(&self, code_id: u64) -> StdResult { + let request = WasmQuery::CodeInfo { code_id }.into(); + self.query(&request) + } + #[cfg(feature = "staking")] pub fn query_all_validators(&self) -> StdResult> { let request = StakingQuery::AllValidators {}.into(); From e41df95bc01e1bb53c1dea39cc9df7cd57ad3cf1 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 5 Jan 2023 16:03:56 +0100 Subject: [PATCH 097/187] Add code_id to CodeInfoResponse --- packages/std/src/query/wasm.rs | 1 + packages/std/src/testing/mock.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index 3cd5cb2378..54442a0d34 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -76,6 +76,7 @@ impl ContractInfoResponse { #[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, JsonSchema)] #[cfg(feature = "cosmwasm_1_2")] pub struct CodeInfoResponse { + pub code_id: u64, /// The address that initially stored the code pub creator: String, /// The hash of the Wasm blob diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 598881782b..03ab1d0936 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -1496,6 +1496,7 @@ mod tests { if code_id == 4 { use crate::CodeInfoResponse; let response = CodeInfoResponse { + code_id, creator: "lalala".into(), checksum: Binary::from_base64( "hM8ggQ/UKcr1iJjDIQ/LcXWaJ77N2uCNvehmjqL0cl0=", @@ -1571,7 +1572,7 @@ mod tests { match result { SystemResult::Ok(ContractResult::Ok(value)) => assert_eq!( value, - br#"{"creator":"lalala","checksum":"hM8ggQ/UKcr1iJjDIQ/LcXWaJ77N2uCNvehmjqL0cl0="}"# + br#"{"code_id":4,"creator":"lalala","checksum":"hM8ggQ/UKcr1iJjDIQ/LcXWaJ77N2uCNvehmjqL0cl0="}"# ), res => panic!("Unexpected result: {:?}", res), } From afd3c34657705595ee8d847baf3d1680da2acd54 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 5 Jan 2023 16:06:34 +0100 Subject: [PATCH 098/187] Test cosmwasm_1_1,cosmwasm_1_2 in local cosmwasm-std testing --- devtools/test_workspace.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/test_workspace.sh b/devtools/test_workspace.sh index 0fdcfb2012..f1790536e0 100755 --- a/devtools/test_workspace.sh +++ b/devtools/test_workspace.sh @@ -4,7 +4,7 @@ command -v shellcheck >/dev/null && shellcheck "$0" cargo fmt (cd packages/crypto && cargo test) -(cd packages/std && cargo test --features iterator) +(cd packages/std && cargo test --features iterator,cosmwasm_1_1,cosmwasm_1_2) (cd packages/storage && cargo test --features iterator) (cd packages/schema && cargo test) (cd packages/schema-derive && cargo test) From 224b80c2fb40f56547ed1344aef82b0589ee018c Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 5 Jan 2023 16:10:54 +0100 Subject: [PATCH 099/187] Make checksum HexBinary --- packages/std/src/query/wasm.rs | 4 +++- packages/std/src/testing/mock.rs | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index 54442a0d34..13070c18f1 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -2,6 +2,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::Binary; +#[cfg(feature = "cosmwasm_1_2")] +use crate::HexBinary; use super::query_response::QueryResponseType; @@ -80,7 +82,7 @@ pub struct CodeInfoResponse { /// The address that initially stored the code pub creator: String, /// The hash of the Wasm blob - pub checksum: Binary, + pub checksum: HexBinary, } #[cfg(feature = "cosmwasm_1_2")] diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 03ab1d0936..023ef30ff8 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -1492,14 +1492,14 @@ mod tests { } #[cfg(feature = "cosmwasm_1_2")] WasmQuery::CodeInfo { code_id } => { + use crate::{CodeInfoResponse, HexBinary}; let code_id = *code_id; if code_id == 4 { - use crate::CodeInfoResponse; let response = CodeInfoResponse { code_id, creator: "lalala".into(), - checksum: Binary::from_base64( - "hM8ggQ/UKcr1iJjDIQ/LcXWaJ77N2uCNvehmjqL0cl0=", + checksum: HexBinary::from_hex( + "84cf20810fd429caf58898c3210fcb71759a27becddae08dbde8668ea2f4725d", ) .unwrap(), }; @@ -1572,7 +1572,7 @@ mod tests { match result { SystemResult::Ok(ContractResult::Ok(value)) => assert_eq!( value, - br#"{"code_id":4,"creator":"lalala","checksum":"hM8ggQ/UKcr1iJjDIQ/LcXWaJ77N2uCNvehmjqL0cl0="}"# + br#"{"code_id":4,"creator":"lalala","checksum":"84cf20810fd429caf58898c3210fcb71759a27becddae08dbde8668ea2f4725d"}"# ), res => panic!("Unexpected result: {:?}", res), } From d980067810d18723f75cdb47bd1166625087c45d Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 3 Jan 2023 18:16:58 +0100 Subject: [PATCH 100/187] Export Instantiate2AddressError and make it usable --- packages/std/src/addresses.rs | 12 +++++++++++- packages/std/src/lib.rs | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/std/src/addresses.rs b/packages/std/src/addresses.rs index 880e2171b7..39a4719291 100644 --- a/packages/std/src/addresses.rs +++ b/packages/std/src/addresses.rs @@ -7,6 +7,7 @@ use sha2::{ use std::borrow::Cow; use std::fmt; use std::ops::Deref; +use thiserror::Error; use crate::{binary::Binary, HexBinary}; @@ -275,7 +276,7 @@ impl fmt::Display for CanonicalAddr { } } -#[derive(Debug)] +#[derive(Error, Debug, PartialEq, Eq)] pub enum Instantiate2AddressError { /// Checksum must be 32 bytes InvalidChecksumLength, @@ -283,6 +284,15 @@ pub enum Instantiate2AddressError { InvalidSaltLength, } +impl fmt::Display for Instantiate2AddressError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Instantiate2AddressError::InvalidChecksumLength => write!(f, "invalid checksum length"), + Instantiate2AddressError::InvalidSaltLength => write!(f, "invalid salt length"), + } + } +} + /// Creates a contract address using the predictable address format introduced with /// wasmd 0.29. When using instantiate2, this is a way to precompute the address. /// When using instantiate, the contract address will use a different algorithm and diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index d40d25d68f..a15f0f4c62 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -26,7 +26,7 @@ mod timestamp; mod traits; mod types; -pub use crate::addresses::{instantiate2_address, Addr, CanonicalAddr}; +pub use crate::addresses::{instantiate2_address, Addr, CanonicalAddr, Instantiate2AddressError}; pub use crate::binary::Binary; pub use crate::coin::{coin, coins, has_coins, Coin}; pub use crate::deps::{Deps, DepsMut, OwnedDeps}; From e86d906d9728ed2b6c9572a8ee45ae16ea9bb16c Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 3 Jan 2023 18:33:36 +0100 Subject: [PATCH 101/187] Add virus contract --- contracts/README.md | 8 + contracts/virus/.cargo/config | 6 + contracts/virus/Cargo.lock | 1936 +++++++++++++++++++ contracts/virus/Cargo.toml | 42 + contracts/virus/README.md | 3 + contracts/virus/schema/raw/execute.json | 35 + contracts/virus/schema/raw/instantiate.json | 6 + contracts/virus/schema/virus.json | 50 + contracts/virus/src/bin/schema.rs | 10 + contracts/virus/src/contract.rs | 99 + contracts/virus/src/errors.rs | 11 + contracts/virus/src/lib.rs | 3 + contracts/virus/src/msg.rs | 15 + contracts/virus/tests/integration.rs | 1 + 14 files changed, 2225 insertions(+) create mode 100644 contracts/virus/.cargo/config create mode 100644 contracts/virus/Cargo.lock create mode 100644 contracts/virus/Cargo.toml create mode 100644 contracts/virus/README.md create mode 100644 contracts/virus/schema/raw/execute.json create mode 100644 contracts/virus/schema/raw/instantiate.json create mode 100644 contracts/virus/schema/virus.json create mode 100644 contracts/virus/src/bin/schema.rs create mode 100644 contracts/virus/src/contract.rs create mode 100644 contracts/virus/src/errors.rs create mode 100644 contracts/virus/src/lib.rs create mode 100644 contracts/virus/src/msg.rs create mode 100644 contracts/virus/tests/integration.rs diff --git a/contracts/README.md b/contracts/README.md index cb89fc0039..1f581ed2e0 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -36,6 +36,8 @@ Introducing the development contracts in the order they were created. 9. **cyberpunk** is an attempt to cleanup hackatom and make writing runtime tests (cosmwasm-vm/wamsmvm) easier by avoid the need for the escrow setup that hackatom has. +10. **virus** is a contract that reproduces itself and does nothing useful + beyond that, showing how to use instantiate2 from a contract. ## Optimized builds @@ -92,6 +94,11 @@ docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_staking",target=/code/contracts/staking/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ cosmwasm/rust-optimizer:0.12.9 ./contracts/staking + +docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="devcontract_cache_virus",target=/code/contracts/virus/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer:0.12.9 ./contracts/virus ``` ## Entry points @@ -107,3 +114,4 @@ points in order to demonstrate and test the flexibility we have. | queue | yes | yes | | reflect | yes | no | | staking | yes | no | +| virus | no | no | diff --git a/contracts/virus/.cargo/config b/contracts/virus/.cargo/config new file mode 100644 index 0000000000..f5174787c2 --- /dev/null +++ b/contracts/virus/.cargo/config @@ -0,0 +1,6 @@ +[alias] +wasm = "build --release --lib --target wasm32-unknown-unknown" +wasm-debug = "build --lib --target wasm32-unknown-unknown" +unit-test = "test --lib" +integration-test = "test --test integration" +schema = "run --bin schema" diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock new file mode 100644 index 0000000000..c46c654d81 --- /dev/null +++ b/contracts/virus/Cargo.lock @@ -0,0 +1,1936 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" +dependencies = [ + "gimli 0.24.0", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.3", + "once_cell", + "version_check", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7815ea54e4d821e791162e078acbebfd6d8c8939cd559c9335dceb1c8ca7282" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object 0.25.3", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "base64ct" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" + +[[package]] +name = "bytecheck" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314889ea31cda264cb7c3d6e6e5c9415a987ecb0e72c17c00d36fbb881d34abe" +dependencies = [ + "bytecheck_derive", + "ptr_meta", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a2b3b92c135dae665a6f760205b89187638e83bed17ef3e44e83c712cf30600" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clru" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "591ff76ca0691bd91c1b0b5b987e5cf93b21ec810ad96665c5a569c60846dd93" + +[[package]] +name = "const-oid" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "722e23542a15cea1f65d4a1419c4cfd7a26706c70871a13a04238ca3f40f1661" + +[[package]] +name = "corosensei" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9847f90f32a50b0dcbd68bc23ff242798b13080b97b0569f6ed96a45ce4cf2cd" +dependencies = [ + "autocfg", + "cfg-if", + "libc", + "scopeguard", + "windows-sys", +] + +[[package]] +name = "cosmwasm-crypto" +version = "1.2.0-beta.0" +dependencies = [ + "digest 0.10.3", + "ed25519-zebra", + "k256", + "rand_core 0.6.3", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.2.0-beta.0" +dependencies = [ + "syn", +] + +[[package]] +name = "cosmwasm-schema" +version = "1.2.0-beta.0" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "1.2.0-beta.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cosmwasm-std" +version = "1.2.0-beta.0" +dependencies = [ + "base64", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "sha2 0.10.3", + "thiserror", + "uint", +] + +[[package]] +name = "cosmwasm-vm" +version = "1.2.0-beta.0" +dependencies = [ + "bitflags", + "bytecheck", + "clru", + "cosmwasm-crypto", + "cosmwasm-std", + "enumset", + "hex", + "loupe", + "parity-wasm", + "schemars", + "serde", + "serde_json", + "sha2 0.10.3", + "thiserror", + "wasmer", + "wasmer-middlewares", +] + +[[package]] +name = "cpufeatures" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b" +dependencies = [ + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "gimli 0.26.1", + "log", + "regalloc", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" + +[[package]] +name = "cranelift-entity" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" + +[[package]] +name = "cranelift-frontend" +version = "0.82.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2b443d17d49dad5ef0ede301c3179cc923b8822f3393b4d2c28c269dd4a122" +dependencies = [ + "generic-array", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "darling" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", + "subtle", +] + +[[package]] +name = "dyn-clone" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" + +[[package]] +name = "dynasm" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add9a102807b524ec050363f09e06f1504214b0e1c7797f64261c891022dce8b" +dependencies = [ + "bitflags", + "byteorder", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dynasmrt" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" +dependencies = [ + "byteorder", + "dynasm", + "memmap2", +] + +[[package]] +name = "ecdsa" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd46e0c364655e5baf2f5e99b603e7a09905da9966d7928d7470af393b28670" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519-zebra" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +dependencies = [ + "curve25519-dalek", + "hex", + "rand_core 0.6.3", + "serde", + "sha2 0.9.5", + "thiserror", + "zeroize", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "elliptic-curve" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c47abd0a791d2ac0c7aa1118715f85b83689e4522c4e3a244e159d4fc9848a8d" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "digest 0.10.3", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.3", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-iterator" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "enumset" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e76129da36102af021b8e5000dab2c1c30dbef85c1e482beeff8da5dde0e0b0" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6451128aa6655d880755345d085494cf7561a6bee7c8dc821e5d77e6d267ecd4" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "ff" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df689201f395c6b90dfe87127685f8dbfc083a5e779e613575d8bd7314300c3e" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "group" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7391856def869c1c81063a03457c676fbcd419709c3dfb33d8d319de484b154d" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758" +dependencies = [ + "ahash", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.3", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown 0.11.2", + "serde", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "js-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8a5a96d92d849c4499d99461da81c9cdc1467418a8ed2aaeb407e8d85940ed" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2 0.10.3", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "leb128" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libloading" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "loupe" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" +dependencies = [ + "indexmap", + "loupe-derive", + "rustversion", +] + +[[package]] +name = "loupe-derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memmap2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4647a11b578fead29cdbb34d4adef8dd3dc35b876c9c6d5240d83f205abfe96e" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "more-asserts" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40bec70ba014595f99f7aa110b84331ffe1ee9aece7fe6f387cc7e3ecda4d456" +dependencies = [ + "crc32fast", + "hashbrown 0.11.2", + "indexmap", + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parity-wasm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" + +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.3", + "rand_hc", +] + +[[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 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.3", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core 0.6.3", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regalloc" +version = "0.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" +dependencies = [ + "log", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "region" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "rfc6979" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c86280f057430a52f4861551b092a01b419b8eacefc7c995eacb9dc132fe32" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "rkyv" +version = "0.7.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5230ae2981a885590b0dc84e0b24c0ed23ad24f7adc0eb824b26cafa961f7c36" +dependencies = [ + "bytecheck", + "hashbrown 0.12.0", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc752d5925dbcb324522f3a4c93193d17f107b2e11810913aa3ad352fa01480" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustversion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "schemars" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures 0.1.5", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899bf02746a2c92bf1053d9327dadb252b01af1f81f90cdb902411f518bc7215" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.2", + "digest 0.10.3", +] + +[[package]] +name = "signature" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +dependencies = [ + "digest 0.10.3", + "rand_core 0.6.3", +] + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "target-lexicon" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bffcddbc2458fa3e6058414599e3c838a022abae82e5c67b4f7f80298d5bff" + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "uint" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "virus" +version = "0.0.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cosmwasm-vm", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" + +[[package]] +name = "wasmer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea8d8361c9d006ea3d7797de7bd6b1492ffd0f91a22430cfda6c1658ad57bedf" +dependencies = [ + "cfg-if", + "indexmap", + "js-sys", + "loupe", + "more-asserts", + "target-lexicon", + "thiserror", + "wasm-bindgen", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-compiler-cranelift", + "wasmer-compiler-singlepass", + "wasmer-derive", + "wasmer-engine", + "wasmer-engine-dylib", + "wasmer-engine-universal", + "wasmer-types", + "wasmer-vm", + "winapi", +] + +[[package]] +name = "wasmer-artifact" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aaf9428c29c1d8ad2ac0e45889ba8a568a835e33fd058964e5e500f2f7ce325" +dependencies = [ + "enumset", + "loupe", + "thiserror", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-compiler" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67a6cd866aed456656db2cfea96c18baabbd33f676578482b85c51e1ee19d2c" +dependencies = [ + "enumset", + "loupe", + "rkyv", + "serde", + "serde_bytes", + "smallvec", + "target-lexicon", + "thiserror", + "wasmer-types", + "wasmparser", +] + +[[package]] +name = "wasmer-compiler-cranelift" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48be2f9f6495f08649e4f8b946a2cbbe119faf5a654aa1457f9504a99d23dae0" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "gimli 0.26.1", + "loupe", + "more-asserts", + "rayon", + "smallvec", + "target-lexicon", + "tracing", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-compiler-singlepass" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ca2a35204d8befa85062bc7aac259a8db8070b801b8a783770ba58231d729e" +dependencies = [ + "byteorder", + "dynasm", + "dynasmrt", + "gimli 0.26.1", + "lazy_static", + "loupe", + "more-asserts", + "rayon", + "smallvec", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-derive" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e50405cc2a2f74ff574584710a5f2c1d5c93744acce2ca0866084739284b51" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "wasmer-engine" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f98f010978c244db431b392aeab0661df7ea0822343334f8f2a920763548e45" +dependencies = [ + "backtrace", + "enumset", + "lazy_static", + "loupe", + "memmap2", + "more-asserts", + "rustc-demangle", + "serde", + "serde_bytes", + "target-lexicon", + "thiserror", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-engine-dylib" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0358af9c154724587731175553805648d9acb8f6657880d165e378672b7e53" +dependencies = [ + "cfg-if", + "enum-iterator", + "enumset", + "leb128", + "libloading", + "loupe", + "object 0.28.3", + "rkyv", + "serde", + "tempfile", + "tracing", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-engine", + "wasmer-object", + "wasmer-types", + "wasmer-vm", + "which", +] + +[[package]] +name = "wasmer-engine-universal" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440dc3d93c9ca47865a4f4edd037ea81bf983b5796b59b3d712d844b32dbef15" +dependencies = [ + "cfg-if", + "enumset", + "leb128", + "loupe", + "region", + "rkyv", + "wasmer-compiler", + "wasmer-engine", + "wasmer-engine-universal-artifact", + "wasmer-types", + "wasmer-vm", + "winapi", +] + +[[package]] +name = "wasmer-engine-universal-artifact" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f1db3f54152657eb6e86c44b66525ff7801dad8328fe677da48dd06af9ad41" +dependencies = [ + "enum-iterator", + "enumset", + "loupe", + "rkyv", + "thiserror", + "wasmer-artifact", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-middlewares" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7812438ed2f37203a37007cdb5332b8475cb2b16e15d51299b2647894e9ed3a" +dependencies = [ + "loupe", + "wasmer", + "wasmer-types", + "wasmer-vm", +] + +[[package]] +name = "wasmer-object" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d831335ff3a44ecf451303f6f891175c642488036b92ceceb24ac8623a8fa8b" +dependencies = [ + "object 0.28.3", + "thiserror", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-types" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39df01ea05dc0a9bab67e054c7cb01521e53b35a7bb90bd02eca564ed0b2667f" +dependencies = [ + "backtrace", + "enum-iterator", + "indexmap", + "loupe", + "more-asserts", + "rkyv", + "serde", + "thiserror", +] + +[[package]] +name = "wasmer-vm" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d965fa61f4dc4cdb35a54daaf7ecec3563fbb94154a6c35433f879466247dd" +dependencies = [ + "backtrace", + "cc", + "cfg-if", + "corosensei", + "enum-iterator", + "indexmap", + "lazy_static", + "libc", + "loupe", + "mach", + "memoffset", + "more-asserts", + "region", + "rkyv", + "scopeguard", + "serde", + "thiserror", + "wasmer-artifact", + "wasmer-types", + "winapi", +] + +[[package]] +name = "wasmparser" +version = "0.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" + +[[package]] +name = "which" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe" +dependencies = [ + "either", + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43dbb096663629518eb1dfa72d80243ca5a6aca764cae62a2df70af760a9be75" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" + +[[package]] +name = "windows_i686_gnu" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" + +[[package]] +name = "windows_i686_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/contracts/virus/Cargo.toml b/contracts/virus/Cargo.toml new file mode 100644 index 0000000000..24df513fab --- /dev/null +++ b/contracts/virus/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "virus" +version = "0.0.0" +authors = ["Simon Warta "] +edition = "2021" +publish = false +license = "Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = true + +[features] +# Add feature "cranelift" to default if you need 32 bit or ARM support +default = [] +# Use cranelift backend instead of singlepass. This is required for development on 32 bit or ARM machines. +cranelift = ["cosmwasm-vm/cranelift"] +# for quicker tests, cargo test --lib +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"] + +[dependencies] +cosmwasm-schema = { path = "../../packages/schema" } +cosmwasm-std = { path = "../../packages/std", features = ["cosmwasm_1_2"] } +schemars = "0.8.3" +serde = { version = "1.0.103", default-features = false, features = ["derive"] } +thiserror = "1.0.26" + +[dev-dependencies] +cosmwasm-vm = { path = "../../packages/vm", default-features = false, features = ["iterator"] } diff --git a/contracts/virus/README.md b/contracts/virus/README.md new file mode 100644 index 0000000000..497dbf17e3 --- /dev/null +++ b/contracts/virus/README.md @@ -0,0 +1,3 @@ +# Virus contract + +A contract that clones itself over various levels. diff --git a/contracts/virus/schema/raw/execute.json b/contracts/virus/schema/raw/execute.json new file mode 100644 index 0000000000..0c6d37f103 --- /dev/null +++ b/contracts/virus/schema/raw/execute.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "spread" + ], + "properties": { + "spread": { + "type": "object", + "required": [ + "levels", + "parent_path" + ], + "properties": { + "levels": { + "description": "The number of levels of spreading. When set to 0, the contract performs a no-op.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "parent_path": { + "description": "A slash separated path to the instance creating this one. The root is the empty string.", + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] +} diff --git a/contracts/virus/schema/raw/instantiate.json b/contracts/virus/schema/raw/instantiate.json new file mode 100644 index 0000000000..1352613d57 --- /dev/null +++ b/contracts/virus/schema/raw/instantiate.json @@ -0,0 +1,6 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "additionalProperties": false +} diff --git a/contracts/virus/schema/virus.json b/contracts/virus/schema/virus.json new file mode 100644 index 0000000000..71f03d0963 --- /dev/null +++ b/contracts/virus/schema/virus.json @@ -0,0 +1,50 @@ +{ + "contract_name": "virus", + "contract_version": "0.0.0", + "idl_version": "1.0.0", + "instantiate": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "additionalProperties": false + }, + "execute": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "oneOf": [ + { + "type": "object", + "required": [ + "spread" + ], + "properties": { + "spread": { + "type": "object", + "required": [ + "levels", + "parent_path" + ], + "properties": { + "levels": { + "description": "The number of levels of spreading. When set to 0, the contract performs a no-op.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "parent_path": { + "description": "A slash separated path to the instance creating this one. The root is the empty string.", + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, + "query": null, + "migrate": null, + "sudo": null, + "responses": null +} diff --git a/contracts/virus/src/bin/schema.rs b/contracts/virus/src/bin/schema.rs new file mode 100644 index 0000000000..3417811600 --- /dev/null +++ b/contracts/virus/src/bin/schema.rs @@ -0,0 +1,10 @@ +use cosmwasm_schema::write_api; + +use virus::msg::{ExecuteMsg, InstantiateMsg}; + +fn main() { + write_api! { + instantiate: InstantiateMsg, + execute: ExecuteMsg, + } +} diff --git a/contracts/virus/src/contract.rs b/contracts/virus/src/contract.rs new file mode 100644 index 0000000000..dabd590cbd --- /dev/null +++ b/contracts/virus/src/contract.rs @@ -0,0 +1,99 @@ +use cosmwasm_std::{ + entry_point, instantiate2_address, to_binary, Attribute, Binary, CodeInfoResponse, + ContractInfoResponse, DepsMut, Env, MessageInfo, Response, StdError, StdResult, WasmMsg, +}; + +use crate::errors::ContractError; +use crate::msg::{ExecuteMsg, InstantiateMsg}; + +#[entry_point] +pub fn instantiate( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: InstantiateMsg, +) -> StdResult { + Err(StdError::generic_err( + "You can only use this contract for migrations", + )) +} + +#[entry_point] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + ExecuteMsg::Spread { + parent_path, + levels, + } => execute_spread(deps, env, info, parent_path, levels), + } +} + +/// Basic reproduction number +const R0: u32 = 2; + +pub fn execute_spread( + deps: DepsMut, + env: Env, + _info: MessageInfo, + parent_path: String, + levels: u32, +) -> Result { + if levels == 0 { + return Ok(Response::new()); + } + + let creator = deps.api.addr_canonicalize(env.contract.address.as_str())?; + let ContractInfoResponse { code_id, .. } = deps + .querier + .query_wasm_contract_info(env.contract.address)?; + let CodeInfoResponse { checksum, .. } = deps.querier.query_wasm_code_info(code_id)?; + + let mut msgs = Vec::::new(); + let mut attributes = Vec::::new(); + for i in 0..R0 { + let path = format!("{parent_path}/{i}"); + let label = format!("Instance {path}"); + let salt = Binary::from(path.as_bytes()); + + attributes.push(Attribute::new(format!("path{i}"), path.clone())); + + let address = deps + .api + .addr_humanize(&instantiate2_address(&checksum, &creator, &salt)?)?; + attributes.push(Attribute::new( + format!("predicted_address{i}"), + address.clone(), + )); + + msgs.push(WasmMsg::Instantiate2 { + admin: None, + code_id, + label, + msg: to_binary(&InstantiateMsg {})?, + funds: vec![], + salt, + }); + + // we know the address of the newly instantiated contract, so let's execute it right away + msgs.push(WasmMsg::Execute { + contract_addr: address.into(), + msg: to_binary(&ExecuteMsg::Spread { + parent_path: path, + levels: levels - 1, + })?, + funds: vec![], + }); + } + + Ok(Response::new() + .add_attributes(attributes) + .add_messages(msgs)) +} + +#[cfg(test)] +mod tests {} diff --git a/contracts/virus/src/errors.rs b/contracts/virus/src/errors.rs new file mode 100644 index 0000000000..5a5361b574 --- /dev/null +++ b/contracts/virus/src/errors.rs @@ -0,0 +1,11 @@ +use cosmwasm_std::{Instantiate2AddressError, StdError}; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + /// this is needed so we can use `bucket.load(...)?` and have it auto-converted to the custom error + Std(#[from] StdError), + #[error("{0}")] + Instantiate2Address(#[from] Instantiate2AddressError), +} diff --git a/contracts/virus/src/lib.rs b/contracts/virus/src/lib.rs new file mode 100644 index 0000000000..33208e28f1 --- /dev/null +++ b/contracts/virus/src/lib.rs @@ -0,0 +1,3 @@ +pub mod contract; +mod errors; +pub mod msg; diff --git a/contracts/virus/src/msg.rs b/contracts/virus/src/msg.rs new file mode 100644 index 0000000000..cdf26cc717 --- /dev/null +++ b/contracts/virus/src/msg.rs @@ -0,0 +1,15 @@ +use cosmwasm_schema::cw_serde; + +#[cw_serde] +pub struct InstantiateMsg {} + +#[cw_serde] +pub enum ExecuteMsg { + Spread { + /// A slash separated path to the instance creating this one. + /// The root is the empty string. + parent_path: String, + /// The number of levels of spreading. When set to 0, the contract performs a no-op. + levels: u32, + }, +} diff --git a/contracts/virus/tests/integration.rs b/contracts/virus/tests/integration.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/contracts/virus/tests/integration.rs @@ -0,0 +1 @@ + From af99739be4a9aab12ad858e71436df232e284b7f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 5 Jan 2023 17:44:12 +0100 Subject: [PATCH 102/187] Test contract_virus in CI --- .circleci/config.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index ad9fc54090..9d3e0d6975 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -65,6 +65,7 @@ workflows: - contract_queue - contract_reflect - contract_staking + - contract_virus - fmt - fmt_extra - clippy: @@ -138,6 +139,9 @@ jobs: keys: - v4-arm64-contracts-rust:1.60.0-{{ checksum "contracts/crypto-verify/Cargo.lock" }}-{{ checksum "contracts/hackatom/Cargo.lock" }}-{{ checksum "contracts/queue/Cargo.lock" }}-{{ checksum "contracts/reflect/Cargo.lock" }}-{{ checksum "contracts/staking/Cargo.lock" }} - v4-arm64-contracts-rust:1.60.0- + # Test a few contracts that do something potentially interesting in the VM + # to test contract execution on ARM64. + # No need to add all contracts here. - run: name: "contracts/crypto-verify: integration-test" working_directory: ~/project/contracts/crypto-verify @@ -761,6 +765,33 @@ jobs: - target/wasm32-unknown-unknown/release/deps key: cargocache-v2-contract_staking-rust:1.60.0-{{ checksum "Cargo.lock" }} + contract_virus: + docker: + - image: rust:1.60.0 + environment: + RUST_BACKTRACE: 1 + working_directory: ~/cosmwasm/contracts/virus + steps: + - checkout: + path: ~/cosmwasm + - run: + name: Version information + command: rustc --version; cargo --version; rustup --version + - restore_cache: + keys: + - cargocache-v2-contract_virus-rust:1.60.0-{{ checksum "Cargo.lock" }} + - check_contract + - save_cache: + paths: + - /usr/local/cargo/registry + - target/debug/.fingerprint + - target/debug/build + - target/debug/deps + - target/wasm32-unknown-unknown/release/.fingerprint + - target/wasm32-unknown-unknown/release/build + - target/wasm32-unknown-unknown/release/deps + key: cargocache-v2-contract_virus-rust:1.60.0-{{ checksum "Cargo.lock" }} + fmt: docker: - image: rust:1.60.0 From f1c2ef6392b2323df2c23c0eff35b6cbcf18786d Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 5 Jan 2023 18:07:43 +0100 Subject: [PATCH 103/187] Let feature cosmwasm_1_2 enable cosmwasm_1_1 in cosmwasm-std --- .circleci/config.yml | 10 +++++----- devtools/check_workspace.sh | 2 +- devtools/test_workspace.sh | 2 +- packages/std/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9d3e0d6975..3c01ff12e9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -362,15 +362,15 @@ jobs: - run: name: Build library for native target (all features) working_directory: ~/project/packages/std - command: cargo build --locked --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 + command: cargo build --locked --features abort,iterator,staking,stargate,cosmwasm_1_2 - run: name: Build library for wasm target (all features) working_directory: ~/project/packages/std - command: cargo wasm --locked --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 + command: cargo wasm --locked --features abort,iterator,staking,stargate,cosmwasm_1_2 - run: name: Run unit tests (all features) working_directory: ~/project/packages/std - command: cargo test --locked --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 + command: cargo test --locked --features abort,iterator,staking,stargate,cosmwasm_1_2 - save_cache: paths: - /usr/local/cargo/registry @@ -913,7 +913,7 @@ jobs: - run: name: Clippy linting on std (all feature flags) working_directory: ~/project/packages/std - command: cargo clippy --all-targets --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 -- -D warnings + command: cargo clippy --all-targets --features abort,iterator,staking,stargate,cosmwasm_1_2 -- -D warnings - run: name: Clippy linting on storage (no feature flags) working_directory: ~/project/packages/storage @@ -990,7 +990,7 @@ jobs: CRYPTO=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/crypto --packages cosmwasm-crypto" DERIVE=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/derive --packages cosmwasm-derive" SCHEMA=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/schema --packages cosmwasm-schema" - STD=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/std --packages cosmwasm-std --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2" + STD=" cargo tarpaulin --skip-clean --out Xml --output-dir reports/std --packages cosmwasm-std --features abort,iterator,staking,stargate,cosmwasm_1_2" STORAGE="cargo tarpaulin --skip-clean --out Xml --output-dir reports/storage --packages cosmwasm-storage" docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin:0.21.0 \ sh -c "$CRYPTO && $DERIVE && $SCHEMA && $STD && $STORAGE" diff --git a/devtools/check_workspace.sh b/devtools/check_workspace.sh index 7304866eed..1747d316d6 100755 --- a/devtools/check_workspace.sh +++ b/devtools/check_workspace.sh @@ -10,7 +10,7 @@ cargo fmt # default, min, all cargo check cargo check --no-default-features - cargo check --features abort,iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2 + cargo check --features abort,iterator,staking,stargate,cosmwasm_1_2 cargo wasm-debug cargo wasm-debug --features iterator,staking,stargate cargo clippy --all-targets --features iterator,staking,stargate -- -D warnings diff --git a/devtools/test_workspace.sh b/devtools/test_workspace.sh index f1790536e0..5ade3f183f 100755 --- a/devtools/test_workspace.sh +++ b/devtools/test_workspace.sh @@ -4,7 +4,7 @@ command -v shellcheck >/dev/null && shellcheck "$0" cargo fmt (cd packages/crypto && cargo test) -(cd packages/std && cargo test --features iterator,cosmwasm_1_1,cosmwasm_1_2) +(cd packages/std && cargo test --features iterator,cosmwasm_1_2) (cd packages/storage && cargo test --features iterator) (cd packages/schema && cargo test) (cd packages/schema-derive && cargo test) diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 8a8c1f0615..54545e9976 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -38,7 +38,7 @@ ibc3 = ["stargate"] cosmwasm_1_1 = [] # This feature makes `GovMsg::VoteWeighted` available for the contract to call, but requires # the host blockchain to run CosmWasm `1.2.0` or higher. -cosmwasm_1_2 = [] +cosmwasm_1_2 = ["cosmwasm_1_1"] [dependencies] base64 = "0.13.0" From c3cde9b6acd8196a61939c70d407110770a4489d Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 5 Jan 2023 18:35:54 +0100 Subject: [PATCH 104/187] Add FileSystemCache::remove --- packages/vm/src/modules/file_system_cache.rs | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/packages/vm/src/modules/file_system_cache.rs b/packages/vm/src/modules/file_system_cache.rs index a529e432de..95b1a3e288 100644 --- a/packages/vm/src/modules/file_system_cache.rs +++ b/packages/vm/src/modules/file_system_cache.rs @@ -1,3 +1,4 @@ +use std::fs; use std::io; use std::path::PathBuf; use thiserror::Error; @@ -137,6 +138,22 @@ impl FileSystemCache { Ok(()) } + /// Removes a serialized module from the file system. + /// + /// Returns true if the file existed and false if the file did not exist. + pub fn remove(&mut self, checksum: &Checksum) -> VmResult { + let filename = checksum.to_hex(); + let file_path = self.latest_modules_path().join(filename); + + if file_path.exists() { + fs::remove_file(file_path) + .map_err(|_e| VmError::cache_err("Error deleting module from disk"))?; + Ok(true) + } else { + Ok(false) + } + } + /// The path to the latest version of the modules. fn latest_modules_path(&self) -> PathBuf { let version = format!( @@ -225,4 +242,34 @@ mod tests { ); let _serialized_module = fs::read(file_path).unwrap(); } + + #[test] + fn file_system_cache_remove_works() { + let tmp_dir = TempDir::new().unwrap(); + let mut cache = unsafe { FileSystemCache::new(tmp_dir.path()).unwrap() }; + + // Create module + let wasm = wat::parse_str(SOME_WAT).unwrap(); + let checksum = Checksum::generate(&wasm); + + // Store module + let module = compile(&wasm, None, &[]).unwrap(); + cache.store(&checksum, &module).unwrap(); + + // It's there + let store = make_runtime_store(TESTING_MEMORY_LIMIT); + assert!(cache.load(&checksum, &store).unwrap().is_some()); + + // Remove module + let existed = cache.remove(&checksum).unwrap(); + assert!(existed); + + // it's gone now + let store = make_runtime_store(TESTING_MEMORY_LIMIT); + assert!(cache.load(&checksum, &store).unwrap().is_none()); + + // Remove again + let existed = cache.remove(&checksum).unwrap(); + assert!(!existed); + } } From b72579fb1d967a4e48b4e6c4a0e18de292dfd895 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 5 Jan 2023 22:23:45 +0100 Subject: [PATCH 105/187] Add Cache::remove_wasm --- CHANGELOG.md | 2 + packages/vm/src/cache.rs | 87 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5012273c5e..c0079be3a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ and this project adheres to get reverted. ([#1513]) - cosmwasm-std: Add new `WasmQuery::CodeInfo` to get the checksum of a code ID ([#1561]). +- cosmwasm-vm: Add `Cache::remove_wasm` to remove obsolete Wasm blobs and their + compiled modules. [#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436 [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs index f971530ba9..263979f0ca 100644 --- a/packages/vm/src/cache.rs +++ b/packages/vm/src/cache.rs @@ -1,5 +1,5 @@ use std::collections::HashSet; -use std::fs::{File, OpenOptions}; +use std::fs::{self, File, OpenOptions}; use std::io::{Read, Write}; use std::marker::PhantomData; use std::path::{Path, PathBuf}; @@ -57,6 +57,7 @@ pub struct CacheOptions { } pub struct CacheInner { + /// The directory in which the Wasm blobs are stored in the file system. wasm_path: PathBuf, /// Instances memory limit in bytes. Use a value that is divisible by the Wasm page size 65536, /// e.g. full MiBs. @@ -161,6 +162,25 @@ where Ok(checksum) } + /// Removes the Wasm blob for the given checksum from disk and its + /// compiled module from the file system cache. + /// + /// The existence of the original code is required since the caller (wasmd) + /// has to keep track of which entries we have here. + pub fn remove_wasm(&self, checksum: &Checksum) -> VmResult<()> { + let mut cache = self.inner.lock().unwrap(); + + // Remove compiled moduled from disk (if it exists). + // Here we could also delete from memory caches but this is not really + // necessary as they are pushed out from the LRU over time or disappear + // when the node process restarts. + cache.fs_cache.remove(checksum)?; + + let path = &cache.wasm_path; + remove_wasm_from_disk(path, checksum)?; + Ok(()) + } + /// Retrieves a Wasm blob that was previously stored via save_wasm. /// When the cache is instantiated with the same base dir, this finds Wasm files on disc across multiple cache instances (i.e. node restarts). /// This function is public to allow a checksum to Wasm lookup in the blockchain. @@ -364,6 +384,23 @@ fn load_wasm_from_disk(dir: impl Into, checksum: &Checksum) -> VmResult Ok(wasm) } +/// Removes the Wasm blob for the given checksum from disk. +/// +/// In contrast to the file system cache, the existence of the original +/// code is required. So a non-existent file leads to an error as it +/// indicates a bug. +fn remove_wasm_from_disk(dir: impl Into, checksum: &Checksum) -> VmResult<()> { + let path = dir.into().join(checksum.to_hex()); + + if !path.exists() { + return Err(VmError::cache_err("Wasm file does not exist")); + } + + fs::remove_file(path).map_err(|_e| VmError::cache_err("Error removing Wasm file from disk"))?; + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -573,6 +610,37 @@ mod tests { } } + #[test] + fn remove_wasm_works() { + let cache: Cache = + unsafe { Cache::new(make_testing_options()).unwrap() }; + + // Store + let checksum = cache.save_wasm(CONTRACT).unwrap(); + + // Exists + cache.load_wasm(&checksum).unwrap(); + + // Remove + cache.remove_wasm(&checksum).unwrap(); + + // Does not exist anymore + match cache.load_wasm(&checksum).unwrap_err() { + VmError::CacheErr { msg, .. } => { + assert_eq!(msg, "Error opening Wasm file for reading") + } + e => panic!("Unexpected error: {:?}", e), + } + + // Removing again fails + match cache.remove_wasm(&checksum).unwrap_err() { + VmError::CacheErr { msg, .. } => { + assert_eq!(msg, "Wasm file does not exist") + } + e => panic!("Unexpected error: {:?}", e), + } + } + #[test] fn get_instance_finds_cached_module() { let cache = unsafe { Cache::new(make_testing_options()).unwrap() }; @@ -988,6 +1056,23 @@ mod tests { assert_eq!(code, loaded); } + #[test] + fn remove_wasm_from_disk_works() { + let tmp_dir = TempDir::new().unwrap(); + let path = tmp_dir.path(); + let code = vec![12u8; 17]; + let checksum = save_wasm_to_disk(path, &code).unwrap(); + + remove_wasm_from_disk(path, &checksum).unwrap(); + + // removing again fails + + match remove_wasm_from_disk(path, &checksum).unwrap_err() { + VmError::CacheErr { msg } => assert_eq!(msg, "Wasm file does not exist"), + err => panic!("Unexpected error: {:?}", err), + } + } + #[test] fn analyze_works() { let cache: Cache = From 2eb97078418ca81a8dd1858871681ab97c4cd079 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 9 Jan 2023 14:01:13 +0100 Subject: [PATCH 106/187] Set version: 1.2.0-beta.1 --- Cargo.lock | 16 ++++++++-------- contracts/burner/Cargo.lock | 12 ++++++------ contracts/crypto-verify/Cargo.lock | 14 +++++++------- contracts/cyberpunk/Cargo.lock | 14 +++++++------- contracts/floaty/Cargo.lock | 14 +++++++------- contracts/hackatom/Cargo.lock | 14 +++++++------- contracts/ibc-reflect-send/Cargo.lock | 14 +++++++------- contracts/ibc-reflect/Cargo.lock | 14 +++++++------- contracts/queue/Cargo.lock | 12 ++++++------ contracts/reflect/Cargo.lock | 14 +++++++------- contracts/staking/Cargo.lock | 14 +++++++------- contracts/virus/Cargo.lock | 12 ++++++------ packages/check/Cargo.toml | 6 +++--- packages/crypto/Cargo.toml | 2 +- packages/derive/Cargo.toml | 2 +- packages/schema-derive/Cargo.toml | 2 +- packages/schema/Cargo.toml | 6 +++--- packages/std/Cargo.toml | 6 +++--- packages/storage/Cargo.toml | 4 ++-- packages/vm/Cargo.toml | 6 +++--- 20 files changed, 99 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c939cf06c2..a1f4a425a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "cosmwasm-check" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "anyhow", "clap", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "criterion", @@ -276,7 +276,7 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "syn", @@ -284,7 +284,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "anyhow", "cosmwasm-schema-derive", @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "chrono", @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "serde", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index 20129c0bbf..589314d265 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -174,7 +174,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -185,14 +185,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -203,7 +203,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index 92ebf0a51e..3e8436c182 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -169,7 +169,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -180,14 +180,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -198,7 +198,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -207,7 +207,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "serde", @@ -233,7 +233,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index 04d7002ab4..909cb32f3c 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -203,14 +203,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -221,7 +221,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "serde", @@ -256,7 +256,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index b1857e209a..d239763137 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index b46d6b0382..ed498ec5b7 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index ec798a0102..cbc830b156 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index a60ff962fb..755dbb1dbb 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index 69f5ecff87..2b0f4a530a 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index d5ba929da6..0fe87e3355 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index ad437ec305..881e97a462 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock index c46c654d81..df0f4018ce 100644 --- a/contracts/virus/Cargo.lock +++ b/contracts/virus/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" dependencies = [ "bitflags", "bytecheck", diff --git a/packages/check/Cargo.toml b/packages/check/Cargo.toml index a2d0cfe904..4ff693f28a 100644 --- a/packages/check/Cargo.toml +++ b/packages/check/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-check" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" authors = ["Mauro Lacy "] edition = "2021" description = "A CLI tool for verifying CosmWasm smart contracts" @@ -11,5 +11,5 @@ license = "Apache-2.0" anyhow = "1.0.57" clap = "2" colored = "2" -cosmwasm-vm = { path = "../vm", version = "1.2.0-beta.0" } -cosmwasm-std = { path = "../std", version = "1.2.0-beta.0" } +cosmwasm-vm = { path = "../vm", version = "1.2.0-beta.1" } +cosmwasm-std = { path = "../std", version = "1.2.0-beta.1" } diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index 441efe5197..d390a0eb5f 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-crypto" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" authors = ["Mauro Lacy "] edition = "2021" description = "Crypto bindings for cosmwasm contracts" diff --git a/packages/derive/Cargo.toml b/packages/derive/Cargo.toml index 2a1eea212e..1ef336cbb4 100644 --- a/packages/derive/Cargo.toml +++ b/packages/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" authors = ["Simon Warta "] edition = "2021" description = "A package for auto-generated code used for CosmWasm contract development. This is shipped as part of cosmwasm-std. Do not use directly." diff --git a/packages/schema-derive/Cargo.toml b/packages/schema-derive/Cargo.toml index 743ccb4a58..5a4e776491 100644 --- a/packages/schema-derive/Cargo.toml +++ b/packages/schema-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" authors = ["Tomasz Kurcz "] edition = "2021" description = "Derive macros for cosmwasm-schema" diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index b883c13463..88f5df5588 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" authors = ["Simon Warta ", "Ethan Frey "] edition = "2021" description = "A dev-dependency for CosmWasm contracts to generate JSON Schema files." @@ -8,7 +8,7 @@ repository = "https://github.com/CosmWasm/cosmwasm/tree/main/packages/schema" license = "Apache-2.0" [dependencies] -cosmwasm-schema-derive = { version = "=1.2.0-beta.0", path = "../schema-derive" } +cosmwasm-schema-derive = { version = "=1.2.0-beta.1", path = "../schema-derive" } schemars = "0.8.3" serde = "1.0" serde_json = "1.0.40" @@ -16,6 +16,6 @@ thiserror = "1.0.26" [dev-dependencies] anyhow = "1.0.57" -cosmwasm-std = { version = "1.2.0-beta.0", path = "../std" } +cosmwasm-std = { version = "1.2.0-beta.1", path = "../std" } semver = "1" tempfile = "3" diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 54545e9976..7645600597 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-std" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" authors = ["Ethan Frey "] edition = "2021" description = "Standard library for Wasm based smart contracts on Cosmos blockchains" @@ -42,7 +42,7 @@ cosmwasm_1_2 = ["cosmwasm_1_1"] [dependencies] base64 = "0.13.0" -cosmwasm-derive = { path = "../derive", version = "1.2.0-beta.0" } +cosmwasm-derive = { path = "../derive", version = "1.2.0-beta.1" } derivative = "2" forward_ref = "1" hex = "0.4" @@ -54,7 +54,7 @@ thiserror = "1.0.26" uint = "0.9.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -cosmwasm-crypto = { path = "../crypto", version = "1.2.0-beta.0" } +cosmwasm-crypto = { path = "../crypto", version = "1.2.0-beta.1" } [dev-dependencies] cosmwasm-schema = { path = "../schema" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index b726c7d125..a582c7ded8 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-storage" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" authors = ["Ethan Frey "] edition = "2021" description = "CosmWasm library with useful helpers for Storage patterns" @@ -16,5 +16,5 @@ iterator = ["cosmwasm-std/iterator"] [dependencies] # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.0-beta.0", default-features = false } +cosmwasm-std = { path = "../std", version = "1.2.0-beta.1", default-features = false } serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index fcfdcb8ac9..60ba7e1600 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-vm" -version = "1.2.0-beta.0" +version = "1.2.0-beta.1" authors = ["Ethan Frey "] edition = "2021" description = "VM bindings to run cosmwams contracts" @@ -41,8 +41,8 @@ required-features = ["iterator"] [dependencies] clru = "0.4.0" # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.0-beta.0", default-features = false } -cosmwasm-crypto = { path = "../crypto", version = "1.2.0-beta.0" } +cosmwasm-std = { path = "../std", version = "1.2.0-beta.1", default-features = false } +cosmwasm-crypto = { path = "../crypto", version = "1.2.0-beta.1" } hex = "0.4" parity-wasm = "0.42" schemars = "0.8.3" From 89fbcb9c3529ccae023bb84053be37e3efd06487 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 9 Jan 2023 15:39:28 +0100 Subject: [PATCH 107/187] Test and fix GovMsg serialization --- packages/std/src/results/cosmos_msg.rs | 45 +++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index cc24034322..9ee3a9a90a 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -213,7 +213,7 @@ pub enum GovMsg { #[cfg(feature = "cosmwasm_1_2")] VoteWeighted { proposal_id: u64, - vote: WeightedVoteOption, + options: Vec, }, } @@ -359,4 +359,47 @@ mod tests { "Execute { contract_addr: \"joe\", msg: Binary(009f9296), funds: [] }" ); } + + #[test] + #[cfg(feature = "stargate")] + fn gov_msg_serializes_to_correct_json() { + // Vote + let msg = GovMsg::Vote { + proposal_id: 4, + vote: VoteOption::NoWithVeto, + }; + let json = to_binary(&msg).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"vote":{"proposal_id":4,"vote":"no_with_veto"}}"#, + ); + + // VoteWeighted + #[cfg(feature = "cosmwasm_1_2")] + { + let msg = GovMsg::VoteWeighted { + proposal_id: 25, + options: vec![ + WeightedVoteOption { + weight: Decimal::percent(25), + option: VoteOption::Yes, + }, + WeightedVoteOption { + weight: Decimal::percent(25), + option: VoteOption::No, + }, + WeightedVoteOption { + weight: Decimal::percent(50), + option: VoteOption::Abstain, + }, + ], + }; + + let json = to_binary(&msg).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"vote_weighted":{"proposal_id":25,"options":[{"option":"yes","weight":"0.25"},{"option":"no","weight":"0.25"},{"option":"abstain","weight":"0.5"}]}}"#, + ); + } + } } From 63e71be2e9215901f59a95badf6ea457fde3ebea Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 9 Jan 2023 15:39:42 +0100 Subject: [PATCH 108/187] Add comment to vote field --- packages/std/src/results/cosmos_msg.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index 9ee3a9a90a..3696caea64 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -208,7 +208,14 @@ pub enum WasmMsg { #[serde(rename_all = "snake_case")] pub enum GovMsg { /// This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address. - Vote { proposal_id: u64, vote: VoteOption }, + Vote { + proposal_id: u64, + /// The vote option. + /// + /// This should be called "option" for consistency with Cosmos SDK. Sorry for that. + /// See . + vote: VoteOption, + }, /// This maps directly to [MsgVoteWeighted](https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/proto/cosmos/gov/v1beta1/tx.proto#L66-L78) in the Cosmos SDK with voter set to the contract address. #[cfg(feature = "cosmwasm_1_2")] VoteWeighted { From e9ee6f52a3e56dfa388facdb63f3a988da198825 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 9 Jan 2023 17:53:31 +0100 Subject: [PATCH 109/187] Update schemas --- contracts/ibc-reflect-send/schema/ibc-reflect-send.json | 7 ++++++- contracts/ibc-reflect-send/schema/packet_msg.json | 7 ++++++- contracts/ibc-reflect-send/schema/raw/execute.json | 7 ++++++- contracts/ibc-reflect/schema/packet_msg.json | 7 ++++++- contracts/reflect/schema/raw/execute.json | 7 ++++++- contracts/reflect/schema/reflect.json | 7 ++++++- 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json index b42ac67e89..1498f82a21 100644 --- a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json +++ b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json @@ -378,7 +378,12 @@ "minimum": 0.0 }, "vote": { - "$ref": "#/definitions/VoteOption" + "description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See .", + "allOf": [ + { + "$ref": "#/definitions/VoteOption" + } + ] } } } diff --git a/contracts/ibc-reflect-send/schema/packet_msg.json b/contracts/ibc-reflect-send/schema/packet_msg.json index 7bc2a45e21..4bf172b75e 100644 --- a/contracts/ibc-reflect-send/schema/packet_msg.json +++ b/contracts/ibc-reflect-send/schema/packet_msg.json @@ -316,7 +316,12 @@ "minimum": 0.0 }, "vote": { - "$ref": "#/definitions/VoteOption" + "description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See .", + "allOf": [ + { + "$ref": "#/definitions/VoteOption" + } + ] } } } diff --git a/contracts/ibc-reflect-send/schema/raw/execute.json b/contracts/ibc-reflect-send/schema/raw/execute.json index a382cb2aac..198ed94097 100644 --- a/contracts/ibc-reflect-send/schema/raw/execute.json +++ b/contracts/ibc-reflect-send/schema/raw/execute.json @@ -367,7 +367,12 @@ "minimum": 0.0 }, "vote": { - "$ref": "#/definitions/VoteOption" + "description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See .", + "allOf": [ + { + "$ref": "#/definitions/VoteOption" + } + ] } } } diff --git a/contracts/ibc-reflect/schema/packet_msg.json b/contracts/ibc-reflect/schema/packet_msg.json index 259c21b1bd..432e357fe3 100644 --- a/contracts/ibc-reflect/schema/packet_msg.json +++ b/contracts/ibc-reflect/schema/packet_msg.json @@ -245,7 +245,12 @@ "minimum": 0.0 }, "vote": { - "$ref": "#/definitions/VoteOption" + "description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See .", + "allOf": [ + { + "$ref": "#/definitions/VoteOption" + } + ] } } } diff --git a/contracts/reflect/schema/raw/execute.json b/contracts/reflect/schema/raw/execute.json index 1ccfba3b0e..8568a9e798 100644 --- a/contracts/reflect/schema/raw/execute.json +++ b/contracts/reflect/schema/raw/execute.json @@ -362,7 +362,12 @@ "minimum": 0.0 }, "vote": { - "$ref": "#/definitions/VoteOption" + "description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See .", + "allOf": [ + { + "$ref": "#/definitions/VoteOption" + } + ] } } } diff --git a/contracts/reflect/schema/reflect.json b/contracts/reflect/schema/reflect.json index 603c401cd4..1f91a514a4 100644 --- a/contracts/reflect/schema/reflect.json +++ b/contracts/reflect/schema/reflect.json @@ -372,7 +372,12 @@ "minimum": 0.0 }, "vote": { - "$ref": "#/definitions/VoteOption" + "description": "The vote option.\n\nThis should be called \"option\" for consistency with Cosmos SDK. Sorry for that. See .", + "allOf": [ + { + "$ref": "#/definitions/VoteOption" + } + ] } } } From 5bad054733bc601f0d9f38fadfefde223ccad00f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 10 Jan 2023 16:03:38 +0100 Subject: [PATCH 110/187] Move some test code --- packages/std/src/results/cosmos_msg.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index 3696caea64..f69b37564e 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -331,13 +331,13 @@ mod tests { } } - #[cosmwasm_schema::cw_serde] - enum ExecuteMsg { - Mint { coin: Coin }, - } - #[test] fn wasm_msg_debug_decodes_binary_string_when_possible() { + #[cosmwasm_schema::cw_serde] + enum ExecuteMsg { + Mint { coin: Coin }, + } + let msg = WasmMsg::Execute { contract_addr: "joe".to_string(), msg: to_binary(&ExecuteMsg::Mint { From 76365af99fec75c686f6336c4c421af3eb4a2ae7 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 10 Jan 2023 16:03:56 +0100 Subject: [PATCH 111/187] Add WasmMsg::Instantiate/Instantiate2 serialization tests --- packages/std/src/results/cosmos_msg.rs | 63 ++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index f69b37564e..c62ba25185 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -331,6 +331,69 @@ mod tests { } } + #[test] + fn wasm_msg_serializes_to_correct_json() { + // Instantiate with admin + let msg = WasmMsg::Instantiate { + admin: Some("king".to_string()), + code_id: 7897, + msg: br#"{"claim":{}}"#.into(), + funds: vec![], + label: "my instance".to_string(), + }; + let json = to_binary(&msg).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"instantiate":{"admin":"king","code_id":7897,"msg":"eyJjbGFpbSI6e319","funds":[],"label":"my instance"}}"#, + ); + + // Instantiate without admin + let msg = WasmMsg::Instantiate { + admin: None, + code_id: 7897, + msg: br#"{"claim":{}}"#.into(), + funds: vec![], + label: "my instance".to_string(), + }; + let json = to_binary(&msg).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"instantiate":{"admin":null,"code_id":7897,"msg":"eyJjbGFpbSI6e319","funds":[],"label":"my instance"}}"#, + ); + + // Instantiate with funds + let msg = WasmMsg::Instantiate { + admin: None, + code_id: 7897, + msg: br#"{"claim":{}}"#.into(), + funds: vec![coin(321, "stones")], + label: "my instance".to_string(), + }; + let json = to_binary(&msg).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"instantiate":{"admin":null,"code_id":7897,"msg":"eyJjbGFpbSI6e319","funds":[{"denom":"stones","amount":"321"}],"label":"my instance"}}"#, + ); + + // Instantiate2 + #[cfg(feature = "cosmwasm_1_2")] + { + let msg = WasmMsg::Instantiate2 { + admin: None, + code_id: 7897, + label: "my instance".to_string(), + msg: br#"{"claim":{}}"#.into(), + funds: vec![coin(321, "stones")], + salt: Binary::from_base64("UkOVazhiwoo=").unwrap(), + }; + let json = to_binary(&msg).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"instantiate2":{"admin":null,"code_id":7897,"label":"my instance","msg":"eyJjbGFpbSI6e319","funds":[{"denom":"stones","amount":"321"}],"salt":"UkOVazhiwoo="}}"#, + ); + } + } + #[test] fn wasm_msg_debug_decodes_binary_string_when_possible() { #[cosmwasm_schema::cw_serde] From d15b463844c9859f2e371c449923ebd129ee7bc3 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 11 Jan 2023 11:20:46 +0100 Subject: [PATCH 112/187] Test serialisation of WasmQuery::ContractInfo/CodeInfo, Contract/CodeInfoResponse --- packages/std/src/query/wasm.rs | 65 ++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/packages/std/src/query/wasm.rs b/packages/std/src/query/wasm.rs index 13070c18f1..039251a4d7 100644 --- a/packages/std/src/query/wasm.rs +++ b/packages/std/src/query/wasm.rs @@ -87,3 +87,68 @@ pub struct CodeInfoResponse { #[cfg(feature = "cosmwasm_1_2")] impl QueryResponseType for CodeInfoResponse {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::to_binary; + + #[test] + fn wasm_query_contract_info_serialization() { + let query = WasmQuery::ContractInfo { + contract_addr: "aabbccdd456".into(), + }; + let json = to_binary(&query).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"contract_info":{"contract_addr":"aabbccdd456"}}"#, + ); + } + + #[test] + #[cfg(feature = "cosmwasm_1_2")] + fn wasm_query_code_info_serialization() { + let query = WasmQuery::CodeInfo { code_id: 70 }; + let json = to_binary(&query).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"code_info":{"code_id":70}}"#, + ); + } + + #[test] + fn contract_info_response_serialization() { + let response = ContractInfoResponse { + code_id: 67, + creator: "jane".to_string(), + admin: Some("king".to_string()), + pinned: true, + ibc_port: Some("wasm.123".to_string()), + }; + let json = to_binary(&response).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"code_id":67,"creator":"jane","admin":"king","pinned":true,"ibc_port":"wasm.123"}"#, + ); + } + + #[test] + #[cfg(feature = "cosmwasm_1_2")] + fn code_info_response_serialization() { + use crate::HexBinary; + + let response = CodeInfoResponse { + code_id: 67, + creator: "jane".to_string(), + checksum: HexBinary::from_hex( + "f7bb7b18fb01bbf425cf4ed2cd4b7fb26a019a7fc75a4dc87e8a0b768c501f00", + ) + .unwrap(), + }; + let json = to_binary(&response).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"code_id":67,"creator":"jane","checksum":"f7bb7b18fb01bbf425cf4ed2cd4b7fb26a019a7fc75a4dc87e8a0b768c501f00"}"#, + ); + } +} From b4261e20fb65a6070ffa4d31e1c74818a071fc6f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 11 Jan 2023 18:33:48 +0100 Subject: [PATCH 113/187] Test SystemError::NoSuchContract/NoSuchCode serialization --- packages/std/src/errors/system_error.rs | 45 +++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/std/src/errors/system_error.rs b/packages/std/src/errors/system_error.rs index 97d7bba3cb..d763f213c8 100644 --- a/packages/std/src/errors/system_error.rs +++ b/packages/std/src/errors/system_error.rs @@ -65,3 +65,48 @@ impl std::fmt::Display for SystemError { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{from_slice, to_vec}; + + #[test] + fn system_error_no_such_contract_serialization() { + let err = SystemError::NoSuchContract { + addr: "gibtsnicht".to_string(), + }; + + // ser + let json = to_vec(&err).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"no_such_contract":{"addr":"gibtsnicht"}}"#, + ); + + // de + let err: SystemError = from_slice(br#"{"no_such_contract":{"addr":"nada"}}"#).unwrap(); + assert_eq!( + err, + SystemError::NoSuchContract { + addr: "nada".to_string() + } + ); + } + + #[test] + fn system_error_no_such_code_serialization() { + let err = SystemError::NoSuchCode { code_id: 13 }; + + // ser + let json = to_vec(&err).unwrap(); + assert_eq!( + String::from_utf8_lossy(&json), + r#"{"no_such_code":{"code_id":13}}"#, + ); + + // de + let err: SystemError = from_slice(br#"{"no_such_code":{"code_id":987}}"#).unwrap(); + assert_eq!(err, SystemError::NoSuchCode { code_id: 987 },); + } +} From 6f6d4b1a2042ad70c53d1a7f313781a6a75cc7ab Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 12 Jan 2023 16:34:58 +0100 Subject: [PATCH 114/187] Test size_of for Uint64/128/256/512 --- packages/std/src/math/uint128.rs | 5 +++++ packages/std/src/math/uint256.rs | 5 +++++ packages/std/src/math/uint512.rs | 5 +++++ packages/std/src/math/uint64.rs | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index f6d8041184..a6f3681c40 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -540,6 +540,11 @@ mod tests { use super::*; use crate::{from_slice, to_vec}; + #[test] + fn size_of_works() { + assert_eq!(std::mem::size_of::(), 16); + } + #[test] fn uint128_zero_works() { let zero = Uint128::zero(); diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index 3469b1d80a..743281735d 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -668,6 +668,11 @@ mod tests { use super::*; use crate::{from_slice, to_vec}; + #[test] + fn size_of_works() { + assert_eq!(std::mem::size_of::(), 32); + } + #[test] fn uint256_new_works() { let num = Uint256::new([1; 32]); diff --git a/packages/std/src/math/uint512.rs b/packages/std/src/math/uint512.rs index fe7c1c7a2d..99e3b87359 100644 --- a/packages/std/src/math/uint512.rs +++ b/packages/std/src/math/uint512.rs @@ -623,6 +623,11 @@ mod tests { use super::*; use crate::{from_slice, to_vec}; + #[test] + fn size_of_works() { + assert_eq!(std::mem::size_of::(), 64); + } + #[test] fn uint512_new_works() { let num = Uint512::new([1; 64]); diff --git a/packages/std/src/math/uint64.rs b/packages/std/src/math/uint64.rs index 57cf1154f4..97032633e2 100644 --- a/packages/std/src/math/uint64.rs +++ b/packages/std/src/math/uint64.rs @@ -494,6 +494,11 @@ mod tests { use super::*; use crate::{from_slice, to_vec}; + #[test] + fn size_of_works() { + assert_eq!(std::mem::size_of::(), 8); + } + #[test] fn uint64_zero_works() { let zero = Uint64::zero(); From 3cf3c67a267fefa3900083ca8ab9ca065fdf383b Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 12 Jan 2023 17:21:38 +0100 Subject: [PATCH 115/187] Set version: 1.2.0-rc.1 --- Cargo.lock | 16 ++++++++-------- contracts/burner/Cargo.lock | 12 ++++++------ contracts/crypto-verify/Cargo.lock | 14 +++++++------- contracts/cyberpunk/Cargo.lock | 14 +++++++------- contracts/floaty/Cargo.lock | 14 +++++++------- contracts/hackatom/Cargo.lock | 14 +++++++------- contracts/ibc-reflect-send/Cargo.lock | 14 +++++++------- contracts/ibc-reflect/Cargo.lock | 14 +++++++------- contracts/queue/Cargo.lock | 12 ++++++------ contracts/reflect/Cargo.lock | 14 +++++++------- contracts/staking/Cargo.lock | 14 +++++++------- contracts/virus/Cargo.lock | 12 ++++++------ packages/check/Cargo.toml | 6 +++--- packages/crypto/Cargo.toml | 2 +- packages/derive/Cargo.toml | 2 +- packages/schema-derive/Cargo.toml | 2 +- packages/schema/Cargo.toml | 6 +++--- packages/std/Cargo.toml | 6 +++--- packages/storage/Cargo.toml | 4 ++-- packages/vm/Cargo.toml | 6 +++--- 20 files changed, 99 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1f4a425a2..9604275615 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "cosmwasm-check" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "anyhow", "clap", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "criterion", @@ -276,7 +276,7 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "syn", @@ -284,7 +284,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "anyhow", "cosmwasm-schema-derive", @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "chrono", @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "serde", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index 589314d265..975c437322 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -174,7 +174,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -185,14 +185,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -203,7 +203,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index 3e8436c182..187d140bdc 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -169,7 +169,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -180,14 +180,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -198,7 +198,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -207,7 +207,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "serde", @@ -233,7 +233,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index 909cb32f3c..35f96f2141 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -203,14 +203,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -221,7 +221,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "serde", @@ -256,7 +256,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index d239763137..1628503aae 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index ed498ec5b7..449690c348 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index cbc830b156..cef2629547 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index 755dbb1dbb..0a502905a3 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index 2b0f4a530a..b9bc042b47 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index 0fe87e3355..d543df2de5 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index 881e97a462..ffaa239794 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock index df0f4018ce..e7745e4945 100644 --- a/contracts/virus/Cargo.lock +++ b/contracts/virus/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" dependencies = [ "bitflags", "bytecheck", diff --git a/packages/check/Cargo.toml b/packages/check/Cargo.toml index 4ff693f28a..e50773015d 100644 --- a/packages/check/Cargo.toml +++ b/packages/check/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-check" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" authors = ["Mauro Lacy "] edition = "2021" description = "A CLI tool for verifying CosmWasm smart contracts" @@ -11,5 +11,5 @@ license = "Apache-2.0" anyhow = "1.0.57" clap = "2" colored = "2" -cosmwasm-vm = { path = "../vm", version = "1.2.0-beta.1" } -cosmwasm-std = { path = "../std", version = "1.2.0-beta.1" } +cosmwasm-vm = { path = "../vm", version = "1.2.0-rc.1" } +cosmwasm-std = { path = "../std", version = "1.2.0-rc.1" } diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index d390a0eb5f..ff6e0b6f9f 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-crypto" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" authors = ["Mauro Lacy "] edition = "2021" description = "Crypto bindings for cosmwasm contracts" diff --git a/packages/derive/Cargo.toml b/packages/derive/Cargo.toml index 1ef336cbb4..4485606ec6 100644 --- a/packages/derive/Cargo.toml +++ b/packages/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" authors = ["Simon Warta "] edition = "2021" description = "A package for auto-generated code used for CosmWasm contract development. This is shipped as part of cosmwasm-std. Do not use directly." diff --git a/packages/schema-derive/Cargo.toml b/packages/schema-derive/Cargo.toml index 5a4e776491..c063f4c68f 100644 --- a/packages/schema-derive/Cargo.toml +++ b/packages/schema-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema-derive" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" authors = ["Tomasz Kurcz "] edition = "2021" description = "Derive macros for cosmwasm-schema" diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index 88f5df5588..0700262526 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" authors = ["Simon Warta ", "Ethan Frey "] edition = "2021" description = "A dev-dependency for CosmWasm contracts to generate JSON Schema files." @@ -8,7 +8,7 @@ repository = "https://github.com/CosmWasm/cosmwasm/tree/main/packages/schema" license = "Apache-2.0" [dependencies] -cosmwasm-schema-derive = { version = "=1.2.0-beta.1", path = "../schema-derive" } +cosmwasm-schema-derive = { version = "=1.2.0-rc.1", path = "../schema-derive" } schemars = "0.8.3" serde = "1.0" serde_json = "1.0.40" @@ -16,6 +16,6 @@ thiserror = "1.0.26" [dev-dependencies] anyhow = "1.0.57" -cosmwasm-std = { version = "1.2.0-beta.1", path = "../std" } +cosmwasm-std = { version = "1.2.0-rc.1", path = "../std" } semver = "1" tempfile = "3" diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 7645600597..4be42c970f 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-std" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" authors = ["Ethan Frey "] edition = "2021" description = "Standard library for Wasm based smart contracts on Cosmos blockchains" @@ -42,7 +42,7 @@ cosmwasm_1_2 = ["cosmwasm_1_1"] [dependencies] base64 = "0.13.0" -cosmwasm-derive = { path = "../derive", version = "1.2.0-beta.1" } +cosmwasm-derive = { path = "../derive", version = "1.2.0-rc.1" } derivative = "2" forward_ref = "1" hex = "0.4" @@ -54,7 +54,7 @@ thiserror = "1.0.26" uint = "0.9.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -cosmwasm-crypto = { path = "../crypto", version = "1.2.0-beta.1" } +cosmwasm-crypto = { path = "../crypto", version = "1.2.0-rc.1" } [dev-dependencies] cosmwasm-schema = { path = "../schema" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index a582c7ded8..a6b75470e4 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-storage" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" authors = ["Ethan Frey "] edition = "2021" description = "CosmWasm library with useful helpers for Storage patterns" @@ -16,5 +16,5 @@ iterator = ["cosmwasm-std/iterator"] [dependencies] # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.0-beta.1", default-features = false } +cosmwasm-std = { path = "../std", version = "1.2.0-rc.1", default-features = false } serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index 60ba7e1600..07c9c53cbf 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-vm" -version = "1.2.0-beta.1" +version = "1.2.0-rc.1" authors = ["Ethan Frey "] edition = "2021" description = "VM bindings to run cosmwams contracts" @@ -41,8 +41,8 @@ required-features = ["iterator"] [dependencies] clru = "0.4.0" # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.0-beta.1", default-features = false } -cosmwasm-crypto = { path = "../crypto", version = "1.2.0-beta.1" } +cosmwasm-std = { path = "../std", version = "1.2.0-rc.1", default-features = false } +cosmwasm-crypto = { path = "../crypto", version = "1.2.0-rc.1" } hex = "0.4" parity-wasm = "0.42" schemars = "0.8.3" From cb4cc5ea39d7a55564321241409db7399a3c01cb Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Tue, 3 Jan 2023 20:12:33 +0100 Subject: [PATCH 116/187] Support fraction multiply --- packages/std/src/errors/mod.rs | 5 +- packages/std/src/errors/std_error.rs | 11 +- packages/std/src/lib.rs | 2 +- packages/std/src/math/decimal.rs | 4 +- packages/std/src/math/decimal256.rs | 4 +- packages/std/src/math/fraction.rs | 27 ++++- packages/std/src/math/mod.rs | 2 +- packages/std/src/math/uint128.rs | 172 ++++++++++++++++++++++++++- 8 files changed, 214 insertions(+), 13 deletions(-) diff --git a/packages/std/src/errors/mod.rs b/packages/std/src/errors/mod.rs index bf7e61f433..01793bfe17 100644 --- a/packages/std/src/errors/mod.rs +++ b/packages/std/src/errors/mod.rs @@ -5,8 +5,9 @@ mod verification_error; pub use recover_pubkey_error::RecoverPubkeyError; pub use std_error::{ - CheckedFromRatioError, CheckedMultiplyRatioError, ConversionOverflowError, DivideByZeroError, - OverflowError, OverflowOperation, RoundUpOverflowError, StdError, StdResult, + CheckedFromRatioError, CheckedMultiplyFractionalError, CheckedMultiplyRatioError, + ConversionOverflowError, DivideByZeroError, OverflowError, OverflowOperation, + RoundUpOverflowError, StdError, StdResult, }; pub use system_error::SystemError; pub use verification_error::VerificationError; diff --git a/packages/std/src/errors/std_error.rs b/packages/std/src/errors/std_error.rs index fa5c27f328..101c1a040d 100644 --- a/packages/std/src/errors/std_error.rs +++ b/packages/std/src/errors/std_error.rs @@ -543,7 +543,7 @@ impl ConversionOverflowError { } #[derive(Error, Debug, PartialEq, Eq)] -#[error("Cannot devide {operand} by zero")] +#[error("Cannot divide {operand} by zero")] pub struct DivideByZeroError { pub operand: String, } @@ -556,6 +556,15 @@ impl DivideByZeroError { } } +#[derive(Error, Debug, PartialEq, Eq)] +pub enum CheckedMultiplyFractionalError { + #[error("{0}")] + DivideByZero(#[from] DivideByZeroError), + + #[error("{0}")] + ConversionOverflow(#[from] ConversionOverflowError), +} + #[derive(Error, Debug, PartialEq, Eq)] pub enum CheckedMultiplyRatioError { #[error("Denominator must not be zero")] diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index a15f0f4c62..af696d5d12 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -46,7 +46,7 @@ pub use crate::ibc::{ #[cfg(feature = "iterator")] pub use crate::iterator::{Order, Record}; pub use crate::math::{ - Decimal, Decimal256, Decimal256RangeExceeded, DecimalRangeExceeded, Fraction, Isqrt, Uint128, + Decimal, Decimal256, Decimal256RangeExceeded, DecimalRangeExceeded, Fractional, Isqrt, Uint128, Uint256, Uint512, Uint64, }; pub use crate::never::Never; diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 72975e22e3..867b8dc6bd 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -12,7 +12,7 @@ use crate::errors::{ OverflowOperation, RoundUpOverflowError, StdError, }; -use super::Fraction; +use super::Fractional; use super::Isqrt; use super::{Uint128, Uint256}; @@ -359,7 +359,7 @@ impl Decimal { } } -impl Fraction for Decimal { +impl Fractional for Decimal { #[inline] fn numerator(&self) -> Uint128 { self.0 diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 0c2b134b5b..7d5c3c981f 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -13,7 +13,7 @@ use crate::errors::{ }; use crate::{Decimal, Uint512}; -use super::Fraction; +use super::Fractional; use super::Isqrt; use super::Uint256; @@ -376,7 +376,7 @@ impl Decimal256 { } } -impl Fraction for Decimal256 { +impl Fractional for Decimal256 { #[inline] fn numerator(&self) -> Uint256 { self.0 diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index ca187ad78c..489db1a3d9 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -1,7 +1,9 @@ +use serde::{Deserialize, Serialize}; + /// A fraction `p`/`q` with integers `p` and `q`. /// /// `p` is called the numerator and `q` is called the denominator. -pub trait Fraction: Sized { +pub trait Fractional: Sized { /// Returns the numerator `p` fn numerator(&self) -> T; /// Returns the denominator `q` @@ -12,3 +14,26 @@ pub trait Fraction: Sized { /// If `p` is zero, None is returned. fn inv(&self) -> Option; } + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct Fraction(T, T); + +impl Fraction { + pub fn new(numerator: T, denominator: T) -> Self { + Self(numerator, denominator) + } +} + +impl Fractional for Fraction { + fn numerator(&self) -> T { + self.0.clone() + } + + fn denominator(&self) -> T { + self.1.clone() + } + + fn inv(&self) -> Option { + unimplemented!() + } +} diff --git a/packages/std/src/math/mod.rs b/packages/std/src/math/mod.rs index 706d23005d..8151fd6f56 100644 --- a/packages/std/src/math/mod.rs +++ b/packages/std/src/math/mod.rs @@ -9,7 +9,7 @@ mod uint64; pub use decimal::{Decimal, DecimalRangeExceeded}; pub use decimal256::{Decimal256, Decimal256RangeExceeded}; -pub use fraction::Fraction; +pub use fraction::Fractional; pub use isqrt::Isqrt; pub use uint128::Uint128; pub use uint256::Uint256; diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index a6f3681c40..3d999ea600 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -8,9 +8,10 @@ use std::ops::{ use std::str::FromStr; use crate::errors::{ - CheckedMultiplyRatioError, DivideByZeroError, OverflowError, OverflowOperation, StdError, + CheckedMultiplyFractionalError, CheckedMultiplyRatioError, DivideByZeroError, OverflowError, + OverflowOperation, StdError, }; -use crate::{ConversionOverflowError, Uint256, Uint64}; +use crate::{ConversionOverflowError, Fractional, Uint256, Uint64}; /// A thin wrapper around u128 that is using strings for JSON encoding/decoding, /// such that the full u128 range can be used for clients that convert JSON numbers to floats, @@ -136,6 +137,37 @@ impl Uint128 { .unwrap() } + pub fn mul_floored, T: Into>(self, rhs: F) -> Self { + self.checked_mul_floored(rhs).unwrap() + } + + pub fn checked_mul_floored, T: Into>( + self, + rhs: F, + ) -> Result { + let res = self + .full_mul(rhs.numerator()) + .checked_div(Uint256::from(rhs.denominator().into()))?; + Ok(res.try_into()?) + } + + pub fn mul_ceil + Clone, T: Into>(self, rhs: F) -> Self { + self.checked_mul_ceil(rhs).unwrap() + } + + pub fn checked_mul_ceil + Clone, T: Into>( + self, + rhs: F, + ) -> Result { + let mut result = self.checked_mul_floored(rhs.clone())?; + let numerator = Uint256::from(rhs.numerator().into()); + let denominator = Uint256::from(rhs.denominator().into()); + if !numerator.checked_rem(denominator)?.is_zero() { + result += Uint128::one(); + }; + Ok(result) + } + pub fn checked_add(self, other: Self) -> Result { self.0 .checked_add(other.0) @@ -538,7 +570,9 @@ impl PartialEq for &Uint128 { #[cfg(test)] mod tests { use super::*; - use crate::{from_slice, to_vec}; + use crate::errors::CheckedMultiplyFractionalError::{ConversionOverflow, DivideByZero}; + use crate::math::fraction::Fraction; + use crate::{from_slice, to_vec, Decimal}; #[test] fn size_of_works() { @@ -1039,4 +1073,136 @@ mod tests { assert_eq!(&lhs == &rhs, expected); } } + + #[test] + fn mul_floored_works_with_zero() { + let fraction = Fraction::new(Uint128::zero(), Uint128::new(21)); + let res = Uint128::new(123456).mul_floored(fraction); + assert_eq!(Uint128::zero(), res) + } + + #[test] + fn mul_floored_does_nothing_with_one() { + let fraction = Fraction::new(Uint128::one(), Uint128::one()); + let res = Uint128::new(123456).mul_floored(fraction); + assert_eq!(Uint128::new(123456), res) + } + + #[test] + fn mul_floored_rounds_down_with_normal_case() { + let fraction = Fraction::new(8u128, 21u128); + let res = Uint128::new(123456).mul_floored(fraction); // 47030.8571 + assert_eq!(Uint128::new(47030), res) + } + + #[test] + fn mul_floored_works_with_decimal() { + let decimal = Decimal::from_ratio(8u128, 21u128); + let res = Uint128::new(123456).mul_floored(decimal); // 47030.8571 + assert_eq!(Uint128::new(47030), res) + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn mul_floored_panics_on_overflow() { + let fraction = Fraction::new(21u128, 8u128); + Uint128::MAX.mul_floored(fraction); + } + + #[test] + fn checked_mul_floored_does_not_panic_on_overflow() { + let fraction = Fraction::new(21u128, 8u128); + assert_eq!( + Uint128::MAX.checked_mul_floored(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint256", + target_type: "Uint128", + value: "893241213167463466591358344508391555069".to_string() + })), + ); + } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn mul_floored_panics_on_zero_div() { + let fraction = Fraction::new(21u128, 0u128); + Uint128::new(123456).mul_floored(fraction); + } + + #[test] + fn checked_mul_floored_does_not_panic_on_zero_div() { + let fraction = Fraction::new(21u128, 0u128); + assert_eq!( + Uint128::new(123456).checked_mul_floored(fraction), + Err(DivideByZero(DivideByZeroError { + operand: "2592576".to_string() + })), + ); + } + + #[test] + fn mul_ceil_works_with_zero() { + let fraction = Fraction::new(Uint128::zero(), Uint128::new(21)); + let res = Uint128::new(123456).mul_ceil(fraction); + assert_eq!(Uint128::zero(), res) + } + + #[test] + fn mul_ceil_does_nothing_with_one() { + let fraction = Fraction::new(Uint128::one(), Uint128::one()); + let res = Uint128::new(123456).mul_ceil(fraction); + assert_eq!(Uint128::new(123456), res) + } + + #[test] + fn mul_ceil_rounds_up_with_normal_case() { + let fraction = Fraction::new(8u128, 21u128); + let res = Uint128::new(123456).mul_ceil(fraction); // 47030.8571 + assert_eq!(Uint128::new(47031), res) + } + + #[test] + fn mul_ceil_works_with_decimal() { + let decimal = Decimal::from_ratio(8u128, 21u128); + let res = Uint128::new(123456).mul_ceil(decimal); // 47030.8571 + assert_eq!(Uint128::new(47031), res) + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn mul_ceil_panics_on_overflow() { + let fraction = Fraction::new(21u128, 8u128); + Uint128::MAX.mul_ceil(fraction); + } + + #[test] + fn checked_mul_ceil_does_not_panic_on_overflow() { + let fraction = Fraction::new(21u128, 8u128); + assert_eq!( + Uint128::MAX.checked_mul_ceil(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint256", + target_type: "Uint128", + value: "893241213167463466591358344508391555069".to_string() + })), + ); + } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn mul_ceil_panics_on_zero_div() { + let fraction = Fraction::new(21u128, 0u128); + Uint128::new(123456).mul_ceil(fraction); + } + + #[test] + fn checked_mul_ceil_does_not_panic_on_zero_div() { + let fraction = Fraction::new(21u128, 0u128); + assert_eq!( + Uint128::new(123456).checked_mul_ceil(fraction), + Err(DivideByZero(DivideByZeroError { + operand: "2592576".to_string() + })), + ); + } } From 1135c8af73c8d8bcab85d582b265eab24bca4475 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Tue, 3 Jan 2023 21:47:14 +0100 Subject: [PATCH 117/187] Add macro abstraction support --- packages/std/src/errors/std_error.rs | 3 ++ packages/std/src/math/fraction.rs | 63 ++++++++++++++++++++++++++++ packages/std/src/math/uint128.rs | 56 +++++++------------------ 3 files changed, 81 insertions(+), 41 deletions(-) diff --git a/packages/std/src/errors/std_error.rs b/packages/std/src/errors/std_error.rs index 101c1a040d..89df9b793a 100644 --- a/packages/std/src/errors/std_error.rs +++ b/packages/std/src/errors/std_error.rs @@ -563,6 +563,9 @@ pub enum CheckedMultiplyFractionalError { #[error("{0}")] ConversionOverflow(#[from] ConversionOverflowError), + + #[error("{0}")] + Overflow(#[from] OverflowError), } #[derive(Error, Debug, PartialEq, Eq)] diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index 489db1a3d9..10e824c8fe 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -1,5 +1,8 @@ use serde::{Deserialize, Serialize}; +use crate::errors::CheckedMultiplyFractionalError; +use crate::Uint512; + /// A fraction `p`/`q` with integers `p` and `q`. /// /// `p` is called the numerator and `q` is called the denominator. @@ -37,3 +40,63 @@ impl Fractional for Fraction { unimplemented!() } } + +pub trait FractionMath { + fn checked_mul_floored, T: Into>( + self, + rhs: F, + ) -> Result + where + Self: Sized; + + fn mul_floored, T: Into>(self, rhs: F) -> Self; + + fn checked_mul_ceil + Clone, T: Into>( + self, + rhs: F, + ) -> Result + where + Self: Sized; + + fn mul_ceil + Clone, T: Into>(self, rhs: F) -> Self; +} + +#[macro_export] +macro_rules! fraction_math { + ($name:ident) => { + impl FractionMath for $name { + fn checked_mul_floored, T: Into>( + self, + rhs: F, + ) -> Result { + let res = Uint512::from(self) + .checked_mul(rhs.numerator().into())? + .checked_div(rhs.denominator().into())?; + Ok(res.try_into()?) + } + + fn mul_floored, T: Into>(self, rhs: F) -> Self { + self.checked_mul_floored(rhs).unwrap() + } + + fn mul_ceil + Clone, T: Into>(self, rhs: F) -> Self { + self.checked_mul_ceil(rhs).unwrap() + } + + fn checked_mul_ceil + Clone, T: Into>( + self, + rhs: F, + ) -> Result { + let floor_result = self.checked_mul_floored(rhs.clone())?; + let numerator = rhs.numerator().into(); + let denominator = rhs.denominator().into(); + if !numerator.checked_rem(denominator)?.is_zero() { + let ceil_result = Uint512::one().checked_add(floor_result.into())?; + Ok(ceil_result.try_into()?) + } else { + Ok(floor_result) + } + } + } + }; +} diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index 3d999ea600..91e315aa1f 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -1,17 +1,19 @@ -use forward_ref::{forward_ref_binop, forward_ref_op_assign}; -use schemars::JsonSchema; -use serde::{de, ser, Deserialize, Deserializer, Serialize}; use std::fmt::{self}; use std::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Shr, ShrAssign, Sub, SubAssign, }; use std::str::FromStr; +use forward_ref::{forward_ref_binop, forward_ref_op_assign}; +use schemars::JsonSchema; +use serde::{de, ser, Deserialize, Deserializer, Serialize}; + +use crate::errors::CheckedMultiplyFractionalError; use crate::errors::{ - CheckedMultiplyFractionalError, CheckedMultiplyRatioError, DivideByZeroError, OverflowError, - OverflowOperation, StdError, + CheckedMultiplyRatioError, DivideByZeroError, OverflowError, OverflowOperation, StdError, }; -use crate::{ConversionOverflowError, Fractional, Uint256, Uint64}; +use crate::math::fraction::FractionMath; +use crate::{fraction_math, ConversionOverflowError, Fractional, Uint256, Uint512, Uint64}; /// A thin wrapper around u128 that is using strings for JSON encoding/decoding, /// such that the full u128 range can be used for clients that convert JSON numbers to floats, @@ -137,37 +139,6 @@ impl Uint128 { .unwrap() } - pub fn mul_floored, T: Into>(self, rhs: F) -> Self { - self.checked_mul_floored(rhs).unwrap() - } - - pub fn checked_mul_floored, T: Into>( - self, - rhs: F, - ) -> Result { - let res = self - .full_mul(rhs.numerator()) - .checked_div(Uint256::from(rhs.denominator().into()))?; - Ok(res.try_into()?) - } - - pub fn mul_ceil + Clone, T: Into>(self, rhs: F) -> Self { - self.checked_mul_ceil(rhs).unwrap() - } - - pub fn checked_mul_ceil + Clone, T: Into>( - self, - rhs: F, - ) -> Result { - let mut result = self.checked_mul_floored(rhs.clone())?; - let numerator = Uint256::from(rhs.numerator().into()); - let denominator = Uint256::from(rhs.denominator().into()); - if !numerator.checked_rem(denominator)?.is_zero() { - result += Uint128::one(); - }; - Ok(result) - } - pub fn checked_add(self, other: Self) -> Result { self.0 .checked_add(other.0) @@ -262,6 +233,8 @@ impl Uint128 { } } +fraction_math!(Uint128); + // `From` is implemented manually instead of // using `impl> From for Uint128` because // of the conflict with `TryFrom<&str>` as described here @@ -569,11 +542,12 @@ impl PartialEq for &Uint128 { #[cfg(test)] mod tests { - use super::*; use crate::errors::CheckedMultiplyFractionalError::{ConversionOverflow, DivideByZero}; - use crate::math::fraction::Fraction; + use crate::math::fraction::{Fraction, FractionMath}; use crate::{from_slice, to_vec, Decimal}; + use super::*; + #[test] fn size_of_works() { assert_eq!(std::mem::size_of::(), 16); @@ -1115,7 +1089,7 @@ mod tests { assert_eq!( Uint128::MAX.checked_mul_floored(fraction), Err(ConversionOverflow(ConversionOverflowError { - source_type: "Uint256", + source_type: "Uint512", target_type: "Uint128", value: "893241213167463466591358344508391555069".to_string() })), @@ -1181,7 +1155,7 @@ mod tests { assert_eq!( Uint128::MAX.checked_mul_ceil(fraction), Err(ConversionOverflow(ConversionOverflowError { - source_type: "Uint256", + source_type: "Uint512", target_type: "Uint128", value: "893241213167463466591358344508391555069".to_string() })), From 33df9fdcec4b0ec1adeae22f4ce4dcb1dbf08e15 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Tue, 3 Jan 2023 22:00:58 +0100 Subject: [PATCH 118/187] Higher bit size tests --- packages/std/src/math/uint128.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index 91e315aa1f..c455b6bfa7 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -544,7 +544,7 @@ impl PartialEq for &Uint128 { mod tests { use crate::errors::CheckedMultiplyFractionalError::{ConversionOverflow, DivideByZero}; use crate::math::fraction::{Fraction, FractionMath}; - use crate::{from_slice, to_vec, Decimal}; + use crate::{from_slice, to_vec, Decimal, Decimal256}; use super::*; @@ -1069,6 +1069,13 @@ mod tests { assert_eq!(Uint128::new(47030), res) } + #[test] + fn mul_floored_works_with_higher_bit_sizes() { + let fraction = Fraction::new(Uint256::from(8u128), Uint256::from(21u128)); + let res = Uint128::new(123456).mul_floored(fraction); // 47030.8571 + assert_eq!(Uint128::new(47030), res) + } + #[test] fn mul_floored_works_with_decimal() { let decimal = Decimal::from_ratio(8u128, 21u128); @@ -1076,6 +1083,13 @@ mod tests { assert_eq!(Uint128::new(47030), res) } + #[test] + fn mul_floored_works_with_decimal256() { + let decimal = Decimal256::from_ratio(8u128, 21u128); + let res = Uint128::new(123456).mul_floored(decimal); // 47030.8571 + assert_eq!(Uint128::new(47030), res) + } + #[test] #[should_panic(expected = "ConversionOverflowError")] fn mul_floored_panics_on_overflow() { @@ -1135,6 +1149,13 @@ mod tests { assert_eq!(Uint128::new(47031), res) } + #[test] + fn mul_ceil_works_with_higher_bit_sizes() { + let fraction = Fraction::new(Uint256::from(8u128), Uint256::from(21u128)); + let res = Uint128::new(123456).mul_ceil(fraction); // 47030.8571 + assert_eq!(Uint128::new(47031), res) + } + #[test] fn mul_ceil_works_with_decimal() { let decimal = Decimal::from_ratio(8u128, 21u128); @@ -1142,6 +1163,13 @@ mod tests { assert_eq!(Uint128::new(47031), res) } + #[test] + fn mul_ceil_works_with_decimal256() { + let decimal = Decimal256::from_ratio(8u128, 21u128); + let res = Uint128::new(123456).mul_ceil(decimal); // 47030.8571 + assert_eq!(Uint128::new(47031), res) + } + #[test] #[should_panic(expected = "ConversionOverflowError")] fn mul_ceil_panics_on_overflow() { From 70fc13509ad04d9845c8991257efb3261b0f08c4 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Wed, 4 Jan 2023 17:02:56 +0100 Subject: [PATCH 119/187] Macro & math updates --- packages/std/src/errors/mod.rs | 2 +- packages/std/src/errors/std_error.rs | 2 +- packages/std/src/lib.rs | 2 +- packages/std/src/math/decimal.rs | 4 +- packages/std/src/math/decimal256.rs | 4 +- packages/std/src/math/fraction.rs | 72 +++++++----------------- packages/std/src/math/mod.rs | 2 +- packages/std/src/math/uint128.rs | 82 ++++++++++++---------------- 8 files changed, 63 insertions(+), 107 deletions(-) diff --git a/packages/std/src/errors/mod.rs b/packages/std/src/errors/mod.rs index 01793bfe17..705382b732 100644 --- a/packages/std/src/errors/mod.rs +++ b/packages/std/src/errors/mod.rs @@ -5,7 +5,7 @@ mod verification_error; pub use recover_pubkey_error::RecoverPubkeyError; pub use std_error::{ - CheckedFromRatioError, CheckedMultiplyFractionalError, CheckedMultiplyRatioError, + CheckedFromRatioError, CheckedMultiplyFractionError, CheckedMultiplyRatioError, ConversionOverflowError, DivideByZeroError, OverflowError, OverflowOperation, RoundUpOverflowError, StdError, StdResult, }; diff --git a/packages/std/src/errors/std_error.rs b/packages/std/src/errors/std_error.rs index 89df9b793a..79b6a82f27 100644 --- a/packages/std/src/errors/std_error.rs +++ b/packages/std/src/errors/std_error.rs @@ -557,7 +557,7 @@ impl DivideByZeroError { } #[derive(Error, Debug, PartialEq, Eq)] -pub enum CheckedMultiplyFractionalError { +pub enum CheckedMultiplyFractionError { #[error("{0}")] DivideByZero(#[from] DivideByZeroError), diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index af696d5d12..a15f0f4c62 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -46,7 +46,7 @@ pub use crate::ibc::{ #[cfg(feature = "iterator")] pub use crate::iterator::{Order, Record}; pub use crate::math::{ - Decimal, Decimal256, Decimal256RangeExceeded, DecimalRangeExceeded, Fractional, Isqrt, Uint128, + Decimal, Decimal256, Decimal256RangeExceeded, DecimalRangeExceeded, Fraction, Isqrt, Uint128, Uint256, Uint512, Uint64, }; pub use crate::never::Never; diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 867b8dc6bd..72975e22e3 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -12,7 +12,7 @@ use crate::errors::{ OverflowOperation, RoundUpOverflowError, StdError, }; -use super::Fractional; +use super::Fraction; use super::Isqrt; use super::{Uint128, Uint256}; @@ -359,7 +359,7 @@ impl Decimal { } } -impl Fractional for Decimal { +impl Fraction for Decimal { #[inline] fn numerator(&self) -> Uint128 { self.0 diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 7d5c3c981f..0c2b134b5b 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -13,7 +13,7 @@ use crate::errors::{ }; use crate::{Decimal, Uint512}; -use super::Fractional; +use super::Fraction; use super::Isqrt; use super::Uint256; @@ -376,7 +376,7 @@ impl Decimal256 { } } -impl Fractional for Decimal256 { +impl Fraction for Decimal256 { #[inline] fn numerator(&self) -> Uint256 { self.0 diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index 10e824c8fe..7d6afedcba 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -1,12 +1,7 @@ -use serde::{Deserialize, Serialize}; - -use crate::errors::CheckedMultiplyFractionalError; -use crate::Uint512; - /// A fraction `p`/`q` with integers `p` and `q`. /// /// `p` is called the numerator and `q` is called the denominator. -pub trait Fractional: Sized { +pub trait Fraction: Sized { /// Returns the numerator `p` fn numerator(&self) -> T; /// Returns the denominator `q` @@ -18,16 +13,7 @@ pub trait Fractional: Sized { fn inv(&self) -> Option; } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct Fraction(T, T); - -impl Fraction { - pub fn new(numerator: T, denominator: T) -> Self { - Self(numerator, denominator) - } -} - -impl Fractional for Fraction { +impl Fraction for (T, T) { fn numerator(&self) -> T { self.0.clone() } @@ -37,66 +23,46 @@ impl Fractional for Fraction { } fn inv(&self) -> Option { - unimplemented!() + Some((self.1.clone(), self.0.clone())) } } -pub trait FractionMath { - fn checked_mul_floored, T: Into>( - self, - rhs: F, - ) -> Result - where - Self: Sized; - - fn mul_floored, T: Into>(self, rhs: F) -> Self; - - fn checked_mul_ceil + Clone, T: Into>( - self, - rhs: F, - ) -> Result - where - Self: Sized; - - fn mul_ceil + Clone, T: Into>(self, rhs: F) -> Self; -} - #[macro_export] -macro_rules! fraction_math { - ($name:ident) => { - impl FractionMath for $name { - fn checked_mul_floored, T: Into>( +macro_rules! impl_mul_fraction { + ($UintBase:ident, $UintLarger:ident) => { + impl $UintBase { + pub fn checked_mul_floored, T: Into<$UintBase>>( self, rhs: F, - ) -> Result { - let res = Uint512::from(self) - .checked_mul(rhs.numerator().into())? - .checked_div(rhs.denominator().into())?; + ) -> Result { + let res = self + .full_mul(rhs.numerator().into()) + .checked_div($UintLarger::from(rhs.denominator().into()))?; Ok(res.try_into()?) } - fn mul_floored, T: Into>(self, rhs: F) -> Self { + pub fn mul_floored, T: Into<$UintBase>>(self, rhs: F) -> Self { self.checked_mul_floored(rhs).unwrap() } - fn mul_ceil + Clone, T: Into>(self, rhs: F) -> Self { - self.checked_mul_ceil(rhs).unwrap() - } - - fn checked_mul_ceil + Clone, T: Into>( + pub fn checked_mul_ceil + Clone, T: Into<$UintBase>>( self, rhs: F, - ) -> Result { + ) -> Result { let floor_result = self.checked_mul_floored(rhs.clone())?; let numerator = rhs.numerator().into(); let denominator = rhs.denominator().into(); if !numerator.checked_rem(denominator)?.is_zero() { - let ceil_result = Uint512::one().checked_add(floor_result.into())?; + let ceil_result = $UintLarger::one().checked_add(floor_result.into())?; Ok(ceil_result.try_into()?) } else { Ok(floor_result) } } + + pub fn mul_ceil + Clone, T: Into<$UintBase>>(self, rhs: F) -> Self { + self.checked_mul_ceil(rhs).unwrap() + } } }; } diff --git a/packages/std/src/math/mod.rs b/packages/std/src/math/mod.rs index 8151fd6f56..706d23005d 100644 --- a/packages/std/src/math/mod.rs +++ b/packages/std/src/math/mod.rs @@ -9,7 +9,7 @@ mod uint64; pub use decimal::{Decimal, DecimalRangeExceeded}; pub use decimal256::{Decimal256, Decimal256RangeExceeded}; -pub use fraction::Fractional; +pub use fraction::Fraction; pub use isqrt::Isqrt; pub use uint128::Uint128; pub use uint256::Uint256; diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index c455b6bfa7..48234453f8 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -8,12 +8,11 @@ use forward_ref::{forward_ref_binop, forward_ref_op_assign}; use schemars::JsonSchema; use serde::{de, ser, Deserialize, Deserializer, Serialize}; -use crate::errors::CheckedMultiplyFractionalError; use crate::errors::{ - CheckedMultiplyRatioError, DivideByZeroError, OverflowError, OverflowOperation, StdError, + CheckedMultiplyFractionError, CheckedMultiplyRatioError, DivideByZeroError, OverflowError, + OverflowOperation, StdError, }; -use crate::math::fraction::FractionMath; -use crate::{fraction_math, ConversionOverflowError, Fractional, Uint256, Uint512, Uint64}; +use crate::{impl_mul_fraction, ConversionOverflowError, Fraction, Uint256, Uint64}; /// A thin wrapper around u128 that is using strings for JSON encoding/decoding, /// such that the full u128 range can be used for clients that convert JSON numbers to floats, @@ -233,7 +232,7 @@ impl Uint128 { } } -fraction_math!(Uint128); +impl_mul_fraction!(Uint128, Uint256); // `From` is implemented manually instead of // using `impl> From for Uint128` because @@ -542,9 +541,8 @@ impl PartialEq for &Uint128 { #[cfg(test)] mod tests { - use crate::errors::CheckedMultiplyFractionalError::{ConversionOverflow, DivideByZero}; - use crate::math::fraction::{Fraction, FractionMath}; - use crate::{from_slice, to_vec, Decimal, Decimal256}; + use crate::errors::CheckedMultiplyFractionError::{ConversionOverflow, DivideByZero}; + use crate::{from_slice, to_vec, Decimal}; use super::*; @@ -1050,30 +1048,33 @@ mod tests { #[test] fn mul_floored_works_with_zero() { - let fraction = Fraction::new(Uint128::zero(), Uint128::new(21)); + let fraction = (Uint128::zero(), Uint128::new(21)); let res = Uint128::new(123456).mul_floored(fraction); assert_eq!(Uint128::zero(), res) } #[test] fn mul_floored_does_nothing_with_one() { - let fraction = Fraction::new(Uint128::one(), Uint128::one()); + let fraction = (Uint128::one(), Uint128::one()); let res = Uint128::new(123456).mul_floored(fraction); assert_eq!(Uint128::new(123456), res) } #[test] fn mul_floored_rounds_down_with_normal_case() { - let fraction = Fraction::new(8u128, 21u128); + let fraction = (8u128, 21u128); let res = Uint128::new(123456).mul_floored(fraction); // 47030.8571 assert_eq!(Uint128::new(47030), res) } #[test] - fn mul_floored_works_with_higher_bit_sizes() { - let fraction = Fraction::new(Uint256::from(8u128), Uint256::from(21u128)); - let res = Uint128::new(123456).mul_floored(fraction); // 47030.8571 - assert_eq!(Uint128::new(47030), res) + fn mul_floored_works_when_operation_temporarily_takes_above_max() { + let fraction = (8u128, 21u128); + let res = Uint128::MAX.mul_floored(fraction); // 129_631_377_874_643_224_176_523_659_974_006_937_697.14285 + assert_eq!( + Uint128::new(129_631_377_874_643_224_176_523_659_974_006_937_697), + res + ) } #[test] @@ -1083,27 +1084,20 @@ mod tests { assert_eq!(Uint128::new(47030), res) } - #[test] - fn mul_floored_works_with_decimal256() { - let decimal = Decimal256::from_ratio(8u128, 21u128); - let res = Uint128::new(123456).mul_floored(decimal); // 47030.8571 - assert_eq!(Uint128::new(47030), res) - } - #[test] #[should_panic(expected = "ConversionOverflowError")] fn mul_floored_panics_on_overflow() { - let fraction = Fraction::new(21u128, 8u128); + let fraction = (21u128, 8u128); Uint128::MAX.mul_floored(fraction); } #[test] fn checked_mul_floored_does_not_panic_on_overflow() { - let fraction = Fraction::new(21u128, 8u128); + let fraction = (21u128, 8u128); assert_eq!( Uint128::MAX.checked_mul_floored(fraction), Err(ConversionOverflow(ConversionOverflowError { - source_type: "Uint512", + source_type: "Uint256", target_type: "Uint128", value: "893241213167463466591358344508391555069".to_string() })), @@ -1113,13 +1107,13 @@ mod tests { #[test] #[should_panic(expected = "DivideByZeroError")] fn mul_floored_panics_on_zero_div() { - let fraction = Fraction::new(21u128, 0u128); + let fraction = (21u128, 0u128); Uint128::new(123456).mul_floored(fraction); } #[test] fn checked_mul_floored_does_not_panic_on_zero_div() { - let fraction = Fraction::new(21u128, 0u128); + let fraction = (21u128, 0u128); assert_eq!( Uint128::new(123456).checked_mul_floored(fraction), Err(DivideByZero(DivideByZeroError { @@ -1130,30 +1124,33 @@ mod tests { #[test] fn mul_ceil_works_with_zero() { - let fraction = Fraction::new(Uint128::zero(), Uint128::new(21)); + let fraction = (Uint128::zero(), Uint128::new(21)); let res = Uint128::new(123456).mul_ceil(fraction); assert_eq!(Uint128::zero(), res) } #[test] fn mul_ceil_does_nothing_with_one() { - let fraction = Fraction::new(Uint128::one(), Uint128::one()); + let fraction = (Uint128::one(), Uint128::one()); let res = Uint128::new(123456).mul_ceil(fraction); assert_eq!(Uint128::new(123456), res) } #[test] fn mul_ceil_rounds_up_with_normal_case() { - let fraction = Fraction::new(8u128, 21u128); + let fraction = (8u128, 21u128); let res = Uint128::new(123456).mul_ceil(fraction); // 47030.8571 assert_eq!(Uint128::new(47031), res) } #[test] - fn mul_ceil_works_with_higher_bit_sizes() { - let fraction = Fraction::new(Uint256::from(8u128), Uint256::from(21u128)); - let res = Uint128::new(123456).mul_ceil(fraction); // 47030.8571 - assert_eq!(Uint128::new(47031), res) + fn mul_ceil_works_when_operation_temporarily_takes_above_max() { + let fraction = (8u128, 21u128); + let res = Uint128::MAX.mul_ceil(fraction); // 129_631_377_874_643_224_176_523_659_974_006_937_697.14285 + assert_eq!( + Uint128::new(129_631_377_874_643_224_176_523_659_974_006_937_698), + res + ) } #[test] @@ -1163,27 +1160,20 @@ mod tests { assert_eq!(Uint128::new(47031), res) } - #[test] - fn mul_ceil_works_with_decimal256() { - let decimal = Decimal256::from_ratio(8u128, 21u128); - let res = Uint128::new(123456).mul_ceil(decimal); // 47030.8571 - assert_eq!(Uint128::new(47031), res) - } - #[test] #[should_panic(expected = "ConversionOverflowError")] fn mul_ceil_panics_on_overflow() { - let fraction = Fraction::new(21u128, 8u128); + let fraction = (21u128, 8u128); Uint128::MAX.mul_ceil(fraction); } #[test] fn checked_mul_ceil_does_not_panic_on_overflow() { - let fraction = Fraction::new(21u128, 8u128); + let fraction = (21u128, 8u128); assert_eq!( Uint128::MAX.checked_mul_ceil(fraction), Err(ConversionOverflow(ConversionOverflowError { - source_type: "Uint512", + source_type: "Uint256", target_type: "Uint128", value: "893241213167463466591358344508391555069".to_string() })), @@ -1193,13 +1183,13 @@ mod tests { #[test] #[should_panic(expected = "DivideByZeroError")] fn mul_ceil_panics_on_zero_div() { - let fraction = Fraction::new(21u128, 0u128); + let fraction = (21u128, 0u128); Uint128::new(123456).mul_ceil(fraction); } #[test] fn checked_mul_ceil_does_not_panic_on_zero_div() { - let fraction = Fraction::new(21u128, 0u128); + let fraction = (21u128, 0u128); assert_eq!( Uint128::new(123456).checked_mul_ceil(fraction), Err(DivideByZero(DivideByZeroError { From eddb6b30d49e5893ceafd4f15ae6af179b35d86d Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Wed, 4 Jan 2023 22:16:37 +0100 Subject: [PATCH 120/187] extend macro to Uint64/256 --- packages/std/src/math/fraction.rs | 18 +-- packages/std/src/math/uint128.rs | 4 +- packages/std/src/math/uint256.rs | 187 +++++++++++++++++++++++++++++- packages/std/src/math/uint64.rs | 142 ++++++++++++++++++++++- 4 files changed, 333 insertions(+), 18 deletions(-) diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index 7d6afedcba..eca7cea8f0 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -29,23 +29,24 @@ impl Fraction for (T, T) { #[macro_export] macro_rules! impl_mul_fraction { - ($UintBase:ident, $UintLarger:ident) => { - impl $UintBase { - pub fn checked_mul_floored, T: Into<$UintBase>>( + ($Uint:ident) => { + impl $Uint { + pub fn checked_mul_floored, T: Into<$Uint>>( self, rhs: F, ) -> Result { + let divisor = rhs.denominator().into(); let res = self .full_mul(rhs.numerator().into()) - .checked_div($UintLarger::from(rhs.denominator().into()))?; + .checked_div(divisor.into())?; Ok(res.try_into()?) } - pub fn mul_floored, T: Into<$UintBase>>(self, rhs: F) -> Self { + pub fn mul_floored, T: Into<$Uint>>(self, rhs: F) -> Self { self.checked_mul_floored(rhs).unwrap() } - pub fn checked_mul_ceil + Clone, T: Into<$UintBase>>( + pub fn checked_mul_ceil + Clone, T: Into<$Uint>>( self, rhs: F, ) -> Result { @@ -53,14 +54,13 @@ macro_rules! impl_mul_fraction { let numerator = rhs.numerator().into(); let denominator = rhs.denominator().into(); if !numerator.checked_rem(denominator)?.is_zero() { - let ceil_result = $UintLarger::one().checked_add(floor_result.into())?; - Ok(ceil_result.try_into()?) + Ok($Uint::one().checked_add(floor_result)?) } else { Ok(floor_result) } } - pub fn mul_ceil + Clone, T: Into<$UintBase>>(self, rhs: F) -> Self { + pub fn mul_ceil + Clone, T: Into<$Uint>>(self, rhs: F) -> Self { self.checked_mul_ceil(rhs).unwrap() } } diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index 48234453f8..1372c64aaf 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -232,7 +232,7 @@ impl Uint128 { } } -impl_mul_fraction!(Uint128, Uint256); +impl_mul_fraction!(Uint128); // `From` is implemented manually instead of // using `impl> From for Uint128` because @@ -1175,7 +1175,7 @@ mod tests { Err(ConversionOverflow(ConversionOverflowError { source_type: "Uint256", target_type: "Uint128", - value: "893241213167463466591358344508391555069".to_string() + value: "893241213167463466591358344508391555069".to_string() // raises prior to rounding up })), ); } diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index 743281735d..f7ad54e32c 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -9,10 +9,10 @@ use std::ops::{ use std::str::FromStr; use crate::errors::{ - CheckedMultiplyRatioError, ConversionOverflowError, DivideByZeroError, OverflowError, - OverflowOperation, StdError, + CheckedMultiplyFractionError, CheckedMultiplyRatioError, ConversionOverflowError, + DivideByZeroError, OverflowError, OverflowOperation, StdError, }; -use crate::{Uint128, Uint512, Uint64}; +use crate::{impl_mul_fraction, Fraction, Uint128, Uint512, Uint64}; /// This module is purely a workaround that lets us ignore lints for all the code /// the `construct_uint!` macro generates. @@ -336,6 +336,8 @@ impl Uint256 { } } +impl_mul_fraction!(Uint256); + impl From for Uint256 { fn from(val: Uint128) -> Self { val.u128().into() @@ -666,7 +668,8 @@ impl PartialEq for &Uint256 { #[cfg(test)] mod tests { use super::*; - use crate::{from_slice, to_vec}; + use crate::errors::CheckedMultiplyFractionError::{ConversionOverflow, DivideByZero}; + use crate::{from_slice, to_vec, Decimal, Decimal256}; #[test] fn size_of_works() { @@ -1664,4 +1667,180 @@ mod tests { assert_eq!(&lhs == &rhs, expected); } } + + #[test] + fn mul_floored_works_with_zero() { + let fraction = (Uint256::zero(), Uint256::from(21u32)); + let res = Uint256::from(123456u32).mul_floored(fraction); + assert_eq!(Uint256::zero(), res) + } + + #[test] + fn mul_floored_does_nothing_with_one() { + let fraction = (Uint256::one(), Uint256::one()); + let res = Uint256::from(123456u32).mul_floored(fraction); + assert_eq!(Uint256::from(123456u32), res) + } + + #[test] + fn mul_floored_rounds_down_with_normal_case() { + let fraction = (Uint256::from(8u128), Uint256::from(21u128)); + let res = Uint256::from(123456u32).mul_floored(fraction); // 47030.8571 + assert_eq!(Uint256::from(47030u32), res) + } + + #[test] + fn mul_floored_works_when_operation_temporarily_takes_above_max() { + let fraction = (8u128, 21u128); + let res = Uint256::MAX.mul_floored(fraction); // 44_111_272_090_406_169_685_169_899_050_928_726_801_245_708_444_053_548_205_507_651_050_633_573_196_165.71428571 + assert_eq!( + Uint256::from_str( + "44111272090406169685169899050928726801245708444053548205507651050633573196165" + ) + .unwrap(), + res + ) + } + + #[test] + fn mul_floored_works_with_decimal() { + let decimal = Decimal::from_ratio(8u128, 21u128); + let res = Uint256::from(123456u32).mul_floored(decimal); // 47030.8571 + assert_eq!(Uint256::from(47030u32), res) + } + + #[test] + fn mul_floored_works_with_decimal256() { + let decimal = Decimal256::from_ratio(8u128, 21u128); + let res = Uint256::from(123456u32).mul_floored(decimal); // 47030.8571 + assert_eq!(Uint256::from(47030u32), res) + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn mul_floored_panics_on_overflow() { + let fraction = (21u128, 8u128); + Uint256::MAX.mul_floored(fraction); + } + + #[test] + fn checked_mul_floored_does_not_panic_on_overflow() { + let fraction = (21u128, 8u128); + assert_eq!( + Uint256::MAX.checked_mul_floored(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint512", + target_type: "Uint256", + value: + "303954234247955012986873835647805758114833709747306480603576158020771965304829" + .to_string() + })), + ); + } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn mul_floored_panics_on_zero_div() { + let fraction = (21u128, 0u128); + Uint256::from(123456u32).mul_floored(fraction); + } + + #[test] + fn checked_mul_floored_does_not_panic_on_zero_div() { + let fraction = (21u128, 0u128); + assert_eq!( + Uint256::from(123456u32).checked_mul_floored(fraction), + Err(DivideByZero(DivideByZeroError { + operand: "2592576".to_string() + })), + ); + } + + #[test] + fn mul_ceil_works_with_zero() { + let fraction = (Uint256::zero(), Uint256::from(21u32)); + let res = Uint256::from(123456u32).mul_ceil(fraction); + assert_eq!(Uint256::zero(), res) + } + + #[test] + fn mul_ceil_does_nothing_with_one() { + let fraction = (Uint256::one(), Uint256::one()); + let res = Uint256::from(123456u32).mul_ceil(fraction); + assert_eq!(Uint256::from(123456u32), res) + } + + #[test] + fn mul_ceil_rounds_up_with_normal_case() { + let fraction = (8u128, 21u128); + let res = Uint256::from(123456u32).mul_ceil(fraction); // 47030.8571 + assert_eq!(Uint256::from(47031u32), res) + } + + #[test] + fn mul_ceil_works_when_operation_temporarily_takes_above_max() { + let fraction = (8u128, 21u128); + let res = Uint256::MAX.mul_ceil(fraction); // 44_111_272_090_406_169_685_169_899_050_928_726_801_245_708_444_053_548_205_507_651_050_633_573_196_165.71428571 + assert_eq!( + Uint256::from_str( + "44111272090406169685169899050928726801245708444053548205507651050633573196166" + ) + .unwrap(), + res + ) + } + + #[test] + fn mul_ceil_works_with_decimal() { + let decimal = Decimal::from_ratio(8u128, 21u128); + let res = Uint256::from(123456u32).mul_ceil(decimal); // 47030.8571 + assert_eq!(Uint256::from(47031u32), res) + } + + #[test] + fn mul_ceil_works_with_decimal256() { + let decimal = Decimal256::from_ratio(8u128, 21u128); + let res = Uint256::from(123456u32).mul_ceil(decimal); // 47030.8571 + assert_eq!(Uint256::from(47031u32), res) + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn mul_ceil_panics_on_overflow() { + let fraction = (21u128, 8u128); + Uint256::MAX.mul_ceil(fraction); + } + + #[test] + fn checked_mul_ceil_does_not_panic_on_overflow() { + let fraction = (21u128, 8u128); + assert_eq!( + Uint256::MAX.checked_mul_ceil(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint512", + target_type: "Uint256", + value: + "303954234247955012986873835647805758114833709747306480603576158020771965304829" // raises prior to rounding up + .to_string() + })), + ); + } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn mul_ceil_panics_on_zero_div() { + let fraction = (21u128, 0u128); + Uint256::from(123456u32).mul_ceil(fraction); + } + + #[test] + fn checked_mul_ceil_does_not_panic_on_zero_div() { + let fraction = (21u128, 0u128); + assert_eq!( + Uint256::from(123456u32).checked_mul_ceil(fraction), + Err(DivideByZero(DivideByZeroError { + operand: "2592576".to_string() + })), + ); + } } diff --git a/packages/std/src/math/uint64.rs b/packages/std/src/math/uint64.rs index 97032633e2..afe0baeb58 100644 --- a/packages/std/src/math/uint64.rs +++ b/packages/std/src/math/uint64.rs @@ -7,9 +7,10 @@ use std::ops::{ }; use crate::errors::{ - CheckedMultiplyRatioError, DivideByZeroError, OverflowError, OverflowOperation, StdError, + CheckedMultiplyFractionError, CheckedMultiplyRatioError, DivideByZeroError, OverflowError, + OverflowOperation, StdError, }; -use crate::Uint128; +use crate::{impl_mul_fraction, Fraction, Uint128}; /// A thin wrapper around u64 that is using strings for JSON encoding/decoding, /// such that the full u64 range can be used for clients that convert JSON numbers to floats, @@ -226,6 +227,8 @@ impl Uint64 { } } +impl_mul_fraction!(Uint64); + // `From` is implemented manually instead of // using `impl> From for Uint64` because // of the conflict with `TryFrom<&str>` as described here @@ -492,7 +495,8 @@ impl PartialEq for &Uint64 { #[cfg(test)] mod tests { use super::*; - use crate::{from_slice, to_vec}; + use crate::errors::CheckedMultiplyFractionError::{ConversionOverflow, DivideByZero}; + use crate::{from_slice, to_vec, ConversionOverflowError}; #[test] fn size_of_works() { @@ -955,4 +959,136 @@ mod tests { assert_eq!(&lhs == &rhs, expected); } } + + #[test] + fn mul_floored_works_with_zero() { + let fraction = (0u32, 21u32); + let res = Uint64::new(123456).mul_floored(fraction); + assert_eq!(Uint64::zero(), res) + } + + #[test] + fn mul_floored_does_nothing_with_one() { + let fraction = (Uint64::one(), Uint64::one()); + let res = Uint64::new(123456).mul_floored(fraction); + assert_eq!(Uint64::new(123456), res) + } + + #[test] + fn mul_floored_rounds_down_with_normal_case() { + let fraction = (8u64, 21u64); + let res = Uint64::new(123456).mul_floored(fraction); // 47030.8571 + assert_eq!(Uint64::new(47030), res) + } + + #[test] + fn mul_floored_works_when_operation_temporarily_takes_above_max() { + let fraction = (8u64, 21u64); + let res = Uint64::MAX.mul_floored(fraction); // 7_027_331_075_698_876_805.71428571 + assert_eq!(Uint64::new(7_027_331_075_698_876_805), res) + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn mul_floored_panics_on_overflow() { + let fraction = (21u64, 8u64); + Uint64::MAX.mul_floored(fraction); + } + + #[test] + fn checked_mul_floored_does_not_panic_on_overflow() { + let fraction = (21u64, 8u64); + assert_eq!( + Uint64::MAX.checked_mul_floored(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint128", + target_type: "Uint64", + value: "48422703193487572989".to_string() + })), + ); + } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn mul_floored_panics_on_zero_div() { + let fraction = (21u64, 0u64); + Uint64::new(123456).mul_floored(fraction); + } + + #[test] + fn checked_mul_floored_does_not_panic_on_zero_div() { + let fraction = (21u64, 0u64); + assert_eq!( + Uint64::new(123456).checked_mul_floored(fraction), + Err(DivideByZero(DivideByZeroError { + operand: "2592576".to_string() + })), + ); + } + + #[test] + fn mul_ceil_works_with_zero() { + let fraction = (Uint64::zero(), Uint64::new(21)); + let res = Uint64::new(123456).mul_ceil(fraction); + assert_eq!(Uint64::zero(), res) + } + + #[test] + fn mul_ceil_does_nothing_with_one() { + let fraction = (Uint64::one(), Uint64::one()); + let res = Uint64::new(123456).mul_ceil(fraction); + assert_eq!(Uint64::new(123456), res) + } + + #[test] + fn mul_ceil_rounds_up_with_normal_case() { + let fraction = (8u64, 21u64); + let res = Uint64::new(123456).mul_ceil(fraction); // 47030.8571 + assert_eq!(Uint64::new(47031), res) + } + + #[test] + fn mul_ceil_works_when_operation_temporarily_takes_above_max() { + let fraction = (8u64, 21u64); + let res = Uint64::MAX.mul_ceil(fraction); // 7_027_331_075_698_876_805.71428571 + assert_eq!(Uint64::new(7_027_331_075_698_876_806), res) + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn mul_ceil_panics_on_overflow() { + let fraction = (21u64, 8u64); + Uint64::MAX.mul_ceil(fraction); + } + + #[test] + fn checked_mul_ceil_does_not_panic_on_overflow() { + let fraction = (21u64, 8u64); + assert_eq!( + Uint64::MAX.checked_mul_ceil(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint128", + target_type: "Uint64", + value: "48422703193487572989".to_string() // raises prior to rounding up + })), + ); + } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn mul_ceil_panics_on_zero_div() { + let fraction = (21u64, 0u64); + Uint64::new(123456).mul_ceil(fraction); + } + + #[test] + fn checked_mul_ceil_does_not_panic_on_zero_div() { + let fraction = (21u64, 0u64); + assert_eq!( + Uint64::new(123456).checked_mul_ceil(fraction), + Err(DivideByZero(DivideByZeroError { + operand: "2592576".to_string() + })), + ); + } } From 9a51c7c9c74eb02212d5fe0770b65e409e5d8cc6 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Sat, 7 Jan 2023 00:46:11 +0100 Subject: [PATCH 121/187] tests + trait update --- packages/std/src/math/fraction.rs | 39 +++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index eca7cea8f0..6b2762f868 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -1,3 +1,5 @@ +use crate::Uint256; + /// A fraction `p`/`q` with integers `p` and `q`. /// /// `p` is called the numerator and `q` is called the denominator. @@ -13,17 +15,21 @@ pub trait Fraction: Sized { fn inv(&self) -> Option; } -impl Fraction for (T, T) { +impl> Fraction for (T, T) { fn numerator(&self) -> T { - self.0.clone() + self.0 } fn denominator(&self) -> T { - self.1.clone() + self.1 } fn inv(&self) -> Option { - Some((self.1.clone(), self.0.clone())) + if self.numerator().into() == Uint256::zero() { + None + } else { + Some((self.1, self.0)) + } } } @@ -46,13 +52,13 @@ macro_rules! impl_mul_fraction { self.checked_mul_floored(rhs).unwrap() } - pub fn checked_mul_ceil + Clone, T: Into<$Uint>>( + pub fn checked_mul_ceil, T: Into<$Uint>>( self, rhs: F, ) -> Result { - let floor_result = self.checked_mul_floored(rhs.clone())?; let numerator = rhs.numerator().into(); let denominator = rhs.denominator().into(); + let floor_result = self.checked_mul_floored(rhs)?; if !numerator.checked_rem(denominator)?.is_zero() { Ok($Uint::one().checked_add(floor_result)?) } else { @@ -60,9 +66,28 @@ macro_rules! impl_mul_fraction { } } - pub fn mul_ceil + Clone, T: Into<$Uint>>(self, rhs: F) -> Self { + pub fn mul_ceil, T: Into<$Uint>>(self, rhs: F) -> Self { self.checked_mul_ceil(rhs).unwrap() } } }; } + +#[cfg(test)] +mod tests { + use crate::{Fraction, Uint128, Uint64}; + + #[test] + fn fraction_tuple_methods() { + let fraction = (Uint64::one(), Uint64::new(2)); + assert_eq!(Uint64::one(), fraction.numerator()); + assert_eq!(Uint64::new(2), fraction.denominator()); + assert_eq!(Some((Uint64::new(2), Uint64::one())), fraction.inv()); + } + + #[test] + fn inverse_with_zero_denominator() { + let fraction = (Uint128::zero(), Uint128::one()); + assert_eq!(None, fraction.inv()); + } +} From df4503ce11984e96c8f2fbb08123c7ff6e8498c7 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Sun, 8 Jan 2023 11:16:33 +0100 Subject: [PATCH 122/187] Ensure no rounds on even divides --- packages/std/src/math/fraction.rs | 8 +++++--- packages/std/src/math/uint128.rs | 14 ++++++++++++++ packages/std/src/math/uint256.rs | 14 ++++++++++++++ packages/std/src/math/uint64.rs | 14 ++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index 6b2762f868..bd8762fac5 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -56,10 +56,12 @@ macro_rules! impl_mul_fraction { self, rhs: F, ) -> Result { - let numerator = rhs.numerator().into(); - let denominator = rhs.denominator().into(); + let divisor = rhs.denominator().into(); + let remainder = self + .full_mul(rhs.numerator().into()) + .checked_rem(divisor.into())?; let floor_result = self.checked_mul_floored(rhs)?; - if !numerator.checked_rem(denominator)?.is_zero() { + if !remainder.is_zero() { Ok($Uint::one().checked_add(floor_result)?) } else { Ok(floor_result) diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index 1372c64aaf..390880398a 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -1067,6 +1067,13 @@ mod tests { assert_eq!(Uint128::new(47030), res) } + #[test] + fn mul_floored_does_not_round_on_even_divide() { + let fraction = (2u128, 5u128); + let res = Uint128::new(25).mul_floored(fraction); + assert_eq!(Uint128::new(10), res) + } + #[test] fn mul_floored_works_when_operation_temporarily_takes_above_max() { let fraction = (8u128, 21u128); @@ -1143,6 +1150,13 @@ mod tests { assert_eq!(Uint128::new(47031), res) } + #[test] + fn mul_ceil_does_not_round_on_even_divide() { + let fraction = (2u128, 5u128); + let res = Uint128::new(25).mul_ceil(fraction); + assert_eq!(Uint128::new(10), res) + } + #[test] fn mul_ceil_works_when_operation_temporarily_takes_above_max() { let fraction = (8u128, 21u128); diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index f7ad54e32c..68c9bf0e71 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -1689,6 +1689,13 @@ mod tests { assert_eq!(Uint256::from(47030u32), res) } + #[test] + fn mul_floored_does_not_round_on_even_divide() { + let fraction = (2u128, 5u128); + let res = Uint256::from(25u32).mul_floored(fraction); + assert_eq!(Uint256::from(10u32), res) + } + #[test] fn mul_floored_works_when_operation_temporarily_takes_above_max() { let fraction = (8u128, 21u128); @@ -1777,6 +1784,13 @@ mod tests { assert_eq!(Uint256::from(47031u32), res) } + #[test] + fn mul_ceil_does_not_round_on_even_divide() { + let fraction = (2u128, 5u128); + let res = Uint256::from(25u32).mul_ceil(fraction); + assert_eq!(Uint256::from(10u32), res) + } + #[test] fn mul_ceil_works_when_operation_temporarily_takes_above_max() { let fraction = (8u128, 21u128); diff --git a/packages/std/src/math/uint64.rs b/packages/std/src/math/uint64.rs index afe0baeb58..2600dbab94 100644 --- a/packages/std/src/math/uint64.rs +++ b/packages/std/src/math/uint64.rs @@ -981,6 +981,13 @@ mod tests { assert_eq!(Uint64::new(47030), res) } + #[test] + fn mul_floored_does_not_round_on_even_divide() { + let fraction = (2u64, 5u64); + let res = Uint64::new(25).mul_floored(fraction); + assert_eq!(Uint64::new(10), res) + } + #[test] fn mul_floored_works_when_operation_temporarily_takes_above_max() { let fraction = (8u64, 21u64); @@ -1047,6 +1054,13 @@ mod tests { assert_eq!(Uint64::new(47031), res) } + #[test] + fn mul_ceil_does_not_round_on_even_divide() { + let fraction = (2u64, 5u64); + let res = Uint64::new(25).mul_ceil(fraction); + assert_eq!(Uint64::new(10), res) + } + #[test] fn mul_ceil_works_when_operation_temporarily_takes_above_max() { let fraction = (8u64, 21u64); From cdc653dd7524720391625fc6d4857245a16199d5 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Sun, 8 Jan 2023 11:17:53 +0100 Subject: [PATCH 123/187] Improve zero denom check --- packages/std/src/math/fraction.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index bd8762fac5..5f8a117e92 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -1,5 +1,3 @@ -use crate::Uint256; - /// A fraction `p`/`q` with integers `p` and `q`. /// /// `p` is called the numerator and `q` is called the denominator. @@ -15,7 +13,7 @@ pub trait Fraction: Sized { fn inv(&self) -> Option; } -impl> Fraction for (T, T) { +impl + PartialEq> Fraction for (T, T) { fn numerator(&self) -> T { self.0 } @@ -25,7 +23,7 @@ impl> Fraction for (T, T) { } fn inv(&self) -> Option { - if self.numerator().into() == Uint256::zero() { + if self.numerator() == 0u8.into() { None } else { Some((self.1, self.0)) From 8b63fcd4faef054fe71d9edfbab15582d643adb9 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Sun, 8 Jan 2023 12:07:58 +0100 Subject: [PATCH 124/187] make floor/ceil tenses consistent --- packages/std/src/math/fraction.rs | 8 +++--- packages/std/src/math/uint128.rs | 40 ++++++++++++++-------------- packages/std/src/math/uint256.rs | 44 +++++++++++++++---------------- packages/std/src/math/uint64.rs | 36 ++++++++++++------------- 4 files changed, 64 insertions(+), 64 deletions(-) diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index 5f8a117e92..e170869bf3 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -35,7 +35,7 @@ impl + PartialEq> Fraction for (T, T) { macro_rules! impl_mul_fraction { ($Uint:ident) => { impl $Uint { - pub fn checked_mul_floored, T: Into<$Uint>>( + pub fn checked_mul_floor, T: Into<$Uint>>( self, rhs: F, ) -> Result { @@ -46,8 +46,8 @@ macro_rules! impl_mul_fraction { Ok(res.try_into()?) } - pub fn mul_floored, T: Into<$Uint>>(self, rhs: F) -> Self { - self.checked_mul_floored(rhs).unwrap() + pub fn mul_floor, T: Into<$Uint>>(self, rhs: F) -> Self { + self.checked_mul_floor(rhs).unwrap() } pub fn checked_mul_ceil, T: Into<$Uint>>( @@ -58,7 +58,7 @@ macro_rules! impl_mul_fraction { let remainder = self .full_mul(rhs.numerator().into()) .checked_rem(divisor.into())?; - let floor_result = self.checked_mul_floored(rhs)?; + let floor_result = self.checked_mul_floor(rhs)?; if !remainder.is_zero() { Ok($Uint::one().checked_add(floor_result)?) } else { diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index 390880398a..9bc21ac54d 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -1047,37 +1047,37 @@ mod tests { } #[test] - fn mul_floored_works_with_zero() { + fn mul_floor_works_with_zero() { let fraction = (Uint128::zero(), Uint128::new(21)); - let res = Uint128::new(123456).mul_floored(fraction); + let res = Uint128::new(123456).mul_floor(fraction); assert_eq!(Uint128::zero(), res) } #[test] - fn mul_floored_does_nothing_with_one() { + fn mul_floor_does_nothing_with_one() { let fraction = (Uint128::one(), Uint128::one()); - let res = Uint128::new(123456).mul_floored(fraction); + let res = Uint128::new(123456).mul_floor(fraction); assert_eq!(Uint128::new(123456), res) } #[test] - fn mul_floored_rounds_down_with_normal_case() { + fn mul_floor_rounds_down_with_normal_case() { let fraction = (8u128, 21u128); - let res = Uint128::new(123456).mul_floored(fraction); // 47030.8571 + let res = Uint128::new(123456).mul_floor(fraction); // 47030.8571 assert_eq!(Uint128::new(47030), res) } #[test] - fn mul_floored_does_not_round_on_even_divide() { + fn mul_floor_does_not_round_on_even_divide() { let fraction = (2u128, 5u128); - let res = Uint128::new(25).mul_floored(fraction); + let res = Uint128::new(25).mul_floor(fraction); assert_eq!(Uint128::new(10), res) } #[test] - fn mul_floored_works_when_operation_temporarily_takes_above_max() { + fn mul_floor_works_when_operation_temporarily_takes_above_max() { let fraction = (8u128, 21u128); - let res = Uint128::MAX.mul_floored(fraction); // 129_631_377_874_643_224_176_523_659_974_006_937_697.14285 + let res = Uint128::MAX.mul_floor(fraction); // 129_631_377_874_643_224_176_523_659_974_006_937_697.14285 assert_eq!( Uint128::new(129_631_377_874_643_224_176_523_659_974_006_937_697), res @@ -1085,24 +1085,24 @@ mod tests { } #[test] - fn mul_floored_works_with_decimal() { + fn mul_floor_works_with_decimal() { let decimal = Decimal::from_ratio(8u128, 21u128); - let res = Uint128::new(123456).mul_floored(decimal); // 47030.8571 + let res = Uint128::new(123456).mul_floor(decimal); // 47030.8571 assert_eq!(Uint128::new(47030), res) } #[test] #[should_panic(expected = "ConversionOverflowError")] - fn mul_floored_panics_on_overflow() { + fn mul_floor_panics_on_overflow() { let fraction = (21u128, 8u128); - Uint128::MAX.mul_floored(fraction); + Uint128::MAX.mul_floor(fraction); } #[test] - fn checked_mul_floored_does_not_panic_on_overflow() { + fn checked_mul_floor_does_not_panic_on_overflow() { let fraction = (21u128, 8u128); assert_eq!( - Uint128::MAX.checked_mul_floored(fraction), + Uint128::MAX.checked_mul_floor(fraction), Err(ConversionOverflow(ConversionOverflowError { source_type: "Uint256", target_type: "Uint128", @@ -1113,16 +1113,16 @@ mod tests { #[test] #[should_panic(expected = "DivideByZeroError")] - fn mul_floored_panics_on_zero_div() { + fn mul_floor_panics_on_zero_div() { let fraction = (21u128, 0u128); - Uint128::new(123456).mul_floored(fraction); + Uint128::new(123456).mul_floor(fraction); } #[test] - fn checked_mul_floored_does_not_panic_on_zero_div() { + fn checked_mul_floor_does_not_panic_on_zero_div() { let fraction = (21u128, 0u128); assert_eq!( - Uint128::new(123456).checked_mul_floored(fraction), + Uint128::new(123456).checked_mul_floor(fraction), Err(DivideByZero(DivideByZeroError { operand: "2592576".to_string() })), diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index 68c9bf0e71..664cdb8651 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -1669,37 +1669,37 @@ mod tests { } #[test] - fn mul_floored_works_with_zero() { + fn mul_floor_works_with_zero() { let fraction = (Uint256::zero(), Uint256::from(21u32)); - let res = Uint256::from(123456u32).mul_floored(fraction); + let res = Uint256::from(123456u32).mul_floor(fraction); assert_eq!(Uint256::zero(), res) } #[test] - fn mul_floored_does_nothing_with_one() { + fn mul_floor_does_nothing_with_one() { let fraction = (Uint256::one(), Uint256::one()); - let res = Uint256::from(123456u32).mul_floored(fraction); + let res = Uint256::from(123456u32).mul_floor(fraction); assert_eq!(Uint256::from(123456u32), res) } #[test] - fn mul_floored_rounds_down_with_normal_case() { + fn mul_floor_rounds_down_with_normal_case() { let fraction = (Uint256::from(8u128), Uint256::from(21u128)); - let res = Uint256::from(123456u32).mul_floored(fraction); // 47030.8571 + let res = Uint256::from(123456u32).mul_floor(fraction); // 47030.8571 assert_eq!(Uint256::from(47030u32), res) } #[test] - fn mul_floored_does_not_round_on_even_divide() { + fn mul_floor_does_not_round_on_even_divide() { let fraction = (2u128, 5u128); - let res = Uint256::from(25u32).mul_floored(fraction); + let res = Uint256::from(25u32).mul_floor(fraction); assert_eq!(Uint256::from(10u32), res) } #[test] - fn mul_floored_works_when_operation_temporarily_takes_above_max() { + fn mul_floor_works_when_operation_temporarily_takes_above_max() { let fraction = (8u128, 21u128); - let res = Uint256::MAX.mul_floored(fraction); // 44_111_272_090_406_169_685_169_899_050_928_726_801_245_708_444_053_548_205_507_651_050_633_573_196_165.71428571 + let res = Uint256::MAX.mul_floor(fraction); // 44_111_272_090_406_169_685_169_899_050_928_726_801_245_708_444_053_548_205_507_651_050_633_573_196_165.71428571 assert_eq!( Uint256::from_str( "44111272090406169685169899050928726801245708444053548205507651050633573196165" @@ -1710,31 +1710,31 @@ mod tests { } #[test] - fn mul_floored_works_with_decimal() { + fn mul_floor_works_with_decimal() { let decimal = Decimal::from_ratio(8u128, 21u128); - let res = Uint256::from(123456u32).mul_floored(decimal); // 47030.8571 + let res = Uint256::from(123456u32).mul_floor(decimal); // 47030.8571 assert_eq!(Uint256::from(47030u32), res) } #[test] - fn mul_floored_works_with_decimal256() { + fn mul_floor_works_with_decimal256() { let decimal = Decimal256::from_ratio(8u128, 21u128); - let res = Uint256::from(123456u32).mul_floored(decimal); // 47030.8571 + let res = Uint256::from(123456u32).mul_floor(decimal); // 47030.8571 assert_eq!(Uint256::from(47030u32), res) } #[test] #[should_panic(expected = "ConversionOverflowError")] - fn mul_floored_panics_on_overflow() { + fn mul_floor_panics_on_overflow() { let fraction = (21u128, 8u128); - Uint256::MAX.mul_floored(fraction); + Uint256::MAX.mul_floor(fraction); } #[test] - fn checked_mul_floored_does_not_panic_on_overflow() { + fn checked_mul_floor_does_not_panic_on_overflow() { let fraction = (21u128, 8u128); assert_eq!( - Uint256::MAX.checked_mul_floored(fraction), + Uint256::MAX.checked_mul_floor(fraction), Err(ConversionOverflow(ConversionOverflowError { source_type: "Uint512", target_type: "Uint256", @@ -1747,16 +1747,16 @@ mod tests { #[test] #[should_panic(expected = "DivideByZeroError")] - fn mul_floored_panics_on_zero_div() { + fn mul_floor_panics_on_zero_div() { let fraction = (21u128, 0u128); - Uint256::from(123456u32).mul_floored(fraction); + Uint256::from(123456u32).mul_floor(fraction); } #[test] - fn checked_mul_floored_does_not_panic_on_zero_div() { + fn checked_mul_floor_does_not_panic_on_zero_div() { let fraction = (21u128, 0u128); assert_eq!( - Uint256::from(123456u32).checked_mul_floored(fraction), + Uint256::from(123456u32).checked_mul_floor(fraction), Err(DivideByZero(DivideByZeroError { operand: "2592576".to_string() })), diff --git a/packages/std/src/math/uint64.rs b/packages/std/src/math/uint64.rs index 2600dbab94..7cba8cb0e9 100644 --- a/packages/std/src/math/uint64.rs +++ b/packages/std/src/math/uint64.rs @@ -961,52 +961,52 @@ mod tests { } #[test] - fn mul_floored_works_with_zero() { + fn mul_floor_works_with_zero() { let fraction = (0u32, 21u32); - let res = Uint64::new(123456).mul_floored(fraction); + let res = Uint64::new(123456).mul_floor(fraction); assert_eq!(Uint64::zero(), res) } #[test] - fn mul_floored_does_nothing_with_one() { + fn mul_floor_does_nothing_with_one() { let fraction = (Uint64::one(), Uint64::one()); - let res = Uint64::new(123456).mul_floored(fraction); + let res = Uint64::new(123456).mul_floor(fraction); assert_eq!(Uint64::new(123456), res) } #[test] - fn mul_floored_rounds_down_with_normal_case() { + fn mul_floor_rounds_down_with_normal_case() { let fraction = (8u64, 21u64); - let res = Uint64::new(123456).mul_floored(fraction); // 47030.8571 + let res = Uint64::new(123456).mul_floor(fraction); // 47030.8571 assert_eq!(Uint64::new(47030), res) } #[test] - fn mul_floored_does_not_round_on_even_divide() { + fn mul_floor_does_not_round_on_even_divide() { let fraction = (2u64, 5u64); - let res = Uint64::new(25).mul_floored(fraction); + let res = Uint64::new(25).mul_floor(fraction); assert_eq!(Uint64::new(10), res) } #[test] - fn mul_floored_works_when_operation_temporarily_takes_above_max() { + fn mul_floor_works_when_operation_temporarily_takes_above_max() { let fraction = (8u64, 21u64); - let res = Uint64::MAX.mul_floored(fraction); // 7_027_331_075_698_876_805.71428571 + let res = Uint64::MAX.mul_floor(fraction); // 7_027_331_075_698_876_805.71428571 assert_eq!(Uint64::new(7_027_331_075_698_876_805), res) } #[test] #[should_panic(expected = "ConversionOverflowError")] - fn mul_floored_panics_on_overflow() { + fn mul_floor_panics_on_overflow() { let fraction = (21u64, 8u64); - Uint64::MAX.mul_floored(fraction); + Uint64::MAX.mul_floor(fraction); } #[test] - fn checked_mul_floored_does_not_panic_on_overflow() { + fn checked_mul_floor_does_not_panic_on_overflow() { let fraction = (21u64, 8u64); assert_eq!( - Uint64::MAX.checked_mul_floored(fraction), + Uint64::MAX.checked_mul_floor(fraction), Err(ConversionOverflow(ConversionOverflowError { source_type: "Uint128", target_type: "Uint64", @@ -1017,16 +1017,16 @@ mod tests { #[test] #[should_panic(expected = "DivideByZeroError")] - fn mul_floored_panics_on_zero_div() { + fn mul_floor_panics_on_zero_div() { let fraction = (21u64, 0u64); - Uint64::new(123456).mul_floored(fraction); + Uint64::new(123456).mul_floor(fraction); } #[test] - fn checked_mul_floored_does_not_panic_on_zero_div() { + fn checked_mul_floor_does_not_panic_on_zero_div() { let fraction = (21u64, 0u64); assert_eq!( - Uint64::new(123456).checked_mul_floored(fraction), + Uint64::new(123456).checked_mul_floor(fraction), Err(DivideByZero(DivideByZeroError { operand: "2592576".to_string() })), From e79ab95eef56cfb881e39c4c430a3d6f1322cbc4 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Thu, 12 Jan 2023 11:10:33 +0100 Subject: [PATCH 125/187] Add fraction division support --- packages/std/src/math/fraction.rs | 47 +++++++++ packages/std/src/math/uint128.rs | 142 ++++++++++++++++++++++++++++ packages/std/src/math/uint256.rs | 152 ++++++++++++++++++++++++++++++ packages/std/src/math/uint64.rs | 110 +++++++++++++++++++++ 4 files changed, 451 insertions(+) diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index e170869bf3..de3a85a0d5 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -69,6 +69,53 @@ macro_rules! impl_mul_fraction { pub fn mul_ceil, T: Into<$Uint>>(self, rhs: F) -> Self { self.checked_mul_ceil(rhs).unwrap() } + + pub fn div_floor, T: Into<$Uint>>(self, rhs: F) -> Self + where + Self: Sized, + { + self.checked_div_floor(rhs).unwrap() + } + + pub fn checked_div_floor, T: Into<$Uint>>( + self, + rhs: F, + ) -> Result + where + Self: Sized, + { + let divisor = rhs.numerator().into(); + let res = self + .full_mul(rhs.denominator().into()) + .checked_div(divisor.into())?; + Ok(res.try_into()?) + } + + pub fn div_ceil, T: Into<$Uint>>(self, rhs: F) -> Self + where + Self: Sized, + { + self.checked_div_ceil(rhs).unwrap() + } + + pub fn checked_div_ceil, T: Into<$Uint>>( + self, + rhs: F, + ) -> Result + where + Self: Sized, + { + let divisor = rhs.numerator().into(); + let remainder = self + .full_mul(rhs.denominator().into()) + .checked_rem(divisor.into())?; + let floor_result = self.checked_div_floor(rhs)?; + if !remainder.is_zero() { + Ok($Uint::one().checked_add(floor_result)?) + } else { + Ok(floor_result) + } + } } }; } diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index 9bc21ac54d..2296f40bff 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -1211,4 +1211,146 @@ mod tests { })), ); } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn div_floor_raises_with_zero() { + let fraction = (Uint128::zero(), Uint128::new(21)); + Uint128::new(123456).div_floor(fraction); + } + + #[test] + fn div_floor_does_nothing_with_one() { + let fraction = (Uint128::one(), Uint128::one()); + let res = Uint128::new(123456).div_floor(fraction); + assert_eq!(Uint128::new(123456), res) + } + + #[test] + fn div_floor_rounds_down_with_normal_case() { + let fraction = (5u128, 21u128); + let res = Uint128::new(123456).div_floor(fraction); // 518515.2 + assert_eq!(Uint128::new(518515), res) + } + + #[test] + fn div_floor_does_not_round_on_even_divide() { + let fraction = (5u128, 2u128); + let res = Uint128::new(25).div_floor(fraction); + assert_eq!(Uint128::new(10), res) + } + + #[test] + fn div_floor_works_when_operation_temporarily_takes_above_max() { + let fraction = (21u128, 8u128); + let res = Uint128::MAX.div_floor(fraction); // 129_631_377_874_643_224_176_523_659_974_006_937_697.1428 + assert_eq!( + Uint128::new(129_631_377_874_643_224_176_523_659_974_006_937_697), + res + ) + } + + #[test] + fn div_floor_works_with_decimal() { + let decimal = Decimal::from_ratio(21u128, 8u128); + let res = Uint128::new(123456).div_floor(decimal); // 47030.8571 + assert_eq!(Uint128::new(47030), res) + } + + #[test] + fn div_floor_works_with_decimal_evenly() { + let res = Uint128::new(60).div_floor(Decimal::from_atomics(6u128, 0).unwrap()); + assert_eq!(res, Uint128::new(10)); + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn div_floor_panics_on_overflow() { + let fraction = (8u128, 21u128); + Uint128::MAX.div_floor(fraction); + } + + #[test] + fn div_floor_does_not_panic_on_overflow() { + let fraction = (8u128, 21u128); + assert_eq!( + Uint128::MAX.checked_div_floor(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint256", + target_type: "Uint128", + value: "893241213167463466591358344508391555069".to_string() + })), + ); + } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn div_ceil_raises_with_zero() { + let fraction = (Uint128::zero(), Uint128::new(21)); + Uint128::new(123456).div_ceil(fraction); + } + + #[test] + fn div_ceil_does_nothing_with_one() { + let fraction = (Uint128::one(), Uint128::one()); + let res = Uint128::new(123456).div_ceil(fraction); + assert_eq!(Uint128::new(123456), res) + } + + #[test] + fn div_ceil_rounds_up_with_normal_case() { + let fraction = (5u128, 21u128); + let res = Uint128::new(123456).div_ceil(fraction); // 518515.2 + assert_eq!(Uint128::new(518516), res) + } + + #[test] + fn div_ceil_does_not_round_on_even_divide() { + let fraction = (5u128, 2u128); + let res = Uint128::new(25).div_ceil(fraction); + assert_eq!(Uint128::new(10), res) + } + + #[test] + fn div_ceil_works_when_operation_temporarily_takes_above_max() { + let fraction = (21u128, 8u128); + let res = Uint128::MAX.div_ceil(fraction); // 129_631_377_874_643_224_176_523_659_974_006_937_697.1428 + assert_eq!( + Uint128::new(129_631_377_874_643_224_176_523_659_974_006_937_698), + res + ) + } + + #[test] + fn div_ceil_works_with_decimal() { + let decimal = Decimal::from_ratio(21u128, 8u128); + let res = Uint128::new(123456).div_ceil(decimal); // 47030.8571 + assert_eq!(Uint128::new(47031), res) + } + + #[test] + fn div_ceil_works_with_decimal_evenly() { + let res = Uint128::new(60).div_ceil(Decimal::from_atomics(6u128, 0).unwrap()); + assert_eq!(res, Uint128::new(10)); + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn div_ceil_panics_on_overflow() { + let fraction = (8u128, 21u128); + Uint128::MAX.div_ceil(fraction); + } + + #[test] + fn div_ceil_does_not_panic_on_overflow() { + let fraction = (8u128, 21u128); + assert_eq!( + Uint128::MAX.checked_div_ceil(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint256", + target_type: "Uint128", + value: "893241213167463466591358344508391555069".to_string() + })), + ); + } } diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index 664cdb8651..d613436730 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -1857,4 +1857,156 @@ mod tests { })), ); } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn div_floor_raises_with_zero() { + let fraction = (Uint256::zero(), Uint256::from(21u32)); + Uint256::from(123456u128).div_floor(fraction); + } + + #[test] + fn div_floor_does_nothing_with_one() { + let fraction = (Uint256::one(), Uint256::one()); + let res = Uint256::from(123456u128).div_floor(fraction); + assert_eq!(Uint256::from(123456u128), res) + } + + #[test] + fn div_floor_rounds_down_with_normal_case() { + let fraction = (5u128, 21u128); + let res = Uint256::from(123456u128).div_floor(fraction); // 518515.2 + assert_eq!(Uint256::from(518515u128), res) + } + + #[test] + fn div_floor_does_not_round_on_even_divide() { + let fraction = (5u128, 2u128); + let res = Uint256::from(25u128).div_floor(fraction); + assert_eq!(Uint256::from(10u128), res) + } + + #[test] + fn div_floor_works_when_operation_temporarily_takes_above_max() { + let fraction = (21u128, 8u128); + let res = Uint256::MAX.div_floor(fraction); // 44_111_272_090_406_169_685_169_899_050_928_726_801_245_708_444_053_548_205_507_651_050_633_573_196_165.71428571 + assert_eq!( + Uint256::from_str( + "44111272090406169685169899050928726801245708444053548205507651050633573196165" + ) + .unwrap(), + res + ) + } + + #[test] + fn div_floor_works_with_decimal() { + let decimal = Decimal::from_ratio(21u128, 8u128); + let res = Uint256::from(123456u128).div_floor(decimal); // 47030.8571 + assert_eq!(Uint256::from(47030u128), res) + } + + #[test] + fn div_floor_works_with_decimal_evenly() { + let res = Uint256::from(60u128).div_floor(Decimal::from_atomics(6u128, 0).unwrap()); + assert_eq!(res, Uint256::from(10u128)); + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn div_floor_panics_on_overflow() { + let fraction = (8u128, 21u128); + Uint256::MAX.div_floor(fraction); + } + + #[test] + fn div_floor_does_not_panic_on_overflow() { + let fraction = (8u128, 21u128); + assert_eq!( + Uint256::MAX.checked_div_floor(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint512", + target_type: "Uint256", + value: + "303954234247955012986873835647805758114833709747306480603576158020771965304829" + .to_string() + })), + ); + } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn div_ceil_raises_with_zero() { + let fraction = (Uint256::zero(), Uint256::from(21u128)); + Uint256::from(123456u128).div_ceil(fraction); + } + + #[test] + fn div_ceil_does_nothing_with_one() { + let fraction = (Uint256::one(), Uint256::one()); + let res = Uint256::from(123456u128).div_ceil(fraction); + assert_eq!(Uint256::from(123456u128), res) + } + + #[test] + fn div_ceil_rounds_up_with_normal_case() { + let fraction = (5u128, 21u128); + let res = Uint256::from(123456u128).div_ceil(fraction); // 518515.2 + assert_eq!(Uint256::from(518516u128), res) + } + + #[test] + fn div_ceil_does_not_round_on_even_divide() { + let fraction = (5u128, 2u128); + let res = Uint256::from(25u128).div_ceil(fraction); + assert_eq!(Uint256::from(10u128), res) + } + + #[test] + fn div_ceil_works_when_operation_temporarily_takes_above_max() { + let fraction = (21u128, 8u128); + let res = Uint256::MAX.div_ceil(fraction); // 44_111_272_090_406_169_685_169_899_050_928_726_801_245_708_444_053_548_205_507_651_050_633_573_196_165.71428571 + assert_eq!( + Uint256::from_str( + "44111272090406169685169899050928726801245708444053548205507651050633573196166" + ) + .unwrap(), + res + ) + } + + #[test] + fn div_ceil_works_with_decimal() { + let decimal = Decimal::from_ratio(21u128, 8u128); + let res = Uint256::from(123456u128).div_ceil(decimal); // 47030.8571 + assert_eq!(Uint256::from(47031u128), res) + } + + #[test] + fn div_ceil_works_with_decimal_evenly() { + let res = Uint256::from(60u128).div_ceil(Decimal::from_atomics(6u128, 0).unwrap()); + assert_eq!(res, Uint256::from(10u128)); + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn div_ceil_panics_on_overflow() { + let fraction = (8u128, 21u128); + Uint256::MAX.div_ceil(fraction); + } + + #[test] + fn div_ceil_does_not_panic_on_overflow() { + let fraction = (8u128, 21u128); + assert_eq!( + Uint256::MAX.checked_div_ceil(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint512", + target_type: "Uint256", + value: + "303954234247955012986873835647805758114833709747306480603576158020771965304829" + .to_string() // raises prior to rounding up + })), + ); + } } diff --git a/packages/std/src/math/uint64.rs b/packages/std/src/math/uint64.rs index 7cba8cb0e9..d6fc5fca95 100644 --- a/packages/std/src/math/uint64.rs +++ b/packages/std/src/math/uint64.rs @@ -1105,4 +1105,114 @@ mod tests { })), ); } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn div_floor_raises_with_zero() { + let fraction = (Uint64::zero(), Uint64::new(21)); + Uint64::new(123456).div_floor(fraction); + } + + #[test] + fn div_floor_does_nothing_with_one() { + let fraction = (Uint64::one(), Uint64::one()); + let res = Uint64::new(123456).div_floor(fraction); + assert_eq!(Uint64::new(123456), res) + } + + #[test] + fn div_floor_rounds_down_with_normal_case() { + let fraction = (5u64, 21u64); + let res = Uint64::new(123456).div_floor(fraction); // 518515.2 + assert_eq!(Uint64::new(518515), res) + } + + #[test] + fn div_floor_does_not_round_on_even_divide() { + let fraction = (5u64, 2u64); + let res = Uint64::new(25).div_floor(fraction); + assert_eq!(Uint64::new(10), res) + } + + #[test] + fn div_floor_works_when_operation_temporarily_takes_above_max() { + let fraction = (21u64, 8u64); + let res = Uint64::MAX.div_floor(fraction); // 7_027_331_075_698_876_805.71428 + assert_eq!(Uint64::new(7_027_331_075_698_876_805), res) + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn div_floor_panics_on_overflow() { + let fraction = (8u64, 21u64); + Uint64::MAX.div_floor(fraction); + } + + #[test] + fn div_floor_does_not_panic_on_overflow() { + let fraction = (8u64, 21u64); + assert_eq!( + Uint64::MAX.checked_div_floor(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint128", + target_type: "Uint64", + value: "48422703193487572989".to_string() + })), + ); + } + + #[test] + #[should_panic(expected = "DivideByZeroError")] + fn div_ceil_raises_with_zero() { + let fraction = (Uint64::zero(), Uint64::new(21)); + Uint64::new(123456).div_ceil(fraction); + } + + #[test] + fn div_ceil_does_nothing_with_one() { + let fraction = (Uint64::one(), Uint64::one()); + let res = Uint64::new(123456).div_ceil(fraction); + assert_eq!(Uint64::new(123456), res) + } + + #[test] + fn div_ceil_rounds_up_with_normal_case() { + let fraction = (5u64, 21u64); + let res = Uint64::new(123456).div_ceil(fraction); // 518515.2 + assert_eq!(Uint64::new(518516), res) + } + + #[test] + fn div_ceil_does_not_round_on_even_divide() { + let fraction = (5u64, 2u64); + let res = Uint64::new(25).div_ceil(fraction); + assert_eq!(Uint64::new(10), res) + } + + #[test] + fn div_ceil_works_when_operation_temporarily_takes_above_max() { + let fraction = (21u64, 8u64); + let res = Uint64::MAX.div_ceil(fraction); // 7_027_331_075_698_876_805.71428 + assert_eq!(Uint64::new(7_027_331_075_698_876_806), res) + } + + #[test] + #[should_panic(expected = "ConversionOverflowError")] + fn div_ceil_panics_on_overflow() { + let fraction = (8u64, 21u64); + Uint64::MAX.div_ceil(fraction); + } + + #[test] + fn div_ceil_does_not_panic_on_overflow() { + let fraction = (8u64, 21u64); + assert_eq!( + Uint64::MAX.checked_div_ceil(fraction), + Err(ConversionOverflow(ConversionOverflowError { + source_type: "Uint128", + target_type: "Uint64", + value: "48422703193487572989".to_string() + })), + ); + } } From c1b78e9d0c1143377a4e3729410384ae0e43941b Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Wed, 18 Jan 2023 15:53:29 +0100 Subject: [PATCH 126/187] Ceil math without redundant expansion --- packages/std/src/math/fraction.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index de3a85a0d5..44025ac212 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -54,11 +54,10 @@ macro_rules! impl_mul_fraction { self, rhs: F, ) -> Result { - let divisor = rhs.denominator().into(); - let remainder = self - .full_mul(rhs.numerator().into()) - .checked_rem(divisor.into())?; - let floor_result = self.checked_mul_floor(rhs)?; + let dividend = self.full_mul(rhs.numerator().into()); + let divisor = rhs.denominator().into().into(); + let floor_result = dividend.checked_div(divisor)?.try_into()?; + let remainder = dividend.checked_rem(divisor)?; if !remainder.is_zero() { Ok($Uint::one().checked_add(floor_result)?) } else { @@ -105,11 +104,10 @@ macro_rules! impl_mul_fraction { where Self: Sized, { - let divisor = rhs.numerator().into(); - let remainder = self - .full_mul(rhs.denominator().into()) - .checked_rem(divisor.into())?; - let floor_result = self.checked_div_floor(rhs)?; + let dividend = self.full_mul(rhs.denominator().into()); + let divisor = rhs.numerator().into().into(); + let floor_result = dividend.checked_div(divisor)?.try_into()?; + let remainder = dividend.checked_rem(divisor)?; if !remainder.is_zero() { Ok($Uint::one().checked_add(floor_result)?) } else { From fac345e88e618052c9076d17a613958173b47594 Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Wed, 18 Jan 2023 16:32:06 +0100 Subject: [PATCH 127/187] Add rustdocs --- packages/std/src/math/fraction.rs | 66 ++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/packages/std/src/math/fraction.rs b/packages/std/src/math/fraction.rs index 44025ac212..0056f4a0a0 100644 --- a/packages/std/src/math/fraction.rs +++ b/packages/std/src/math/fraction.rs @@ -35,6 +35,17 @@ impl + PartialEq> Fraction for (T, T) { macro_rules! impl_mul_fraction { ($Uint:ident) => { impl $Uint { + /// Multiply `self` with a struct implementing [`Fraction`] (e.g. [`crate::Decimal`]). + /// Result is rounded down. + /// + /// ## Examples + /// + /// ``` + /// use cosmwasm_std::Uint128; + /// let fraction = (8u128, 21u128); + /// let res = Uint128::new(123456).checked_mul_floor(fraction).unwrap(); + /// assert_eq!(Uint128::new(47030), res); // 47030.8571 rounds down + /// ``` pub fn checked_mul_floor, T: Into<$Uint>>( self, rhs: F, @@ -46,10 +57,22 @@ macro_rules! impl_mul_fraction { Ok(res.try_into()?) } + /// Same operation as `checked_mul_floor` except unwrapped pub fn mul_floor, T: Into<$Uint>>(self, rhs: F) -> Self { self.checked_mul_floor(rhs).unwrap() } + /// Multiply `self` with a struct implementing [`Fraction`] (e.g. [`crate::Decimal`]). + /// Result is rounded up. + /// + /// ## Examples + /// + /// ``` + /// use cosmwasm_std::Uint128; + /// let fraction = (8u128, 21u128); + /// let res = Uint128::new(123456).checked_mul_ceil(fraction).unwrap(); + /// assert_eq!(Uint128::new(47031), res); // 47030.8571 rounds up + /// ``` pub fn checked_mul_ceil, T: Into<$Uint>>( self, rhs: F, @@ -65,17 +88,22 @@ macro_rules! impl_mul_fraction { } } + /// Same operation as `checked_mul_ceil` except unwrapped pub fn mul_ceil, T: Into<$Uint>>(self, rhs: F) -> Self { self.checked_mul_ceil(rhs).unwrap() } - pub fn div_floor, T: Into<$Uint>>(self, rhs: F) -> Self - where - Self: Sized, - { - self.checked_div_floor(rhs).unwrap() - } - + /// Divide `self` with a struct implementing [`Fraction`] (e.g. [`crate::Decimal`]). + /// Result is rounded down. + /// + /// ## Examples + /// + /// ``` + /// use cosmwasm_std::Uint128; + /// let fraction = (4u128, 5u128); + /// let res = Uint128::new(789).checked_div_floor(fraction).unwrap(); + /// assert_eq!(Uint128::new(986), res); // 986.25 rounds down + /// ``` pub fn checked_div_floor, T: Into<$Uint>>( self, rhs: F, @@ -90,13 +118,25 @@ macro_rules! impl_mul_fraction { Ok(res.try_into()?) } - pub fn div_ceil, T: Into<$Uint>>(self, rhs: F) -> Self + /// Same operation as `checked_div_floor` except unwrapped + pub fn div_floor, T: Into<$Uint>>(self, rhs: F) -> Self where Self: Sized, { - self.checked_div_ceil(rhs).unwrap() + self.checked_div_floor(rhs).unwrap() } + /// Divide `self` with a struct implementing [`Fraction`] (e.g. [`crate::Decimal`]). + /// Result is rounded up. + /// + /// ## Examples + /// + /// ``` + /// use cosmwasm_std::Uint128; + /// let fraction = (4u128, 5u128); + /// let res = Uint128::new(789).checked_div_ceil(fraction).unwrap(); + /// assert_eq!(Uint128::new(987), res); // 986.25 rounds up + /// ``` pub fn checked_div_ceil, T: Into<$Uint>>( self, rhs: F, @@ -114,6 +154,14 @@ macro_rules! impl_mul_fraction { Ok(floor_result) } } + + /// Same operation as `checked_div_ceil` except unwrapped + pub fn div_ceil, T: Into<$Uint>>(self, rhs: F) -> Self + where + Self: Sized, + { + self.checked_div_ceil(rhs).unwrap() + } } }; } From d8c52e53eb86d2dab2fbe652fd4ee683ba00cbab Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Wed, 18 Jan 2023 16:40:32 +0100 Subject: [PATCH 128/187] add to changlog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0079be3a8..b7b4fd59eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,11 +33,15 @@ and this project adheres to ([#1561]). - cosmwasm-vm: Add `Cache::remove_wasm` to remove obsolete Wasm blobs and their compiled modules. +- cosmwasm-std: Implement fraction multiplication and division. Assists with + Uint & Decimal arithmetic and exposes methods for flooring/ceiling result + ([#1485], [#1566]). [#1436]: https://github.com/CosmWasm/cosmwasm/issues/1436 [#1437]: https://github.com/CosmWasm/cosmwasm/issues/1437 -[#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 [#1478]: https://github.com/CosmWasm/cosmwasm/pull/1478 +[#1481]: https://github.com/CosmWasm/cosmwasm/pull/1481 +[#1485]: https://github.com/CosmWasm/cosmwasm/issues/1485 [#1513]: https://github.com/CosmWasm/cosmwasm/pull/1513 [#1533]: https://github.com/CosmWasm/cosmwasm/pull/1533 [#1550]: https://github.com/CosmWasm/cosmwasm/issues/1550 @@ -45,6 +49,7 @@ and this project adheres to [#1554]: https://github.com/CosmWasm/cosmwasm/pull/1554 [#1560]: https://github.com/CosmWasm/cosmwasm/pull/1560 [#1561]: https://github.com/CosmWasm/cosmwasm/pull/1561 +[#1566]: https://github.com/CosmWasm/cosmwasm/pull/1566 ### Changed From 96130f8eae2da0de32f44c594ba212a66dcb8b32 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 23 Jan 2023 12:42:58 +0100 Subject: [PATCH 129/187] Update bumpalo to 3.12.0 --- Cargo.lock | 4 ++-- contracts/burner/Cargo.lock | 4 ++-- contracts/crypto-verify/Cargo.lock | 4 ++-- contracts/cyberpunk/Cargo.lock | 4 ++-- contracts/floaty/Cargo.lock | 4 ++-- contracts/hackatom/Cargo.lock | 4 ++-- contracts/ibc-reflect-send/Cargo.lock | 4 ++-- contracts/ibc-reflect/Cargo.lock | 4 ++-- contracts/queue/Cargo.lock | 4 ++-- contracts/reflect/Cargo.lock | 4 ++-- contracts/staking/Cargo.lock | 4 ++-- contracts/virus/Cargo.lock | 4 ++-- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9604275615..79eb734d56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index 975c437322..181701d128 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "burner" diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index 187d140bdc..ae10f6d1dc 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index 35f96f2141..11a7eebc5c 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index 1628503aae..8baf510210 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index 449690c348..16cf4c2c5d 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index cef2629547..2679bb7895 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index 0a502905a3..764b289d8b 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index b9bc042b47..5c077df376 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index d543df2de5..f81a5eb3cf 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index ffaa239794..db3276dc82 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock index e7745e4945..1c527ed61b 100644 --- a/contracts/virus/Cargo.lock +++ b/contracts/virus/Cargo.lock @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bytecheck" From bd374ea72dcb47d5a9dc6fdfb7b04e86a8e87995 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 24 Jan 2023 13:30:09 +0100 Subject: [PATCH 130/187] Add docs on using cosmwasm-std --- docs/USING_COSMWASM_STD.md | 89 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 docs/USING_COSMWASM_STD.md diff --git a/docs/USING_COSMWASM_STD.md b/docs/USING_COSMWASM_STD.md new file mode 100644 index 0000000000..45841e908b --- /dev/null +++ b/docs/USING_COSMWASM_STD.md @@ -0,0 +1,89 @@ +# Using cosmwasm-std + +cosmwasm-std is the standard library for building contracts in CosmWasm. It is +compiled as part of the contract to Wasm. When creating a dependency to +cosmwasm-std, the required Wasm imports and exports are created implicitely via +C interfaces, e.g.: + +```rust +// Exports +#[no_mangle] +extern "C" fn interface_version_8() -> () { /* ... */ } +#[no_mangle] +extern "C" fn allocate(size: usize) -> u32 { /* ... */ } +#[no_mangle] +extern "C" fn deallocate(pointer: u32) { /* ... */ } + +// Imports +extern "C" { + #[cfg(feature = "abort")] + fn abort(source_ptr: u32); + + fn db_read(key: u32) -> u32; + fn db_write(key: u32, value: u32); + fn db_remove(key: u32); + + /* ... */ +} +``` + +As those exports are not namespaced, only one version of cosmwasm-std must exist +in the dependency tree. Otherwise conflicting C exports are created. + +## cosmwasm-std features + +The libarary comes with the following features: + +| Feature | Enabled by default | Description | +| ------------ | ------------------ | -------------------------------------------------------------------------- | +| iterator | x | Storage iterators | +| abort | x | A panic handler that aborts the contract execution with a helpfull message | +| stargate | | Cosmos SDK 0.40+ features and IBC | +| ibc3 | | New fields added in IBC v3 | +| staking | | Access to the staking module | +| baktraces | | Add backtraces to errors (for unit testing) | +| cosmwasm_1_1 | | Features that require CosmWasm 1.1+ on the chain | +| cosmwasm_1_2 | | Features that require CosmWasm 1.2+ on the chain | + +## The cosmwasm-std dependency for contract developers + +As a contract developer you can simply specify the dependency as follows in +`Cargo.toml`: + +```toml +cosmwasm-std = { version = "1.2.0" } +``` + +Please note that it is recommended to set all 3 version components and use the +minimum version you are willing to accept in the contract. For contracts this +would usually be the latest stable version. + +Most likely you also want to enable the `stargate`, which is pretty basic these +days and maybe you know your chain supports CosmWasm 1.2 or higher. Then you add +those features: + +```toml +cosmwasm-std = { version = "1.2.0", features = ["stargate", "cosmwasm_1_2"] } +``` + +## The cosmwasm-std dependency for library developers + +When you are creating a library that uses cosmwasm-std, you should be incredibly +careful with which features you require. The moment you add e.g. `cosmwasm_1_2` +there it becomes impossible to use the contract in chains with lower CosmWasm +versions. If you add `abort`, it becomes impossible for the contract developer +to opt out of the abort feature due to your library. Since this affects the +default features `abort` and `iterator`, you should always disable default +features. + +Also libraries should define a loose version range that allows the contract +developer to control which cosmwasm-std version they want to use in the final +project. E.g. if your library does not work with 1.0.0 due to a bug fixed in +1.0.1, your min version is 1.0.1 and not the latest stable. + +A typical dependency then looks like this: + +```toml +# We really need `stargate` here as this is an IBC related library. `abort` and `iterator` are not needed. +cosmwasm-std = { version = "1.0.1", default-features = false, features = ["stargate"] } +``` From baa6ad56782fd8fd424532d2f7225469d6b0d14e Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 24 Jan 2023 13:39:55 +0100 Subject: [PATCH 131/187] Add MIGRATING section for 1.2 Closes #1522 --- MIGRATING.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/MIGRATING.md b/MIGRATING.md index b9cadf4b64..0000f999fc 100644 --- a/MIGRATING.md +++ b/MIGRATING.md @@ -4,6 +4,47 @@ This guide explains what is needed to upgrade contracts when migrating over major releases of `cosmwasm`. Note that you can also view the [complete CHANGELOG](./CHANGELOG.md) to understand the differences. +## 1.1.x -> 1.2.0 + +- Update `cosmwasm-*` dependencies in Cargo.toml (skip the ones you don't use): + + ``` + [dependencies] + cosmwasm-std = "1.2.0" + cosmwasm-storage = "1.2.0" + # ... + + [dev-dependencies] + cosmwasm-schema = "1.2.0" + cosmwasm-vm = "1.2.0" + # ... + ``` + +- If you want to use a fewture that os only available on CosmWasm 1.2+ chains, + use this feature: + + ```diff + -cosmwasm-std = { version = "1.1.0", features = ["stargate"] } + +cosmwasm-std = { version = "1.1.0", features = ["stargate", "cosmwasm_1_2"] } + ``` + + Please note that `cosmwasm_1_2` implies `cosmwasm_1_1`, so there is no need to + set both. + +- If you use mixed type multiplication between `Uint{64,128,256}` and + `Decimal{,256}`, check out + `mul_floor`/`checked_mul_floor`/`mul_ceil`/`checked_mul_ceil`. Mixed type + arithmetic [will be removed](https://github.com/CosmWasm/cosmwasm/issues/1485) + at some point. + + ```diff + let a = Uint128::new(123); + let b = Decimal::percent(150) + + -let c = a * b; + +let c = a.mul_floor(b); + ``` + ## 1.0.0 -> 1.1.0 - Update `cosmwasm-*` dependencies in Cargo.toml (skip the ones you don't use): From 2dabcf0da461720cdd3597af2587a56f69d0fefb Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 24 Jan 2023 15:01:47 +0100 Subject: [PATCH 132/187] Set version: 1.2.0 --- CHANGELOG.md | 5 ++++- Cargo.lock | 16 ++++++++-------- contracts/burner/Cargo.lock | 12 ++++++------ contracts/crypto-verify/Cargo.lock | 14 +++++++------- contracts/cyberpunk/Cargo.lock | 14 +++++++------- contracts/floaty/Cargo.lock | 14 +++++++------- contracts/hackatom/Cargo.lock | 14 +++++++------- contracts/ibc-reflect-send/Cargo.lock | 14 +++++++------- contracts/ibc-reflect/Cargo.lock | 14 +++++++------- contracts/queue/Cargo.lock | 12 ++++++------ contracts/reflect/Cargo.lock | 14 +++++++------- contracts/staking/Cargo.lock | 14 +++++++------- contracts/virus/Cargo.lock | 12 ++++++------ packages/check/Cargo.toml | 6 +++--- packages/crypto/Cargo.toml | 2 +- packages/derive/Cargo.toml | 2 +- packages/schema-derive/Cargo.toml | 2 +- packages/schema/Cargo.toml | 6 +++--- packages/std/Cargo.toml | 6 +++--- packages/storage/Cargo.toml | 4 ++-- packages/vm/Cargo.toml | 6 +++--- 21 files changed, 103 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7b4fd59eb..1adcf6d475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to ## [Unreleased] +## [1.2.0] - 2023-01-24 + ### Added - cosmwasm-std: Add `GovMsg::VoteWeighted`. In order to use this in a contract, @@ -1608,7 +1610,8 @@ Some main points: All future Changelog entries will reference this base -[unreleased]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.9...HEAD +[unreleased]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.0...HEAD +[1.2.0]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.9...v1.2.0 [1.1.9]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.8...v1.1.9 [1.1.8]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.6...v1.1.8 [1.1.6]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.5...v1.1.6 diff --git a/Cargo.lock b/Cargo.lock index 79eb734d56..eae3adcab8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "cosmwasm-check" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "anyhow", "clap", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "criterion", @@ -276,7 +276,7 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "syn", @@ -284,7 +284,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "anyhow", "cosmwasm-schema-derive", @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "chrono", @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "serde", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index 181701d128..20a0bf204d 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -174,7 +174,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -185,14 +185,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -203,7 +203,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index ae10f6d1dc..0fa8440fb7 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -169,7 +169,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -180,14 +180,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -198,7 +198,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -207,7 +207,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "serde", @@ -233,7 +233,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index 11a7eebc5c..c5987f97dc 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -203,14 +203,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -221,7 +221,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "serde", @@ -256,7 +256,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index 8baf510210..495ecd0e42 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index 16cf4c2c5d..b76cc69f07 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index 2679bb7895..9c5b2a1f77 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index 764b289d8b..46792be82f 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index 5c077df376..0c284845a1 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index f81a5eb3cf..64da836cd1 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index db3276dc82..35a8d3288d 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock index 1c527ed61b..4e6882ec84 100644 --- a/contracts/virus/Cargo.lock +++ b/contracts/virus/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" dependencies = [ "bitflags", "bytecheck", diff --git a/packages/check/Cargo.toml b/packages/check/Cargo.toml index e50773015d..e09ee94e48 100644 --- a/packages/check/Cargo.toml +++ b/packages/check/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-check" -version = "1.2.0-rc.1" +version = "1.2.0" authors = ["Mauro Lacy "] edition = "2021" description = "A CLI tool for verifying CosmWasm smart contracts" @@ -11,5 +11,5 @@ license = "Apache-2.0" anyhow = "1.0.57" clap = "2" colored = "2" -cosmwasm-vm = { path = "../vm", version = "1.2.0-rc.1" } -cosmwasm-std = { path = "../std", version = "1.2.0-rc.1" } +cosmwasm-vm = { path = "../vm", version = "1.2.0" } +cosmwasm-std = { path = "../std", version = "1.2.0" } diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index ff6e0b6f9f..cbadde4722 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-crypto" -version = "1.2.0-rc.1" +version = "1.2.0" authors = ["Mauro Lacy "] edition = "2021" description = "Crypto bindings for cosmwasm contracts" diff --git a/packages/derive/Cargo.toml b/packages/derive/Cargo.toml index 4485606ec6..5a111016fb 100644 --- a/packages/derive/Cargo.toml +++ b/packages/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-derive" -version = "1.2.0-rc.1" +version = "1.2.0" authors = ["Simon Warta "] edition = "2021" description = "A package for auto-generated code used for CosmWasm contract development. This is shipped as part of cosmwasm-std. Do not use directly." diff --git a/packages/schema-derive/Cargo.toml b/packages/schema-derive/Cargo.toml index c063f4c68f..04b09449e2 100644 --- a/packages/schema-derive/Cargo.toml +++ b/packages/schema-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema-derive" -version = "1.2.0-rc.1" +version = "1.2.0" authors = ["Tomasz Kurcz "] edition = "2021" description = "Derive macros for cosmwasm-schema" diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index 0700262526..01d1b23c2e 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema" -version = "1.2.0-rc.1" +version = "1.2.0" authors = ["Simon Warta ", "Ethan Frey "] edition = "2021" description = "A dev-dependency for CosmWasm contracts to generate JSON Schema files." @@ -8,7 +8,7 @@ repository = "https://github.com/CosmWasm/cosmwasm/tree/main/packages/schema" license = "Apache-2.0" [dependencies] -cosmwasm-schema-derive = { version = "=1.2.0-rc.1", path = "../schema-derive" } +cosmwasm-schema-derive = { version = "=1.2.0", path = "../schema-derive" } schemars = "0.8.3" serde = "1.0" serde_json = "1.0.40" @@ -16,6 +16,6 @@ thiserror = "1.0.26" [dev-dependencies] anyhow = "1.0.57" -cosmwasm-std = { version = "1.2.0-rc.1", path = "../std" } +cosmwasm-std = { version = "1.2.0", path = "../std" } semver = "1" tempfile = "3" diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 4be42c970f..42e053bf58 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-std" -version = "1.2.0-rc.1" +version = "1.2.0" authors = ["Ethan Frey "] edition = "2021" description = "Standard library for Wasm based smart contracts on Cosmos blockchains" @@ -42,7 +42,7 @@ cosmwasm_1_2 = ["cosmwasm_1_1"] [dependencies] base64 = "0.13.0" -cosmwasm-derive = { path = "../derive", version = "1.2.0-rc.1" } +cosmwasm-derive = { path = "../derive", version = "1.2.0" } derivative = "2" forward_ref = "1" hex = "0.4" @@ -54,7 +54,7 @@ thiserror = "1.0.26" uint = "0.9.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -cosmwasm-crypto = { path = "../crypto", version = "1.2.0-rc.1" } +cosmwasm-crypto = { path = "../crypto", version = "1.2.0" } [dev-dependencies] cosmwasm-schema = { path = "../schema" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index a6b75470e4..6332d2e1b2 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-storage" -version = "1.2.0-rc.1" +version = "1.2.0" authors = ["Ethan Frey "] edition = "2021" description = "CosmWasm library with useful helpers for Storage patterns" @@ -16,5 +16,5 @@ iterator = ["cosmwasm-std/iterator"] [dependencies] # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.0-rc.1", default-features = false } +cosmwasm-std = { path = "../std", version = "1.2.0", default-features = false } serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index 07c9c53cbf..0fb8290d5b 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-vm" -version = "1.2.0-rc.1" +version = "1.2.0" authors = ["Ethan Frey "] edition = "2021" description = "VM bindings to run cosmwams contracts" @@ -41,8 +41,8 @@ required-features = ["iterator"] [dependencies] clru = "0.4.0" # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.0-rc.1", default-features = false } -cosmwasm-crypto = { path = "../crypto", version = "1.2.0-rc.1" } +cosmwasm-std = { path = "../std", version = "1.2.0", default-features = false } +cosmwasm-crypto = { path = "../crypto", version = "1.2.0" } hex = "0.4" parity-wasm = "0.42" schemars = "0.8.3" From 4628c7e98d32867d1d139b966ffb2a97ab05c476 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 25 Jan 2023 11:59:03 +0100 Subject: [PATCH 133/187] Make fields of WeightedVoteOption public --- CHANGELOG.md | 7 +++ packages/std/src/results/cosmos_msg.rs | 73 +++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1adcf6d475..33fbbdf0dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ and this project adheres to ## [Unreleased] +### Fixed + +- cosmwasm-std: Make fields of `WeightedVoteOption` public to allow constructing + it ([#1597]). + +[#1597]: https://github.com/CosmWasm/cosmwasm/issues/1597 + ## [1.2.0] - 2023-01-24 ### Added diff --git a/packages/std/src/results/cosmos_msg.rs b/packages/std/src/results/cosmos_msg.rs index c62ba25185..3e93ba1868 100644 --- a/packages/std/src/results/cosmos_msg.rs +++ b/packages/std/src/results/cosmos_msg.rs @@ -203,6 +203,75 @@ pub enum WasmMsg { ClearAdmin { contract_addr: String }, } +/// This message type allows the contract interact with the [x/gov] module in order +/// to cast votes. +/// +/// [x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov +/// +/// ## Examples +/// +/// Cast a simple vote: +/// +/// ``` +/// # use cosmwasm_std::{ +/// # HexBinary, +/// # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, +/// # Response, QueryResponse, +/// # }; +/// # type ExecuteMsg = (); +/// use cosmwasm_std::{GovMsg, VoteOption}; +/// +/// #[entry_point] +/// pub fn execute( +/// deps: DepsMut, +/// env: Env, +/// info: MessageInfo, +/// msg: ExecuteMsg, +/// ) -> Result { +/// // ... +/// Ok(Response::new().add_message(GovMsg::Vote { +/// proposal_id: 4, +/// vote: VoteOption::Yes, +/// })) +/// } +/// ``` +/// +/// Cast a weighted vote: +/// +/// ``` +/// # use cosmwasm_std::{ +/// # HexBinary, +/// # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, +/// # Response, QueryResponse, +/// # }; +/// # type ExecuteMsg = (); +/// # #[cfg(feature = "cosmwasm_1_2")] +/// use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption}; +/// +/// # #[cfg(feature = "cosmwasm_1_2")] +/// #[entry_point] +/// pub fn execute( +/// deps: DepsMut, +/// env: Env, +/// info: MessageInfo, +/// msg: ExecuteMsg, +/// ) -> Result { +/// // ... +/// Ok(Response::new().add_message(GovMsg::VoteWeighted { +/// proposal_id: 4, +/// options: vec![ +/// WeightedVoteOption { +/// option: VoteOption::Yes, +/// weight: Decimal::percent(65), +/// }, +/// WeightedVoteOption { +/// option: VoteOption::Abstain, +/// weight: Decimal::percent(35), +/// }, +/// ], +/// })) +/// } +/// ``` #[cfg(feature = "stargate")] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -237,8 +306,8 @@ pub enum VoteOption { #[cfg(all(feature = "stargate", feature = "cosmwasm_1_2"))] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct WeightedVoteOption { - option: VoteOption, - weight: Decimal, + pub option: VoteOption, + pub weight: Decimal, } /// Shortcut helper as the construction of WasmMsg::Instantiate can be quite verbose in contract code. From 7b89a920ceed2ef1e99d9ce6318212dac1a8b99a Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 25 Jan 2023 11:59:34 +0100 Subject: [PATCH 134/187] Add abort and cosmwasm_1_2 to docs --- packages/std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 42e053bf58..831b45ae22 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -9,7 +9,7 @@ license = "Apache-2.0" readme = "README.md" [package.metadata.docs.rs] -features = ["stargate", "staking", "ibc3"] +features = ["abort", "stargate", "staking", "ibc3", "cosmwasm_1_2"] [features] default = ["iterator", "abort"] From 648afc1c7d45b62279043d13ac8c464c045df009 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 25 Jan 2023 12:00:50 +0100 Subject: [PATCH 135/187] Add rust-analyzer settings --- .gitignore | 1 - .vscode/settings.json | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index b0ea61c7fa..6f20a8ecdb 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ target/ artifacts/ # IDEs -.vscode/ .idea/ *.iml diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..4fc9b25774 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.cargo.features": ["abort", "stargate", "staking", "cosmwasm_1_2"] +} From 90779fa30db7207b4f880e394101b3a801a9231c Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 25 Jan 2023 12:17:47 +0100 Subject: [PATCH 136/187] Update schemas to doc changes --- contracts/ibc-reflect-send/schema/ibc-reflect-send.json | 1 + contracts/ibc-reflect-send/schema/packet_msg.json | 1 + contracts/ibc-reflect-send/schema/raw/execute.json | 1 + contracts/ibc-reflect/schema/packet_msg.json | 1 + contracts/reflect/schema/raw/execute.json | 1 + contracts/reflect/schema/reflect.json | 1 + 6 files changed, 6 insertions(+) diff --git a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json index 1498f82a21..33fb5467c8 100644 --- a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json +++ b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json @@ -357,6 +357,7 @@ "type": "object" }, "GovMsg": { + "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ { "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", diff --git a/contracts/ibc-reflect-send/schema/packet_msg.json b/contracts/ibc-reflect-send/schema/packet_msg.json index 4bf172b75e..ed5b77d0b8 100644 --- a/contracts/ibc-reflect-send/schema/packet_msg.json +++ b/contracts/ibc-reflect-send/schema/packet_msg.json @@ -295,6 +295,7 @@ "type": "object" }, "GovMsg": { + "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ { "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", diff --git a/contracts/ibc-reflect-send/schema/raw/execute.json b/contracts/ibc-reflect-send/schema/raw/execute.json index 198ed94097..db374275af 100644 --- a/contracts/ibc-reflect-send/schema/raw/execute.json +++ b/contracts/ibc-reflect-send/schema/raw/execute.json @@ -346,6 +346,7 @@ "type": "object" }, "GovMsg": { + "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ { "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", diff --git a/contracts/ibc-reflect/schema/packet_msg.json b/contracts/ibc-reflect/schema/packet_msg.json index 432e357fe3..bd940ab4f0 100644 --- a/contracts/ibc-reflect/schema/packet_msg.json +++ b/contracts/ibc-reflect/schema/packet_msg.json @@ -224,6 +224,7 @@ "type": "object" }, "GovMsg": { + "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ { "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", diff --git a/contracts/reflect/schema/raw/execute.json b/contracts/reflect/schema/raw/execute.json index 8568a9e798..732cf6db15 100644 --- a/contracts/reflect/schema/raw/execute.json +++ b/contracts/reflect/schema/raw/execute.json @@ -341,6 +341,7 @@ ] }, "GovMsg": { + "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ { "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", diff --git a/contracts/reflect/schema/reflect.json b/contracts/reflect/schema/reflect.json index 1f91a514a4..f73dcfe4bf 100644 --- a/contracts/reflect/schema/reflect.json +++ b/contracts/reflect/schema/reflect.json @@ -351,6 +351,7 @@ ] }, "GovMsg": { + "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, vote: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ { "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", From 28b49f9c972061d6d6133c84c6a48bc27b440e90 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 26 Jan 2023 11:21:23 +0100 Subject: [PATCH 137/187] Improve comments on high/low-S handling of secp256k1_verify/secp256k1_recover_pubkey --- packages/crypto/src/secp256k1.rs | 85 +++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index 4783de67c9..9bceee4dfd 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -35,6 +35,11 @@ pub const ECDSA_PUBKEY_MAX_LEN: usize = ECDSA_UNCOMPRESSED_PUBKEY_LEN; /// - signature: Serialized "compact" signature (64 bytes). /// - public key: [Serialized according to SEC 2](https://www.oreilly.com/library/view/programming-bitcoin/9781492031482/ch04.html) /// (33 or 65 bytes). +/// +/// This implementation accepts both high-S and low-S signatures. Some applications +/// including Ethereum transactions consider high-S signatures invalid in order to +/// avoid maleability. If that's the case for your protocol, the signature needs +/// to be tested for low-S in addition to this verification. pub fn secp256k1_verify( message_hash: &[u8], signature: &[u8], @@ -49,7 +54,10 @@ pub fn secp256k1_verify( let mut signature = Signature::from_bytes(&signature).map_err(|e| CryptoError::generic_err(e.to_string()))?; - // Non low-S signatures require normalization + + // High-S signatures require normalization since our verification implementation + // rejects them by default. If we had a verifier that does not restrict to + // low-S only, this step was not needed. if let Some(normalized) = signature.normalize_s() { signature = normalized; } @@ -74,6 +82,22 @@ pub fn secp256k1_verify( /// /// Returns the recovered pubkey in compressed form, which can be used /// in secp256k1_verify directly. +/// +/// This implementation accepts both high-S and low-S signatures. This is the +/// same behavior as Ethereum's `ecrecover`. The reason is that high-S signatures +/// may be perfectly valid if the application protocol does not disallow them. +/// Or as [EIP-2] put it "The ECDSA recover precompiled contract remains unchanged +/// and will keep accepting high s-values; this is useful e.g. if a contract +/// recovers old Bitcoin signatures.". +/// +/// See also OpenZeppilin's [ECDSA.recover implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.1/contracts/utils/cryptography/ECDSA.sol#L138-L149) +/// which adds further restrictions to avoid potential siganture maleability. +/// Please note that restricting signatures to low-S does not make signatures unique +/// in the sense that for each (pubkey, message) there is only one signature. The +/// signer can generate an arbitrary amount of valid signatures. +/// +/// +/// [EIP-2]: https://eips.ethereum.org/EIPS/eip-2 pub fn secp256k1_recover_pubkey( message_hash: &[u8], signature: &[u8], @@ -161,7 +185,10 @@ mod tests { elliptic_curve::rand_core::OsRng, elliptic_curve::sec1::ToEncodedPoint, }; + use serde::Deserialize; use sha2::Sha256; + use std::fs::File; + use std::io::BufReader; // For generic signature verification const MSG: &str = "Hello World!"; @@ -181,6 +208,15 @@ mod tests { // Test data originally from https://github.com/cosmos/cosmjs/blob/v0.24.0-alpha.22/packages/crypto/src/secp256k1.spec.ts#L195-L394 const COSMOS_SECP256K1_TESTS_JSON: &str = "./testdata/secp256k1_tests.json"; + #[derive(Deserialize, Debug)] + struct Encoded { + message: String, + message_hash: String, + signature: String, + #[serde(rename = "pubkey")] + public_key: String, + } + #[test] fn test_secp256k1_verify() { // Explicit / external hashing @@ -266,20 +302,6 @@ mod tests { #[test] fn test_cosmos_extra_secp256k1_verify() { - use std::fs::File; - use std::io::BufReader; - - use serde::Deserialize; - - #[derive(Deserialize, Debug)] - struct Encoded { - message: String, - message_hash: String, - signature: String, - #[serde(rename = "pubkey")] - public_key: String, - } - // Open the file in read-only mode with buffer. let file = File::open(COSMOS_SECP256K1_TESTS_JSON).unwrap(); let reader = BufReader::new(file); @@ -288,15 +310,13 @@ mod tests { for (i, encoded) in (1..).zip(codes) { let message = hex::decode(&encoded.message).unwrap(); + let signature = hex::decode(&encoded.signature).unwrap(); + let public_key = hex::decode(&encoded.public_key).unwrap(); let hash = hex::decode(&encoded.message_hash).unwrap(); let message_hash = Sha256::digest(message); assert_eq!(hash.as_slice(), message_hash.as_slice()); - let signature = hex::decode(&encoded.signature).unwrap(); - - let public_key = hex::decode(&encoded.public_key).unwrap(); - // secp256k1_verify() works assert!( secp256k1_verify(&message_hash, &signature, &public_key).unwrap(), @@ -327,6 +347,7 @@ mod tests { } // Test data from https://github.com/randombit/botan/blob/2.9.0/src/tests/data/pubkey/ecdsa_key_recovery.vec + // This is a high-s value (`0x81F1A4457589F30D76AB9F89E748A68C8A94C30FE0BAC8FB5C0B54EA70BF6D2F > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0` is true) { let expected_x = "F3F8BB913AA68589A2C8C607A877AB05252ADBD963E1BE846DDEB8456942AEDC"; let expected_y = "A2ED51F08CA3EF3DAC0A7504613D54CD539FC1B3CBC92453CD704B6A2D012B2C"; @@ -349,6 +370,32 @@ mod tests { let pubkey = secp256k1_recover_pubkey(&message_hash, &r_s, recovery_param).unwrap(); assert_eq!(pubkey, expected); } + + let file = File::open(COSMOS_SECP256K1_TESTS_JSON).unwrap(); + let reader = BufReader::new(file); + let codes: Vec = serde_json::from_reader(reader).unwrap(); + for (i, encoded) in (1..).zip(codes) { + let message = hex::decode(&encoded.message).unwrap(); + let signature = hex::decode(&encoded.signature).unwrap(); + let public_key = hex::decode(&encoded.public_key).unwrap(); + + let hash = hex::decode(&encoded.message_hash).unwrap(); + let message_hash = Sha256::digest(message); + assert_eq!(hash.as_slice(), message_hash.as_slice()); + + // Since the recovery param is mossing in the test vectors, we try both 0 and 1 + let try0 = secp256k1_recover_pubkey(&message_hash, &signature, 0); + let try1 = secp256k1_recover_pubkey(&message_hash, &signature, 1); + match (try0, try1) { + (Ok(recovered0), Ok(recovered1)) => { + // Got two different pubkeys. Without the recoverey param, we don't know which one is the right one. + assert!(recovered0 == public_key || recovered1 == public_key) + }, + (Ok(recovered), Err(_)) => assert_eq!(recovered, public_key), + (Err(_), Ok(recovered)) => assert_eq!(recovered, public_key), + (Err(_), Err(_)) => panic!("secp256k1_recover_pubkey failed (test case {i} in {COSMOS_SECP256K1_TESTS_JSON})"), + } + } } #[test] From 07a01eba174217ef9ab237c18c3ac399d3fcc84b Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 26 Jan 2023 11:44:12 +0100 Subject: [PATCH 138/187] Improve some test code --- packages/crypto/src/secp256k1.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index 9bceee4dfd..b2f606227c 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -292,11 +292,8 @@ mod tests { let message_hash = Sha256::digest(message); // secp256k1_verify works - assert!( - secp256k1_verify(&message_hash, &signature, &public_key).unwrap(), - "secp256k1_verify() failed (test case {})", - i - ); + let valid = secp256k1_verify(&message_hash, &signature, &public_key).unwrap(); + assert!(valid, "secp256k1_verify() failed (test case {i})",); } } @@ -318,10 +315,10 @@ mod tests { assert_eq!(hash.as_slice(), message_hash.as_slice()); // secp256k1_verify() works + let valid = secp256k1_verify(&message_hash, &signature, &public_key).unwrap(); assert!( - secp256k1_verify(&message_hash, &signature, &public_key).unwrap(), - "verify() failed (test case {})", - i + valid, + "secp256k1_verify failed (test case {i} in {COSMOS_SECP256K1_TESTS_JSON})" ); } } From 401b6fb50fcbb3a2dbf1e9465232478600a2dbc3 Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Thu, 26 Jan 2023 12:20:41 +0200 Subject: [PATCH 139/187] Debug impl for Decimal256 uses decimal output. --- packages/std/src/math/decimal.rs | 18 +++++++++++++++++- packages/std/src/math/decimal256.rs | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 72975e22e3..005d9e1844 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -19,7 +19,7 @@ use super::{Uint128, Uint256}; /// A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0 /// /// The greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18) -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] pub struct Decimal(#[schemars(with = "String")] Uint128); #[derive(Error, Debug, PartialEq, Eq)] @@ -457,6 +457,12 @@ impl fmt::Display for Decimal { } } +impl fmt::Debug for Decimal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + impl Add for Decimal { type Output = Self; @@ -2015,4 +2021,14 @@ mod tests { assert_eq!(&lhs == &rhs, expected); } } + + #[test] + fn decimal_implements_debug() { + let test_cases = ["5", "5.01", "42", "0", "2"]; + + for s in test_cases { + let decimal = Decimal::from_str(s).unwrap(); + assert_eq!(s, format!("{:?}", decimal)); + } + } } diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 0c2b134b5b..0a96886827 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -22,7 +22,7 @@ use super::Uint256; /// The greatest possible value that can be represented is /// 115792089237316195423570985008687907853269984665640564039457.584007913129639935 /// (which is (2^256 - 1) / 10^18) -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] pub struct Decimal256(#[schemars(with = "String")] Uint256); #[derive(Error, Debug, PartialEq, Eq)] @@ -482,6 +482,12 @@ impl fmt::Display for Decimal256 { } } +impl fmt::Debug for Decimal256 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } +} + impl Add for Decimal256 { type Output = Self; @@ -2162,4 +2168,14 @@ mod tests { assert_eq!(&lhs == &rhs, expected); } } + + #[test] + fn decimal256_implements_debug() { + let test_cases = ["5", "5.01", "42", "0", "2"]; + + for s in test_cases { + let decimal256 = Decimal256::from_str(s).unwrap(); + assert_eq!(s, format!("{:?}", decimal256)); + } + } } From bfb15c6744720a3347c7f63739fced0acb46416e Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Thu, 26 Jan 2023 14:19:23 +0200 Subject: [PATCH 140/187] Include type in Debug output --- packages/std/src/math/decimal.rs | 4 ++-- packages/std/src/math/decimal256.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 005d9e1844..c1dd504db2 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -459,7 +459,7 @@ impl fmt::Display for Decimal { impl fmt::Debug for Decimal { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self) + write!(f, "Decimal({})", self) } } @@ -2028,7 +2028,7 @@ mod tests { for s in test_cases { let decimal = Decimal::from_str(s).unwrap(); - assert_eq!(s, format!("{:?}", decimal)); + assert_eq!(format!("Decimal({})", s), format!("{:?}", decimal)); } } } diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 0a96886827..c987f739fa 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -484,7 +484,7 @@ impl fmt::Display for Decimal256 { impl fmt::Debug for Decimal256 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self) + write!(f, "Decimal256({})", self) } } @@ -2175,7 +2175,7 @@ mod tests { for s in test_cases { let decimal256 = Decimal256::from_str(s).unwrap(); - assert_eq!(s, format!("{:?}", decimal256)); + assert_eq!(format!("Decimal256({})", s), format!("{:?}", decimal256)); } } } From 3ba7f27567b438d2274b7ffdd5ce517253d356f3 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 26 Jan 2023 17:55:23 +0100 Subject: [PATCH 141/187] Improve decimal{,256}_implements_debug test code --- packages/std/src/math/decimal.rs | 7 +++++-- packages/std/src/math/decimal256.rs | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index c1dd504db2..a146c62b94 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -2024,11 +2024,14 @@ mod tests { #[test] fn decimal_implements_debug() { - let test_cases = ["5", "5.01", "42", "0", "2"]; + let decimal = Decimal::from_str("123.45").unwrap(); + assert_eq!(format!("{:?}", decimal), "Decimal(123.45)"); + let test_cases = ["5", "5.01", "42", "0", "2"]; for s in test_cases { let decimal = Decimal::from_str(s).unwrap(); - assert_eq!(format!("Decimal({})", s), format!("{:?}", decimal)); + let expected = format!("Decimal({})", s); + assert_eq!(format!("{:?}", decimal), expected); } } } diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index c987f739fa..2ae938e614 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -2171,11 +2171,14 @@ mod tests { #[test] fn decimal256_implements_debug() { - let test_cases = ["5", "5.01", "42", "0", "2"]; + let decimal = Decimal256::from_str("123.45").unwrap(); + assert_eq!(format!("{:?}", decimal), "Decimal256(123.45)"); + let test_cases = ["5", "5.01", "42", "0", "2"]; for s in test_cases { let decimal256 = Decimal256::from_str(s).unwrap(); - assert_eq!(format!("Decimal256({})", s), format!("{:?}", decimal256)); + let expected = format!("Decimal256({})", s); + assert_eq!(format!("{:?}", decimal256), expected); } } } From 28e690507282fcbe9bd2e515ba83e4ba8994c8fe Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 26 Jan 2023 18:04:39 +0100 Subject: [PATCH 142/187] Add CHANGELOG entry --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33fbbdf0dc..ea5f0b20d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,13 @@ and this project adheres to [#1597]: https://github.com/CosmWasm/cosmwasm/issues/1597 +### Changed + +- cosmwasm-std: Improve readability of `Debug` output for `Decimal` and + `Decimal256` ([#1600]). + +[#1600]: https://github.com/CosmWasm/cosmwasm/pull/1600 + ## [1.2.0] - 2023-01-24 ### Added From 4e688bac824833b062ec2a48d0c54ee628b5acf3 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 26 Jan 2023 18:52:14 +0100 Subject: [PATCH 143/187] Add to_uint_floor, to_uint_ceil --- packages/std/src/math/decimal.rs | 48 +++++++++++++++++++++++++++++ packages/std/src/math/decimal256.rs | 48 +++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index a146c62b94..d416a30f40 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -357,6 +357,54 @@ impl Decimal { Err(_) => Self::MAX, } } + + /// Converts this decimal to an unsigned integer by truncating + /// the fractional part, e.g. 22.5 becomes 22. + /// + /// ## Examples + /// + /// ``` + /// use std::str::FromStr; + /// use cosmwasm_std::{Decimal, Uint128}; + /// + /// let d = Decimal::from_str("12.345").unwrap(); + /// assert_eq!(d.to_uint_floor(), Uint128::new(12)); + /// + /// let d = Decimal::from_str("12.999").unwrap(); + /// assert_eq!(d.to_uint_floor(), Uint128::new(12)); + /// + /// let d = Decimal::from_str("75.0").unwrap(); + /// assert_eq!(d.to_uint_floor(), Uint128::new(75)); + /// ``` + pub fn to_uint_floor(self) -> Uint128 { + self.0 / Self::DECIMAL_FRACTIONAL + } + + /// Converts this decimal to an unsigned integer by rounting up + /// to the next integer, e.g. 22.3 becomes 23. + /// + /// ## Examples + /// + /// ``` + /// use std::str::FromStr; + /// use cosmwasm_std::{Decimal, Uint128}; + /// + /// let d = Decimal::from_str("12.345").unwrap(); + /// assert_eq!(d.to_uint_ceil(), Uint128::new(13)); + /// + /// let d = Decimal::from_str("12.999").unwrap(); + /// assert_eq!(d.to_uint_ceil(), Uint128::new(13)); + /// + /// let d = Decimal::from_str("75.0").unwrap(); + /// assert_eq!(d.to_uint_ceil(), Uint128::new(75)); + /// ``` + pub fn to_uint_ceil(self) -> Uint128 { + if (self.0 % Self::DECIMAL_FRACTIONAL).is_zero() { + self.0 / Self::DECIMAL_FRACTIONAL + } else { + self.0 / Self::DECIMAL_FRACTIONAL + Uint128::one() + } + } } impl Fraction for Decimal { diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 2ae938e614..68e113001b 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -374,6 +374,54 @@ impl Decimal256 { Err(_) => Self::MAX, } } + + /// Converts this decimal to an unsigned integer by truncating + /// the fractional part, e.g. 22.5 becomes 22. + /// + /// ## Examples + /// + /// ``` + /// use std::str::FromStr; + /// use cosmwasm_std::{Decimal256, Uint256}; + /// + /// let d = Decimal256::from_str("12.345").unwrap(); + /// assert_eq!(d.to_uint_floor(), Uint256::from(12u64)); + /// + /// let d = Decimal256::from_str("12.999").unwrap(); + /// assert_eq!(d.to_uint_floor(), Uint256::from(12u64)); + /// + /// let d = Decimal256::from_str("75.0").unwrap(); + /// assert_eq!(d.to_uint_floor(), Uint256::from(75u64)); + /// ``` + pub fn to_uint_floor(self) -> Uint256 { + self.0 / Self::DECIMAL_FRACTIONAL + } + + /// Converts this decimal to an unsigned integer by rounting up + /// to the next integer, e.g. 22.3 becomes 23. + /// + /// ## Examples + /// + /// ``` + /// use std::str::FromStr; + /// use cosmwasm_std::{Decimal256, Uint256}; + /// + /// let d = Decimal256::from_str("12.345").unwrap(); + /// assert_eq!(d.to_uint_ceil(), Uint256::from(13u64)); + /// + /// let d = Decimal256::from_str("12.999").unwrap(); + /// assert_eq!(d.to_uint_ceil(), Uint256::from(13u64)); + /// + /// let d = Decimal256::from_str("75.0").unwrap(); + /// assert_eq!(d.to_uint_ceil(), Uint256::from(75u64)); + /// ``` + pub fn to_uint_ceil(self) -> Uint256 { + if (self.0 % Self::DECIMAL_FRACTIONAL).is_zero() { + self.0 / Self::DECIMAL_FRACTIONAL + } else { + self.0 / Self::DECIMAL_FRACTIONAL + Uint256::one() + } + } } impl Fraction for Decimal256 { From 2bcc2d1760f0e5ab657cfdba78a9fc5e7d824f40 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 26 Jan 2023 22:21:41 +0100 Subject: [PATCH 144/187] Add unit tests --- packages/std/src/math/decimal.rs | 36 +++++++++++++++++++++++ packages/std/src/math/decimal256.rs | 44 +++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index d416a30f40..82408f0510 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -2050,6 +2050,42 @@ mod tests { )); } + #[test] + fn decimal_to_uint_floor_works() { + let d = Decimal::from_str("12.000000000000000001").unwrap(); + assert_eq!(d.to_uint_floor(), Uint128::new(12)); + let d = Decimal::from_str("12.345").unwrap(); + assert_eq!(d.to_uint_floor(), Uint128::new(12)); + let d = Decimal::from_str("12.999").unwrap(); + assert_eq!(d.to_uint_floor(), Uint128::new(12)); + + let d = Decimal::from_str("75.0").unwrap(); + assert_eq!(d.to_uint_floor(), Uint128::new(75)); + let d = Decimal::from_str("0.0").unwrap(); + assert_eq!(d.to_uint_floor(), Uint128::new(0)); + + let d = Decimal::MAX; + assert_eq!(d.to_uint_floor(), Uint128::new(340282366920938463463)); + } + + #[test] + fn decimal_to_uint_ceil_works() { + let d = Decimal::from_str("12.000000000000000001").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint128::new(13)); + let d = Decimal::from_str("12.345").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint128::new(13)); + let d = Decimal::from_str("12.999").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint128::new(13)); + + let d = Decimal::from_str("75.0").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint128::new(75)); + let d = Decimal::from_str("0.0").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint128::new(0)); + + let d = Decimal::MAX; + assert_eq!(d.to_uint_ceil(), Uint128::new(340282366920938463464)); + } + #[test] fn decimal_partial_eq() { let test_cases = [ diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 68e113001b..2777b63866 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -2197,6 +2197,50 @@ mod tests { assert_eq!(Decimal256::MAX.checked_ceil(), Err(RoundUpOverflowError)); } + #[test] + fn decimal256_to_uint_floor_works() { + let d = Decimal256::from_str("12.000000000000000001").unwrap(); + assert_eq!(d.to_uint_floor(), Uint256::from_u128(12)); + let d = Decimal256::from_str("12.345").unwrap(); + assert_eq!(d.to_uint_floor(), Uint256::from_u128(12)); + let d = Decimal256::from_str("12.999").unwrap(); + assert_eq!(d.to_uint_floor(), Uint256::from_u128(12)); + + let d = Decimal256::from_str("75.0").unwrap(); + assert_eq!(d.to_uint_floor(), Uint256::from_u128(75)); + let d = Decimal256::from_str("0.0").unwrap(); + assert_eq!(d.to_uint_floor(), Uint256::from_u128(0)); + + let d = Decimal256::MAX; + assert_eq!( + d.to_uint_floor(), + Uint256::from_str("115792089237316195423570985008687907853269984665640564039457") + .unwrap() + ); + } + + #[test] + fn decimal256_to_uint_ceil_works() { + let d = Decimal256::from_str("12.000000000000000001").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint256::from_u128(13)); + let d = Decimal256::from_str("12.345").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint256::from_u128(13)); + let d = Decimal256::from_str("12.999").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint256::from_u128(13)); + + let d = Decimal256::from_str("75.0").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint256::from_u128(75)); + let d = Decimal256::from_str("0.0").unwrap(); + assert_eq!(d.to_uint_ceil(), Uint256::from_u128(0)); + + let d = Decimal256::MAX; + assert_eq!( + d.to_uint_ceil(), + Uint256::from_str("115792089237316195423570985008687907853269984665640564039458") + .unwrap() + ); + } + #[test] fn decimal256_partial_eq() { let test_cases = [ From 3b7b3a4a553fa299de3799352b86ea414c9b4e89 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 30 Jan 2023 13:23:53 +0100 Subject: [PATCH 145/187] Implement to_uint_ceil without modulo operation --- packages/std/src/math/decimal.rs | 10 +++++++--- packages/std/src/math/decimal256.rs | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 82408f0510..80c610cf6b 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -399,10 +399,14 @@ impl Decimal { /// assert_eq!(d.to_uint_ceil(), Uint128::new(75)); /// ``` pub fn to_uint_ceil(self) -> Uint128 { - if (self.0 % Self::DECIMAL_FRACTIONAL).is_zero() { - self.0 / Self::DECIMAL_FRACTIONAL + // Using `q = 1 + ((x - 1) / y); // if x != 0` with unsigned integers x, y, q + // from https://stackoverflow.com/a/2745086/2013738. We know `x + y` CAN overflow. + let x = self.0; + let y = Self::DECIMAL_FRACTIONAL; + if x.is_zero() { + Uint128::zero() } else { - self.0 / Self::DECIMAL_FRACTIONAL + Uint128::one() + Uint128::one() + ((x - Uint128::one()) / y) } } } diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 2777b63866..bd286a5f98 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -416,10 +416,14 @@ impl Decimal256 { /// assert_eq!(d.to_uint_ceil(), Uint256::from(75u64)); /// ``` pub fn to_uint_ceil(self) -> Uint256 { - if (self.0 % Self::DECIMAL_FRACTIONAL).is_zero() { - self.0 / Self::DECIMAL_FRACTIONAL + // Using `q = 1 + ((x - 1) / y); // if x != 0` with unsigned integers x, y, q + // from https://stackoverflow.com/a/2745086/2013738. We know `x + y` CAN overflow. + let x = self.0; + let y = Self::DECIMAL_FRACTIONAL; + if x.is_zero() { + Uint256::zero() } else { - self.0 / Self::DECIMAL_FRACTIONAL + Uint256::one() + Uint256::one() + ((x - Uint256::one()) / y) } } } From a31e81ffbc6f7c25606a24df3d11c86b2c839585 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 30 Jan 2023 13:32:18 +0100 Subject: [PATCH 146/187] Test to_uint_floor for value < 1 --- packages/std/src/math/decimal.rs | 2 ++ packages/std/src/math/decimal256.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index 80c610cf6b..d4c63651bd 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -2062,6 +2062,8 @@ mod tests { assert_eq!(d.to_uint_floor(), Uint128::new(12)); let d = Decimal::from_str("12.999").unwrap(); assert_eq!(d.to_uint_floor(), Uint128::new(12)); + let d = Decimal::from_str("0.98451384").unwrap(); + assert_eq!(d.to_uint_floor(), Uint128::new(0)); let d = Decimal::from_str("75.0").unwrap(); assert_eq!(d.to_uint_floor(), Uint128::new(75)); diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index bd286a5f98..45e7e8d83a 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -2209,6 +2209,8 @@ mod tests { assert_eq!(d.to_uint_floor(), Uint256::from_u128(12)); let d = Decimal256::from_str("12.999").unwrap(); assert_eq!(d.to_uint_floor(), Uint256::from_u128(12)); + let d = Decimal256::from_str("0.98451384").unwrap(); + assert_eq!(d.to_uint_floor(), Uint256::from_u128(0)); let d = Decimal256::from_str("75.0").unwrap(); assert_eq!(d.to_uint_floor(), Uint256::from_u128(75)); From 6ca600b0c8a7ca4afe6af6db33e2d9e18bb8de31 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 30 Jan 2023 13:32:54 +0100 Subject: [PATCH 147/187] Test compatibility with old workaround --- packages/std/src/math/decimal.rs | 13 +++++++++++++ packages/std/src/math/decimal256.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index d4c63651bd..5f1473dfd0 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -2072,6 +2072,19 @@ mod tests { let d = Decimal::MAX; assert_eq!(d.to_uint_floor(), Uint128::new(340282366920938463463)); + + // Does the same as the old workaround `Uint128::one() * my_decimal`. + // This block can be deleted as part of https://github.com/CosmWasm/cosmwasm/issues/1485. + let tests = vec![ + Decimal::from_str("12.345").unwrap(), + Decimal::from_str("0.98451384").unwrap(), + Decimal::from_str("178.0").unwrap(), + Decimal::MIN, + Decimal::MAX, + ]; + for my_decimal in tests.into_iter() { + assert_eq!(my_decimal.to_uint_floor(), Uint128::one() * my_decimal); + } } #[test] diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 45e7e8d83a..1092776c68 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -2223,6 +2223,19 @@ mod tests { Uint256::from_str("115792089237316195423570985008687907853269984665640564039457") .unwrap() ); + + // Does the same as the old workaround `Uint256::one() * my_decimal`. + // This block can be deleted as part of https://github.com/CosmWasm/cosmwasm/issues/1485. + let tests = vec![ + Decimal256::from_str("12.345").unwrap(), + Decimal256::from_str("0.98451384").unwrap(), + Decimal256::from_str("178.0").unwrap(), + Decimal256::MIN, + Decimal256::MAX, + ]; + for my_decimal in tests.into_iter() { + assert_eq!(my_decimal.to_uint_floor(), Uint256::one() * my_decimal); + } } #[test] From 9c76900a7a009671a1506241df133bb527c23fdb Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 30 Jan 2023 13:54:14 +0100 Subject: [PATCH 148/187] Fix virus instantiation --- contracts/virus/src/contract.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/contracts/virus/src/contract.rs b/contracts/virus/src/contract.rs index dabd590cbd..202881b346 100644 --- a/contracts/virus/src/contract.rs +++ b/contracts/virus/src/contract.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ entry_point, instantiate2_address, to_binary, Attribute, Binary, CodeInfoResponse, - ContractInfoResponse, DepsMut, Env, MessageInfo, Response, StdError, StdResult, WasmMsg, + ContractInfoResponse, DepsMut, Env, MessageInfo, Response, StdResult, WasmMsg, }; use crate::errors::ContractError; @@ -13,9 +13,7 @@ pub fn instantiate( _info: MessageInfo, _msg: InstantiateMsg, ) -> StdResult { - Err(StdError::generic_err( - "You can only use this contract for migrations", - )) + Ok(Response::new()) } #[entry_point] @@ -96,4 +94,18 @@ pub fn execute_spread( } #[cfg(test)] -mod tests {} +mod tests { + use super::*; + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + + const CREATOR: &str = "creator"; + + #[test] + fn instantiate_works() { + let mut deps = mock_dependencies(); + let msg = InstantiateMsg {}; + let info = mock_info(CREATOR, &[]); + let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); + assert_eq!(0, res.messages.len()); + } +} From 893786af4309d7550176e8387493a6a08237b123 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 30 Jan 2023 14:36:25 +0100 Subject: [PATCH 149/187] Add CHANGELOG entry for to_uint_floor/to_uint_ceil [ci skip] --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea5f0b20d1..81599bf158 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ and this project adheres to ## [Unreleased] +### Added + +- cosmwasm-std: Add `Decimal{,256}::to_uint_floor` and `::to_uint_ceil` for + efficient and explicit decimal to uint conversion ([#1603]). + +[#1603]: https://github.com/CosmWasm/cosmwasm/pull/1603 + ### Fixed - cosmwasm-std: Make fields of `WeightedVoteOption` public to allow constructing From 9e822c43e2e93449307dc34c3f3bd01317a2a2b5 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 30 Jan 2023 14:38:23 +0100 Subject: [PATCH 150/187] Set version: 1.2.1 --- CHANGELOG.md | 5 ++++- Cargo.lock | 16 ++++++++-------- contracts/burner/Cargo.lock | 12 ++++++------ contracts/crypto-verify/Cargo.lock | 14 +++++++------- contracts/cyberpunk/Cargo.lock | 14 +++++++------- contracts/floaty/Cargo.lock | 14 +++++++------- contracts/hackatom/Cargo.lock | 14 +++++++------- contracts/ibc-reflect-send/Cargo.lock | 14 +++++++------- contracts/ibc-reflect/Cargo.lock | 14 +++++++------- contracts/queue/Cargo.lock | 12 ++++++------ contracts/reflect/Cargo.lock | 14 +++++++------- contracts/staking/Cargo.lock | 14 +++++++------- contracts/virus/Cargo.lock | 12 ++++++------ packages/check/Cargo.toml | 6 +++--- packages/crypto/Cargo.toml | 2 +- packages/derive/Cargo.toml | 2 +- packages/schema-derive/Cargo.toml | 2 +- packages/schema/Cargo.toml | 6 +++--- packages/std/Cargo.toml | 6 +++--- packages/storage/Cargo.toml | 4 ++-- packages/vm/Cargo.toml | 6 +++--- 21 files changed, 103 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81599bf158..4077ac9e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to ## [Unreleased] +## [1.2.1] - 2023-01-30 + ### Added - cosmwasm-std: Add `Decimal{,256}::to_uint_floor` and `::to_uint_ceil` for @@ -1631,7 +1633,8 @@ Some main points: All future Changelog entries will reference this base -[unreleased]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.0...HEAD +[unreleased]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.1...HEAD +[1.2.1]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.0...v1.2.1 [1.2.0]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.9...v1.2.0 [1.1.9]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.8...v1.1.9 [1.1.8]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.6...v1.1.8 diff --git a/Cargo.lock b/Cargo.lock index eae3adcab8..450164ed4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "cosmwasm-check" -version = "1.2.0" +version = "1.2.1" dependencies = [ "anyhow", "clap", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "criterion", @@ -276,7 +276,7 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "syn", @@ -284,7 +284,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "anyhow", "cosmwasm-schema-derive", @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "chrono", @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "serde", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index 20a0bf204d..64ab9e5c20 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -174,7 +174,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -185,14 +185,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -203,7 +203,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index 0fa8440fb7..373b1570ea 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -169,7 +169,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -180,14 +180,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -198,7 +198,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -207,7 +207,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "serde", @@ -233,7 +233,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index c5987f97dc..ae70be30ec 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -203,14 +203,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -221,7 +221,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "serde", @@ -256,7 +256,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index 495ecd0e42..6d88927bcc 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index b76cc69f07..1115f5ad91 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index 9c5b2a1f77..96690b1028 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index 46792be82f..9f4ff5b1b7 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index 0c284845a1..36b1b458a5 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index 64da836cd1..76cb94c658 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index 35a8d3288d..f08f9f6c11 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock index 4e6882ec84..69daf93200 100644 --- a/contracts/virus/Cargo.lock +++ b/contracts/virus/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" dependencies = [ "bitflags", "bytecheck", diff --git a/packages/check/Cargo.toml b/packages/check/Cargo.toml index e09ee94e48..a99865dbd8 100644 --- a/packages/check/Cargo.toml +++ b/packages/check/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-check" -version = "1.2.0" +version = "1.2.1" authors = ["Mauro Lacy "] edition = "2021" description = "A CLI tool for verifying CosmWasm smart contracts" @@ -11,5 +11,5 @@ license = "Apache-2.0" anyhow = "1.0.57" clap = "2" colored = "2" -cosmwasm-vm = { path = "../vm", version = "1.2.0" } -cosmwasm-std = { path = "../std", version = "1.2.0" } +cosmwasm-vm = { path = "../vm", version = "1.2.1" } +cosmwasm-std = { path = "../std", version = "1.2.1" } diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index cbadde4722..7691f40bb2 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-crypto" -version = "1.2.0" +version = "1.2.1" authors = ["Mauro Lacy "] edition = "2021" description = "Crypto bindings for cosmwasm contracts" diff --git a/packages/derive/Cargo.toml b/packages/derive/Cargo.toml index 5a111016fb..38a24c375d 100644 --- a/packages/derive/Cargo.toml +++ b/packages/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-derive" -version = "1.2.0" +version = "1.2.1" authors = ["Simon Warta "] edition = "2021" description = "A package for auto-generated code used for CosmWasm contract development. This is shipped as part of cosmwasm-std. Do not use directly." diff --git a/packages/schema-derive/Cargo.toml b/packages/schema-derive/Cargo.toml index 04b09449e2..61314c5324 100644 --- a/packages/schema-derive/Cargo.toml +++ b/packages/schema-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema-derive" -version = "1.2.0" +version = "1.2.1" authors = ["Tomasz Kurcz "] edition = "2021" description = "Derive macros for cosmwasm-schema" diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index 01d1b23c2e..faa8e5854b 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema" -version = "1.2.0" +version = "1.2.1" authors = ["Simon Warta ", "Ethan Frey "] edition = "2021" description = "A dev-dependency for CosmWasm contracts to generate JSON Schema files." @@ -8,7 +8,7 @@ repository = "https://github.com/CosmWasm/cosmwasm/tree/main/packages/schema" license = "Apache-2.0" [dependencies] -cosmwasm-schema-derive = { version = "=1.2.0", path = "../schema-derive" } +cosmwasm-schema-derive = { version = "=1.2.1", path = "../schema-derive" } schemars = "0.8.3" serde = "1.0" serde_json = "1.0.40" @@ -16,6 +16,6 @@ thiserror = "1.0.26" [dev-dependencies] anyhow = "1.0.57" -cosmwasm-std = { version = "1.2.0", path = "../std" } +cosmwasm-std = { version = "1.2.1", path = "../std" } semver = "1" tempfile = "3" diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 831b45ae22..7b286142b8 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-std" -version = "1.2.0" +version = "1.2.1" authors = ["Ethan Frey "] edition = "2021" description = "Standard library for Wasm based smart contracts on Cosmos blockchains" @@ -42,7 +42,7 @@ cosmwasm_1_2 = ["cosmwasm_1_1"] [dependencies] base64 = "0.13.0" -cosmwasm-derive = { path = "../derive", version = "1.2.0" } +cosmwasm-derive = { path = "../derive", version = "1.2.1" } derivative = "2" forward_ref = "1" hex = "0.4" @@ -54,7 +54,7 @@ thiserror = "1.0.26" uint = "0.9.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -cosmwasm-crypto = { path = "../crypto", version = "1.2.0" } +cosmwasm-crypto = { path = "../crypto", version = "1.2.1" } [dev-dependencies] cosmwasm-schema = { path = "../schema" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index 6332d2e1b2..e3b95773ad 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-storage" -version = "1.2.0" +version = "1.2.1" authors = ["Ethan Frey "] edition = "2021" description = "CosmWasm library with useful helpers for Storage patterns" @@ -16,5 +16,5 @@ iterator = ["cosmwasm-std/iterator"] [dependencies] # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.0", default-features = false } +cosmwasm-std = { path = "../std", version = "1.2.1", default-features = false } serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index 0fb8290d5b..1e5c85759b 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-vm" -version = "1.2.0" +version = "1.2.1" authors = ["Ethan Frey "] edition = "2021" description = "VM bindings to run cosmwams contracts" @@ -41,8 +41,8 @@ required-features = ["iterator"] [dependencies] clru = "0.4.0" # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.0", default-features = false } -cosmwasm-crypto = { path = "../crypto", version = "1.2.0" } +cosmwasm-std = { path = "../std", version = "1.2.1", default-features = false } +cosmwasm-crypto = { path = "../crypto", version = "1.2.1" } hex = "0.4" parity-wasm = "0.42" schemars = "0.8.3" From 32f308a1a56ae5b8278947891306f7a374c3df94 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 30 Jan 2023 18:16:17 +0100 Subject: [PATCH 151/187] Add type-safe unwrap example --- packages/std/src/never.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/std/src/never.rs b/packages/std/src/never.rs index 4b9f6c7b8a..51173892f5 100644 --- a/packages/std/src/never.rs +++ b/packages/std/src/never.rs @@ -7,6 +7,24 @@ /// /// Once the ! type is stable, this is not needed anymore. /// See . +/// +/// ## Examples +/// +/// When using `Never` in a `Result`, we can unwrap in a type-safe way: +/// +/// ``` +/// use cosmwasm_std::Never; +/// +/// pub fn safe_unwrap(res: Result) -> T { +/// match res { +/// Ok(value) => value, +/// Err(err) => match err {}, +/// } +/// } +/// +/// let res: Result = Ok(5); +/// assert_eq!(safe_unwrap(res), 5); +/// ``` pub enum Never {} // The Debug implementation is needed to allow the use of `Result::unwrap`. From 30db426e2f8185ef977d24c8b560786a0f3bb07d Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez Date: Wed, 8 Feb 2023 10:09:13 +0100 Subject: [PATCH 152/187] Expose CheckedMultiplyFractionError publicly --- packages/std/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index a15f0f4c62..ccc28b2c91 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -31,9 +31,9 @@ pub use crate::binary::Binary; pub use crate::coin::{coin, coins, has_coins, Coin}; pub use crate::deps::{Deps, DepsMut, OwnedDeps}; pub use crate::errors::{ - CheckedFromRatioError, CheckedMultiplyRatioError, ConversionOverflowError, DivideByZeroError, - OverflowError, OverflowOperation, RecoverPubkeyError, StdError, StdResult, SystemError, - VerificationError, + CheckedFromRatioError, CheckedMultiplyFractionError, CheckedMultiplyRatioError, + ConversionOverflowError, DivideByZeroError, OverflowError, OverflowOperation, + RecoverPubkeyError, StdError, StdResult, SystemError, VerificationError, }; pub use crate::hex_binary::HexBinary; #[cfg(feature = "stargate")] From 4eb32795a944c62b56a376f1359226c1ae9184f0 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Wed, 22 Feb 2023 13:48:01 +0200 Subject: [PATCH 153/187] Fix backtraces feature --- Cargo.lock | 8 ++++---- packages/crypto/Cargo.toml | 7 +++++-- packages/crypto/src/lib.rs | 3 ++- packages/std/src/lib.rs | 3 ++- packages/vm/src/lib.rs | 3 ++- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 450164ed4e..b0dd83c5b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1743,18 +1743,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index 7691f40bb2..8e2107099f 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -23,11 +23,14 @@ k256 = { version = "0.11.1", features = ["ecdsa"] } ed25519-zebra = "3" digest = "0.10" rand_core = { version = "0.6", features = ["getrandom"] } -thiserror = "1.0.26" +thiserror = "1.0.38" [dev-dependencies] criterion = "0.3" -serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } +serde = { version = "1.0.103", default-features = false, features = [ + "derive", + "alloc", +] } serde_json = "1.0.40" sha2 = "0.10" base64 = "0.13.0" diff --git a/packages/crypto/src/lib.rs b/packages/crypto/src/lib.rs index 97bf244c43..01ee97bbf7 100644 --- a/packages/crypto/src/lib.rs +++ b/packages/crypto/src/lib.rs @@ -2,7 +2,8 @@ //! Please don't use any of these types directly, as //! they might change frequently, or be removed in the future. //! This crate does not adhere to semantic versioning. -#![cfg_attr(feature = "backtraces", feature(backtrace))] +#![cfg_attr(feature = "backtraces", feature(error_generic_member_access))] +#![cfg_attr(feature = "backtraces", feature(provide_any))] mod ed25519; mod errors; diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index a15f0f4c62..13087241c5 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -1,4 +1,5 @@ -#![cfg_attr(feature = "backtraces", feature(backtrace))] +#![cfg_attr(feature = "backtraces", feature(error_generic_member_access))] +#![cfg_attr(feature = "backtraces", feature(provide_any))] // Exposed on all platforms diff --git a/packages/vm/src/lib.rs b/packages/vm/src/lib.rs index 986275853b..19bb888f82 100644 --- a/packages/vm/src/lib.rs +++ b/packages/vm/src/lib.rs @@ -1,4 +1,5 @@ -#![cfg_attr(feature = "backtraces", feature(backtrace))] +#![cfg_attr(feature = "backtraces", feature(error_generic_member_access))] +#![cfg_attr(feature = "backtraces", feature(provide_any))] mod backend; mod cache; From 3bee042f1ddef316e4454040226f985bbfb91474 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 2 Mar 2023 10:53:44 +0100 Subject: [PATCH 154/187] Add update_crate script --- devtools/update_crate.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100755 devtools/update_crate.sh diff --git a/devtools/update_crate.sh b/devtools/update_crate.sh new file mode 100755 index 0000000000..500d36f6e0 --- /dev/null +++ b/devtools/update_crate.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -o errexit -o nounset -o pipefail +command -v shellcheck >/dev/null && shellcheck "$0" + +CRATE_NAME="$1" + +# Update root Cargo.lock +cargo update -p "$CRATE_NAME" + +for contract_dir in contracts/*/; do + ( + cd "$contract_dir" + cargo update -p "$CRATE_NAME" + ) +done From 1f10b7876205c0e85602b2974f0a31590d7359e4 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 2 Mar 2023 10:54:00 +0100 Subject: [PATCH 155/187] Update schemars to 0.8.12 --- Cargo.lock | 12 ++++++------ contracts/burner/Cargo.lock | 12 ++++++------ contracts/crypto-verify/Cargo.lock | 12 ++++++------ contracts/cyberpunk/Cargo.lock | 12 ++++++------ contracts/floaty/Cargo.lock | 12 ++++++------ contracts/hackatom/Cargo.lock | 12 ++++++------ contracts/ibc-reflect-send/Cargo.lock | 12 ++++++------ contracts/ibc-reflect/Cargo.lock | 12 ++++++------ contracts/queue/Cargo.lock | 12 ++++++------ contracts/reflect/Cargo.lock | 12 ++++++------ contracts/staking/Cargo.lock | 12 ++++++------ contracts/virus/Cargo.lock | 12 ++++++------ 12 files changed, 72 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 450164ed4e..055a5732eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1503,9 +1503,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b5a3c80cea1ab61f4260238409510e814e38b4b563c06044edf91e7dc070e3" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1515,9 +1515,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ae4dce13e8614c46ac3c38ef1c0d668b101df6ac39817aebdaa26642ddae9b" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1607,9 +1607,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index 64ab9e5c20..56ca559f5c 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -1223,9 +1223,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1235,9 +1235,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1311,9 +1311,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index 373b1570ea..dc4e38526b 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -1271,9 +1271,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1283,9 +1283,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1359,9 +1359,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index ae70be30ec..db0f949870 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -1273,9 +1273,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1285,9 +1285,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1361,9 +1361,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index 6d88927bcc..6c8bc31a67 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -1233,9 +1233,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1245,9 +1245,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1321,9 +1321,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index 1115f5ad91..11cf5a009c 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -1234,9 +1234,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1246,9 +1246,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1322,9 +1322,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index 96690b1028..db1014cba7 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -1232,9 +1232,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1244,9 +1244,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1320,9 +1320,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index 9f4ff5b1b7..bde4bf016a 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -1232,9 +1232,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1244,9 +1244,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1320,9 +1320,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index 36b1b458a5..db3ffc084c 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -1223,9 +1223,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1235,9 +1235,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1311,9 +1311,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index 76cb94c658..dfda6dbb1d 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -1233,9 +1233,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1245,9 +1245,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1321,9 +1321,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index f08f9f6c11..df8d3d66ce 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -1226,9 +1226,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1238,9 +1238,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1314,9 +1314,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock index 69daf93200..4b3cd2be27 100644 --- a/contracts/virus/Cargo.lock +++ b/contracts/virus/Cargo.lock @@ -1212,9 +1212,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" dependencies = [ "dyn-clone", "schemars_derive", @@ -1224,9 +1224,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" dependencies = [ "proc-macro2", "quote", @@ -1300,9 +1300,9 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ "proc-macro2", "quote", From 3895f20c1142da31a6414d9c57f03dae4f7ec341 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 2 Mar 2023 11:11:06 +0100 Subject: [PATCH 156/187] Re-generate schemas --- contracts/reflect/schema/raw/execute.json | 35 +++++++++++++++++++---- contracts/reflect/schema/reflect.json | 35 +++++++++++++++++++---- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/contracts/reflect/schema/raw/execute.json b/contracts/reflect/schema/raw/execute.json index 732cf6db15..5460db7a9b 100644 --- a/contracts/reflect/schema/raw/execute.json +++ b/contracts/reflect/schema/raw/execute.json @@ -532,12 +532,35 @@ }, "ReplyOn": { "description": "Use this to define when the contract gets a response callback. If you only need it for errors or success you can select just those in order to save gas.", - "type": "string", - "enum": [ - "always", - "error", - "success", - "never" + "oneOf": [ + { + "description": "Always perform a callback after SubMsg is processed", + "type": "string", + "enum": [ + "always" + ] + }, + { + "description": "Only callback if SubMsg returned an error, no callback on success case", + "type": "string", + "enum": [ + "error" + ] + }, + { + "description": "Only callback if SubMsg was successful, no callback on error case", + "type": "string", + "enum": [ + "success" + ] + }, + { + "description": "Never make a callback - this is like the original CosmosMsg semantics", + "type": "string", + "enum": [ + "never" + ] + } ] }, "StakingMsg": { diff --git a/contracts/reflect/schema/reflect.json b/contracts/reflect/schema/reflect.json index f73dcfe4bf..aa6f6da44c 100644 --- a/contracts/reflect/schema/reflect.json +++ b/contracts/reflect/schema/reflect.json @@ -542,12 +542,35 @@ }, "ReplyOn": { "description": "Use this to define when the contract gets a response callback. If you only need it for errors or success you can select just those in order to save gas.", - "type": "string", - "enum": [ - "always", - "error", - "success", - "never" + "oneOf": [ + { + "description": "Always perform a callback after SubMsg is processed", + "type": "string", + "enum": [ + "always" + ] + }, + { + "description": "Only callback if SubMsg returned an error, no callback on success case", + "type": "string", + "enum": [ + "error" + ] + }, + { + "description": "Only callback if SubMsg was successful, no callback on error case", + "type": "string", + "enum": [ + "success" + ] + }, + { + "description": "Never make a callback - this is like the original CosmosMsg semantics", + "type": "string", + "enum": [ + "never" + ] + } ] }, "StakingMsg": { From e5a623ca40d68d6bb755025b60f7d8ab351770b1 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 2 Mar 2023 11:40:20 +0100 Subject: [PATCH 157/187] Upgrade clippy job to Rust 1.67.1 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3c01ff12e9..d299a74156 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -72,7 +72,7 @@ workflows: matrix: parameters: # Run with MSRV and some modern stable Rust - rust-version: ["1.60.0", "1.66.0"] + rust-version: ["1.60.0", "1.67.1"] - benchmarking: requires: - package_vm From d436094b346b9b4bd3a73a07bbf2a3f9f1037cef Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 2 Mar 2023 11:59:17 +0100 Subject: [PATCH 158/187] Add CHANGELOG entry for CheckedMultiplyFractionError --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4077ac9e36..8c818e9af7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to ## [Unreleased] +### Fixed + +- cosmwasm-std: Add missing export `CheckedMultiplyFractionError` ([#1608]). + +[#1608]: https://github.com/CosmWasm/cosmwasm/pull/1608 + ## [1.2.1] - 2023-01-30 ### Added From c19953d6bdcb4db350d5dae9f9353510562b6022 Mon Sep 17 00:00:00 2001 From: Nikhil Suri Date: Sat, 4 Mar 2023 22:38:54 +0000 Subject: [PATCH 159/187] Add mocking capabilities for ibc querying --- packages/std/src/testing/mock.rs | 191 ++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 3 deletions(-) diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index 023ef30ff8..e283024f41 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -33,6 +33,8 @@ use crate::timestamp::Timestamp; use crate::traits::{Api, Querier, QuerierResult}; use crate::types::{BlockInfo, ContractInfo, Env, MessageInfo, TransactionInfo}; use crate::Attribute; +#[cfg(feature = "stargate")] +use crate::{ChannelResponse, IbcQuery, ListChannelsResponse, PortIdResponse}; use super::riffle_shuffle; @@ -435,6 +437,8 @@ pub struct MockQuerier { #[cfg(feature = "staking")] staking: StakingQuerier, wasm: WasmQuerier, + #[cfg(feature = "stargate")] + ibc: IbcQuerier, /// A handler to handle custom queries. This is set to a dummy handler that /// always errors by default. Update it via `with_custom_handler`. /// @@ -449,6 +453,8 @@ impl MockQuerier { #[cfg(feature = "staking")] staking: StakingQuerier::default(), wasm: WasmQuerier::default(), + #[cfg(feature = "stargate")] + ibc: IbcQuerier::default(), // strange argument notation suggested as a workaround here: https://github.com/rust-lang/rust/issues/41078#issuecomment-294296365 custom_handler: Box::from(|_: &_| -> MockQuerierCustomHandlerResult { SystemResult::Err(SystemError::UnsupportedRequest { @@ -477,6 +483,11 @@ impl MockQuerier { self.staking = StakingQuerier::new(denom, validators, delegations); } + #[cfg(feature = "stargate")] + pub fn update_ibc(&mut self, port_id: &str, channels: &[IbcChannel]) { + self.ibc = IbcQuerier::new(port_id, channels); + } + pub fn update_wasm(&mut self, handler: WH) where WH: Fn(&WasmQuery) -> QuerierResult, @@ -527,9 +538,7 @@ impl MockQuerier { kind: "Stargate".to_string(), }), #[cfg(feature = "stargate")] - QueryRequest::Ibc(_) => SystemResult::Err(SystemError::UnsupportedRequest { - kind: "Ibc".to_string(), - }), + QueryRequest::Ibc(msg) => self.ibc.query(msg), } } } @@ -675,6 +684,70 @@ impl BankQuerier { } } +#[cfg(feature = "stargate")] +#[derive(Clone, Default)] +pub struct IbcQuerier { + port_id: String, + channels: Vec, +} + +#[cfg(feature = "stargate")] +impl IbcQuerier { + /// Create a mock querier where: + /// - port_id is the port the "contract" is bound to + /// - channels are a list of ibc channels + pub fn new(port_id: &str, channels: &[IbcChannel]) -> Self { + IbcQuerier { + port_id: port_id.to_string(), + channels: channels.to_vec(), + } + } + + pub fn query(&self, request: &IbcQuery) -> QuerierResult { + let contract_result: ContractResult = match request { + IbcQuery::Channel { + channel_id, + port_id, + } => { + let channel = self + .channels + .iter() + .find(|c| match port_id { + Some(p) => c.endpoint.channel_id.eq(channel_id) && c.endpoint.port_id.eq(p), + None => { + c.endpoint.channel_id.eq(channel_id) + && c.endpoint.port_id == self.port_id + } + }) + .cloned(); + let res = ChannelResponse { channel }; + to_binary(&res).into() + } + IbcQuery::ListChannels { port_id } => { + let channels = self + .channels + .iter() + .filter(|c| match port_id { + Some(p) => c.endpoint.port_id.eq(p), + None => c.endpoint.port_id == self.port_id, + }) + .cloned() + .collect(); + let res = ListChannelsResponse { channels }; + to_binary(&res).into() + } + IbcQuery::PortId {} => { + let res = PortIdResponse { + port_id: self.port_id.clone(), + }; + to_binary(&res).into() + } + }; + // system result is always ok in the mock implementation + SystemResult::Ok(contract_result) + } +} + #[cfg(feature = "staking")] #[derive(Clone, Default)] pub struct StakingQuerier { @@ -1189,6 +1262,118 @@ mod tests { assert_eq!(res.amount, coin(0, "ELF")); } + #[cfg(feature = "stargate")] + #[test] + fn ibc_querier_channel_existing() { + let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc"); + let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc"); + + let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2]); + + // query existing + let query = &IbcQuery::Channel { + channel_id: "channel-0".to_string(), + port_id: Some("my_port".to_string()), + }; + let raw = ibc.query(query).unwrap().unwrap(); + let chan: ChannelResponse = from_binary(&raw).unwrap(); + assert_eq!(chan.channel, Some(chan1)); + } + + #[cfg(feature = "stargate")] + #[test] + fn ibc_querier_channel_existing_no_port() { + let chan1 = IbcChannel { + endpoint: IbcEndpoint { + port_id: "myport".to_string(), + channel_id: "channel-0".to_string(), + }, + counterparty_endpoint: IbcEndpoint { + port_id: "their_port".to_string(), + channel_id: "channel-7".to_string(), + }, + order: IbcOrder::Ordered, + version: "ibc".to_string(), + connection_id: "connection-2".to_string(), + }; + let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc"); + + let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2]); + + // query existing + let query = &IbcQuery::Channel { + channel_id: "channel-0".to_string(), + port_id: Some("myport".to_string()), + }; + let raw = ibc.query(query).unwrap().unwrap(); + let chan: ChannelResponse = from_binary(&raw).unwrap(); + assert_eq!(chan.channel, Some(chan1)); + } + + #[cfg(feature = "stargate")] + #[test] + fn ibc_querier_channel_none() { + let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc"); + let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc"); + + let ibc = IbcQuerier::new("myport", &[chan1, chan2]); + + // query non-existing + let query = &IbcQuery::Channel { + channel_id: "channel-0".to_string(), + port_id: None, + }; + let raw = ibc.query(query).unwrap().unwrap(); + let chan: ChannelResponse = from_binary(&raw).unwrap(); + assert_eq!(chan.channel, None); + } + + #[cfg(feature = "stargate")] + #[test] + fn ibc_querier_channels_matching() { + let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc"); + let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc"); + + let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2.clone()]); + + // query channels matching "my_port" (should match both above) + let query = &&IbcQuery::ListChannels { + port_id: Some("my_port".to_string()), + }; + let raw = ibc.query(query).unwrap().unwrap(); + let res: ListChannelsResponse = from_binary(&raw).unwrap(); + assert_eq!(res.channels, vec![chan1, chan2]); + } + + #[cfg(feature = "stargate")] + #[test] + fn ibc_querier_channels_no_matching() { + let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc"); + let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc"); + + let ibc = IbcQuerier::new("myport", &[chan1, chan2]); + + // query channels matching "myport" (should be none) + let query = &&IbcQuery::ListChannels { port_id: None }; + let raw = ibc.query(query).unwrap().unwrap(); + let res: ListChannelsResponse = from_binary(&raw).unwrap(); + assert_eq!(res.channels, vec![]); + } + + #[cfg(feature = "stargate")] + #[test] + fn ibc_querier_port() { + let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc"); + + let ibc = IbcQuerier::new("myport", &[chan1]); + + // query channels matching "myport" (should be none) + let query = &&IbcQuery::PortId {}; + let raw = ibc.query(query).unwrap().unwrap(); + let res: PortIdResponse = from_binary(&raw).unwrap(); + assert_eq!(res.port_id, "myport"); + } + #[cfg(feature = "staking")] #[test] fn staking_querier_all_validators() { From 30ea965a65d500a691cf6f645d737aefde4005ee Mon Sep 17 00:00:00 2001 From: TomL94 Date: Sun, 5 Mar 2023 12:04:34 +0200 Subject: [PATCH 160/187] Update contracts' cargo.lock --- contracts/burner/Cargo.lock | 8 ++++---- contracts/crypto-verify/Cargo.lock | 8 ++++---- contracts/cyberpunk/Cargo.lock | 8 ++++---- contracts/floaty/Cargo.lock | 8 ++++---- contracts/hackatom/Cargo.lock | 8 ++++---- contracts/ibc-reflect-send/Cargo.lock | 8 ++++---- contracts/ibc-reflect/Cargo.lock | 8 ++++---- contracts/queue/Cargo.lock | 8 ++++---- contracts/reflect/Cargo.lock | 8 ++++---- contracts/staking/Cargo.lock | 8 ++++---- contracts/virus/Cargo.lock | 8 ++++---- 11 files changed, 44 insertions(+), 44 deletions(-) diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index 56ca559f5c..f613b9a2db 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -1438,18 +1438,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index dc4e38526b..ee27054a22 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -1496,18 +1496,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index db0f949870..2dfea418e2 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -1488,18 +1488,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index 6c8bc31a67..4413bbd35e 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -1448,18 +1448,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index 11cf5a009c..68e5f33a73 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -1449,18 +1449,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index db1014cba7..adf7c89ef0 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -1447,18 +1447,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index bde4bf016a..2b006e26ed 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -1447,18 +1447,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index db3ffc084c..cdaee9dacb 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -1438,18 +1438,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index dfda6dbb1d..f26ddb5536 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -1448,18 +1448,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index df8d3d66ce..a71c08b1d8 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -1475,18 +1475,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock index 4b3cd2be27..a18cd16f0e 100644 --- a/contracts/virus/Cargo.lock +++ b/contracts/virus/Cargo.lock @@ -1427,18 +1427,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", From 63364659b4fe54b9ecd68c1e93a7152f6e43561a Mon Sep 17 00:00:00 2001 From: Simon Warta <2603011+webmaster128@users.noreply.github.com> Date: Mon, 6 Mar 2023 09:51:02 +0100 Subject: [PATCH 161/187] Update packages/crypto/Cargo.toml --- packages/crypto/Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index 8e2107099f..e2933e0fa6 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -27,10 +27,7 @@ thiserror = "1.0.38" [dev-dependencies] criterion = "0.3" -serde = { version = "1.0.103", default-features = false, features = [ - "derive", - "alloc", -] } +serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } serde_json = "1.0.40" sha2 = "0.10" base64 = "0.13.0" From f0890e1960469c921473e8f008b7c7aa12802996 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 6 Mar 2023 10:01:07 +0100 Subject: [PATCH 162/187] Add CHANGELOG entry for backtraces fix --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c818e9af7..7f34f092d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,12 @@ and this project adheres to ### Fixed +- all: Fix `backtraces` feature for newer versions of Rust. This still requires + Rust nightly ([#1613]). - cosmwasm-std: Add missing export `CheckedMultiplyFractionError` ([#1608]). [#1608]: https://github.com/CosmWasm/cosmwasm/pull/1608 +[#1613]: https://github.com/CosmWasm/cosmwasm/pull/1613 ## [1.2.1] - 2023-01-30 From 687d6672ef65d4a9d23d53e5be26a7da1f712ab1 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 7 Mar 2023 17:29:00 +0100 Subject: [PATCH 163/187] Remove unnecessary double references --- packages/std/src/testing/mock.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/std/src/testing/mock.rs b/packages/std/src/testing/mock.rs index e283024f41..d219236578 100644 --- a/packages/std/src/testing/mock.rs +++ b/packages/std/src/testing/mock.rs @@ -1337,7 +1337,7 @@ mod tests { let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2.clone()]); // query channels matching "my_port" (should match both above) - let query = &&IbcQuery::ListChannels { + let query = &IbcQuery::ListChannels { port_id: Some("my_port".to_string()), }; let raw = ibc.query(query).unwrap().unwrap(); @@ -1354,7 +1354,7 @@ mod tests { let ibc = IbcQuerier::new("myport", &[chan1, chan2]); // query channels matching "myport" (should be none) - let query = &&IbcQuery::ListChannels { port_id: None }; + let query = &IbcQuery::ListChannels { port_id: None }; let raw = ibc.query(query).unwrap().unwrap(); let res: ListChannelsResponse = from_binary(&raw).unwrap(); assert_eq!(res.channels, vec![]); @@ -1368,7 +1368,7 @@ mod tests { let ibc = IbcQuerier::new("myport", &[chan1]); // query channels matching "myport" (should be none) - let query = &&IbcQuery::PortId {}; + let query = &IbcQuery::PortId {}; let raw = ibc.query(query).unwrap().unwrap(); let res: PortIdResponse = from_binary(&raw).unwrap(); assert_eq!(res.port_id, "myport"); From e32896d94a724cf30391c12d4bc10cbfec8b3e65 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 7 Mar 2023 17:35:25 +0100 Subject: [PATCH 164/187] Add CHANGELOG entry for #1620 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f34f092d3..59e5e0fb6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to ## [Unreleased] +### Added + +- cosmwasm-std: Add an IBC querier implementation to `testing::MockQuerier` + ([#1620], [#1624]). + +[#1620]: https://github.com/CosmWasm/cosmwasm/pull/1620 +[#1624]: https://github.com/CosmWasm/cosmwasm/pull/1624 + ### Fixed - all: Fix `backtraces` feature for newer versions of Rust. This still requires From 28b2e251385075cb02b3b3c95ee6a08f7792ac9a Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 7 Mar 2023 17:49:15 +0100 Subject: [PATCH 165/187] Add #[must_use] annotations to Timestamp math functions --- CHANGELOG.md | 1 + packages/std/src/timestamp.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59e5e0fb6a..d4ca2834d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to - cosmwasm-std: Add an IBC querier implementation to `testing::MockQuerier` ([#1620], [#1624]). +- cosmwasm-std: Add `#[must_use]` annotations to `Timestamp` math functions. [#1620]: https://github.com/CosmWasm/cosmwasm/pull/1620 [#1624]: https://github.com/CosmWasm/cosmwasm/pull/1624 diff --git a/packages/std/src/timestamp.rs b/packages/std/src/timestamp.rs index fa96fb477c..a8e4ea8585 100644 --- a/packages/std/src/timestamp.rs +++ b/packages/std/src/timestamp.rs @@ -38,19 +38,23 @@ impl Timestamp { Timestamp(Uint64::new(seconds_since_epoch * 1_000_000_000)) } + #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn plus_seconds(&self, addition: u64) -> Timestamp { self.plus_nanos(addition * 1_000_000_000) } + #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn plus_nanos(&self, addition: u64) -> Timestamp { let nanos = Uint64::new(self.0.u64() + addition); Timestamp(nanos) } + #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn minus_seconds(&self, subtrahend: u64) -> Timestamp { self.minus_nanos(subtrahend * 1_000_000_000) } + #[must_use = "this returns the result of the operation, without modifying the original"] pub const fn minus_nanos(&self, subtrahend: u64) -> Timestamp { let nanos = Uint64::new(self.0.u64() - subtrahend); Timestamp(nanos) From 6e336912edc0e6b2d321f3f7f5fb517cabc04714 Mon Sep 17 00:00:00 2001 From: Simon Warta <2603011+webmaster128@users.noreply.github.com> Date: Wed, 8 Mar 2023 11:18:11 +0100 Subject: [PATCH 166/187] Update packages/crypto/src/secp256k1.rs Co-authored-by: Mauro Lacy --- packages/crypto/src/secp256k1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index b2f606227c..c072e22342 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -95,7 +95,7 @@ pub fn secp256k1_verify( /// Please note that restricting signatures to low-S does not make signatures unique /// in the sense that for each (pubkey, message) there is only one signature. The /// signer can generate an arbitrary amount of valid signatures. -/// +/// /// /// [EIP-2]: https://eips.ethereum.org/EIPS/eip-2 pub fn secp256k1_recover_pubkey( From 1104982eaf4fc9ba7fb6567c8a05756ff5673eff Mon Sep 17 00:00:00 2001 From: Simon Warta <2603011+webmaster128@users.noreply.github.com> Date: Wed, 8 Mar 2023 11:18:21 +0100 Subject: [PATCH 167/187] Update packages/crypto/src/secp256k1.rs Co-authored-by: Mauro Lacy --- packages/crypto/src/secp256k1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index c072e22342..d8193894ca 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -38,7 +38,7 @@ pub const ECDSA_PUBKEY_MAX_LEN: usize = ECDSA_UNCOMPRESSED_PUBKEY_LEN; /// /// This implementation accepts both high-S and low-S signatures. Some applications /// including Ethereum transactions consider high-S signatures invalid in order to -/// avoid maleability. If that's the case for your protocol, the signature needs +/// avoid malleability. If that's the case for your protocol, the signature needs /// to be tested for low-S in addition to this verification. pub fn secp256k1_verify( message_hash: &[u8], From fca5d20cbf371dbc598f225e818ba4b277509fdf Mon Sep 17 00:00:00 2001 From: Simon Warta <2603011+webmaster128@users.noreply.github.com> Date: Wed, 8 Mar 2023 11:18:31 +0100 Subject: [PATCH 168/187] Update packages/crypto/src/secp256k1.rs Co-authored-by: Mauro Lacy --- packages/crypto/src/secp256k1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index d8193894ca..aff73ee405 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -385,7 +385,7 @@ mod tests { let try1 = secp256k1_recover_pubkey(&message_hash, &signature, 1); match (try0, try1) { (Ok(recovered0), Ok(recovered1)) => { - // Got two different pubkeys. Without the recoverey param, we don't know which one is the right one. + // Got two different pubkeys. Without the recovery param, we don't know which one is the right one. assert!(recovered0 == public_key || recovered1 == public_key) }, (Ok(recovered), Err(_)) => assert_eq!(recovered, public_key), From 46c709888dba414aad53d52e6068635cd94bc140 Mon Sep 17 00:00:00 2001 From: Simon Warta <2603011+webmaster128@users.noreply.github.com> Date: Wed, 8 Mar 2023 11:18:47 +0100 Subject: [PATCH 169/187] Update packages/crypto/src/secp256k1.rs Co-authored-by: Mauro Lacy --- packages/crypto/src/secp256k1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index aff73ee405..fda2ec51a9 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -90,7 +90,7 @@ pub fn secp256k1_verify( /// and will keep accepting high s-values; this is useful e.g. if a contract /// recovers old Bitcoin signatures.". /// -/// See also OpenZeppilin's [ECDSA.recover implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.1/contracts/utils/cryptography/ECDSA.sol#L138-L149) +/// See also OpenZeppelin's [ECDSA.recover implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.1/contracts/utils/cryptography/ECDSA.sol#L138-L149) /// which adds further restrictions to avoid potential siganture maleability. /// Please note that restricting signatures to low-S does not make signatures unique /// in the sense that for each (pubkey, message) there is only one signature. The From 5ecada96f07a4a0894939ca073c449389204ae1a Mon Sep 17 00:00:00 2001 From: Simon Warta <2603011+webmaster128@users.noreply.github.com> Date: Wed, 8 Mar 2023 11:19:05 +0100 Subject: [PATCH 170/187] Update packages/crypto/src/secp256k1.rs Co-authored-by: Mauro Lacy --- packages/crypto/src/secp256k1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index fda2ec51a9..0a65893af8 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -91,7 +91,7 @@ pub fn secp256k1_verify( /// recovers old Bitcoin signatures.". /// /// See also OpenZeppelin's [ECDSA.recover implementation](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.1/contracts/utils/cryptography/ECDSA.sol#L138-L149) -/// which adds further restrictions to avoid potential siganture maleability. +/// which adds further restrictions to avoid potential signature malleability. /// Please note that restricting signatures to low-S does not make signatures unique /// in the sense that for each (pubkey, message) there is only one signature. The /// signer can generate an arbitrary amount of valid signatures. From 74ddd303e6a225734c3ee06b338865240e543e25 Mon Sep 17 00:00:00 2001 From: Simon Warta <2603011+webmaster128@users.noreply.github.com> Date: Wed, 8 Mar 2023 11:23:08 +0100 Subject: [PATCH 171/187] Update packages/crypto/src/secp256k1.rs Co-authored-by: Mauro Lacy --- packages/crypto/src/secp256k1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index 0a65893af8..ae42f83a5d 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -380,7 +380,7 @@ mod tests { let message_hash = Sha256::digest(message); assert_eq!(hash.as_slice(), message_hash.as_slice()); - // Since the recovery param is mossing in the test vectors, we try both 0 and 1 + // Since the recovery param is missing in the test vectors, we try both 0 and 1 let try0 = secp256k1_recover_pubkey(&message_hash, &signature, 0); let try1 = secp256k1_recover_pubkey(&message_hash, &signature, 1); match (try0, try1) { From 479178dc1cfd566ec2e79d4814d3188a877c17b7 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 8 Mar 2023 13:36:32 +0100 Subject: [PATCH 172/187] Set version: 1.2.2 --- CHANGELOG.md | 5 ++++- Cargo.lock | 16 ++++++++-------- contracts/burner/Cargo.lock | 12 ++++++------ contracts/crypto-verify/Cargo.lock | 14 +++++++------- contracts/cyberpunk/Cargo.lock | 14 +++++++------- contracts/floaty/Cargo.lock | 14 +++++++------- contracts/hackatom/Cargo.lock | 14 +++++++------- contracts/ibc-reflect-send/Cargo.lock | 14 +++++++------- contracts/ibc-reflect/Cargo.lock | 14 +++++++------- contracts/queue/Cargo.lock | 12 ++++++------ contracts/reflect/Cargo.lock | 14 +++++++------- contracts/staking/Cargo.lock | 14 +++++++------- contracts/virus/Cargo.lock | 12 ++++++------ packages/check/Cargo.toml | 6 +++--- packages/crypto/Cargo.toml | 2 +- packages/derive/Cargo.toml | 2 +- packages/schema-derive/Cargo.toml | 2 +- packages/schema/Cargo.toml | 6 +++--- packages/std/Cargo.toml | 6 +++--- packages/storage/Cargo.toml | 4 ++-- packages/vm/Cargo.toml | 6 +++--- 21 files changed, 103 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4ca2834d8..481d980afb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to ## [Unreleased] +## [1.2.2] - 2023-03-08 + ### Added - cosmwasm-std: Add an IBC querier implementation to `testing::MockQuerier` @@ -1651,7 +1653,8 @@ Some main points: All future Changelog entries will reference this base -[unreleased]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.1...HEAD +[unreleased]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.2...HEAD +[1.2.2]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.1...v1.2.2 [1.2.1]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.0...v1.2.1 [1.2.0]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.9...v1.2.0 [1.1.9]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.8...v1.1.9 diff --git a/Cargo.lock b/Cargo.lock index bf22bb3b85..5747ff6670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "cosmwasm-check" -version = "1.2.1" +version = "1.2.2" dependencies = [ "anyhow", "clap", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "criterion", @@ -276,7 +276,7 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "syn", @@ -284,7 +284,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "anyhow", "cosmwasm-schema-derive", @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "chrono", @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "serde", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index f613b9a2db..bf45efb652 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -174,7 +174,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -185,14 +185,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -203,7 +203,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index ee27054a22..ea8e54fda2 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -169,7 +169,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -180,14 +180,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -198,7 +198,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -207,7 +207,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "serde", @@ -233,7 +233,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index 2dfea418e2..0703c242d4 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -203,14 +203,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -221,7 +221,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "serde", @@ -256,7 +256,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index 4413bbd35e..e4b2f89ba9 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index 68e5f33a73..2c99f6dcb2 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index adf7c89ef0..c5476f7a93 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index 2b006e26ed..580aa5a367 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index cdaee9dacb..0ef494e360 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index f26ddb5536..109202788c 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index a71c08b1d8..25b4f2599b 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock index a18cd16f0e..a87e7ee0d4 100644 --- a/contracts/virus/Cargo.lock +++ b/contracts/virus/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" dependencies = [ "bitflags", "bytecheck", diff --git a/packages/check/Cargo.toml b/packages/check/Cargo.toml index a99865dbd8..ade4cfa491 100644 --- a/packages/check/Cargo.toml +++ b/packages/check/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-check" -version = "1.2.1" +version = "1.2.2" authors = ["Mauro Lacy "] edition = "2021" description = "A CLI tool for verifying CosmWasm smart contracts" @@ -11,5 +11,5 @@ license = "Apache-2.0" anyhow = "1.0.57" clap = "2" colored = "2" -cosmwasm-vm = { path = "../vm", version = "1.2.1" } -cosmwasm-std = { path = "../std", version = "1.2.1" } +cosmwasm-vm = { path = "../vm", version = "1.2.2" } +cosmwasm-std = { path = "../std", version = "1.2.2" } diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index e2933e0fa6..0e7fdfafbe 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-crypto" -version = "1.2.1" +version = "1.2.2" authors = ["Mauro Lacy "] edition = "2021" description = "Crypto bindings for cosmwasm contracts" diff --git a/packages/derive/Cargo.toml b/packages/derive/Cargo.toml index 38a24c375d..236b8bfacf 100644 --- a/packages/derive/Cargo.toml +++ b/packages/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-derive" -version = "1.2.1" +version = "1.2.2" authors = ["Simon Warta "] edition = "2021" description = "A package for auto-generated code used for CosmWasm contract development. This is shipped as part of cosmwasm-std. Do not use directly." diff --git a/packages/schema-derive/Cargo.toml b/packages/schema-derive/Cargo.toml index 61314c5324..220c2b88d0 100644 --- a/packages/schema-derive/Cargo.toml +++ b/packages/schema-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema-derive" -version = "1.2.1" +version = "1.2.2" authors = ["Tomasz Kurcz "] edition = "2021" description = "Derive macros for cosmwasm-schema" diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index faa8e5854b..981fda9b3e 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema" -version = "1.2.1" +version = "1.2.2" authors = ["Simon Warta ", "Ethan Frey "] edition = "2021" description = "A dev-dependency for CosmWasm contracts to generate JSON Schema files." @@ -8,7 +8,7 @@ repository = "https://github.com/CosmWasm/cosmwasm/tree/main/packages/schema" license = "Apache-2.0" [dependencies] -cosmwasm-schema-derive = { version = "=1.2.1", path = "../schema-derive" } +cosmwasm-schema-derive = { version = "=1.2.2", path = "../schema-derive" } schemars = "0.8.3" serde = "1.0" serde_json = "1.0.40" @@ -16,6 +16,6 @@ thiserror = "1.0.26" [dev-dependencies] anyhow = "1.0.57" -cosmwasm-std = { version = "1.2.1", path = "../std" } +cosmwasm-std = { version = "1.2.2", path = "../std" } semver = "1" tempfile = "3" diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 7b286142b8..93101489d4 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-std" -version = "1.2.1" +version = "1.2.2" authors = ["Ethan Frey "] edition = "2021" description = "Standard library for Wasm based smart contracts on Cosmos blockchains" @@ -42,7 +42,7 @@ cosmwasm_1_2 = ["cosmwasm_1_1"] [dependencies] base64 = "0.13.0" -cosmwasm-derive = { path = "../derive", version = "1.2.1" } +cosmwasm-derive = { path = "../derive", version = "1.2.2" } derivative = "2" forward_ref = "1" hex = "0.4" @@ -54,7 +54,7 @@ thiserror = "1.0.26" uint = "0.9.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -cosmwasm-crypto = { path = "../crypto", version = "1.2.1" } +cosmwasm-crypto = { path = "../crypto", version = "1.2.2" } [dev-dependencies] cosmwasm-schema = { path = "../schema" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index e3b95773ad..4b7b0b22b3 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-storage" -version = "1.2.1" +version = "1.2.2" authors = ["Ethan Frey "] edition = "2021" description = "CosmWasm library with useful helpers for Storage patterns" @@ -16,5 +16,5 @@ iterator = ["cosmwasm-std/iterator"] [dependencies] # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.1", default-features = false } +cosmwasm-std = { path = "../std", version = "1.2.2", default-features = false } serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index 1e5c85759b..d2929ce19c 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-vm" -version = "1.2.1" +version = "1.2.2" authors = ["Ethan Frey "] edition = "2021" description = "VM bindings to run cosmwams contracts" @@ -41,8 +41,8 @@ required-features = ["iterator"] [dependencies] clru = "0.4.0" # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.1", default-features = false } -cosmwasm-crypto = { path = "../crypto", version = "1.2.1" } +cosmwasm-std = { path = "../std", version = "1.2.2", default-features = false } +cosmwasm-crypto = { path = "../crypto", version = "1.2.2" } hex = "0.4" parity-wasm = "0.42" schemars = "0.8.3" From 3a052bab38679d2a18e1f5c394efeff8601a8347 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 13 Mar 2023 17:43:08 +0100 Subject: [PATCH 173/187] Use saturating increments for Stats fields --- CHANGELOG.md | 3 +++ packages/vm/src/cache.rs | 20 ++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 481d980afb..a9407f0864 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to ## [Unreleased] +- cosmwasm-vm: Use saturating increments for `Stats` fields to ensure we don't + run into overflow issues. + ## [1.2.2] - 2023-03-08 ### Added diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs index 263979f0ca..3984e5e114 100644 --- a/packages/vm/src/cache.rs +++ b/packages/vm/src/cache.rs @@ -25,6 +25,13 @@ const CACHE_DIR: &str = "cache"; // Cacheable things. const MODULES_DIR: &str = "modules"; +/// Statistics about the usage of a cache instance. Those values are node +/// specific and must not be used in a consensus critical context. +/// When a node is hit by a client for simulations or other queries, hits and misses +/// increase. Also a node restart will reset the values. +/// +/// All values should be increment using saturated addition to ensure the node does not +/// crash in case the stats exceed the integer limit. #[derive(Debug, Default, Clone, Copy)] pub struct Stats { pub hits_pinned_memory_cache: u32, @@ -228,7 +235,7 @@ where // Try to get module from the memory cache if let Some(module) = cache.memory_cache.load(checksum)? { - cache.stats.hits_memory_cache += 1; + cache.stats.hits_memory_cache = cache.stats.hits_memory_cache.saturating_add(1); return cache .pinned_memory_cache .store(checksum, module.module, module.size); @@ -237,7 +244,7 @@ where // Try to get module from file system cache let store = make_runtime_store(Some(cache.instance_memory_limit)); if let Some(module) = cache.fs_cache.load(checksum, &store)? { - cache.stats.hits_fs_cache += 1; + cache.stats.hits_fs_cache = cache.stats.hits_fs_cache.saturating_add(1); let module_size = loupe::size_of_val(&module); return cache .pinned_memory_cache @@ -295,20 +302,21 @@ where let mut cache = self.inner.lock().unwrap(); // Try to get module from the pinned memory cache if let Some(module) = cache.pinned_memory_cache.load(checksum)? { - cache.stats.hits_pinned_memory_cache += 1; + cache.stats.hits_pinned_memory_cache = + cache.stats.hits_pinned_memory_cache.saturating_add(1); return Ok(module); } // Get module from memory cache if let Some(module) = cache.memory_cache.load(checksum)? { - cache.stats.hits_memory_cache += 1; + cache.stats.hits_memory_cache = cache.stats.hits_memory_cache.saturating_add(1); return Ok(module.module); } // Get module from file system cache let store = make_runtime_store(Some(cache.instance_memory_limit)); if let Some(module) = cache.fs_cache.load(checksum, &store)? { - cache.stats.hits_fs_cache += 1; + cache.stats.hits_fs_cache = cache.stats.hits_fs_cache.saturating_add(1); let module_size = loupe::size_of_val(&module); cache .memory_cache @@ -322,7 +330,7 @@ where // serialization format. If you do not replay all transactions, previous calls of `save_wasm` // stored the old module format. let wasm = self.load_wasm_with_path(&cache.wasm_path, checksum)?; - cache.stats.misses += 1; + cache.stats.misses = cache.stats.misses.saturating_add(1); let module = compile(&wasm, Some(cache.instance_memory_limit), &[])?; cache.fs_cache.store(checksum, &module)?; let module_size = loupe::size_of_val(&module); From 28471aac48a490cf2d9220be976bf2272936a499 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 14 Mar 2023 13:24:34 +0100 Subject: [PATCH 174/187] Discourage the use of u128/i128 as message fields --- docs/MESSAGE_TYPES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/MESSAGE_TYPES.md b/docs/MESSAGE_TYPES.md index faaf1e65d1..05ff61a0c3 100644 --- a/docs/MESSAGE_TYPES.md +++ b/docs/MESSAGE_TYPES.md @@ -14,7 +14,7 @@ Rust types as well as `cosmwasm_std` types and how they are encoded in JSON. | bool | `true` or `false` | `true` | | | u32/i32 | number | `123` | | | u64/i64 | number | `123456` | Supported in Rust and Go. Other implementations (`jq`, `JavaScript`) do not support the full uint64/int64 range. | -| u128/i128 | string | `"340282366920938463463374607431768211455", "-2766523308300312711084346401884294402"` | | +| u128/i128 | string | `"340282366920938463463374607431768211455", "-2766523308300312711084346401884294402"` | 🚫 Strongly discouraged because the JSON type in serde-json-wasm is wrong and will change. See [Dev Note #4: u128/i128 serialization][dev-note-4]. | | usize/isize | number | `123456` | 🚫 Don't use this type because it has a different size in unit tests (64 bit) and Wasm (32 bit). Also it tends to issue float instructions such that the contracts cannot be uploaded. | | String | string | `"foo"` | | &str | string | `"foo"` | 🚫 Unsuppored since message types must be owned (DeserializeOwned) | @@ -41,5 +41,7 @@ Rust types as well as `cosmwasm_std` types and how they are encoded in JSON. [binary]: https://docs.rs/cosmwasm-std/1.1.1/cosmwasm_std/struct.Binary.html [hexbinary]: https://docs.rs/cosmwasm-std/1.1.1/cosmwasm_std/struct.HexBinary.html +[dev-note-4]: + https://medium.com/cosmwasm/dev-note-4-u128-i128-serialization-in-cosmwasm-90cb76784d44 [^1]: https://www.json.org/ From a4a6fbfc72454af32f77c7735e7e077b4d25083c Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 4 Jan 2023 23:13:42 +0100 Subject: [PATCH 175/187] Split payment and cleanup implementations --- contracts/burner/schema/burner.json | 1 + contracts/burner/schema/raw/migrate.json | 1 + contracts/burner/src/contract.rs | 124 ++++++++++++++++++----- contracts/burner/src/msg.rs | 13 +++ contracts/burner/tests/integration.rs | 82 +++++++++++---- 5 files changed, 177 insertions(+), 44 deletions(-) diff --git a/contracts/burner/schema/burner.json b/contracts/burner/schema/burner.json index 58e102e12e..9aa679c82d 100644 --- a/contracts/burner/schema/burner.json +++ b/contracts/burner/schema/burner.json @@ -20,6 +20,7 @@ ], "properties": { "payout": { + "description": "The address we send all remaining balance to", "type": "string" } }, diff --git a/contracts/burner/schema/raw/migrate.json b/contracts/burner/schema/raw/migrate.json index 231a265325..30b6f16527 100644 --- a/contracts/burner/schema/raw/migrate.json +++ b/contracts/burner/schema/raw/migrate.json @@ -7,6 +7,7 @@ ], "properties": { "payout": { + "description": "The address we send all remaining balance to", "type": "string" } }, diff --git a/contracts/burner/src/contract.rs b/contracts/burner/src/contract.rs index e486be5b18..e2cd85fb37 100644 --- a/contracts/burner/src/contract.rs +++ b/contracts/burner/src/contract.rs @@ -2,7 +2,7 @@ use cosmwasm_std::{ entry_point, BankMsg, DepsMut, Env, MessageInfo, Order, Response, StdError, StdResult, }; -use crate::msg::{InstantiateMsg, MigrateMsg}; +use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg}; #[entry_point] pub fn instantiate( @@ -18,31 +18,58 @@ pub fn instantiate( #[entry_point] pub fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> StdResult { - // delete all state - let keys: Vec<_> = deps - .storage - .range(None, None, Order::Ascending) - .map(|(k, _)| k) - .collect(); - let count = keys.len(); - for k in keys { - deps.storage.remove(&k); - } - // get balance and send all to recipient let balance = deps.querier.query_all_balances(env.contract.address)?; let send = BankMsg::Send { to_address: msg.payout.clone(), amount: balance, }; + Ok(Response::new() + .add_message(send) + .add_attribute("action", "burn") + .add_attribute("payout", msg.payout)) +} + +#[entry_point] +pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> StdResult { + match msg { + ExecuteMsg::Cleanup { limit } => execute_cleanup(deps, env, info, limit), + } +} + +pub fn execute_cleanup( + deps: DepsMut, + _env: Env, + _info: MessageInfo, + limit: Option, +) -> StdResult { + // the number of elements we can still take (decreasing over time) + let mut limit = limit.unwrap_or(u32::MAX) as usize; - let data_msg = format!("burnt {} keys", count).into_bytes(); + let mut deleted = 0; + const PER_SCAN: usize = 20; + loop { + let take_this_scan = std::cmp::min(PER_SCAN, limit); + let keys: Vec<_> = deps + .storage + .range(None, None, Order::Ascending) + .take(take_this_scan) + .map(|(k, _)| k) + .collect(); + let deleted_this_scan = keys.len(); + for k in keys { + deps.storage.remove(&k); + } + deleted += deleted_this_scan; + limit -= deleted_this_scan; + if limit == 0 || deleted_this_scan < take_this_scan { + break; + } + } Ok(Response::new() - .add_message(send) .add_attribute("action", "burn") - .add_attribute("payout", msg.payout) - .set_data(data_msg)) + .add_attribute("deleted_entries", deleted.to_string())) } #[cfg(test)] @@ -51,7 +78,18 @@ mod tests { use cosmwasm_std::testing::{ mock_dependencies, mock_dependencies_with_balance, mock_env, mock_info, }; - use cosmwasm_std::{coins, StdError, Storage, SubMsg}; + use cosmwasm_std::{coins, Attribute, StdError, Storage, SubMsg}; + + /// Gets the value of the first attribute with the given key + fn first_attr(data: impl AsRef<[Attribute]>, search_key: &str) -> Option { + data.as_ref().iter().find_map(|a| { + if a.key == search_key { + Some(a.value.clone()) + } else { + None + } + }) + } #[test] fn instantiate_fails() { @@ -70,16 +108,9 @@ mod tests { } #[test] - fn migrate_cleans_up_data() { + fn migrate_sends_funds() { let mut deps = mock_dependencies_with_balance(&coins(123456, "gold")); - // store some sample data - deps.storage.set(b"foo", b"bar"); - deps.storage.set(b"key2", b"data2"); - deps.storage.set(b"key3", b"cool stuff"); - let cnt = deps.storage.range(None, None, Order::Ascending).count(); - assert_eq!(3, cnt); - // change the verifier via migrate let payout = String::from("someone else"); let msg = MigrateMsg { @@ -96,9 +127,48 @@ mod tests { amount: coins(123456, "gold"), }) ); + } + + #[test] + fn execute_cleans_up_data() { + let mut deps = mock_dependencies_with_balance(&coins(123456, "gold")); + + // store some sample data + deps.storage.set(b"foo", b"bar"); + deps.storage.set(b"key2", b"data2"); + deps.storage.set(b"key3", b"cool stuff"); + let cnt = deps.storage.range(None, None, Order::Ascending).count(); + assert_eq!(cnt, 3); + + // change the verifier via migrate + let payout = String::from("someone else"); + let msg = MigrateMsg { payout }; + let _res = migrate(deps.as_mut(), mock_env(), msg).unwrap(); + + let res = execute( + deps.as_mut(), + mock_env(), + mock_info("anon", &[]), + ExecuteMsg::Cleanup { limit: Some(2) }, + ) + .unwrap(); + assert_eq!(first_attr(res.attributes, "deleted_entries").unwrap(), "2"); + + // One item should be left + let cnt = deps.storage.range(None, None, Order::Ascending).count(); + assert_eq!(cnt, 1); + + let res = execute( + deps.as_mut(), + mock_env(), + mock_info("anon", &[]), + ExecuteMsg::Cleanup { limit: Some(2) }, + ) + .unwrap(); + assert_eq!(first_attr(res.attributes, "deleted_entries").unwrap(), "1"); - // check there is no data in storage + // Now all are gone let cnt = deps.storage.range(None, None, Order::Ascending).count(); - assert_eq!(0, cnt); + assert_eq!(cnt, 0); } } diff --git a/contracts/burner/src/msg.rs b/contracts/burner/src/msg.rs index f948004231..602223eccb 100644 --- a/contracts/burner/src/msg.rs +++ b/contracts/burner/src/msg.rs @@ -2,9 +2,22 @@ use cosmwasm_schema::cw_serde; #[cw_serde] pub struct MigrateMsg { + /// The address we send all remaining balance to pub payout: String, } /// A placeholder where we don't take any input #[cw_serde] pub struct InstantiateMsg {} + +#[cw_serde] +pub enum ExecuteMsg { + /// Cleans up the given number of state elements. + /// Call this multiple times to increamentally clean up state. + Cleanup { + /// The number of state elements to delete. + /// + /// Set this to None for unlimited cleanup (if your state is small or you are feeling YOLO) + limit: Option, + }, +} diff --git a/contracts/burner/tests/integration.rs b/contracts/burner/tests/integration.rs index 8f30c2cca7..fe6069d4c9 100644 --- a/contracts/burner/tests/integration.rs +++ b/contracts/burner/tests/integration.rs @@ -17,10 +17,10 @@ //! }); //! 4. Anywhere you see query(&deps, ...) you must replace it with query(&mut deps, ...) -use cosmwasm_std::{coins, BankMsg, ContractResult, Order, Response, SubMsg}; -use cosmwasm_vm::testing::{instantiate, migrate, mock_env, mock_info, mock_instance}; +use cosmwasm_std::{coins, Attribute, BankMsg, ContractResult, Order, Response, SubMsg}; +use cosmwasm_vm::testing::{execute, instantiate, migrate, mock_env, mock_info, mock_instance}; -use burner::msg::{InstantiateMsg, MigrateMsg}; +use burner::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg}; use cosmwasm_vm::Storage; // This line will test the output of cargo wasm @@ -28,6 +28,17 @@ static WASM: &[u8] = include_bytes!("../target/wasm32-unknown-unknown/release/bu // You can uncomment this line instead to test productionified build from rust-optimizer // static WASM: &[u8] = include_bytes!("../contract.wasm"); +/// Gets the value of the first attribute with the given key +fn first_attr(data: impl AsRef<[Attribute]>, search_key: &str) -> Option { + data.as_ref().iter().find_map(|a| { + if a.key == search_key { + Some(a.value.clone()) + } else { + None + } + }) +} + #[test] fn instantiate_fails() { let mut deps = mock_instance(WASM, &[]); @@ -44,21 +55,9 @@ fn instantiate_fails() { } #[test] -fn migrate_cleans_up_data() { +fn migrate_sends_funds() { let mut deps = mock_instance(WASM, &coins(123456, "gold")); - // store some sample data - deps.with_storage(|storage| { - storage.set(b"foo", b"bar").0.unwrap(); - storage.set(b"key2", b"data2").0.unwrap(); - storage.set(b"key3", b"cool stuff").0.unwrap(); - let iter_id = storage.scan(None, None, Order::Ascending).0.unwrap(); - let cnt = storage.all(iter_id).0.unwrap().len(); - assert_eq!(3, cnt); - Ok(()) - }) - .unwrap(); - // change the verifier via migrate let payout = String::from("someone else"); let msg = MigrateMsg { @@ -75,12 +74,61 @@ fn migrate_cleans_up_data() { amount: coins(123456, "gold"), }), ); +} + +#[test] +fn execute_cleans_up_data() { + let mut deps = mock_instance(WASM, &coins(123456, "gold")); + + // store some sample data + deps.with_storage(|storage| { + storage.set(b"foo", b"bar").0.unwrap(); + storage.set(b"key2", b"data2").0.unwrap(); + storage.set(b"key3", b"cool stuff").0.unwrap(); + let iter_id = storage.scan(None, None, Order::Ascending).0.unwrap(); + let cnt = storage.all(iter_id).0.unwrap().len(); + assert_eq!(cnt, 3); + Ok(()) + }) + .unwrap(); + + // change the verifier via migrate + let payout = String::from("someone else"); + let msg = MigrateMsg { payout }; + let _res: Response = migrate(&mut deps, mock_env(), msg).unwrap(); + + let res: Response = execute( + &mut deps, + mock_env(), + mock_info("anon", &[]), + ExecuteMsg::Cleanup { limit: Some(2) }, + ) + .unwrap(); + assert_eq!(first_attr(res.attributes, "deleted_entries").unwrap(), "2"); + + // One item should be left + deps.with_storage(|storage| { + let iter_id = storage.scan(None, None, Order::Ascending).0.unwrap(); + let cnt = storage.all(iter_id).0.unwrap().len(); + assert_eq!(cnt, 1); + Ok(()) + }) + .unwrap(); + + let res: Response = execute( + &mut deps, + mock_env(), + mock_info("anon", &[]), + ExecuteMsg::Cleanup { limit: Some(2) }, + ) + .unwrap(); + assert_eq!(first_attr(res.attributes, "deleted_entries").unwrap(), "1"); // check there is no data in storage deps.with_storage(|storage| { let iter_id = storage.scan(None, None, Order::Ascending).0.unwrap(); let cnt = storage.all(iter_id).0.unwrap().len(); - assert_eq!(0, cnt); + assert_eq!(cnt, 0); Ok(()) }) .unwrap(); From 86313551f38e8ade85a06ef3617a0159f7d7f69c Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 4 Jan 2023 23:19:58 +0100 Subject: [PATCH 176/187] Remove license files at contract level --- contracts/burner/LICENSE | 202 --------------------------------------- contracts/burner/NOTICE | 13 --- 2 files changed, 215 deletions(-) delete mode 100644 contracts/burner/LICENSE delete mode 100644 contracts/burner/NOTICE diff --git a/contracts/burner/LICENSE b/contracts/burner/LICENSE deleted file mode 100644 index d645695673..0000000000 --- a/contracts/burner/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You 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 the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You 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 the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/contracts/burner/NOTICE b/contracts/burner/NOTICE deleted file mode 100644 index b8f34a8f13..0000000000 --- a/contracts/burner/NOTICE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2020 Ethan Frey - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. From 4ed470acd374f3c47dae19d205329875ce0e29ad Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 4 Jan 2023 23:20:32 +0100 Subject: [PATCH 177/187] Add me to authors --- contracts/burner/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/burner/Cargo.toml b/contracts/burner/Cargo.toml index 93a74b7efe..7484840261 100644 --- a/contracts/burner/Cargo.toml +++ b/contracts/burner/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "burner" version = "0.0.0" -authors = ["Ethan Frey "] +authors = ["Ethan Frey ", "Simon Warta "] edition = "2021" publish = false license = "Apache-2.0" From 7c3cf31c347e173cd3cabfb89641fe729f4f2495 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 5 Jan 2023 17:59:05 +0100 Subject: [PATCH 178/187] Bump to cosmwasm/rust-optimizer:0.12.11 --- .circleci/config.yml | 2 +- README.md | 2 +- contracts/README.md | 20 ++++++++++---------- packages/vm/README.md | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d299a74156..166f2be8be 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1036,7 +1036,7 @@ jobs: name: Build development contracts command: | echo "Building all contracts under ./contracts" - docker run --volumes-from with_code cosmwasm/rust-optimizer:0.12.9 ./contracts/*/ + docker run --volumes-from with_code cosmwasm/rust-optimizer:0.12.11 ./contracts/*/ - run: name: Check development contracts command: | diff --git a/README.md b/README.md index b71dab0b68..f2c06ae3b8 100644 --- a/README.md +++ b/README.md @@ -412,7 +412,7 @@ but the quickstart guide is: docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 + cosmwasm/rust-optimizer:0.12.11 ``` It will output a highly size-optimized build as `contract.wasm` in `$CODE`. With diff --git a/contracts/README.md b/contracts/README.md index 1f581ed2e0..f4b931d197 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -53,52 +53,52 @@ reason, use the following commands: docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_burner",target=/code/contracts/burner/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/burner + cosmwasm/rust-optimizer:0.12.11 ./contracts/burner docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_crypto_verify",target=/code/contracts/crypto-verify/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/crypto-verify + cosmwasm/rust-optimizer:0.12.11 ./contracts/crypto-verify docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_floaty",target=/code/contracts/floaty/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/floaty + cosmwasm/rust-optimizer:0.12.11 ./contracts/floaty docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_hackatom",target=/code/contracts/hackatom/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/hackatom + cosmwasm/rust-optimizer:0.12.11 ./contracts/hackatom docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_ibc_reflect",target=/code/contracts/ibc-reflect/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/ibc-reflect + cosmwasm/rust-optimizer:0.12.11 ./contracts/ibc-reflect docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_ibc_reflect_send",target=/code/contracts/ibc-reflect-send/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/ibc-reflect-send + cosmwasm/rust-optimizer:0.12.11 ./contracts/ibc-reflect-send docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_queue",target=/code/contracts/queue/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/queue + cosmwasm/rust-optimizer:0.12.11 ./contracts/queue docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_reflect",target=/code/contracts/reflect/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/reflect + cosmwasm/rust-optimizer:0.12.11 ./contracts/reflect docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_staking",target=/code/contracts/staking/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/staking + cosmwasm/rust-optimizer:0.12.11 ./contracts/staking docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_virus",target=/code/contracts/virus/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/virus + cosmwasm/rust-optimizer:0.12.11 ./contracts/virus ``` ## Entry points diff --git a/packages/vm/README.md b/packages/vm/README.md index 2d85697bed..26baa85caa 100644 --- a/packages/vm/README.md +++ b/packages/vm/README.md @@ -53,25 +53,25 @@ To rebuild the test contracts, go to the repo root and do docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_cyberpunk",target=/code/contracts/cyberpunk/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.10 ./contracts/cyberpunk \ + cosmwasm/rust-optimizer:0.12.11 ./contracts/cyberpunk \ && cp artifacts/cyberpunk.wasm packages/vm/testdata/cyberpunk.wasm docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_hackatom",target=/code/contracts/hackatom/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/hackatom \ + cosmwasm/rust-optimizer:0.12.11 ./contracts/hackatom \ && cp artifacts/hackatom.wasm packages/vm/testdata/hackatom_1.0.wasm docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_ibc_reflect",target=/code/contracts/ibc-reflect/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/ibc-reflect \ + cosmwasm/rust-optimizer:0.12.11 ./contracts/ibc-reflect \ && cp artifacts/ibc_reflect.wasm packages/vm/testdata/ibc_reflect_1.0.wasm docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_floaty",target=/code/contracts/floaty/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.9 ./contracts/floaty \ + cosmwasm/rust-optimizer:0.12.11 ./contracts/floaty \ && cp artifacts/floaty.wasm packages/vm/testdata/floaty_1.0.wasm ``` From a3d5c4c3c3588d9f1375c34b566ee329fdfc12b4 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 22 Mar 2023 11:00:00 +0100 Subject: [PATCH 179/187] Set version: 1.2.3 --- CHANGELOG.md | 5 ++++- Cargo.lock | 16 ++++++++-------- contracts/burner/Cargo.lock | 12 ++++++------ contracts/crypto-verify/Cargo.lock | 14 +++++++------- contracts/cyberpunk/Cargo.lock | 14 +++++++------- contracts/floaty/Cargo.lock | 14 +++++++------- contracts/hackatom/Cargo.lock | 14 +++++++------- contracts/ibc-reflect-send/Cargo.lock | 14 +++++++------- contracts/ibc-reflect/Cargo.lock | 14 +++++++------- contracts/queue/Cargo.lock | 12 ++++++------ contracts/reflect/Cargo.lock | 14 +++++++------- contracts/staking/Cargo.lock | 14 +++++++------- contracts/virus/Cargo.lock | 12 ++++++------ packages/check/Cargo.toml | 6 +++--- packages/crypto/Cargo.toml | 2 +- packages/derive/Cargo.toml | 2 +- packages/schema-derive/Cargo.toml | 2 +- packages/schema/Cargo.toml | 6 +++--- packages/std/Cargo.toml | 6 +++--- packages/storage/Cargo.toml | 4 ++-- packages/vm/Cargo.toml | 6 +++--- 21 files changed, 103 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9407f0864..c889600c51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to ## [Unreleased] +## [1.2.3] - 2023-03-22 + - cosmwasm-vm: Use saturating increments for `Stats` fields to ensure we don't run into overflow issues. @@ -1656,7 +1658,8 @@ Some main points: All future Changelog entries will reference this base -[unreleased]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.2...HEAD +[unreleased]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.3...HEAD +[1.2.3]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.2...v1.2.3 [1.2.2]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.1...v1.2.2 [1.2.1]: https://github.com/CosmWasm/cosmwasm/compare/v1.2.0...v1.2.1 [1.2.0]: https://github.com/CosmWasm/cosmwasm/compare/v1.1.9...v1.2.0 diff --git a/Cargo.lock b/Cargo.lock index 5747ff6670..8b50daa42a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "cosmwasm-check" -version = "1.2.2" +version = "1.2.3" dependencies = [ "anyhow", "clap", @@ -257,7 +257,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "criterion", @@ -276,7 +276,7 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "syn", @@ -284,7 +284,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "anyhow", "cosmwasm-schema-derive", @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "chrono", @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "serde", @@ -338,7 +338,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/burner/Cargo.lock b/contracts/burner/Cargo.lock index bf45efb652..1f34106c3c 100644 --- a/contracts/burner/Cargo.lock +++ b/contracts/burner/Cargo.lock @@ -174,7 +174,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -185,14 +185,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -203,7 +203,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -212,7 +212,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/crypto-verify/Cargo.lock b/contracts/crypto-verify/Cargo.lock index ea8e54fda2..3a242b0ab1 100644 --- a/contracts/crypto-verify/Cargo.lock +++ b/contracts/crypto-verify/Cargo.lock @@ -169,7 +169,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -180,14 +180,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -198,7 +198,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -207,7 +207,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "serde", @@ -233,7 +233,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/cyberpunk/Cargo.lock b/contracts/cyberpunk/Cargo.lock index 0703c242d4..5d748dc697 100644 --- a/contracts/cyberpunk/Cargo.lock +++ b/contracts/cyberpunk/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -203,14 +203,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -221,7 +221,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -230,7 +230,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "serde", @@ -256,7 +256,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/floaty/Cargo.lock b/contracts/floaty/Cargo.lock index e4b2f89ba9..e71c9a5f03 100644 --- a/contracts/floaty/Cargo.lock +++ b/contracts/floaty/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/hackatom/Cargo.lock b/contracts/hackatom/Cargo.lock index 2c99f6dcb2..ab8b12b3b4 100644 --- a/contracts/hackatom/Cargo.lock +++ b/contracts/hackatom/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect-send/Cargo.lock b/contracts/ibc-reflect-send/Cargo.lock index c5476f7a93..3f968aa2de 100644 --- a/contracts/ibc-reflect-send/Cargo.lock +++ b/contracts/ibc-reflect-send/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/ibc-reflect/Cargo.lock b/contracts/ibc-reflect/Cargo.lock index 580aa5a367..051e88b9d8 100644 --- a/contracts/ibc-reflect/Cargo.lock +++ b/contracts/ibc-reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/queue/Cargo.lock b/contracts/queue/Cargo.lock index 0ef494e360..2f440904e5 100644 --- a/contracts/queue/Cargo.lock +++ b/contracts/queue/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/reflect/Cargo.lock b/contracts/reflect/Cargo.lock index 109202788c..5531ebb18c 100644 --- a/contracts/reflect/Cargo.lock +++ b/contracts/reflect/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/staking/Cargo.lock b/contracts/staking/Cargo.lock index 25b4f2599b..a5f85c41a6 100644 --- a/contracts/staking/Cargo.lock +++ b/contracts/staking/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-std", "serde", @@ -227,7 +227,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/contracts/virus/Cargo.lock b/contracts/virus/Cargo.lock index a87e7ee0d4..e35f813893 100644 --- a/contracts/virus/Cargo.lock +++ b/contracts/virus/Cargo.lock @@ -163,7 +163,7 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" dependencies = [ "digest 0.10.3", "ed25519-zebra", @@ -174,14 +174,14 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" dependencies = [ "proc-macro2", "quote", @@ -201,7 +201,7 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" dependencies = [ "base64", "cosmwasm-crypto", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" dependencies = [ "bitflags", "bytecheck", diff --git a/packages/check/Cargo.toml b/packages/check/Cargo.toml index ade4cfa491..2ddbc968cc 100644 --- a/packages/check/Cargo.toml +++ b/packages/check/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-check" -version = "1.2.2" +version = "1.2.3" authors = ["Mauro Lacy "] edition = "2021" description = "A CLI tool for verifying CosmWasm smart contracts" @@ -11,5 +11,5 @@ license = "Apache-2.0" anyhow = "1.0.57" clap = "2" colored = "2" -cosmwasm-vm = { path = "../vm", version = "1.2.2" } -cosmwasm-std = { path = "../std", version = "1.2.2" } +cosmwasm-vm = { path = "../vm", version = "1.2.3" } +cosmwasm-std = { path = "../std", version = "1.2.3" } diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index 0e7fdfafbe..aa828ad79e 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-crypto" -version = "1.2.2" +version = "1.2.3" authors = ["Mauro Lacy "] edition = "2021" description = "Crypto bindings for cosmwasm contracts" diff --git a/packages/derive/Cargo.toml b/packages/derive/Cargo.toml index 236b8bfacf..5a6d5da5a1 100644 --- a/packages/derive/Cargo.toml +++ b/packages/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-derive" -version = "1.2.2" +version = "1.2.3" authors = ["Simon Warta "] edition = "2021" description = "A package for auto-generated code used for CosmWasm contract development. This is shipped as part of cosmwasm-std. Do not use directly." diff --git a/packages/schema-derive/Cargo.toml b/packages/schema-derive/Cargo.toml index 220c2b88d0..7761b98e71 100644 --- a/packages/schema-derive/Cargo.toml +++ b/packages/schema-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema-derive" -version = "1.2.2" +version = "1.2.3" authors = ["Tomasz Kurcz "] edition = "2021" description = "Derive macros for cosmwasm-schema" diff --git a/packages/schema/Cargo.toml b/packages/schema/Cargo.toml index 981fda9b3e..5e4b4f3711 100644 --- a/packages/schema/Cargo.toml +++ b/packages/schema/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-schema" -version = "1.2.2" +version = "1.2.3" authors = ["Simon Warta ", "Ethan Frey "] edition = "2021" description = "A dev-dependency for CosmWasm contracts to generate JSON Schema files." @@ -8,7 +8,7 @@ repository = "https://github.com/CosmWasm/cosmwasm/tree/main/packages/schema" license = "Apache-2.0" [dependencies] -cosmwasm-schema-derive = { version = "=1.2.2", path = "../schema-derive" } +cosmwasm-schema-derive = { version = "=1.2.3", path = "../schema-derive" } schemars = "0.8.3" serde = "1.0" serde_json = "1.0.40" @@ -16,6 +16,6 @@ thiserror = "1.0.26" [dev-dependencies] anyhow = "1.0.57" -cosmwasm-std = { version = "1.2.2", path = "../std" } +cosmwasm-std = { version = "1.2.3", path = "../std" } semver = "1" tempfile = "3" diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 93101489d4..06d7686e41 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-std" -version = "1.2.2" +version = "1.2.3" authors = ["Ethan Frey "] edition = "2021" description = "Standard library for Wasm based smart contracts on Cosmos blockchains" @@ -42,7 +42,7 @@ cosmwasm_1_2 = ["cosmwasm_1_1"] [dependencies] base64 = "0.13.0" -cosmwasm-derive = { path = "../derive", version = "1.2.2" } +cosmwasm-derive = { path = "../derive", version = "1.2.3" } derivative = "2" forward_ref = "1" hex = "0.4" @@ -54,7 +54,7 @@ thiserror = "1.0.26" uint = "0.9.3" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -cosmwasm-crypto = { path = "../crypto", version = "1.2.2" } +cosmwasm-crypto = { path = "../crypto", version = "1.2.3" } [dev-dependencies] cosmwasm-schema = { path = "../schema" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index 4b7b0b22b3..2d08dbb3e3 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-storage" -version = "1.2.2" +version = "1.2.3" authors = ["Ethan Frey "] edition = "2021" description = "CosmWasm library with useful helpers for Storage patterns" @@ -16,5 +16,5 @@ iterator = ["cosmwasm-std/iterator"] [dependencies] # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.2", default-features = false } +cosmwasm-std = { path = "../std", version = "1.2.3", default-features = false } serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index d2929ce19c..b4b8981bbd 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-vm" -version = "1.2.2" +version = "1.2.3" authors = ["Ethan Frey "] edition = "2021" description = "VM bindings to run cosmwams contracts" @@ -41,8 +41,8 @@ required-features = ["iterator"] [dependencies] clru = "0.4.0" # Uses the path when built locally; uses the given version from crates.io when published -cosmwasm-std = { path = "../std", version = "1.2.2", default-features = false } -cosmwasm-crypto = { path = "../crypto", version = "1.2.2" } +cosmwasm-std = { path = "../std", version = "1.2.3", default-features = false } +cosmwasm-crypto = { path = "../crypto", version = "1.2.3" } hex = "0.4" parity-wasm = "0.42" schemars = "0.8.3" From 9ccb10c628c76cb77c676947c35e771574febf11 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 4 Apr 2023 15:07:40 +0200 Subject: [PATCH 180/187] Bump optimizer to 0.12.13 --- .circleci/config.yml | 2 +- README.md | 2 +- contracts/README.md | 20 ++++++++++---------- packages/vm/README.md | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 166f2be8be..425c01533d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1036,7 +1036,7 @@ jobs: name: Build development contracts command: | echo "Building all contracts under ./contracts" - docker run --volumes-from with_code cosmwasm/rust-optimizer:0.12.11 ./contracts/*/ + docker run --volumes-from with_code cosmwasm/rust-optimizer:0.12.13 ./contracts/*/ - run: name: Check development contracts command: | diff --git a/README.md b/README.md index f2c06ae3b8..cb619b1dff 100644 --- a/README.md +++ b/README.md @@ -412,7 +412,7 @@ but the quickstart guide is: docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 + cosmwasm/rust-optimizer:0.12.13 ``` It will output a highly size-optimized build as `contract.wasm` in `$CODE`. With diff --git a/contracts/README.md b/contracts/README.md index f4b931d197..845af6995d 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -53,52 +53,52 @@ reason, use the following commands: docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_burner",target=/code/contracts/burner/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/burner + cosmwasm/rust-optimizer:0.12.13 ./contracts/burner docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_crypto_verify",target=/code/contracts/crypto-verify/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/crypto-verify + cosmwasm/rust-optimizer:0.12.13 ./contracts/crypto-verify docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_floaty",target=/code/contracts/floaty/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/floaty + cosmwasm/rust-optimizer:0.12.13 ./contracts/floaty docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_hackatom",target=/code/contracts/hackatom/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/hackatom + cosmwasm/rust-optimizer:0.12.13 ./contracts/hackatom docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_ibc_reflect",target=/code/contracts/ibc-reflect/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/ibc-reflect + cosmwasm/rust-optimizer:0.12.13 ./contracts/ibc-reflect docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_ibc_reflect_send",target=/code/contracts/ibc-reflect-send/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/ibc-reflect-send + cosmwasm/rust-optimizer:0.12.13 ./contracts/ibc-reflect-send docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_queue",target=/code/contracts/queue/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/queue + cosmwasm/rust-optimizer:0.12.13 ./contracts/queue docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_reflect",target=/code/contracts/reflect/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/reflect + cosmwasm/rust-optimizer:0.12.13 ./contracts/reflect docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_staking",target=/code/contracts/staking/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/staking + cosmwasm/rust-optimizer:0.12.13 ./contracts/staking docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_virus",target=/code/contracts/virus/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/virus + cosmwasm/rust-optimizer:0.12.13 ./contracts/virus ``` ## Entry points diff --git a/packages/vm/README.md b/packages/vm/README.md index 26baa85caa..793f428beb 100644 --- a/packages/vm/README.md +++ b/packages/vm/README.md @@ -53,25 +53,25 @@ To rebuild the test contracts, go to the repo root and do docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_cyberpunk",target=/code/contracts/cyberpunk/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/cyberpunk \ + cosmwasm/rust-optimizer:0.12.13 ./contracts/cyberpunk \ && cp artifacts/cyberpunk.wasm packages/vm/testdata/cyberpunk.wasm docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_hackatom",target=/code/contracts/hackatom/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/hackatom \ + cosmwasm/rust-optimizer:0.12.13 ./contracts/hackatom \ && cp artifacts/hackatom.wasm packages/vm/testdata/hackatom_1.0.wasm docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_ibc_reflect",target=/code/contracts/ibc-reflect/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/ibc-reflect \ + cosmwasm/rust-optimizer:0.12.13 ./contracts/ibc-reflect \ && cp artifacts/ibc_reflect.wasm packages/vm/testdata/ibc_reflect_1.0.wasm docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_floaty",target=/code/contracts/floaty/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.11 ./contracts/floaty \ + cosmwasm/rust-optimizer:0.12.13 ./contracts/floaty \ && cp artifacts/floaty.wasm packages/vm/testdata/floaty_1.0.wasm ``` From 2ca2ba4291b44d71c061a0cab9d11c3b739f6a25 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 4 Apr 2023 15:12:06 +0200 Subject: [PATCH 181/187] Rename test contracts to 1_2.wasm and add missing abort import --- packages/vm/README.md | 6 +++--- packages/vm/src/environment.rs | 1 + packages/vm/src/imports.rs | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/vm/README.md b/packages/vm/README.md index 793f428beb..7fc48e561f 100644 --- a/packages/vm/README.md +++ b/packages/vm/README.md @@ -60,19 +60,19 @@ docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_hackatom",target=/code/contracts/hackatom/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ cosmwasm/rust-optimizer:0.12.13 ./contracts/hackatom \ - && cp artifacts/hackatom.wasm packages/vm/testdata/hackatom_1.0.wasm + && cp artifacts/hackatom.wasm packages/vm/testdata/hackatom_1.2.wasm docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_ibc_reflect",target=/code/contracts/ibc-reflect/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ cosmwasm/rust-optimizer:0.12.13 ./contracts/ibc-reflect \ - && cp artifacts/ibc_reflect.wasm packages/vm/testdata/ibc_reflect_1.0.wasm + && cp artifacts/ibc_reflect.wasm packages/vm/testdata/ibc_reflect_1.2.wasm docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_floaty",target=/code/contracts/floaty/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ cosmwasm/rust-optimizer:0.12.13 ./contracts/floaty \ - && cp artifacts/floaty.wasm packages/vm/testdata/floaty_1.0.wasm + && cp artifacts/floaty.wasm packages/vm/testdata/floaty_1.2.wasm ``` ## Testing diff --git a/packages/vm/src/environment.rs b/packages/vm/src/environment.rs index d66aa88c8b..4072b3fbbd 100644 --- a/packages/vm/src/environment.rs +++ b/packages/vm/src/environment.rs @@ -413,6 +413,7 @@ mod tests { "ed25519_verify" => Function::new_native(store, |_a: u32, _b: u32, _c: u32| -> u32 { 0 }), "ed25519_batch_verify" => Function::new_native(store, |_a: u32, _b: u32, _c: u32| -> u32 { 0 }), "debug" => Function::new_native(store, |_a: u32| {}), + "abort" => Function::new_native(store, |_a: u32| {}), }, }; let instance = Box::from(WasmerInstance::new(&module, &import_obj).unwrap()); diff --git a/packages/vm/src/imports.rs b/packages/vm/src/imports.rs index 7932887928..bae11f403c 100644 --- a/packages/vm/src/imports.rs +++ b/packages/vm/src/imports.rs @@ -561,6 +561,7 @@ mod tests { "ed25519_verify" => Function::new_native(store, |_a: u32, _b: u32, _c: u32| -> u32 { 0 }), "ed25519_batch_verify" => Function::new_native(store, |_a: u32, _b: u32, _c: u32| -> u32 { 0 }), "debug" => Function::new_native(store, |_a: u32| {}), + "abort" => Function::new_native(store, |_a: u32| {}), }, }; let instance = Box::from(WasmerInstance::new(&module, &import_obj).unwrap()); From 0cfeac7f1ecacab2d272359f19f7ba612ae63603 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 5 Apr 2023 10:53:09 +0200 Subject: [PATCH 182/187] Recompile testdata .wasm files for vm tests and adjust tests --- packages/vm/src/cache.rs | 3 +-- packages/vm/src/instance.rs | 8 ++++---- packages/vm/testdata/cyberpunk.wasm | Bin 165993 -> 170650 bytes packages/vm/testdata/floaty.wasm | 2 +- packages/vm/testdata/floaty_1.2.wasm | Bin 0 -> 163839 bytes packages/vm/testdata/hackatom.wasm | 2 +- packages/vm/testdata/hackatom_1.2.wasm | Bin 0 -> 181627 bytes packages/vm/testdata/ibc_reflect.wasm | 2 +- packages/vm/testdata/ibc_reflect_1.2.wasm | Bin 0 -> 269374 bytes 9 files changed, 8 insertions(+), 9 deletions(-) create mode 100644 packages/vm/testdata/floaty_1.2.wasm create mode 100644 packages/vm/testdata/hackatom_1.2.wasm create mode 100644 packages/vm/testdata/ibc_reflect_1.2.wasm diff --git a/packages/vm/src/cache.rs b/packages/vm/src/cache.rs index 3984e5e114..36c18a6ad1 100644 --- a/packages/vm/src/cache.rs +++ b/packages/vm/src/cache.rs @@ -1102,9 +1102,8 @@ mod tests { report2, AnalysisReport { has_ibc_entry_points: true, - required_capabilities: HashSet::from_iter(vec![ + required_capabilities: HashSet::from_iter([ "iterator".to_string(), - "staking".to_string(), "stargate".to_string() ]), } diff --git a/packages/vm/src/instance.rs b/packages/vm/src/instance.rs index 706f261716..dd33e90b2c 100644 --- a/packages/vm/src/instance.rs +++ b/packages/vm/src/instance.rs @@ -708,7 +708,7 @@ mod tests { let report2 = instance.create_gas_report(); assert_eq!(report2.used_externally, 73); - assert_eq!(report2.used_internally, 5775750198); + assert_eq!(report2.used_internally, 5764950198); assert_eq!(report2.limit, LIMIT); assert_eq!( report2.remaining, @@ -897,7 +897,7 @@ mod tests { .unwrap(); let init_used = orig_gas - instance.get_gas_left(); - assert_eq!(init_used, 5775750271); + assert_eq!(init_used, 5764950271); } #[test] @@ -920,7 +920,7 @@ mod tests { .unwrap(); let execute_used = gas_before_execute - instance.get_gas_left(); - assert_eq!(execute_used, 8627053606); + assert_eq!(execute_used, 8548903606); } #[test] @@ -954,6 +954,6 @@ mod tests { assert_eq!(answer.as_slice(), b"{\"verifier\":\"verifies\"}"); let query_used = gas_before_query - instance.get_gas_left(); - assert_eq!(query_used, 4438350006); + assert_eq!(query_used, 4493700006); } } diff --git a/packages/vm/testdata/cyberpunk.wasm b/packages/vm/testdata/cyberpunk.wasm index 982acad20c86b3607dd8c95d1b6a37f5b87ec6ee..96737a33880c757c4f74550ac4627474067a83a2 100644 GIT binary patch literal 170650 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 literal 165993 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

m~y*eu9rQw9V#m`X9hTHmo19zynF`C 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

nJ?=n>gxU*(UhyE|M&%J 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 literal 0 HcmV?d00001 diff --git a/packages/vm/testdata/hackatom.wasm b/packages/vm/testdata/hackatom.wasm index 76495bcd7b..c7941a1a8f 120000 --- a/packages/vm/testdata/hackatom.wasm +++ b/packages/vm/testdata/hackatom.wasm @@ -1 +1 @@ -hackatom_1.0.wasm \ No newline at end of file +hackatom_1.2.wasm \ No newline at end of file diff --git a/packages/vm/testdata/hackatom_1.2.wasm b/packages/vm/testdata/hackatom_1.2.wasm new file mode 100644 index 0000000000000000000000000000000000000000..f15360139aa648df28bbc97182f1e53ca18d4e16 GIT binary patch literal 181627 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 literal 0 HcmV?d00001 diff --git a/packages/vm/testdata/ibc_reflect.wasm b/packages/vm/testdata/ibc_reflect.wasm index c5b6708f3d..b2876f3146 120000 --- a/packages/vm/testdata/ibc_reflect.wasm +++ b/packages/vm/testdata/ibc_reflect.wasm @@ -1 +1 @@ -ibc_reflect_1.0.wasm \ No newline at end of file +ibc_reflect_1.2.wasm \ No newline at end of file diff --git a/packages/vm/testdata/ibc_reflect_1.2.wasm b/packages/vm/testdata/ibc_reflect_1.2.wasm new file mode 100644 index 0000000000000000000000000000000000000000..228bdfbffff907f9e65442b87a3c1392bc3f4dd9 GIT binary patch literal 269374 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 FqhErKIC%g7 literal 0 HcmV?d00001 From e8b9690ac7a2284f854ba9ec6ec386966cf4c10f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 5 Apr 2023 13:21:08 +0200 Subject: [PATCH 183/187] Fix argon2 benchmarking (not in hackatom anymore) --- packages/vm/benches/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vm/benches/main.rs b/packages/vm/benches/main.rs index 970a1ca9c3..f764394ba7 100644 --- a/packages/vm/benches/main.rs +++ b/packages/vm/benches/main.rs @@ -32,6 +32,7 @@ const INSTANTIATION_THREADS: usize = 128; const CONTRACTS: u64 = 10; static CONTRACT: &[u8] = include_bytes!("../testdata/hackatom.wasm"); +static CYBERPUNK: &[u8] = include_bytes!("../testdata/cyberpunk.wasm"); fn bench_instance(c: &mut Criterion) { let mut group = c.benchmark_group("Instance"); @@ -94,12 +95,11 @@ fn bench_instance(c: &mut Criterion) { ..DEFAULT_INSTANCE_OPTIONS }; let mut instance = - Instance::from_code(CONTRACT, backend, much_gas, Some(DEFAULT_MEMORY_LIMIT)).unwrap(); + Instance::from_code(CYBERPUNK, backend, much_gas, Some(DEFAULT_MEMORY_LIMIT)).unwrap(); let info = mock_info("creator", &coins(1000, "earth")); - let msg = br#"{"verifier": "verifies", "beneficiary": "benefits"}"#; let contract_result = - call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap(); + call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, b"{}").unwrap(); assert!(contract_result.into_result().is_ok()); let mut gas_used = 0; From 3a478e9f4cea6e5c197a6194c723a24aaa68bce5 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 5 Apr 2023 13:22:02 +0200 Subject: [PATCH 184/187] Upgrade criterion to 0.4 --- Cargo.lock | 160 ++++++++++++++++++------------------- packages/crypto/Cargo.toml | 2 +- packages/vm/Cargo.toml | 2 +- 3 files changed, 81 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b50daa42a..c82a7bf2ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "ansi_term" version = "0.12.1" @@ -117,18 +123,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - [[package]] name = "bumpalo" version = "3.12.0" @@ -164,12 +158,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cast" -version = "0.2.7" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" -dependencies = [ - "rustc_version", -] +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" @@ -193,6 +184,33 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ciborium" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" + +[[package]] +name = "ciborium-ll" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "2.34.0" @@ -203,11 +221,32 @@ dependencies = [ "atty", "bitflags", "strsim", - "textwrap", + "textwrap 0.11.0", "unicode-width", "vec_map", ] +[[package]] +name = "clap" +version = "3.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +dependencies = [ + "bitflags", + "clap_lex", + "indexmap", + "textwrap 0.16.0", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clru" version = "0.4.0" @@ -249,7 +288,7 @@ name = "cosmwasm-check" version = "1.2.3" dependencies = [ "anyhow", - "clap", + "clap 2.34.0", "colored", "cosmwasm-std", "cosmwasm-vm", @@ -342,7 +381,7 @@ version = "1.2.3" dependencies = [ "bitflags", "bytecheck", - "clap", + "clap 2.34.0", "clru", "cosmwasm-crypto", "cosmwasm-std", @@ -444,15 +483,16 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.5" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" dependencies = [ + "anes", "atty", "cast", - "clap", + "ciborium", + "clap 3.2.23", "criterion-plot", - "csv", "itertools", "lazy_static", "num-traits", @@ -461,7 +501,6 @@ dependencies = [ "rayon", "regex", "serde", - "serde_cbor", "serde_derive", "serde_json", "tinytemplate", @@ -470,9 +509,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", @@ -551,28 +590,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -973,12 +990,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "itoa" version = "1.0.1" @@ -1171,6 +1182,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "os_str_bytes" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" + [[package]] name = "parity-wasm" version = "0.42.2" @@ -1381,12 +1398,6 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - [[package]] name = "regex-syntax" version = "0.6.25" @@ -1471,15 +1482,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "rustversion" version = "1.0.6" @@ -1584,16 +1586,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" version = "1.0.137" @@ -1622,7 +1614,7 @@ version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ - "itoa 1.0.1", + "itoa", "ryu", "serde", ] @@ -1741,6 +1733,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + [[package]] name = "thiserror" version = "1.0.38" diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index aa828ad79e..bc22c35913 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -26,7 +26,7 @@ rand_core = { version = "0.6", features = ["getrandom"] } thiserror = "1.0.38" [dev-dependencies] -criterion = "0.3" +criterion = "0.4" serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } serde_json = "1.0.40" sha2 = "0.10" diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index b4b8981bbd..38d2e0bce5 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -67,7 +67,7 @@ bitflags = "1.1.0" # https://github.com/CensoredUsername/dynasm-rs/pull/74 # wasmer-middlewares = { path = "../../../wasmer/lib/middlewares" } [dev-dependencies] -criterion = { version = "0.3", features = [ "html_reports" ] } +criterion = { version = "0.4", features = [ "html_reports" ] } hex-literal = "0.3.1" tempfile = "3.1.0" wat = "1.0" From 01ff17c373749be4f1d99e741e706b463cb6c1dc Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 5 Apr 2023 13:24:37 +0200 Subject: [PATCH 185/187] Cleanup benchmarking branch list in CI --- .circleci/config.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 425c01533d..2ce1523101 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -84,14 +84,7 @@ workflows: - main - /^[0-9]+\.[0-9]+$/ # Add your branch here if benchmarking matters to your work - - benchmarking - - update-wasmer - - metering-restart - - load-wasm-speed - - cache-analyze - - fix-benches - - benchmark_argon2 - - get_instance-multi-threaded-benchmark-multi-contract + - fix-benchmarking - coverage deploy: jobs: From 6f415ec32bdc4f8f734d435447df306534d6cbaf Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 6 Apr 2023 14:18:32 +0200 Subject: [PATCH 186/187] Bump clippy to Rust 1.68.2 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2ce1523101..05d72ae197 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -72,7 +72,7 @@ workflows: matrix: parameters: # Run with MSRV and some modern stable Rust - rust-version: ["1.60.0", "1.67.1"] + rust-version: ["1.60.0", "1.68.2"] - benchmarking: requires: - package_vm From 0c092d7dfb41ad39a5bcb469659baeccf7ce1741 Mon Sep 17 00:00:00 2001 From: Itzik Grossman Date: Thu, 4 May 2023 01:19:58 +0300 Subject: [PATCH 187/187] Merge with CW 1.2.3 --- packages/crypto-compat/Cargo.toml | 2 +- packages/std-compat/Cargo.toml | 6 ++- packages/std/Cargo.toml | 2 +- packages/storage-compat/Cargo.toml | 2 +- packages/vm/src/filesystem.rs | 43 ---------------------- packages/vm/testdata/cyberpunk.wasm | Bin 170650 -> 0 bytes packages/vm/testdata/floaty_1.2.wasm | Bin 163839 -> 0 bytes packages/vm/testdata/hackatom_1.2.wasm | Bin 181627 -> 0 bytes packages/vm/testdata/ibc_reflect_1.2.wasm | Bin 269374 -> 0 bytes 9 files changed, 8 insertions(+), 47 deletions(-) delete mode 100644 packages/vm/src/filesystem.rs delete mode 100644 packages/vm/testdata/cyberpunk.wasm delete mode 100644 packages/vm/testdata/floaty_1.2.wasm delete mode 100644 packages/vm/testdata/hackatom_1.2.wasm delete mode 100644 packages/vm/testdata/ibc_reflect_1.2.wasm diff --git a/packages/crypto-compat/Cargo.toml b/packages/crypto-compat/Cargo.toml index 46c14d8ed0..17fe1b0361 100644 --- a/packages/crypto-compat/Cargo.toml +++ b/packages/crypto-compat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.3" authors = [ "SCRT Labs ", ] diff --git a/packages/std-compat/Cargo.toml b/packages/std-compat/Cargo.toml index ee88e0345e..8e01f9d528 100644 --- a/packages/std-compat/Cargo.toml +++ b/packages/std-compat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-std" -version = "1.1.9" +version = "1.2.3" edition = "2021" description = "Compatability layer for contracts that want to use the git versions of the std fork with a patch" @@ -31,6 +31,10 @@ ibc3 = ["secret-cosmwasm-std/ibc3", "stargate"] # the host blockchain to run CosmWasm `1.1.0` or higher. cosmwasm_1_1 = ["secret-cosmwasm-std/cosmwasm_1_1"] +# This feature makes `GovMsg::VoteWeighted` available for the contract to call, but requires +# the host blockchain to run CosmWasm `1.2.0` or higher. +cosmwasm_1_2 = ["secret-cosmwasm-std/cosmwasm_1_2"] + random = ["secret-cosmwasm-std/random"] [dependencies] diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 9d0b97681d..333985480a 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -15,7 +15,7 @@ readme = "README.md" features = ["abort", "stargate", "staking", "ibc3", "cosmwasm_1_2", "random"] [features] -default = ["abort"] +default = [] abort = [] # iterator allows us to iterate over all DB items in a given range # optional as some merkle stores (like tries) don't support this diff --git a/packages/storage-compat/Cargo.toml b/packages/storage-compat/Cargo.toml index eea0473499..360abea3de 100644 --- a/packages/storage-compat/Cargo.toml +++ b/packages/storage-compat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmwasm-storage" -version = "1.1.9" +version = "1.2.3" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/vm/src/filesystem.rs b/packages/vm/src/filesystem.rs deleted file mode 100644 index 45a60f435f..0000000000 --- a/packages/vm/src/filesystem.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::{fs::create_dir_all, path::Path}; - -#[derive(Debug)] -pub struct MkdirPFailure; - -/// An implementation for `mkdir -p`. -/// -/// This is a thin wrapper around fs::create_dir_all that -/// hides all OS specific error messages to ensure they don't end up -/// breaking consensus. -pub fn mkdir_p(path: &Path) -> Result<(), MkdirPFailure> { - create_dir_all(path).map_err(|_e| MkdirPFailure) -} - -#[cfg(test)] -mod tests { - use tempfile::TempDir; - - use super::*; - - #[test] - fn mkdir_p_works() { - let tmp_root = TempDir::new().unwrap(); - - // Can create - let path = tmp_root.path().join("something"); - assert!(!path.is_dir()); - mkdir_p(&path).unwrap(); - assert!(path.is_dir()); - - // Can be called on existing dir - let path = tmp_root.path().join("something else"); - assert!(!path.is_dir()); - mkdir_p(&path).unwrap(); - assert!(path.is_dir()); - mkdir_p(&path).unwrap(); // no-op - assert!(path.is_dir()); - - // Fails for dir with null - let path = tmp_root.path().join("something\0with NULL"); - mkdir_p(&path).unwrap_err(); - } -} diff --git a/packages/vm/testdata/cyberpunk.wasm b/packages/vm/testdata/cyberpunk.wasm deleted file mode 100644 index 96737a33880c757c4f74550ac4627474067a83a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170650 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 diff --git a/packages/vm/testdata/floaty_1.2.wasm b/packages/vm/testdata/floaty_1.2.wasm deleted file mode 100644 index 653c3e884ec9a53009e77fada6d8e6eb8caedc6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163839 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

nJ?=n>gxU*(UhyE|M&%J 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 diff --git a/packages/vm/testdata/hackatom_1.2.wasm b/packages/vm/testdata/hackatom_1.2.wasm deleted file mode 100644 index f15360139aa648df28bbc97182f1e53ca18d4e16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 181627 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 diff --git a/packages/vm/testdata/ibc_reflect_1.2.wasm b/packages/vm/testdata/ibc_reflect_1.2.wasm deleted file mode 100644 index 228bdfbffff907f9e65442b87a3c1392bc3f4dd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 269374 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 FqhErKIC%g7

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 diff --git a/packages/vm/testdata/floaty.wasm b/packages/vm/testdata/floaty.wasm index 8ae4d6a31d..76b5ee18c7 120000 --- a/packages/vm/testdata/floaty.wasm +++ b/packages/vm/testdata/floaty.wasm @@ -1 +1 @@ -floaty_1.0.wasm \ No newline at end of file +floaty_1.2.wasm \ No newline at end of file diff --git a/packages/vm/testdata/floaty_1.2.wasm b/packages/vm/testdata/floaty_1.2.wasm new file mode 100644 index 0000000000000000000000000000000000000000..653c3e884ec9a53009e77fada6d8e6eb8caedc6b GIT binary patch literal 163839 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