diff --git a/CHANGELOG.md b/CHANGELOG.md index 3017dca2af..5332e91881 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ and this project adheres to - cosmwasm-std: Make methods `Uint256::to_be_bytes`/`::to_le_bytes` const. - cosmwasm-std: Make methods `Uint512::to_be_bytes`/`::to_le_bytes` const. - cosmwasm-std: Make method `Uint512::from_le_bytes` const. +- cosmwasm-std: Rename `Pair` to `Record`. `Pair` is now an alias for `Record` + and deprecated. ### Removed diff --git a/MIGRATING.md b/MIGRATING.md index e49f415d7f..0f730db329 100644 --- a/MIGRATING.md +++ b/MIGRATING.md @@ -4,6 +4,32 @@ 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. +## 0.16 -> 1.0 (unreleased) + +- Update CosmWasm dependencies in Cargo.toml (skip the ones you don't use): + + ``` + [dependencies] + cosmwasm-std = "1.0.0" + cosmwasm-storage = "1.0.0" + # ... + + [dev-dependencies] + cosmwasm-schema = "1.0.0" + cosmwasm-vm = "1.0.0" + # ... + ``` + +- Use type `Record` instead of `Pair` + + ```rust + // before + use cosmwasm_std::Pair; + + // after + use cosmwasm_std::Record; + ``` + ## 0.15 -> 0.16 - Update CosmWasm dependencies in Cargo.toml (skip the ones you don't use): diff --git a/README.md b/README.md index b3e728e047..2b2709f9d2 100644 --- a/README.md +++ b/README.md @@ -290,7 +290,7 @@ pub trait Storage { start: Option<&[u8]>, end: Option<&[u8]>, order: Order, - ) -> Box + 'a>; + ) -> Box + 'a>; } ``` diff --git a/packages/std/src/imports.rs b/packages/std/src/imports.rs index 21c9059b84..494f05a0fe 100644 --- a/packages/std/src/imports.rs +++ b/packages/std/src/imports.rs @@ -13,7 +13,7 @@ use crate::serde::from_slice; use crate::traits::{Api, Querier, QuerierResult, Storage}; #[cfg(feature = "iterator")] use crate::{ - iterator::{Order, Pair}, + iterator::{Order, Record}, memory::get_optional_region_address, }; @@ -108,7 +108,7 @@ impl Storage for ExternalStorage { start: Option<&[u8]>, end: Option<&[u8]>, order: Order, - ) -> Box> { + ) -> Box> { // There is lots of gotchas on turning options into regions for FFI, thus this design // See: https://github.com/CosmWasm/cosmwasm/pull/509 let start_region = start.map(build_region); @@ -130,7 +130,7 @@ struct ExternalIterator { #[cfg(feature = "iterator")] impl Iterator for ExternalIterator { - type Item = Pair; + type Item = Record; fn next(&mut self) -> Option { let next_result = unsafe { db_next(self.iterator_id) }; diff --git a/packages/std/src/iterator.rs b/packages/std/src/iterator.rs index 1b9886df79..83c89aabd2 100644 --- a/packages/std/src/iterator.rs +++ b/packages/std/src/iterator.rs @@ -1,8 +1,14 @@ use crate::errors::StdError; use std::convert::TryFrom; -/// A Key-Value pair, returned from our iterators -pub type Pair> = (Vec, V); +/// A record of a key-value storage that is created through an iterator API. +/// The first element (key) is always raw binary data. The second element +/// (value) is binary by default but can be changed to a custom type. This +/// allows contracts to reuse the type when deserializing database records. +pub type Record> = (Vec, V); + +#[deprecated(note = "Renamed to Record, please use this instead")] +pub type Pair> = Record; #[derive(Copy, Clone)] // We assign these to integers to provide a stable API for passing over FFI (to wasm and Go) diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 4c0fe53681..aa2da25cff 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -38,7 +38,10 @@ pub use crate::ibc::{ IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, IbcTimeout, IbcTimeoutBlock, }; #[cfg(feature = "iterator")] -pub use crate::iterator::{Order, Pair}; +#[allow(deprecated)] +pub use crate::iterator::Pair; +#[cfg(feature = "iterator")] +pub use crate::iterator::{Order, Record}; pub use crate::math::{ Decimal, Decimal256, Decimal256RangeExceeded, DecimalRangeExceeded, Fraction, Uint128, Uint256, Uint512, Uint64, diff --git a/packages/std/src/storage.rs b/packages/std/src/storage.rs index 8be6a7f7fc..be80fcdae0 100644 --- a/packages/std/src/storage.rs +++ b/packages/std/src/storage.rs @@ -6,7 +6,7 @@ use std::iter; use std::ops::{Bound, RangeBounds}; #[cfg(feature = "iterator")] -use crate::iterator::{Order, Pair}; +use crate::iterator::{Order, Record}; use crate::traits::Storage; #[derive(Default)] @@ -45,7 +45,7 @@ impl Storage for MemoryStorage { start: Option<&[u8]>, end: Option<&[u8]>, order: Order, - ) -> Box + 'a> { + ) -> Box + 'a> { let bounds = range_bounds(start, end); // BTreeMap.range panics if range is start > end. @@ -96,12 +96,12 @@ fn range_bounds(start: Option<&[u8]>, end: Option<&[u8]>) -> impl RangeBounds, T>::range. +/// The BTreeMap specific key-value pair reference type, as returned by BTreeMap, Vec>::range. /// This is internal as it can change any time if the map implementation is swapped out. -type BTreeMapPairRef<'a, T = Vec> = (&'a Vec, &'a T); +type BTreeMapRecordRef<'a> = (&'a Vec, &'a Vec); #[cfg(feature = "iterator")] -fn clone_item(item_ref: BTreeMapPairRef) -> Pair { +fn clone_item(item_ref: BTreeMapRecordRef) -> Record { let (key, value) = item_ref; (key.clone(), value.clone()) } @@ -160,7 +160,7 @@ mod tests { // unbounded { let iter = store.range(None, None, Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -174,7 +174,7 @@ mod tests { // unbounded (descending) { let iter = store.range(None, None, Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -188,14 +188,14 @@ mod tests { // bounded { let iter = store.range(Some(b"f"), Some(b"n"), Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![(b"foo".to_vec(), b"bar".to_vec())]); } // bounded (descending) { let iter = store.range(Some(b"air"), Some(b"loop"), Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -208,35 +208,35 @@ mod tests { // bounded empty [a, a) { let iter = store.range(Some(b"foo"), Some(b"foo"), Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![]); } // bounded empty [a, a) (descending) { let iter = store.range(Some(b"foo"), Some(b"foo"), Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![]); } // bounded empty [a, b) with b < a { let iter = store.range(Some(b"z"), Some(b"a"), Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![]); } // bounded empty [a, b) with b < a (descending) { let iter = store.range(Some(b"z"), Some(b"a"), Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![]); } // right unbounded { let iter = store.range(Some(b"f"), None, Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -249,7 +249,7 @@ mod tests { // right unbounded (descending) { let iter = store.range(Some(b"f"), None, Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -262,14 +262,14 @@ mod tests { // left unbounded { let iter = store.range(None, Some(b"f"), Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![(b"ant".to_vec(), b"hill".to_vec()),]); } // left unbounded (descending) { let iter = store.range(None, Some(b"no"), Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ diff --git a/packages/std/src/traits.rs b/packages/std/src/traits.rs index 1e2cf2bd0a..d834234824 100644 --- a/packages/std/src/traits.rs +++ b/packages/std/src/traits.rs @@ -7,7 +7,7 @@ use crate::binary::Binary; use crate::coins::Coin; use crate::errors::{RecoverPubkeyError, StdError, StdResult, VerificationError}; #[cfg(feature = "iterator")] -use crate::iterator::{Order, Pair}; +use crate::iterator::{Order, Record}; use crate::query::{ AllBalanceResponse, BalanceResponse, BankQuery, CustomQuery, QueryRequest, WasmQuery, }; @@ -40,7 +40,7 @@ pub trait Storage { start: Option<&[u8]>, end: Option<&[u8]>, order: Order, - ) -> Box + 'a>; + ) -> Box + 'a>; fn set(&mut self, key: &[u8], value: &[u8]); /// Removes a database entry at `key`. diff --git a/packages/storage/src/bucket.rs b/packages/storage/src/bucket.rs index 067ca5cbc7..47e2fb36cf 100644 --- a/packages/storage/src/bucket.rs +++ b/packages/storage/src/bucket.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use cosmwasm_std::{to_vec, StdError, StdResult, Storage}; #[cfg(feature = "iterator")] -use cosmwasm_std::{Order, Pair}; +use cosmwasm_std::{Order, Record}; use crate::length_prefixed::{to_length_prefixed, to_length_prefixed_nested}; #[cfg(feature = "iterator")] @@ -88,7 +88,7 @@ where start: Option<&[u8]>, end: Option<&[u8]>, order: Order, - ) -> Box>> + 'b> { + ) -> Box>> + 'b> { let mapped = range_with_prefix(self.storage, &self.prefix, start, end, order) .map(deserialize_kv::); Box::new(mapped) @@ -159,7 +159,7 @@ where start: Option<&[u8]>, end: Option<&[u8]>, order: Order, - ) -> Box>> + 'b> { + ) -> Box>> + 'b> { let mapped = range_with_prefix(self.storage, &self.prefix, start, end, order) .map(deserialize_kv::); Box::new(mapped) @@ -441,7 +441,7 @@ mod tests { bucket.save(b"maria", &maria).unwrap(); bucket.save(b"jose", &jose).unwrap(); - let res_data: StdResult>> = + let res_data: StdResult>> = bucket.range(None, None, Order::Ascending).collect(); let data = res_data.unwrap(); assert_eq!(data.len(), 2); @@ -450,7 +450,7 @@ mod tests { // also works for readonly let read_bucket = bucket_read::(&store, b"data"); - let res_data: StdResult>> = + let res_data: StdResult>> = read_bucket.range(None, None, Order::Ascending).collect(); let data = res_data.unwrap(); assert_eq!(data.len(), 2); diff --git a/packages/storage/src/namespace_helpers.rs b/packages/storage/src/namespace_helpers.rs index c5d9ecd820..1c2650b911 100644 --- a/packages/storage/src/namespace_helpers.rs +++ b/packages/storage/src/namespace_helpers.rs @@ -1,6 +1,6 @@ use cosmwasm_std::Storage; #[cfg(feature = "iterator")] -use cosmwasm_std::{Order, Pair}; +use cosmwasm_std::{Order, Record}; pub(crate) fn get_with_prefix( storage: &dyn Storage, @@ -37,7 +37,7 @@ pub(crate) fn range_with_prefix<'a>( start: Option<&[u8]>, end: Option<&[u8]>, order: Order, -) -> Box + 'a> { +) -> Box + 'a> { // prepare start, end with prefix let start = match start { Some(s) => concat(namespace, s), @@ -153,7 +153,7 @@ mod tests { // 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(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -179,7 +179,7 @@ mod tests { set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy"); // make sure start and end are applied properly - let res: Vec = + let res: Vec = range_with_prefix(&storage, &prefix, Some(b"b"), Some(b"c"), Order::Ascending) .collect(); assert_eq!(res.len(), 1); @@ -196,7 +196,7 @@ mod tests { .count(); assert_eq!(res_count, 0); - let res: Vec = + 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())); diff --git a/packages/storage/src/prefixed_storage.rs b/packages/storage/src/prefixed_storage.rs index 53e30b2046..6d7779541a 100644 --- a/packages/storage/src/prefixed_storage.rs +++ b/packages/storage/src/prefixed_storage.rs @@ -1,6 +1,6 @@ use cosmwasm_std::Storage; #[cfg(feature = "iterator")] -use cosmwasm_std::{Order, Pair}; +use cosmwasm_std::{Order, Record}; use crate::length_prefixed::{to_length_prefixed, to_length_prefixed_nested}; #[cfg(feature = "iterator")] @@ -64,7 +64,7 @@ impl<'a> Storage for PrefixedStorage<'a> { start: Option<&[u8]>, end: Option<&[u8]>, order: Order, - ) -> Box + 'b> { + ) -> Box + 'b> { range_with_prefix(self.storage, &self.prefix, start, end, order) } } @@ -112,7 +112,7 @@ impl<'a> Storage for ReadonlyPrefixedStorage<'a> { start: Option<&[u8]>, end: Option<&[u8]>, order: Order, - ) -> Box + 'b> { + ) -> Box + 'b> { range_with_prefix(self.storage, &self.prefix, start, end, order) } } diff --git a/packages/storage/src/type_helpers.rs b/packages/storage/src/type_helpers.rs index a32bc3776a..6a36f074e2 100644 --- a/packages/storage/src/type_helpers.rs +++ b/packages/storage/src/type_helpers.rs @@ -2,7 +2,7 @@ use serde::de::DeserializeOwned; use std::any::type_name; #[cfg(feature = "iterator")] -use cosmwasm_std::Pair; +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 @@ -27,7 +27,7 @@ pub(crate) fn must_deserialize(value: &Option>) -> } #[cfg(feature = "iterator")] -pub(crate) fn deserialize_kv(kv: Pair>) -> StdResult> { +pub(crate) fn deserialize_kv(kv: Record>) -> StdResult> { let (k, v) = kv; let t = from_slice::(&v)?; Ok((k, t)) diff --git a/packages/vm/src/backend.rs b/packages/vm/src/backend.rs index 238ac5f4f5..25787786f4 100644 --- a/packages/vm/src/backend.rs +++ b/packages/vm/src/backend.rs @@ -5,7 +5,7 @@ use thiserror::Error; use cosmwasm_std::{Binary, ContractResult, SystemResult}; #[cfg(feature = "iterator")] -use cosmwasm_std::{Order, Pair}; +use cosmwasm_std::{Order, Record}; #[derive(Copy, Clone, Debug)] pub struct GasInfo { @@ -104,7 +104,7 @@ pub trait Storage { /// This call must not change data in the storage, but incrementing an iterator can be a mutating operation on /// the Storage implementation. #[cfg(feature = "iterator")] - fn next(&mut self, iterator_id: u32) -> BackendResult>; + fn next(&mut self, iterator_id: u32) -> BackendResult>; fn set(&mut self, key: &[u8], value: &[u8]) -> BackendResult<()>; diff --git a/packages/vm/src/testing/storage.rs b/packages/vm/src/testing/storage.rs index fb635224a8..d7d0dedd11 100644 --- a/packages/vm/src/testing/storage.rs +++ b/packages/vm/src/testing/storage.rs @@ -7,7 +7,7 @@ use std::convert::TryInto; use std::ops::{Bound, RangeBounds}; #[cfg(feature = "iterator")] -use cosmwasm_std::{Order, Pair}; +use cosmwasm_std::{Order, Record}; #[cfg(feature = "iterator")] use crate::BackendError; @@ -22,7 +22,7 @@ const GAS_COST_RANGE: u64 = 11; #[cfg(feature = "iterator")] #[derive(Default, Debug)] struct Iter { - data: Vec, + data: Vec, position: usize, } @@ -39,8 +39,8 @@ impl MockStorage { } #[cfg(feature = "iterator")] - pub fn all(&mut self, iterator_id: u32) -> BackendResult> { - let mut out: Vec = Vec::new(); + pub fn all(&mut self, iterator_id: u32) -> BackendResult> { + let mut out: Vec = Vec::new(); let mut total = GasInfo::free(); loop { let (result, info) = self.next(iterator_id); @@ -76,7 +76,7 @@ impl Storage for MockStorage { let gas_info = GasInfo::with_externally_used(GAS_COST_RANGE); let bounds = range_bounds(start, end); - let values: Vec = match (bounds.start_bound(), bounds.end_bound()) { + let values: Vec = match (bounds.start_bound(), bounds.end_bound()) { // BTreeMap.range panics if range is start > end. // However, this cases represent just empty range and we treat it as such. (Bound::Included(start), Bound::Excluded(end)) if start > end => Vec::new(), @@ -102,7 +102,7 @@ impl Storage for MockStorage { } #[cfg(feature = "iterator")] - fn next(&mut self, iterator_id: u32) -> BackendResult> { + fn next(&mut self, iterator_id: u32) -> BackendResult> { let iterator = match self.iterators.get_mut(&iterator_id) { Some(i) => i, None => { @@ -113,15 +113,15 @@ impl Storage for MockStorage { } }; - let (value, gas_info): (Option, GasInfo) = if iterator.data.len() > iterator.position - { - let item = iterator.data[iterator.position].clone(); - iterator.position += 1; - let gas_cost = (item.0.len() + item.1.len()) as u64; - (Some(item), GasInfo::with_cost(gas_cost)) - } else { - (None, GasInfo::with_externally_used(GAS_COST_LAST_ITERATION)) - }; + let (value, gas_info): (Option, GasInfo) = + if iterator.data.len() > iterator.position { + let item = iterator.data[iterator.position].clone(); + iterator.position += 1; + let gas_cost = (item.0.len() + item.1.len()) as u64; + (Some(item), GasInfo::with_cost(gas_cost)) + } else { + (None, GasInfo::with_externally_used(GAS_COST_LAST_ITERATION)) + }; (Ok(value), gas_info) } @@ -148,12 +148,12 @@ fn range_bounds(start: Option<&[u8]>, end: Option<&[u8]>) -> impl RangeBounds, T>::range. +/// The BTreeMap specific key-value pair reference type, as returned by BTreeMap, Vec>::range. /// This is internal as it can change any time if the map implementation is swapped out. -type BTreeMapPairRef<'a, T = Vec> = (&'a Vec, &'a T); +type BTreeMapRecordRef<'a> = (&'a Vec, &'a Vec); #[cfg(feature = "iterator")] -fn clone_item(item_ref: BTreeMapPairRef) -> Pair { +fn clone_item(item_ref: BTreeMapRecordRef) -> Record { let (key, value) = item_ref; (key.clone(), value.clone()) }