From c2a8d2ddea7f91e1e11e73aed52d78341a9d9260 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 3 Nov 2023 13:28:01 +0100 Subject: [PATCH 1/6] Delete cosmwasm-storage --- Cargo.lock | 8 - packages/storage/Cargo.toml | 20 - packages/storage/README.md | 204 ---------- packages/storage/src/bucket.rs | 474 ---------------------- packages/storage/src/lib.rs | 17 - packages/storage/src/namespace_helpers.rs | 219 ---------- packages/storage/src/prefixed_storage.rs | 196 --------- packages/storage/src/sequence.rs | 81 ---- packages/storage/src/singleton.rs | 316 --------------- packages/storage/src/type_helpers.rs | 89 ---- 10 files changed, 1624 deletions(-) delete mode 100644 packages/storage/Cargo.toml delete mode 100644 packages/storage/README.md delete mode 100644 packages/storage/src/bucket.rs delete mode 100644 packages/storage/src/lib.rs delete mode 100644 packages/storage/src/namespace_helpers.rs delete mode 100644 packages/storage/src/prefixed_storage.rs delete mode 100644 packages/storage/src/sequence.rs delete mode 100644 packages/storage/src/singleton.rs delete mode 100644 packages/storage/src/type_helpers.rs diff --git a/Cargo.lock b/Cargo.lock index 4b5a1f6cd9..25b1026961 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -514,14 +514,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cosmwasm-storage" -version = "1.5.0" -dependencies = [ - "cosmwasm-std", - "serde", -] - [[package]] name = "cosmwasm-vm" version = "1.5.0" diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml deleted file mode 100644 index 5c38f021d2..0000000000 --- a/packages/storage/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "cosmwasm-storage" -version = "1.5.0" -authors = ["Ethan Frey "] -edition = "2021" -description = "CosmWasm library with useful helpers for Storage patterns" -repository = "https://github.com/CosmWasm/cosmwasm/tree/main/packages/storage" -license = "Apache-2.0" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -default = ["iterator"] -# This enables iterator functionality, as exposed in cosmwasm-std/iterator -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.5.0", default-features = false } -serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"] } diff --git a/packages/storage/README.md b/packages/storage/README.md deleted file mode 100644 index d2bdffb695..0000000000 --- a/packages/storage/README.md +++ /dev/null @@ -1,204 +0,0 @@ -# WARNING: Unmaintained - -This crate is no longer maintained and should not be used anymore. For an -alternative, please check out -[cw-storage-plus](https://crates.io/crates/cw-storage-plus) - -# cosmwasm-storage - -[![cosmwasm-storage on crates.io](https://img.shields.io/crates/v/cosmwasm-storage.svg)](https://crates.io/crates/cosmwasm-storage) - -CosmWasm library with useful helpers for Storage patterns. You can use `Storage` -implementations in `cosmwasm-std`, or rely on these to remove some common -boilerplate. - -## Contents - -- [WARNING: Unmaintained](#warning-unmaintained) -- [cosmwasm-storage](#cosmwasm-storage) - - [Contents](#contents) - - [Prefixed Storage](#prefixed-storage) - - [Typed Storage](#typed-storage) - - [Bucket](#bucket) - - [Singleton](#singleton) - - [License](#license) - -### Prefixed Storage - -One common technique in smart contracts, especially when multiple types of data -are being stored, is to create separate sub-stores with unique prefixes. Thus -instead of directly dealing with storage, we wrap it and put all `Foo` in a -Storage with key `"foo" + id`, and all `Bar` in a Storage with key `"bar" + id`. -This lets us add multiple types of objects without too much cognitive overhead. -Similar separation like Mongo collections or SQL tables. - -Since we have different types for `Storage` and `ReadonlyStorage`, we use two -different constructors: - -```rust -use cosmwasm_std::testing::MockStorage; -use cosmwasm_storage::{prefixed, prefixed_read}; - -let mut store = MockStorage::new(); - -let mut foos = prefixed(b"foo", &mut store); -foos.set(b"one", b"foo"); - -let mut bars = prefixed(b"bar", &mut store); -bars.set(b"one", b"bar"); - -let read_foo = prefixed_read(b"foo", &store); -assert_eq!(b"foo".to_vec(), read_foo.get(b"one").unwrap()); - -let read_bar = prefixed_read(b"bar", &store); -assert_eq!(b"bar".to_vec(), read_bar.get(b"one").unwrap()); -``` - -Please note that only one mutable reference to the underlying store may be valid -at one point. The compiler sees we do not ever use `foos` after constructing -`bars`, so this example is valid. However, if we did use `foos` again at the -bottom, it would properly complain about violating unique mutable reference. - -The takeaway is to create the `PrefixedStorage` objects when needed and not to -hang around to them too long. - -### Typed Storage - -As we divide our storage space into different subspaces or "buckets", we will -quickly notice that each "bucket" works on a unique type. This leads to a lot of -repeated serialization and deserialization boilerplate that can be removed. We -do this by wrapping a `Storage` with a type-aware `TypedStorage` struct that -provides us a higher-level access to the data. - -Note that `TypedStorage` itself does not implement the `Storage` interface, so -when combining with `PrefixStorage`, make sure to wrap the prefix first. - -```rust -use cosmwasm_std::testing::MockStorage; -use cosmwasm_storage::{prefixed, typed}; - -let mut store = MockStorage::new(); -let mut space = prefixed(b"data", &mut store); -let mut bucket = typed::<_, Data>(&mut space); - -// save data -let data = Data { - name: "Maria".to_string(), - age: 42, -}; -bucket.save(b"maria", &data).unwrap(); - -// load it properly -let loaded = bucket.load(b"maria").unwrap(); -assert_eq!(data, loaded); - -// loading empty can return Ok(None) or Err depending on the chosen method: -assert!(bucket.load(b"john").is_err()); -assert_eq!(bucket.may_load(b"john"), Ok(None)); -``` - -Beyond the basic `save`, `load`, and `may_load`, there is a higher-level API -exposed, `update`. `Update` will load the data, apply an operation and save it -again (if the operation was successful). It will also return any error that -occurred, or the final state that was written if successful. - -```rust -let on_birthday = |mut m: Option| match m { - Some(mut d) => { - d.age += 1; - Ok(d) - }, - None => NotFound { kind: "Data" }.fail(), -}; -let output = bucket.update(b"maria", &on_birthday).unwrap(); -let expected = Data { - name: "Maria".to_string(), - age: 43, -}; -assert_eq!(output, expected); -``` - -### Bucket - -Since the above idiom (a subspace for a class of items) is so common and useful, -and there is no easy way to return this from a function (bucket holds a -reference to space, and cannot live longer than the local variable), the two are -often combined into a `Bucket`. A Bucket works just like the example above, -except the creation can be in another function: - -```rust -use cosmwasm_std::StdResult; -use cosmwasm_std::testing::MockStorage; -use cosmwasm_storage::{bucket, Bucket}; - -fn people<'a, S: Storage>(storage: &'a mut S) -> Bucket<'a, S, Data> { - bucket(b"people", storage) -} - -fn do_stuff() -> StdResult<()> { - let mut store = MockStorage::new(); - people(&mut store).save(b"john", &Data{ - name: "John", - age: 314, - })?; - OK(()) -} -``` - -### Singleton - -Singleton is another wrapper around the `TypedStorage` API. There are cases when -we don't need a whole subspace to hold arbitrary key-value lookup for typed -data, but rather a single storage key. The simplest example is some -_configuration_ information for a contract. For example, in the -[name service example](https://github.com/CosmWasm/cosmwasm-examples/tree/master/nameservice), -there is a `Bucket` to look up name to name data, but we also have a `Singleton` -to store global configuration - namely the price of buying a name. - -Please note that in this context, the term "singleton" does not refer to -[the singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern) but a -container for a single element. - -```rust -use cosmwasm_std::{Coin, coin, StdResult}; -use cosmwasm_std::testing::MockStorage; - -use cosmwasm_storage::{singleton}; - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct Config { - pub purchase_price: Option, - pub transfer_price: Option, -} - -fn initialize() -> StdResult<()> { - let mut store = MockStorage::new(); - let config = singleton(&mut store, b"config"); - config.save(&Config{ - purchase_price: Some(coin("5", "FEE")), - transfer_price: None, - })?; - config.update(|mut cfg| { - cfg.transfer_price = Some(coin(2, "FEE")); - Ok(cfg) - })?; - let loaded = config.load()?; - OK(()) -} -``` - -`Singleton` works just like `Bucket`, except the `save`, `load`, `update` -methods don't take a key, and `update` requires the object to already exist, so -the closure takes type `T`, rather than `Option`. (Use `save` to create the -object the first time). For `Buckets`, we often don't know which keys exist, but -`Singleton`s should be initialized when the contract is instantiated. - -Since the heart of much of the smart contract code is simply transformations -upon some stored state, we may be able to just code the state transitions and -let the `TypedStorage` APIs take care of all the boilerplate. - -## License - -This package is part of the cosmwasm repository, licensed under the Apache -License 2.0 (see [NOTICE](https://github.com/CosmWasm/cosmwasm/blob/main/NOTICE) -and [LICENSE](https://github.com/CosmWasm/cosmwasm/blob/main/LICENSE)). diff --git a/packages/storage/src/bucket.rs b/packages/storage/src/bucket.rs deleted file mode 100644 index 81c7a65c33..0000000000 --- a/packages/storage/src/bucket.rs +++ /dev/null @@ -1,474 +0,0 @@ -use serde::{de::DeserializeOwned, ser::Serialize}; -use std::marker::PhantomData; - -use cosmwasm_std::{ - storage_keys::{to_length_prefixed, to_length_prefixed_nested}, - to_json_vec, StdError, StdResult, Storage, -}; -#[cfg(feature = "iterator")] -use cosmwasm_std::{Order, Record}; - -#[cfg(feature = "iterator")] -use crate::namespace_helpers::range_with_prefix; -use crate::namespace_helpers::{get_with_prefix, remove_with_prefix, set_with_prefix}; -#[cfg(feature = "iterator")] -use crate::type_helpers::deserialize_kv; -use crate::type_helpers::{may_deserialize, must_deserialize}; - -/// An alias of Bucket::new for less verbose usage -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub fn bucket<'a, T>(storage: &'a mut dyn Storage, namespace: &[u8]) -> Bucket<'a, T> -where - T: Serialize + DeserializeOwned, -{ - Bucket::new(storage, namespace) -} - -/// An alias of ReadonlyBucket::new for less verbose usage -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub fn bucket_read<'a, T>(storage: &'a dyn Storage, namespace: &[u8]) -> ReadonlyBucket<'a, T> -where - T: Serialize + DeserializeOwned, -{ - ReadonlyBucket::new(storage, namespace) -} - -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub struct Bucket<'a, T> -where - T: Serialize + DeserializeOwned, -{ - storage: &'a mut dyn Storage, - prefix: Vec, - // see https://doc.rust-lang.org/std/marker/struct.PhantomData.html#unused-type-parameters for why this is needed - data: PhantomData, -} - -impl<'a, T> Bucket<'a, T> -where - T: Serialize + DeserializeOwned, -{ - pub fn new(storage: &'a mut dyn Storage, namespace: &[u8]) -> Self { - Bucket { - storage, - prefix: to_length_prefixed(namespace), - data: PhantomData, - } - } - - pub fn multilevel(storage: &'a mut dyn Storage, namespaces: &[&[u8]]) -> Self { - Bucket { - storage, - prefix: to_length_prefixed_nested(namespaces), - data: PhantomData, - } - } - - /// save will serialize the model and store, returns an error on serialization issues - pub fn save(&mut self, key: &[u8], data: &T) -> StdResult<()> { - set_with_prefix(self.storage, &self.prefix, key, &to_json_vec(data)?); - Ok(()) - } - - pub fn remove(&mut self, key: &[u8]) { - remove_with_prefix(self.storage, &self.prefix, key) - } - - /// load will return an error if no data is set at the given key, or on parse error - pub fn load(&self, key: &[u8]) -> StdResult { - let value = get_with_prefix(self.storage, &self.prefix, key); - must_deserialize(&value) - } - - /// may_load will parse the data stored at the key if present, returns Ok(None) if no data there. - /// returns an error on issues parsing - pub fn may_load(&self, key: &[u8]) -> StdResult> { - let value = get_with_prefix(self.storage, &self.prefix, key); - may_deserialize(&value) - } - - #[cfg(feature = "iterator")] - pub fn range<'b>( - &'b self, - start: Option<&[u8]>, - end: Option<&[u8]>, - order: Order, - ) -> Box>> + 'b> { - let mapped = range_with_prefix(self.storage, &self.prefix, start, end, order) - .map(deserialize_kv::); - Box::new(mapped) - } - - /// Loads the data, perform the specified action, and store the result - /// in the database. This is shorthand for some common sequences, which may be useful. - /// - /// If the data exists, `action(Some(value))` is called. Otherwise `action(None)` is called. - pub fn update(&mut self, key: &[u8], action: A) -> Result - where - A: FnOnce(Option) -> Result, - E: From, - { - let input = self.may_load(key)?; - let output = action(input)?; - self.save(key, &output)?; - Ok(output) - } -} - -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub struct ReadonlyBucket<'a, T> -where - T: Serialize + DeserializeOwned, -{ - storage: &'a dyn Storage, - prefix: Vec, - // see https://doc.rust-lang.org/std/marker/struct.PhantomData.html#unused-type-parameters for why this is needed - data: PhantomData, -} - -impl<'a, T> ReadonlyBucket<'a, T> -where - T: Serialize + DeserializeOwned, -{ - pub fn new(storage: &'a dyn Storage, namespace: &[u8]) -> Self { - ReadonlyBucket { - storage, - prefix: to_length_prefixed(namespace), - data: PhantomData, - } - } - - pub fn multilevel(storage: &'a dyn Storage, namespaces: &[&[u8]]) -> Self { - ReadonlyBucket { - storage, - prefix: to_length_prefixed_nested(namespaces), - data: PhantomData, - } - } - - /// load will return an error if no data is set at the given key, or on parse error - pub fn load(&self, key: &[u8]) -> StdResult { - let value = get_with_prefix(self.storage, &self.prefix, key); - must_deserialize(&value) - } - - /// may_load will parse the data stored at the key if present, returns Ok(None) if no data there. - /// returns an error on issues parsing - pub fn may_load(&self, key: &[u8]) -> StdResult> { - let value = get_with_prefix(self.storage, &self.prefix, key); - may_deserialize(&value) - } - - #[cfg(feature = "iterator")] - pub fn range<'b>( - &'b self, - start: Option<&[u8]>, - end: Option<&[u8]>, - order: Order, - ) -> Box>> + 'b> { - let mapped = range_with_prefix(self.storage, &self.prefix, start, end, order) - .map(deserialize_kv::); - Box::new(mapped) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::testing::MockStorage; - use cosmwasm_std::StdError; - use serde::{Deserialize, Serialize}; - - #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] - struct Data { - pub name: String, - pub age: i32, - } - - #[test] - fn store_and_load() { - let mut store = MockStorage::new(); - let mut bucket = bucket::(&mut store, b"data"); - - // save data - let data = Data { - name: "Maria".to_string(), - age: 42, - }; - bucket.save(b"maria", &data).unwrap(); - - // load it properly - let loaded = bucket.load(b"maria").unwrap(); - assert_eq!(data, loaded); - } - - #[test] - fn remove_works() { - let mut store = MockStorage::new(); - let mut bucket = bucket::(&mut store, b"data"); - - // save data - let data = Data { - name: "Maria".to_string(), - age: 42, - }; - bucket.save(b"maria", &data).unwrap(); - assert_eq!(data, bucket.load(b"maria").unwrap()); - - // deleting random key does nothing - bucket.remove(b"foobar"); - assert_eq!(data, bucket.load(b"maria").unwrap()); - - // deleting maria removes the data - bucket.remove(b"maria"); - assert_eq!(None, bucket.may_load(b"maria").unwrap()); - } - - #[test] - fn readonly_works() { - let mut store = MockStorage::new(); - let mut bucket = bucket::(&mut store, b"data"); - - // save data - let data = Data { - name: "Maria".to_string(), - age: 42, - }; - bucket.save(b"maria", &data).unwrap(); - - let reader = bucket_read::(&store, b"data"); - - // check empty data handling - assert!(reader.load(b"john").is_err()); - assert_eq!(reader.may_load(b"john").unwrap(), None); - - // load it properly - let loaded = reader.load(b"maria").unwrap(); - assert_eq!(data, loaded); - } - - #[test] - fn buckets_isolated() { - let mut store = MockStorage::new(); - let mut bucket1 = bucket::(&mut store, b"data"); - - // save data - let data = Data { - name: "Maria".to_string(), - age: 42, - }; - bucket1.save(b"maria", &data).unwrap(); - - let mut bucket2 = bucket::(&mut store, b"dat"); - - // save data (dat, amaria) vs (data, maria) - let data2 = Data { - name: "Amen".to_string(), - age: 67, - }; - bucket2.save(b"amaria", &data2).unwrap(); - - // load one - let reader = bucket_read::(&store, b"data"); - let loaded = reader.load(b"maria").unwrap(); - assert_eq!(data, loaded); - // no cross load - assert_eq!(None, reader.may_load(b"amaria").unwrap()); - - // load the other - let reader2 = bucket_read::(&store, b"dat"); - let loaded2 = reader2.load(b"amaria").unwrap(); - assert_eq!(data2, loaded2); - // no cross load - assert_eq!(None, reader2.may_load(b"maria").unwrap()); - } - - #[test] - fn update_success() { - let mut store = MockStorage::new(); - let mut bucket = bucket::(&mut store, b"data"); - - // initial data - let init = Data { - name: "Maria".to_string(), - age: 42, - }; - bucket.save(b"maria", &init).unwrap(); - - // it's my birthday - let birthday = |mayd: Option| -> StdResult { - let mut d = mayd.ok_or_else(|| StdError::not_found("Data"))?; - d.age += 1; - Ok(d) - }; - let output = bucket.update(b"maria", birthday).unwrap(); - let expected = Data { - name: "Maria".to_string(), - age: 43, - }; - assert_eq!(output, expected); - - // load it properly - let loaded = bucket.load(b"maria").unwrap(); - assert_eq!(loaded, expected); - } - - #[test] - fn update_can_change_variable_from_outer_scope() { - let mut store = MockStorage::new(); - let mut bucket = bucket::(&mut store, b"data"); - let init = Data { - name: "Maria".to_string(), - age: 42, - }; - bucket.save(b"maria", &init).unwrap(); - - // show we can capture data from the closure - let mut old_age = 0i32; - bucket - .update(b"maria", |mayd: Option| -> StdResult<_> { - let mut d = mayd.ok_or_else(|| StdError::not_found("Data"))?; - old_age = d.age; - d.age += 1; - Ok(d) - }) - .unwrap(); - assert_eq!(old_age, 42); - } - - #[test] - fn update_fails_on_error() { - let mut store = MockStorage::new(); - let mut bucket = bucket::(&mut store, b"data"); - - // initial data - let init = Data { - name: "Maria".to_string(), - age: 42, - }; - bucket.save(b"maria", &init).unwrap(); - - // it's my birthday - let output = bucket.update(b"maria", |_d| { - Err(StdError::generic_err("cuz i feel like it")) - }); - assert!(output.is_err()); - - // load it properly - let loaded = bucket.load(b"maria").unwrap(); - assert_eq!(loaded, init); - } - - #[test] - fn update_supports_custom_error_types() { - #[derive(Debug)] - enum MyError { - Std, - NotFound, - } - - impl From for MyError { - fn from(_original: StdError) -> MyError { - MyError::Std - } - } - - let mut store = MockStorage::new(); - let mut bucket = bucket::(&mut store, b"data"); - - // initial data - let init = Data { - name: "Maria".to_string(), - age: 42, - }; - bucket.save(b"maria", &init).unwrap(); - - // it's my birthday - let res = bucket.update(b"bob", |data| { - if let Some(mut data) = data { - if data.age < 0 { - // Uses Into to convert StdError to MyError - return Err(StdError::generic_err("Current age is negative").into()); - } - if data.age > 10 { - to_json_vec(&data)?; // Uses From to convert StdError to MyError - } - data.age += 1; - Ok(data) - } else { - Err(MyError::NotFound) - } - }); - match res.unwrap_err() { - MyError::NotFound { .. } => {} - err => panic!("Unexpected error: {err:?}"), - } - } - - #[test] - fn update_handles_on_no_data() { - let mut store = MockStorage::new(); - let mut bucket = bucket::(&mut store, b"data"); - - let init_value = Data { - name: "Maria".to_string(), - age: 42, - }; - - // it's my birthday - let output = bucket - .update(b"maria", |d| match d { - Some(_) => Err(StdError::generic_err("Ensure this was empty")), - None => Ok(init_value.clone()), - }) - .unwrap(); - assert_eq!(output, init_value); - - // nothing stored - let loaded = bucket.load(b"maria").unwrap(); - assert_eq!(loaded, init_value); - } - - #[test] - #[cfg(feature = "iterator")] - fn range_over_data() { - let mut store = MockStorage::new(); - let mut bucket = bucket::(&mut store, b"data"); - - let jose = Data { - name: "Jose".to_string(), - age: 42, - }; - let maria = Data { - name: "Maria".to_string(), - age: 27, - }; - - bucket.save(b"maria", &maria).unwrap(); - bucket.save(b"jose", &jose).unwrap(); - - let res_data: StdResult>> = - bucket.range(None, None, Order::Ascending).collect(); - let data = res_data.unwrap(); - assert_eq!(data.len(), 2); - assert_eq!(data[0], (b"jose".to_vec(), jose.clone())); - assert_eq!(data[1], (b"maria".to_vec(), maria.clone())); - - // also works for readonly - let read_bucket = bucket_read::(&store, b"data"); - let res_data: StdResult>> = - read_bucket.range(None, None, Order::Ascending).collect(); - let data = res_data.unwrap(); - assert_eq!(data.len(), 2); - assert_eq!(data[0], (b"jose".to_vec(), jose)); - assert_eq!(data[1], (b"maria".to_vec(), maria)); - } -} diff --git a/packages/storage/src/lib.rs b/packages/storage/src/lib.rs deleted file mode 100644 index 3fd3a37946..0000000000 --- a/packages/storage/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![allow(deprecated)] - -mod bucket; -mod namespace_helpers; -mod prefixed_storage; -mod sequence; -mod singleton; -mod type_helpers; - -pub use bucket::{bucket, bucket_read, Bucket, ReadonlyBucket}; -pub use prefixed_storage::{prefixed, prefixed_read, PrefixedStorage, ReadonlyPrefixedStorage}; -pub use sequence::{currval, nextval, sequence}; -pub use singleton::{singleton, singleton_read, ReadonlySingleton, Singleton}; - -// Re-exported for backwads compatibility. -// See https://github.com/CosmWasm/cosmwasm/pull/1676. -pub use cosmwasm_std::storage_keys::{to_length_prefixed, to_length_prefixed_nested}; diff --git a/packages/storage/src/namespace_helpers.rs b/packages/storage/src/namespace_helpers.rs deleted file mode 100644 index 6a24829856..0000000000 --- a/packages/storage/src/namespace_helpers.rs +++ /dev/null @@ -1,219 +0,0 @@ -use cosmwasm_std::Storage; -#[cfg(feature = "iterator")] -use cosmwasm_std::{Order, Record}; - -pub(crate) fn get_with_prefix( - storage: &dyn Storage, - namespace: &[u8], - key: &[u8], -) -> Option> { - storage.get(&concat(namespace, key)) -} - -pub(crate) fn set_with_prefix( - storage: &mut dyn Storage, - namespace: &[u8], - key: &[u8], - value: &[u8], -) { - storage.set(&concat(namespace, key), value); -} - -pub(crate) fn remove_with_prefix(storage: &mut dyn Storage, namespace: &[u8], key: &[u8]) { - storage.remove(&concat(namespace, key)); -} - -#[inline] -fn concat(namespace: &[u8], key: &[u8]) -> Vec { - let mut k = namespace.to_vec(); - k.extend_from_slice(key); - k -} - -#[cfg(feature = "iterator")] -pub(crate) fn range_with_prefix<'a>( - storage: &'a dyn Storage, - namespace: &[u8], - start: Option<&[u8]>, - end: Option<&[u8]>, - order: Order, -) -> Box + 'a> { - // prepare start, end with prefix - let start = match start { - Some(s) => concat(namespace, s), - None => namespace.to_vec(), - }; - let end = match end { - Some(e) => concat(namespace, e), - // end is updating last byte by one - None => namespace_upper_bound(namespace), - }; - - // get iterator from storage - let base_iterator = storage.range(Some(&start), Some(&end), order); - - // make a copy for the closure to handle lifetimes safely - let prefix = namespace.to_vec(); - let mapped = base_iterator.map(move |(k, v)| (trim(&prefix, &k), v)); - Box::new(mapped) -} - -#[cfg(feature = "iterator")] -#[inline] -fn trim(namespace: &[u8], key: &[u8]) -> Vec { - key[namespace.len()..].to_vec() -} - -/// Returns a new vec of same length and last byte incremented by one -/// If last bytes are 255, we handle overflow up the chain. -/// If all bytes are 255, this returns wrong data - but that is never possible as a namespace -#[cfg(feature = "iterator")] -fn namespace_upper_bound(input: &[u8]) -> Vec { - let mut copy = input.to_vec(); - // zero out all trailing 255, increment first that is not such - for i in (0..input.len()).rev() { - if copy[i] == 255 { - copy[i] = 0; - } else { - copy[i] += 1; - break; - } - } - copy -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::{storage_keys::to_length_prefixed, testing::MockStorage}; - - #[test] - fn prefix_get_set() { - let mut storage = MockStorage::new(); - let prefix = to_length_prefixed(b"foo"); - - set_with_prefix(&mut storage, &prefix, b"bar", b"gotcha"); - let rfoo = get_with_prefix(&storage, &prefix, b"bar"); - assert_eq!(rfoo, Some(b"gotcha".to_vec())); - - // no collisions with other prefixes - let other_prefix = to_length_prefixed(b"fo"); - let collision = get_with_prefix(&storage, &other_prefix, b"obar"); - assert_eq!(collision, None); - } - - #[test] - #[cfg(feature = "iterator")] - fn range_works() { - let mut storage = MockStorage::new(); - let prefix = to_length_prefixed(b"foo"); - let other_prefix = to_length_prefixed(b"food"); - - // set some values in this range - set_with_prefix(&mut storage, &prefix, b"bar", b"none"); - set_with_prefix(&mut storage, &prefix, b"snowy", b"day"); - - // set some values outside this range - set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy"); - - // ensure we get proper result from prefixed_range iterator - let mut iter = range_with_prefix(&storage, &prefix, None, None, Order::Descending); - let first = iter.next().unwrap(); - assert_eq!(first, (b"snowy".to_vec(), b"day".to_vec())); - let second = iter.next().unwrap(); - assert_eq!(second, (b"bar".to_vec(), b"none".to_vec())); - assert!(iter.next().is_none()); - - // ensure we get raw result from base range - let iter = storage.range(None, None, Order::Ascending); - assert_eq!(3, iter.count()); - - // foo comes first - let mut iter = storage.range(None, None, Order::Ascending); - let first = iter.next().unwrap(); - let expected_key = concat(&prefix, b"bar"); - assert_eq!(first, (expected_key, b"none".to_vec())); - } - - #[test] - #[cfg(feature = "iterator")] - fn range_with_prefix_wrapover() { - let mut storage = MockStorage::new(); - // if we don't properly wrap over there will be issues here (note 255+1 is used to calculate end) - let prefix = to_length_prefixed(b"f\xff\xff"); - let other_prefix = to_length_prefixed(b"f\xff\x44"); - - // set some values in this range - set_with_prefix(&mut storage, &prefix, b"bar", b"none"); - set_with_prefix(&mut storage, &prefix, b"snowy", b"day"); - - // set some values outside this range - set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy"); - - // ensure we get proper result from prefixed_range iterator - let iter = range_with_prefix(&storage, &prefix, None, None, Order::Descending); - let elements: Vec = iter.collect(); - assert_eq!( - elements, - vec![ - (b"snowy".to_vec(), b"day".to_vec()), - (b"bar".to_vec(), b"none".to_vec()), - ] - ); - } - - #[test] - #[cfg(feature = "iterator")] - fn range_with_start_end_set() { - let mut storage = MockStorage::new(); - // if we don't properly wrap over there will be issues here (note 255+1 is used to calculate end) - let prefix = to_length_prefixed(b"f\xff\xff"); - let other_prefix = to_length_prefixed(b"f\xff\x44"); - - // set some values in this range - set_with_prefix(&mut storage, &prefix, b"bar", b"none"); - set_with_prefix(&mut storage, &prefix, b"snowy", b"day"); - - // set some values outside this range - set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy"); - - // make sure start and end are applied properly - let res: Vec = - range_with_prefix(&storage, &prefix, Some(b"b"), Some(b"c"), Order::Ascending) - .collect(); - assert_eq!(res.len(), 1); - assert_eq!(res[0], (b"bar".to_vec(), b"none".to_vec())); - - // make sure start and end are applied properly - let res_count = range_with_prefix( - &storage, - &prefix, - Some(b"bas"), - Some(b"sno"), - Order::Ascending, - ) - .count(); - assert_eq!(res_count, 0); - - let res: Vec = - range_with_prefix(&storage, &prefix, Some(b"ant"), None, Order::Ascending).collect(); - assert_eq!(res.len(), 2); - assert_eq!(res[0], (b"bar".to_vec(), b"none".to_vec())); - assert_eq!(res[1], (b"snowy".to_vec(), b"day".to_vec())); - } - - #[test] - #[cfg(feature = "iterator")] - fn namespace_upper_bound_works() { - assert_eq!(namespace_upper_bound(b"bob"), b"boc".to_vec()); - assert_eq!(namespace_upper_bound(b"fo\xfe"), b"fo\xff".to_vec()); - assert_eq!(namespace_upper_bound(b"fo\xff"), b"fp\x00".to_vec()); - // multiple \xff roll over - assert_eq!( - namespace_upper_bound(b"fo\xff\xff\xff"), - b"fp\x00\x00\x00".to_vec() - ); - // \xff not at the end are ignored - assert_eq!(namespace_upper_bound(b"\xffabc"), b"\xffabd".to_vec()); - } -} diff --git a/packages/storage/src/prefixed_storage.rs b/packages/storage/src/prefixed_storage.rs deleted file mode 100644 index 97f5bb63a5..0000000000 --- a/packages/storage/src/prefixed_storage.rs +++ /dev/null @@ -1,196 +0,0 @@ -use cosmwasm_std::{ - storage_keys::{to_length_prefixed, to_length_prefixed_nested}, - Storage, -}; -#[cfg(feature = "iterator")] -use cosmwasm_std::{Order, Record}; - -#[cfg(feature = "iterator")] -use crate::namespace_helpers::range_with_prefix; -use crate::namespace_helpers::{get_with_prefix, remove_with_prefix, set_with_prefix}; - -/// An alias of PrefixedStorage::new for less verbose usage -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub fn prefixed<'a>(storage: &'a mut dyn Storage, namespace: &[u8]) -> PrefixedStorage<'a> { - PrefixedStorage::new(storage, namespace) -} - -/// An alias of ReadonlyPrefixedStorage::new for less verbose usage -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub fn prefixed_read<'a>( - storage: &'a dyn Storage, - namespace: &[u8], -) -> ReadonlyPrefixedStorage<'a> { - ReadonlyPrefixedStorage::new(storage, namespace) -} - -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub struct PrefixedStorage<'a> { - storage: &'a mut dyn Storage, - prefix: Vec, -} - -impl<'a> PrefixedStorage<'a> { - pub fn new(storage: &'a mut dyn Storage, namespace: &[u8]) -> Self { - PrefixedStorage { - storage, - prefix: to_length_prefixed(namespace), - } - } - - // Nested namespaces as documented in - // https://github.com/webmaster128/key-namespacing#nesting - pub fn multilevel(storage: &'a mut dyn Storage, namespaces: &[&[u8]]) -> Self { - PrefixedStorage { - storage, - prefix: to_length_prefixed_nested(namespaces), - } - } -} - -impl<'a> Storage for PrefixedStorage<'a> { - fn get(&self, key: &[u8]) -> Option> { - get_with_prefix(self.storage, &self.prefix, key) - } - - fn set(&mut self, key: &[u8], value: &[u8]) { - set_with_prefix(self.storage, &self.prefix, key, value); - } - - fn remove(&mut self, key: &[u8]) { - remove_with_prefix(self.storage, &self.prefix, key); - } - - #[cfg(feature = "iterator")] - /// range allows iteration over a set of keys, either forwards or backwards - /// uses standard rust range notation, and eg db.range(b"foo"..b"bar") also works reverse - fn range<'b>( - &'b self, - start: Option<&[u8]>, - end: Option<&[u8]>, - order: Order, - ) -> Box + 'b> { - range_with_prefix(self.storage, &self.prefix, start, end, order) - } -} - -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub struct ReadonlyPrefixedStorage<'a> { - storage: &'a dyn Storage, - prefix: Vec, -} - -impl<'a> ReadonlyPrefixedStorage<'a> { - pub fn new(storage: &'a dyn Storage, namespace: &[u8]) -> Self { - ReadonlyPrefixedStorage { - storage, - prefix: to_length_prefixed(namespace), - } - } - - // Nested namespaces as documented in - // https://github.com/webmaster128/key-namespacing#nesting - pub fn multilevel(storage: &'a dyn Storage, namespaces: &[&[u8]]) -> Self { - ReadonlyPrefixedStorage { - storage, - prefix: to_length_prefixed_nested(namespaces), - } - } -} - -impl<'a> Storage for ReadonlyPrefixedStorage<'a> { - fn get(&self, key: &[u8]) -> Option> { - get_with_prefix(self.storage, &self.prefix, key) - } - - fn set(&mut self, _key: &[u8], _value: &[u8]) { - unimplemented!(); - } - - fn remove(&mut self, _key: &[u8]) { - unimplemented!(); - } - - #[cfg(feature = "iterator")] - /// range allows iteration over a set of keys, either forwards or backwards - fn range<'b>( - &'b self, - start: Option<&[u8]>, - end: Option<&[u8]>, - order: Order, - ) -> Box + 'b> { - range_with_prefix(self.storage, &self.prefix, start, end, order) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::testing::MockStorage; - - #[test] - fn prefixed_storage_set_and_get() { - let mut storage = MockStorage::new(); - - // set - let mut s1 = PrefixedStorage::new(&mut storage, b"foo"); - s1.set(b"bar", b"gotcha"); - assert_eq!(storage.get(b"\x00\x03foobar").unwrap(), b"gotcha".to_vec()); - - // get - let s2 = PrefixedStorage::new(&mut storage, b"foo"); - assert_eq!(s2.get(b"bar"), Some(b"gotcha".to_vec())); - assert_eq!(s2.get(b"elsewhere"), None); - } - - #[test] - fn prefixed_storage_multilevel_set_and_get() { - let mut storage = MockStorage::new(); - - // set - let mut bar = PrefixedStorage::multilevel(&mut storage, &[b"foo", b"bar"]); - bar.set(b"baz", b"winner"); - assert_eq!( - storage.get(b"\x00\x03foo\x00\x03barbaz").unwrap(), - b"winner".to_vec() - ); - - // get - let bar = PrefixedStorage::multilevel(&mut storage, &[b"foo", b"bar"]); - assert_eq!(bar.get(b"baz"), Some(b"winner".to_vec())); - assert_eq!(bar.get(b"elsewhere"), None); - } - - #[test] - fn readonly_prefixed_storage_get() { - let mut storage = MockStorage::new(); - storage.set(b"\x00\x03foobar", b"gotcha"); - - // try readonly correctly - let s1 = ReadonlyPrefixedStorage::new(&storage, b"foo"); - assert_eq!(s1.get(b"bar"), Some(b"gotcha".to_vec())); - assert_eq!(s1.get(b"elsewhere"), None); - - // no collisions with other prefixes - let s2 = ReadonlyPrefixedStorage::new(&storage, b"fo"); - assert_eq!(s2.get(b"obar"), None); - } - - #[test] - fn readonly_prefixed_storage_multilevel_get() { - let mut storage = MockStorage::new(); - storage.set(b"\x00\x03foo\x00\x03barbaz", b"winner"); - - let bar = ReadonlyPrefixedStorage::multilevel(&storage, &[b"foo", b"bar"]); - assert_eq!(bar.get(b"baz"), Some(b"winner".to_vec())); - assert_eq!(bar.get(b"elsewhere"), None); - } -} diff --git a/packages/storage/src/sequence.rs b/packages/storage/src/sequence.rs deleted file mode 100644 index 6d953f79c5..0000000000 --- a/packages/storage/src/sequence.rs +++ /dev/null @@ -1,81 +0,0 @@ -use cosmwasm_std::{StdResult, Storage}; - -use crate::Singleton; - -/// Sequence creates a custom Singleton to hold an empty sequence -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub fn sequence<'a>(storage: &'a mut dyn Storage, key: &[u8]) -> Singleton<'a, u64> { - Singleton::new(storage, key) -} - -/// currval returns the last value returned by nextval. If the sequence has never been used, -/// then it will return 0. -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub fn currval(seq: &Singleton) -> StdResult { - Ok(seq.may_load()?.unwrap_or_default()) -} - -/// nextval increments the counter by 1 and returns the new value. -/// On the first time it is called (no sequence info in db) it will return 1. -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub fn nextval(seq: &mut Singleton) -> StdResult { - let val = currval(seq)? + 1; - seq.save(&val)?; - Ok(val) -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::testing::MockStorage; - - #[test] - fn walk_through_sequence() { - let mut store = MockStorage::new(); - let mut seq = sequence(&mut store, b"seq"); - - assert_eq!(currval(&seq).unwrap(), 0); - assert_eq!(nextval(&mut seq).unwrap(), 1); - assert_eq!(nextval(&mut seq).unwrap(), 2); - assert_eq!(nextval(&mut seq).unwrap(), 3); - assert_eq!(currval(&seq).unwrap(), 3); - assert_eq!(currval(&seq).unwrap(), 3); - } - - #[test] - fn sequences_independent() { - let mut store = MockStorage::new(); - - let mut seq = sequence(&mut store, b"seq"); - assert_eq!(nextval(&mut seq).unwrap(), 1); - assert_eq!(nextval(&mut seq).unwrap(), 2); - assert_eq!(nextval(&mut seq).unwrap(), 3); - - let mut seq2 = sequence(&mut store, b"seq2"); - assert_eq!(nextval(&mut seq2).unwrap(), 1); - assert_eq!(nextval(&mut seq2).unwrap(), 2); - - let mut seq3 = sequence(&mut store, b"seq"); - assert_eq!(nextval(&mut seq3).unwrap(), 4); - } - - #[test] - fn set_sequence() { - let mut store = MockStorage::new(); - let mut seq = sequence(&mut store, b"seq"); - - assert_eq!(nextval(&mut seq).unwrap(), 1); - assert_eq!(nextval(&mut seq).unwrap(), 2); - - seq.save(&20).unwrap(); - - assert_eq!(currval(&seq).unwrap(), 20); - assert_eq!(nextval(&mut seq).unwrap(), 21); - } -} diff --git a/packages/storage/src/singleton.rs b/packages/storage/src/singleton.rs deleted file mode 100644 index 5afa576e77..0000000000 --- a/packages/storage/src/singleton.rs +++ /dev/null @@ -1,316 +0,0 @@ -use serde::{de::DeserializeOwned, ser::Serialize}; -use std::marker::PhantomData; - -use cosmwasm_std::{storage_keys::to_length_prefixed, to_json_vec, StdError, StdResult, Storage}; - -use crate::type_helpers::{may_deserialize, must_deserialize}; - -/// An alias of Singleton::new for less verbose usage -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub fn singleton<'a, T>(storage: &'a mut dyn Storage, key: &[u8]) -> Singleton<'a, T> -where - T: Serialize + DeserializeOwned, -{ - Singleton::new(storage, key) -} - -/// An alias of ReadonlySingleton::new for less verbose usage -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub fn singleton_read<'a, T>(storage: &'a dyn Storage, key: &[u8]) -> ReadonlySingleton<'a, T> -where - T: Serialize + DeserializeOwned, -{ - ReadonlySingleton::new(storage, key) -} - -/// Singleton effectively combines PrefixedStorage with TypedStorage to -/// work on a single storage key. It performs the to_length_prefixed transformation -/// on the given name to ensure no collisions, and then provides the standard -/// TypedStorage accessors, without requiring a key (which is defined in the constructor) -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub struct Singleton<'a, T> -where - T: Serialize + DeserializeOwned, -{ - storage: &'a mut dyn Storage, - key: Vec, - // see https://doc.rust-lang.org/std/marker/struct.PhantomData.html#unused-type-parameters for why this is needed - data: PhantomData, -} - -impl<'a, T> Singleton<'a, T> -where - T: Serialize + DeserializeOwned, -{ - pub fn new(storage: &'a mut dyn Storage, key: &[u8]) -> Self { - Singleton { - storage, - key: to_length_prefixed(key), - data: PhantomData, - } - } - - /// save will serialize the model and store, returns an error on serialization issues - pub fn save(&mut self, data: &T) -> StdResult<()> { - self.storage.set(&self.key, &to_json_vec(data)?); - Ok(()) - } - - pub fn remove(&mut self) { - self.storage.remove(&self.key) - } - - /// load will return an error if no data is set at the given key, or on parse error - pub fn load(&self) -> StdResult { - let value = self.storage.get(&self.key); - must_deserialize(&value) - } - - /// may_load will parse the data stored at the key if present, returns Ok(None) if no data there. - /// returns an error on issues parsing - pub fn may_load(&self) -> StdResult> { - let value = self.storage.get(&self.key); - may_deserialize(&value) - } - - /// update will load the data, perform the specified action, and store the result - /// in the database. This is shorthand for some common sequences, which may be useful - /// - /// This is the least stable of the APIs, and definitely needs some usage - pub fn update(&mut self, action: A) -> Result - where - A: FnOnce(T) -> Result, - E: From, - { - let input = self.load()?; - let output = action(input)?; - self.save(&output)?; - Ok(output) - } -} - -/// ReadonlySingleton only requires a Storage and exposes only the -/// methods of Singleton that don't modify state. -#[deprecated( - note = "The crate cosmwasm-storage is unmaintained and will be removed in CosmWasm 2.0. Please consider migrating to cw-storage-plus or simple cosmwasm-std storage calls." -)] -pub struct ReadonlySingleton<'a, T> -where - T: Serialize + DeserializeOwned, -{ - storage: &'a dyn Storage, - key: Vec, - // see https://doc.rust-lang.org/std/marker/struct.PhantomData.html#unused-type-parameters for why this is needed - data: PhantomData, -} - -impl<'a, T> ReadonlySingleton<'a, T> -where - T: Serialize + DeserializeOwned, -{ - pub fn new(storage: &'a dyn Storage, key: &[u8]) -> Self { - ReadonlySingleton { - storage, - key: to_length_prefixed(key), - data: PhantomData, - } - } - - /// load will return an error if no data is set at the given key, or on parse error - pub fn load(&self) -> StdResult { - let value = self.storage.get(&self.key); - must_deserialize(&value) - } - - /// may_load will parse the data stored at the key if present, returns Ok(None) if no data there. - /// returns an error on issues parsing - pub fn may_load(&self) -> StdResult> { - let value = self.storage.get(&self.key); - may_deserialize(&value) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::testing::MockStorage; - use serde::{Deserialize, Serialize}; - - use cosmwasm_std::{OverflowError, OverflowOperation, StdError}; - - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Config { - pub owner: String, - pub max_tokens: i32, - } - - #[test] - fn save_and_load() { - let mut store = MockStorage::new(); - let mut single = Singleton::::new(&mut store, b"config"); - - assert!(single.load().is_err()); - assert_eq!(single.may_load().unwrap(), None); - - let cfg = Config { - owner: "admin".to_string(), - max_tokens: 1234, - }; - single.save(&cfg).unwrap(); - - assert_eq!(cfg, single.load().unwrap()); - } - - #[test] - fn remove_works() { - let mut store = MockStorage::new(); - let mut single = Singleton::::new(&mut store, b"config"); - - // store data - let cfg = Config { - owner: "admin".to_string(), - max_tokens: 1234, - }; - single.save(&cfg).unwrap(); - assert_eq!(cfg, single.load().unwrap()); - - // remove it and loads None - single.remove(); - assert_eq!(None, single.may_load().unwrap()); - - // safe to remove 2 times - single.remove(); - assert_eq!(None, single.may_load().unwrap()); - } - - #[test] - fn isolated_reads() { - let mut store = MockStorage::new(); - let mut writer = singleton::(&mut store, b"config"); - - let cfg = Config { - owner: "admin".to_string(), - max_tokens: 1234, - }; - writer.save(&cfg).unwrap(); - - let reader = singleton_read::(&store, b"config"); - assert_eq!(cfg, reader.load().unwrap()); - - let other_reader = singleton_read::(&store, b"config2"); - assert_eq!(other_reader.may_load().unwrap(), None); - } - - #[test] - fn update_success() { - let mut store = MockStorage::new(); - let mut writer = singleton::(&mut store, b"config"); - - let cfg = Config { - owner: "admin".to_string(), - max_tokens: 1234, - }; - writer.save(&cfg).unwrap(); - - let output = writer.update(|mut c| -> StdResult<_> { - c.max_tokens *= 2; - Ok(c) - }); - let expected = Config { - owner: "admin".to_string(), - max_tokens: 2468, - }; - assert_eq!(output.unwrap(), expected); - assert_eq!(writer.load().unwrap(), expected); - } - - #[test] - fn update_can_change_variable_from_outer_scope() { - let mut store = MockStorage::new(); - let mut writer = singleton::(&mut store, b"config"); - let cfg = Config { - owner: "admin".to_string(), - max_tokens: 1234, - }; - writer.save(&cfg).unwrap(); - - let mut old_max_tokens = 0i32; - writer - .update(|mut c| -> StdResult<_> { - old_max_tokens = c.max_tokens; - c.max_tokens *= 2; - Ok(c) - }) - .unwrap(); - assert_eq!(old_max_tokens, 1234); - } - - #[test] - fn update_does_not_change_data_on_error() { - let mut store = MockStorage::new(); - let mut writer = singleton::(&mut store, b"config"); - - let cfg = Config { - owner: "admin".to_string(), - max_tokens: 1234, - }; - writer.save(&cfg).unwrap(); - - let output = - writer.update(|_c| Err(StdError::from(OverflowError::new(OverflowOperation::Sub)))); - match output.unwrap_err() { - StdError::Overflow { .. } => {} - err => panic!("Unexpected error: {err:?}"), - } - assert_eq!(writer.load().unwrap(), cfg); - } - - #[test] - fn update_supports_custom_errors() { - #[derive(Debug)] - enum MyError { - Std(StdError), - Foo, - } - - impl From for MyError { - fn from(original: StdError) -> MyError { - MyError::Std(original) - } - } - - let mut store = MockStorage::new(); - let mut writer = singleton::(&mut store, b"config"); - - let cfg = Config { - owner: "admin".to_string(), - max_tokens: 1234, - }; - writer.save(&cfg).unwrap(); - - let res = writer.update(|mut c| { - if c.max_tokens > 5000 { - return Err(MyError::Foo); - } - if c.max_tokens > 20 { - return Err(StdError::generic_err("broken stuff").into()); // Uses Into to convert StdError to MyError - } - if c.max_tokens > 10 { - to_json_vec(&c)?; // Uses From to convert StdError to MyError - } - c.max_tokens += 20; - Ok(c) - }); - match res.unwrap_err() { - MyError::Std(StdError::GenericErr { .. }) => {} - err => panic!("Unexpected error: {err:?}"), - } - assert_eq!(writer.load().unwrap(), cfg); - } -} diff --git a/packages/storage/src/type_helpers.rs b/packages/storage/src/type_helpers.rs deleted file mode 100644 index 98855de1bc..0000000000 --- a/packages/storage/src/type_helpers.rs +++ /dev/null @@ -1,89 +0,0 @@ -use serde::de::DeserializeOwned; -use std::any::type_name; - -#[cfg(feature = "iterator")] -use cosmwasm_std::Record; -use cosmwasm_std::{from_slice, StdError, StdResult}; - -/// may_deserialize parses json bytes from storage (Option), returning Ok(None) if no data present -/// -/// value is an odd type, but this is meant to be easy to use with output from storage.get (Option>) -/// and value.map(|s| s.as_slice()) seems trickier than &value -pub(crate) fn may_deserialize( - value: &Option>, -) -> StdResult> { - match value { - Some(data) => Ok(Some(from_slice(data)?)), - None => Ok(None), - } -} - -/// must_deserialize parses json bytes from storage (Option), returning NotFound error if no data present -pub(crate) fn must_deserialize(value: &Option>) -> StdResult { - match value { - Some(data) => from_slice(data), - None => Err(StdError::not_found(type_name::())), - } -} - -#[cfg(feature = "iterator")] -pub(crate) fn deserialize_kv(kv: Record>) -> StdResult> { - let (k, v) = kv; - let t = from_slice::(&v)?; - Ok((k, t)) -} - -#[cfg(test)] -mod tests { - use super::*; - use cosmwasm_std::{to_json_vec, StdError}; - use serde::{Deserialize, Serialize}; - - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Person { - pub name: String, - pub age: i32, - } - - #[test] - fn may_deserialize_handles_some() { - let person = Person { - name: "Maria".to_string(), - age: 42, - }; - let value = to_json_vec(&person).unwrap(); - - let may_parse: Option = may_deserialize(&Some(value)).unwrap(); - assert_eq!(may_parse, Some(person)); - } - - #[test] - fn may_deserialize_handles_none() { - let may_parse = may_deserialize::(&None).unwrap(); - assert_eq!(may_parse, None); - } - - #[test] - fn must_deserialize_handles_some() { - let person = Person { - name: "Maria".to_string(), - age: 42, - }; - let value = to_json_vec(&person).unwrap(); - let loaded = Some(value); - - let parsed: Person = must_deserialize(&loaded).unwrap(); - assert_eq!(parsed, person); - } - - #[test] - fn must_deserialize_handles_none() { - let parsed = must_deserialize::(&None); - match parsed.unwrap_err() { - StdError::NotFound { kind, .. } => { - assert_eq!(kind, "cosmwasm_storage::type_helpers::tests::Person") - } - e => panic!("Unexpected error {e}"), - } - } -} From 1dcbfd15f4361a2056fd4b1b9c874f0527878ff5 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 3 Nov 2023 13:32:06 +0100 Subject: [PATCH 2/6] Remove storage from devtools and CI --- .circleci/config.yml | 44 ------------------------------------- .mergify.yml | 1 - codecov.yml | 3 --- devtools/check_workspace.sh | 1 - devtools/clean.sh | 1 - devtools/deadlinks.py | 1 - devtools/test_workspace.sh | 1 - 7 files changed, 52 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 38ee07c097..31a018aa70 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -52,7 +52,6 @@ workflows: - package_schema - package_schema_derive - package_std - - package_storage - package_vm - package_vm_windows - contract_burner @@ -373,37 +372,6 @@ jobs: - target/debug/deps key: cargocache-v2-package_std-rust:1.70.0-{{ checksum "Cargo.lock" }} - package_storage: - docker: - - image: rust:1.70.0 - steps: - - checkout - - run: - name: Version information - command: rustc --version; cargo --version; rustup --version; rustup target list --installed - - restore_cache: - keys: - - cargocache-v2-package_storage-rust:1.70.0-{{ checksum "Cargo.lock" }} - - run: - name: Build library for native target - working_directory: ~/project/packages/storage - command: cargo build --locked - - run: - name: Run unit tests - working_directory: ~/project/packages/storage - command: cargo test --locked - - run: - name: Run unit tests (with iterator support) - working_directory: ~/project/packages/storage - command: cargo test --locked --features iterator - - save_cache: - paths: - - /usr/local/cargo/registry - - target/debug/.fingerprint - - target/debug/build - - target/debug/deps - key: cargocache-v2-package_storage-rust:1.70.0-{{ checksum "Cargo.lock" }} - package_vm: docker: - image: rust:1.70.0 @@ -908,14 +876,6 @@ jobs: 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_4 -- -D warnings - - run: - name: Clippy linting on storage (no feature flags) - working_directory: ~/project/packages/storage - command: cargo clippy --all-targets -- -D warnings - - run: - name: Clippy linting on storage (all feature flags) - working_directory: ~/project/packages/storage - command: cargo clippy --all-targets --features iterator -- -D warnings - run: name: Clippy linting on vm (no feature flags) working_directory: ~/project/packages/vm @@ -986,7 +946,6 @@ jobs: grcov . -s packages/derive --binary-path ./target/debug -t lcov -o ./reports/derive.info grcov . -s packages/schema --binary-path ./target/debug -t lcov -o ./reports/schema.info grcov . -s packages/std --binary-path ./target/debug -t lcov -o ./reports/std.info - grcov . -s packages/storage --binary-path ./target/debug -t lcov -o ./reports/storage.info grcov . -s packages/vm --binary-path ./target/debug -t lcov -o ./reports/vm.info environment: RUSTFLAGS: "-Cinstrument-coverage" @@ -1003,9 +962,6 @@ jobs: - codecov/upload: file: reports/std.info flags: cosmwasm-std - - codecov/upload: - file: reports/storage.info - flags: cosmwasm-storage - codecov/upload: file: reports/vm.info flags: cosmwasm-vm diff --git a/.mergify.yml b/.mergify.yml index 4bb3f061d8..4895cfe743 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -36,7 +36,6 @@ pull_request_rules: - "status-success=ci/circleci: package_schema" - "status-success=ci/circleci: package_schema_derive" - "status-success=ci/circleci: package_std" - - "status-success=ci/circleci: package_storage" - "status-success=ci/circleci: package_vm" - "status-success=ci/circleci: package_vm_windows" actions: diff --git a/codecov.yml b/codecov.yml index b1de3c37b8..036e3b781d 100644 --- a/codecov.yml +++ b/codecov.yml @@ -30,6 +30,3 @@ flags: cosmwasm-std: paths: - packages/std/ - cosmwasm-storage: - paths: - - packages/storage/ diff --git a/devtools/check_workspace.sh b/devtools/check_workspace.sh index 1747d316d6..76f8d387d6 100755 --- a/devtools/check_workspace.sh +++ b/devtools/check_workspace.sh @@ -15,7 +15,6 @@ cargo fmt cargo wasm-debug --features iterator,staking,stargate cargo clippy --all-targets --features iterator,staking,stargate -- -D warnings ) -(cd packages/storage && cargo build && cargo clippy --all-targets --features iterator -- -D warnings) (cd packages/schema && cargo build && cargo clippy --all-targets -- -D warnings) (cd packages/schema-derive && cargo build && cargo clippy --all-targets -- -D warnings) (cd packages/vm && cargo build --features iterator,stargate && cargo clippy --all-targets --features iterator,stargate -- -D warnings) diff --git a/devtools/clean.sh b/devtools/clean.sh index 616c7846ad..ad30e74210 100755 --- a/devtools/clean.sh +++ b/devtools/clean.sh @@ -4,6 +4,5 @@ command -v shellcheck >/dev/null && shellcheck "$0" (cd packages/std && cargo clean) (cd packages/crypto && cargo clean) -(cd packages/storage && cargo clean) (cd packages/schema && cargo clean) (cd packages/vm && cargo clean) diff --git a/devtools/deadlinks.py b/devtools/deadlinks.py index 79d3cc81f3..9dee04a9a8 100755 --- a/devtools/deadlinks.py +++ b/devtools/deadlinks.py @@ -72,7 +72,6 @@ def check_project(project): "cosmwasm_derive", "cosmwasm_schema", "cosmwasm_std", - "cosmwasm_storage", "cosmwasm_vm" ] diff --git a/devtools/test_workspace.sh b/devtools/test_workspace.sh index 5ade3f183f..0303753549 100755 --- a/devtools/test_workspace.sh +++ b/devtools/test_workspace.sh @@ -5,7 +5,6 @@ command -v shellcheck >/dev/null && shellcheck "$0" cargo fmt (cd packages/crypto && cargo test) (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) (cd packages/vm && cargo test --features iterator,stargate) From e7cd96539aee0fa1c99b46c0fcc5995d1cec3a3c Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Fri, 3 Nov 2023 16:21:02 +0100 Subject: [PATCH 3/6] Remove cosmwasm-storage from README --- README.md | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 7536c89f59..50904c6fb4 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,19 @@ The following packages are maintained here: -| Crate | Usage | Download | Docs | Coverage | -| ---------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | -------------------------------------------------- | -| cosmwasm-crypto | Internal only | [![cosmwasm-crypto on crates.io](https://img.shields.io/crates/v/cosmwasm-crypto.svg)](https://crates.io/crates/cosmwasm-crypto) | [![Docs](https://docs.rs/cosmwasm-crypto/badge.svg)](https://docs.rs/cosmwasm-crypto) | [![Coverage][cov-badge-crypto]][cov-link-crypto] | -| cosmwasm-derive | Internal only | [![cosmwasm-derive on crates.io](https://img.shields.io/crates/v/cosmwasm-derive.svg)](https://crates.io/crates/cosmwasm-derive) | [![Docs](https://docs.rs/cosmwasm-derive/badge.svg)](https://docs.rs/cosmwasm-derive) | [![Coverage][cov-badge-derive]][cov-link-derive] | -| cosmwasm-schema | Contract development | [![cosmwasm-schema on crates.io](https://img.shields.io/crates/v/cosmwasm-schema.svg)](https://crates.io/crates/cosmwasm-schema) | [![Docs](https://docs.rs/cosmwasm-schema/badge.svg)](https://docs.rs/cosmwasm-schema) | [![Coverage][cov-badge-schema]][cov-link-schema] | -| cosmwasm-std | Contract development | [![cosmwasm-std on crates.io](https://img.shields.io/crates/v/cosmwasm-std.svg)](https://crates.io/crates/cosmwasm-std) | [![Docs](https://docs.rs/cosmwasm-std/badge.svg)](https://docs.rs/cosmwasm-std) | [![Coverage][cov-badge-std]][cov-link-std] | -| cosmwasm-storage | Contract development | [![cosmwasm-storage on crates.io](https://img.shields.io/crates/v/cosmwasm-storage.svg)](https://crates.io/crates/cosmwasm-storage) | [![Docs](https://docs.rs/cosmwasm-storage/badge.svg)](https://docs.rs/cosmwasm-storage) | [![Coverage][cov-badge-storage]][cov-link-storage] | -| cosmwasm-vm | Host environments | [![cosmwasm-vm on crates.io](https://img.shields.io/crates/v/cosmwasm-vm.svg)](https://crates.io/crates/cosmwasm-vm) | [![Docs](https://docs.rs/cosmwasm-vm/badge.svg)](https://docs.rs/cosmwasm-vm) | ([#1151]) | -| cosmwasm-check | Contract development | [![cosmwasm-check on crates.io](https://img.shields.io/crates/v/cosmwasm-check.svg)](https://crates.io/crates/cosmwasm-check) | `cosmwasm-check -h` | N/A | +| Crate | Usage | Download | Docs | Coverage | +| --------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------ | +| cosmwasm-crypto | Internal only | [![cosmwasm-crypto on crates.io](https://img.shields.io/crates/v/cosmwasm-crypto.svg)](https://crates.io/crates/cosmwasm-crypto) | [![Docs](https://docs.rs/cosmwasm-crypto/badge.svg)](https://docs.rs/cosmwasm-crypto) | [![Coverage][cov-badge-crypto]][cov-link-crypto] | +| cosmwasm-derive | Internal only | [![cosmwasm-derive on crates.io](https://img.shields.io/crates/v/cosmwasm-derive.svg)](https://crates.io/crates/cosmwasm-derive) | [![Docs](https://docs.rs/cosmwasm-derive/badge.svg)](https://docs.rs/cosmwasm-derive) | [![Coverage][cov-badge-derive]][cov-link-derive] | +| cosmwasm-schema | Contract development | [![cosmwasm-schema on crates.io](https://img.shields.io/crates/v/cosmwasm-schema.svg)](https://crates.io/crates/cosmwasm-schema) | [![Docs](https://docs.rs/cosmwasm-schema/badge.svg)](https://docs.rs/cosmwasm-schema) | [![Coverage][cov-badge-schema]][cov-link-schema] | +| cosmwasm-std | Contract development | [![cosmwasm-std on crates.io](https://img.shields.io/crates/v/cosmwasm-std.svg)](https://crates.io/crates/cosmwasm-std) | [![Docs](https://docs.rs/cosmwasm-std/badge.svg)](https://docs.rs/cosmwasm-std) | [![Coverage][cov-badge-std]][cov-link-std] | +| cosmwasm-vm | Host environments | [![cosmwasm-vm on crates.io](https://img.shields.io/crates/v/cosmwasm-vm.svg)](https://crates.io/crates/cosmwasm-vm) | [![Docs](https://docs.rs/cosmwasm-vm/badge.svg)](https://docs.rs/cosmwasm-vm) | [![Coverage][cov-badge-vm]][cov-link-vm] | +| cosmwasm-check | Contract development | [![cosmwasm-check on crates.io](https://img.shields.io/crates/v/cosmwasm-check.svg)](https://crates.io/crates/cosmwasm-check) | `cosmwasm-check -h` | N/A | + +We used to maintain +[cosmwasm-storage](https://crates.io/crates/cosmwasm-storage) here too, but it +is no longer maintained and has been dropped in favor of +[cw-storage-plus](https://github.com/CosmWasm/cw-storage-plus). [cov-badge-crypto]: https://codecov.io/gh/CosmWasm/cosmwasm/branch/main/graph/badge.svg?flag=cosmwasm-crypto @@ -26,8 +30,8 @@ The following packages are maintained here: https://codecov.io/gh/CosmWasm/cosmwasm/branch/main/graph/badge.svg?flag=cosmwasm-schema [cov-badge-std]: https://codecov.io/gh/CosmWasm/cosmwasm/branch/main/graph/badge.svg?flag=cosmwasm-std -[cov-badge-storage]: - https://codecov.io/gh/CosmWasm/cosmwasm/branch/main/graph/badge.svg?flag=cosmwasm-storage +[cov-badge-vm]: + https://codecov.io/gh/CosmWasm/cosmwasm/branch/main/graph/badge.svg?flag=cosmwasm-vm [cov-link-crypto]: https://codecov.io/gh/CosmWasm/cosmwasm/tree/main/packages/crypto [cov-link-derive]: @@ -35,9 +39,7 @@ The following packages are maintained here: [cov-link-schema]: https://codecov.io/gh/CosmWasm/cosmwasm/tree/main/packages/schema [cov-link-std]: https://codecov.io/gh/CosmWasm/cosmwasm/tree/main/packages/std -[cov-link-storage]: - https://codecov.io/gh/CosmWasm/cosmwasm/tree/main/packages/storage -[#1151]: https://github.com/CosmWasm/cosmwasm/issues/1151 +[cov-link-vm]: https://codecov.io/gh/CosmWasm/cosmwasm/tree/main/packages/vm ## Overview @@ -51,17 +53,10 @@ This code is compiled into Wasm bytecode as part of the smart contract. - [cosmwasm-std](https://github.com/CosmWasm/cosmwasm/tree/main/packages/std) - A crate in this workspace. Provides the bindings and all imports needed to build a smart contract. -- [cosmwasm-storage](https://github.com/CosmWasm/cosmwasm/tree/main/packages/storage) - - A crate in this workspace. This optional addition to `cosmwasm-std` includes - convenience helpers for interacting with storage. **This is being deprecated - in favor of - [`cw-storage-plus`](https://github.com/CosmWasm/cw-storage-plus).** See - [issue #1457](https://github.com/CosmWasm/cosmwasm/issues/1457). - [cw-storage-plus](https://github.com/CosmWasm/cw-storage-plus) - A crate which - fills the same role as `cosmwasm-storage`, but with much more powerful types + provides convenience helpers for interacting with storage with powerful types supporting composite primary keys, secondary indexes, automatic snapshotting, - and more. This is used in most modern contracts and likely going to be - stabilized (version `1.0.0`) soon. + and more. This is used in most modern contracts. **Building contracts:** From 26c1acef2b0cf16403d60f13441f025b7273645c Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Mon, 6 Nov 2023 15:20:34 +0100 Subject: [PATCH 4/6] Improve readme wording --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 50904c6fb4..3964683bb2 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,8 @@ The following packages are maintained here: | cosmwasm-vm | Host environments | [![cosmwasm-vm on crates.io](https://img.shields.io/crates/v/cosmwasm-vm.svg)](https://crates.io/crates/cosmwasm-vm) | [![Docs](https://docs.rs/cosmwasm-vm/badge.svg)](https://docs.rs/cosmwasm-vm) | [![Coverage][cov-badge-vm]][cov-link-vm] | | cosmwasm-check | Contract development | [![cosmwasm-check on crates.io](https://img.shields.io/crates/v/cosmwasm-check.svg)](https://crates.io/crates/cosmwasm-check) | `cosmwasm-check -h` | N/A | -We used to maintain -[cosmwasm-storage](https://crates.io/crates/cosmwasm-storage) here too, but it -is no longer maintained and has been dropped in favor of +[cosmwasm-storage](https://crates.io/crates/cosmwasm-storage) is no longer +maintained and has been dropped in favor of [cw-storage-plus](https://github.com/CosmWasm/cw-storage-plus). [cov-badge-crypto]: From 536e8786448bf4fef4f2ed4719f754c9d389d08f Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 7 Nov 2023 11:54:27 +0100 Subject: [PATCH 5/6] Add changelog entry --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 058d3a6817..1138f101fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,13 @@ and this project adheres to [#1902]: https://github.com/CosmWasm/cosmwasm/pull/1902 [#1929]: https://github.com/CosmWasm/cosmwasm/pull/1929 +### Removed + +- cosmwasm-storage: Removed, use [cw-storage-plus] instead. ([#1936]) + +[cw-storage-plus]: https://github.com/CosmWasm/cw-storage-plus +[#1936]: https://github.com/CosmWasm/cosmwasm/pull/1936 + ## [1.5.0] - 2023-10-31 ### Added From 7831a8810cad5840d75923099461c32cb2008a59 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 7 Nov 2023 12:11:55 +0100 Subject: [PATCH 6/6] Split changelog sections --- CHANGELOG.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1138f101fd..0fc1973267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,15 +6,20 @@ and this project adheres to ## [Unreleased] +### Added + +- cosmwasm-std: Add `SubMsg:reply_never` constructor ([#1929]) +- cosmwasm-std: Add optional memo field to `IbcMsg::Transfer`. ([#1878]) + +[#1878]: https://github.com/CosmWasm/cosmwasm/pull/1878 +[#1929]: https://github.com/CosmWasm/cosmwasm/pull/1929 + ### Changed - cosmwasm-std: Replace `ContractInfoResponse::new` with new (unstable) constructor, remove `SubMsgExecutionResponse` (Use `SubMsgResponse` instead) and remove `PartialEq<&str> for Addr` (validate the address and use `PartialEq for Addr` instead). ([#1879]) -- cosmwasm-std: Remove `Mul for Uint128` and - `Mul for Uint256`. Use `Uint{128,256}::mul_floor` instead. - ([#1890]) - cosmwasm-std: `Uint{64,128}::full_mul` now take `Into` as an argument. ([#1874]) - cosmwasm-vm: Make `CacheOptions` non-exhaustive and add a constructor. @@ -22,31 +27,30 @@ and this project adheres to - cosmwasm-std: `Coin::new` now takes `Into` instead of `u128` as the first argument and `DecCoin::new` takes `Into` instead of `Decimal256`. ([#1902]) -- cosmwasm-std: Remove operand strings from `OverflowError`, - `ConversionOverflowError` and `DivideByZeroError`. ([#1896]) -- cosmwasm-std: Add `SubMsg:reply_never` constructor ([#1929]) -- cosmwasm-std: Add optional memo field to `IbcMsg::Transfer`. ([#1878]) - cosmwasm-std: Make inner values of `CanonicalAddr` and `Binary` private and add constructor for `Binary`. ([#1876]) - cosmwasm-vm: Make inner value of `Size` private and add constructor. ([#1876]) -- cosmwasm-std: Remove old IBC version and make v3 the default. ([#1875]) [#1874]: https://github.com/CosmWasm/cosmwasm/pull/1874 -[#1875]: https://github.com/CosmWasm/cosmwasm/pull/1875 [#1876]: https://github.com/CosmWasm/cosmwasm/pull/1876 -[#1878]: https://github.com/CosmWasm/cosmwasm/pull/1878 [#1879]: https://github.com/CosmWasm/cosmwasm/pull/1879 -[#1890]: https://github.com/CosmWasm/cosmwasm/pull/1890 -[#1896]: https://github.com/CosmWasm/cosmwasm/pull/1896 [#1898]: https://github.com/CosmWasm/cosmwasm/pull/1898 [#1902]: https://github.com/CosmWasm/cosmwasm/pull/1902 -[#1929]: https://github.com/CosmWasm/cosmwasm/pull/1929 ### Removed +- cosmwasm-std: Remove `Mul for Uint128` and + `Mul for Uint256`. Use `Uint{128,256}::mul_floor` instead. + ([#1890]) +- cosmwasm-std: Remove operand strings from `OverflowError`, + `ConversionOverflowError` and `DivideByZeroError`. ([#1896]) +- cosmwasm-std: Remove old IBC version and make v3 the default. ([#1875]) - cosmwasm-storage: Removed, use [cw-storage-plus] instead. ([#1936]) [cw-storage-plus]: https://github.com/CosmWasm/cw-storage-plus +[#1875]: https://github.com/CosmWasm/cosmwasm/pull/1875 +[#1890]: https://github.com/CosmWasm/cosmwasm/pull/1890 +[#1896]: https://github.com/CosmWasm/cosmwasm/pull/1896 [#1936]: https://github.com/CosmWasm/cosmwasm/pull/1936 ## [1.5.0] - 2023-10-31