From 2107402c312dbc4faa90fd6468ae4e5622b59beb Mon Sep 17 00:00:00 2001 From: TomL94 Date: Thu, 28 Jul 2022 18:25:42 +0300 Subject: [PATCH 01/37] `packages/serialization` and `packages/storage` compiles --- .gitignore | 2 ++ Cargo.toml | 2 +- packages/serialization/Cargo.toml | 6 +++--- packages/storage/Cargo.toml | 4 ++-- packages/storage/src/append_store.rs | 20 ++++++++--------- packages/storage/src/lib.rs | 8 +++---- packages/toolkit/src/lib.rs | 32 ++++++++++++++-------------- 7 files changed, 38 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 66c02a1..43682a6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ target/ Cargo.lock .idea + +.vscode \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 5eafb8e..07fbd21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["packages/*"] +members = ["packages/storage", "packages/toolkit", "packages/serialization"] # Since `secret-toolkit` depends on all the other packages, this should make `cargo-check` a bit quicker # as it won't have to check all the other packages twice. default-members = ["packages/toolkit"] diff --git a/packages/serialization/Cargo.toml b/packages/serialization/Cargo.toml index d6781e2..80e00ff 100644 --- a/packages/serialization/Cargo.toml +++ b/packages/serialization/Cargo.toml @@ -21,9 +21,9 @@ base64 = ["schemars"] [dependencies] serde = "1.0" bincode2 = { version = "2.0", optional = true } -schemars = { version = "0.7", optional = true } -cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10" } +schemars = { version = "0.8.1", optional = true } +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } [dev-dependencies] serde_json = "1" -cosmwasm-schema = { version = "0.9.2" } +cosmwasm-schema = { version = "1.0" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index 5dcd60a..0461873 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -15,6 +15,6 @@ all-features = true [dependencies] serde = "1.0" -cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10" } -cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10" } +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } secret-toolkit-serialization = { version = "0.3", path = "../serialization" } diff --git a/packages/storage/src/append_store.rs b/packages/storage/src/append_store.rs index a9eb984..13b9ca2 100644 --- a/packages/storage/src/append_store.rs +++ b/packages/storage/src/append_store.rs @@ -8,7 +8,7 @@ use std::marker::PhantomData; use serde::{de::DeserializeOwned, Serialize}; -use cosmwasm_std::{ReadonlyStorage, StdError, StdResult, Storage}; +use cosmwasm_std::{StdError, StdResult, Storage}; use secret_toolkit_serialization::{Bincode2, Serde}; @@ -217,7 +217,7 @@ where pub struct AppendStore<'a, T, S, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, + S: Storage, Ser: Serde, { storage: &'a S, @@ -229,7 +229,7 @@ where impl<'a, T, S> AppendStore<'a, T, S, Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, + S: Storage, { /// Try to use the provided storage as an AppendStore. /// @@ -243,7 +243,7 @@ where impl<'a, T, S, Ser> AppendStore<'a, T, S, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, + S: Storage, Ser: Serde, { /// Try to use the provided storage as an AppendStore. @@ -314,7 +314,7 @@ where impl<'a, T, S, Ser> IntoIterator for AppendStore<'a, T, S, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, + S: Storage, Ser: Serde, { type Item = StdResult; @@ -334,7 +334,7 @@ where impl<'a, T, S, Ser> Clone for AppendStore<'a, T, S, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, + S: Storage, Ser: Serde, { fn clone(&self) -> Self { @@ -354,7 +354,7 @@ where pub struct Iter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, + S: Storage, Ser: Serde, { storage: AppendStore<'a, T, S, Ser>, @@ -365,7 +365,7 @@ where impl<'a, T, S, Ser> Iterator for Iter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, + S: Storage, Ser: Serde, { type Item = StdResult; @@ -400,7 +400,7 @@ where impl<'a, T, S, Ser> DoubleEndedIterator for Iter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, + S: Storage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -428,7 +428,7 @@ where impl<'a, T, S, Ser> ExactSizeIterator for Iter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, + S: Storage, Ser: Serde, { } diff --git a/packages/storage/src/lib.rs b/packages/storage/src/lib.rs index 0bacff8..cb99e83 100644 --- a/packages/storage/src/lib.rs +++ b/packages/storage/src/lib.rs @@ -1,7 +1,7 @@ pub mod append_store; -pub mod deque_store; -pub mod typed_store; +// pub mod deque_store; +// pub mod typed_store; pub use append_store::{AppendStore, AppendStoreMut}; -pub use deque_store::{DequeStore, DequeStoreMut}; -pub use typed_store::{TypedStore, TypedStoreMut}; +// pub use deque_store::{DequeStore, DequeStoreMut}; +// pub use typed_store::{TypedStore, TypedStoreMut}; diff --git a/packages/toolkit/src/lib.rs b/packages/toolkit/src/lib.rs index 2612edb..7e744cb 100644 --- a/packages/toolkit/src/lib.rs +++ b/packages/toolkit/src/lib.rs @@ -1,18 +1,18 @@ -#[cfg(feature = "crypto")] -pub use secret_toolkit_crypto as crypto; -#[cfg(feature = "incubator")] -pub use secret_toolkit_incubator as incubator; -#[cfg(feature = "permit")] -pub use secret_toolkit_permit as permit; -#[cfg(feature = "serialization")] -pub use secret_toolkit_serialization as serialization; -#[cfg(feature = "snip20")] -pub use secret_toolkit_snip20 as snip20; -#[cfg(feature = "snip721")] -pub use secret_toolkit_snip721 as snip721; +// #[cfg(feature = "crypto")] +// pub use secret_toolkit_crypto as crypto; +// #[cfg(feature = "incubator")] +// pub use secret_toolkit_incubator as incubator; +// #[cfg(feature = "permit")] +// pub use secret_toolkit_permit as permit; +// #[cfg(feature = "serialization")] +// pub use secret_toolkit_serialization as serialization; +// #[cfg(feature = "snip20")] +// pub use secret_toolkit_snip20 as snip20; +// #[cfg(feature = "snip721")] +// pub use secret_toolkit_snip721 as snip721; #[cfg(feature = "storage")] pub use secret_toolkit_storage as storage; -#[cfg(feature = "utils")] -pub use secret_toolkit_utils as utils; -#[cfg(feature = "viewing-key")] -pub use secret_toolkit_viewing_key as viewing_key; +// #[cfg(feature = "utils")] +// pub use secret_toolkit_utils as utils; +// #[cfg(feature = "viewing-key")] +// pub use secret_toolkit_viewing_key as viewing_key; From c1a5d802181806eb9a5522fa376f0dc89639e2ea Mon Sep 17 00:00:00 2001 From: TomL94 Date: Sun, 31 Jul 2022 18:38:41 +0300 Subject: [PATCH 02/37] Fixed `packages/crypto` --- Cargo.toml | 2 +- packages/crypto/Cargo.toml | 2 +- packages/crypto/src/secp256k1.rs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 07fbd21..7c5ab11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["packages/storage", "packages/toolkit", "packages/serialization"] +members = ["packages/storage", "packages/toolkit", "packages/serialization", "packages/crypto"] # Since `secret-toolkit` depends on all the other packages, this should make `cargo-check` a bit quicker # as it won't have to check all the other packages twice. default-members = ["packages/toolkit"] diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index 65ae1d1..f56fec8 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -23,7 +23,7 @@ rand_chacha = { version = "0.2.2", default-features = false, optional = true } rand_core = { version = "0.5.1", default-features = false, optional = true } sha2 = { version = "0.9.1", default-features = false, optional = true } secp256k1 = { version = "0.21.3", optional = true } -cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10" } +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } [dev-dependencies] secp256k1-test = { package = "secp256k1", version = "0.17", features = [ diff --git a/packages/crypto/src/secp256k1.rs b/packages/crypto/src/secp256k1.rs index ff25b4f..6448596 100644 --- a/packages/crypto/src/secp256k1.rs +++ b/packages/crypto/src/secp256k1.rs @@ -112,20 +112,20 @@ mod tests { } #[test] - #[ignore] // Crypto functions are not implemented in `MockApi` fn test_sign() { let s = Secp256k1::new(); let (secp_privkey, _) = s.generate_keypair(&mut thread_rng()); - let mock_api = MockApi::new(20); + let mock_api = MockApi::default(); let mut privkey = [0u8; PRIVATE_KEY_SIZE]; privkey.copy_from_slice(&secp_privkey[..]); - let data = sha_256(b"test"); + let data = b"test"; + let data_hash = sha_256(data); let pk = PrivateKey::parse(&privkey).unwrap(); - let signature = pk.sign(&data, mock_api); + let signature = pk.sign(data, mock_api); let pubkey = pk.pubkey(); - assert!(pubkey.verify(&data, signature, mock_api)); + assert!(pubkey.verify(&data_hash, signature, mock_api)); } } From 5700fbb6c0169d73df2332e0200873c63b22f133 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Sun, 31 Jul 2022 19:00:05 +0300 Subject: [PATCH 03/37] `packages/snip20` compiles --- packages/snip20/Cargo.toml | 4 +- packages/snip20/src/batch.rs | 43 +++++------ packages/snip20/src/handle.rs | 124 +++++++++++++++---------------- packages/snip20/src/query.rs | 133 ++++++++++++++++++---------------- 4 files changed, 154 insertions(+), 150 deletions(-) diff --git a/packages/snip20/Cargo.toml b/packages/snip20/Cargo.toml index 160f817..551914f 100644 --- a/packages/snip20/Cargo.toml +++ b/packages/snip20/Cargo.toml @@ -15,6 +15,6 @@ all-features = true [dependencies] serde = "1.0" -schemars = "0.7" -cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10" } +schemars = "0.8.1" +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } secret-toolkit-utils = { version = "0.3", path = "../utils" } diff --git a/packages/snip20/src/batch.rs b/packages/snip20/src/batch.rs index 41868f3..af9581c 100644 --- a/packages/snip20/src/batch.rs +++ b/packages/snip20/src/batch.rs @@ -1,18 +1,18 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Binary, HumanAddr, Uint128}; +use cosmwasm_std::{Binary, Uint128}; #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub struct TransferAction { - pub recipient: HumanAddr, + pub recipient: String, pub amount: Uint128, pub memo: Option, } impl TransferAction { - pub fn new(recipient: HumanAddr, amount: Uint128, memo: Option) -> Self { + pub fn new(recipient: String, amount: Uint128, memo: Option) -> Self { Self { recipient, amount, @@ -24,7 +24,7 @@ impl TransferAction { #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub struct SendAction { - pub recipient: HumanAddr, + pub recipient: String, pub recipient_code_hash: Option, pub amount: Uint128, pub msg: Option, @@ -33,7 +33,7 @@ pub struct SendAction { impl SendAction { pub fn new( - recipient: HumanAddr, + recipient: String, amount: Uint128, msg: Option, memo: Option, @@ -48,7 +48,7 @@ impl SendAction { } pub fn new_with_code_hash( - recipient: HumanAddr, + recipient: String, recipient_code_hash: Option, amount: Uint128, msg: Option, @@ -67,19 +67,14 @@ impl SendAction { #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub struct TransferFromAction { - pub owner: HumanAddr, - pub recipient: HumanAddr, + pub owner: String, + pub recipient: String, pub amount: Uint128, pub memo: Option, } impl TransferFromAction { - pub fn new( - owner: HumanAddr, - recipient: HumanAddr, - amount: Uint128, - memo: Option, - ) -> Self { + pub fn new(owner: String, recipient: String, amount: Uint128, memo: Option) -> Self { Self { owner, recipient, @@ -92,8 +87,8 @@ impl TransferFromAction { #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub struct SendFromAction { - pub owner: HumanAddr, - pub recipient: HumanAddr, + pub owner: String, + pub recipient: String, pub recipient_code_hash: Option, pub amount: Uint128, pub msg: Option, @@ -102,8 +97,8 @@ pub struct SendFromAction { impl SendFromAction { pub fn new( - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, amount: Uint128, msg: Option, memo: Option, @@ -119,8 +114,8 @@ impl SendFromAction { } pub fn new_with_code_hash( - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, recipient_code_hash: Option, amount: Uint128, msg: Option, @@ -140,13 +135,13 @@ impl SendFromAction { #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub struct MintAction { - pub recipient: HumanAddr, + pub recipient: String, pub amount: Uint128, pub memo: Option, } impl MintAction { - pub fn new(recipient: HumanAddr, amount: Uint128, memo: Option) -> Self { + pub fn new(recipient: String, amount: Uint128, memo: Option) -> Self { Self { recipient, amount, @@ -158,13 +153,13 @@ impl MintAction { #[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub struct BurnFromAction { - pub owner: HumanAddr, + pub owner: String, pub amount: Uint128, pub memo: Option, } impl BurnFromAction { - pub fn new(owner: HumanAddr, amount: Uint128, memo: Option) -> Self { + pub fn new(owner: String, amount: Uint128, memo: Option) -> Self { Self { owner, amount, diff --git a/packages/snip20/src/handle.rs b/packages/snip20/src/handle.rs index 4952d68..0ce79e3 100644 --- a/packages/snip20/src/handle.rs +++ b/packages/snip20/src/handle.rs @@ -1,6 +1,6 @@ use serde::Serialize; -use cosmwasm_std::{to_binary, Binary, Coin, CosmosMsg, HumanAddr, StdResult, Uint128, WasmMsg}; +use cosmwasm_std::{to_binary, Binary, Coin, CosmosMsg, StdResult, Uint128, WasmMsg}; use crate::batch::{ BurnFromAction, MintAction, SendAction, SendFromAction, TransferAction, TransferFromAction, @@ -25,13 +25,13 @@ pub enum HandleMsg { // Basic SNIP20 functions Transfer { - recipient: HumanAddr, + recipient: String, amount: Uint128, memo: Option, padding: Option, }, Send { - recipient: HumanAddr, + recipient: String, recipient_code_hash: Option, amount: Uint128, msg: Option, @@ -66,27 +66,27 @@ pub enum HandleMsg { // Allowance functions IncreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expiration: Option, padding: Option, }, DecreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expiration: Option, padding: Option, }, TransferFrom { - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, amount: Uint128, memo: Option, padding: Option, }, SendFrom { - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, recipient_code_hash: Option, amount: Uint128, msg: Option, @@ -102,7 +102,7 @@ pub enum HandleMsg { padding: Option, }, BurnFrom { - owner: HumanAddr, + owner: String, amount: Uint128, memo: Option, padding: Option, @@ -114,7 +114,7 @@ pub enum HandleMsg { // Mint Mint { - recipient: HumanAddr, + recipient: String, amount: Uint128, memo: Option, padding: Option, @@ -124,15 +124,15 @@ pub enum HandleMsg { padding: Option, }, AddMinters { - minters: Vec, + minters: Vec, padding: Option, }, RemoveMinters { - minters: Vec, + minters: Vec, padding: Option, }, SetMinters { - minters: Vec, + minters: Vec, padding: Option, }, } @@ -150,8 +150,8 @@ impl HandleMsg { pub fn to_cosmos_msg( &self, mut block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, send_amount: Option, ) -> StdResult { // can not have block size of 0 @@ -160,18 +160,18 @@ impl HandleMsg { } let mut msg = to_binary(self)?; space_pad(&mut msg.0, block_size); - let mut send = Vec::new(); + let mut funds = Vec::new(); if let Some(amount) = send_amount { - send.push(Coin { + funds.push(Coin { amount, denom: String::from("uscrt"), }); } let execute = WasmMsg::Execute { - msg, contract_addr, - callback_code_hash, - send, + code_hash, + msg, + funds, }; Ok(execute.into()) } @@ -193,7 +193,7 @@ pub fn redeem_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::Redeem { amount, @@ -217,7 +217,7 @@ pub fn deposit_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::Deposit { padding }.to_cosmos_msg( block_size, @@ -239,13 +239,13 @@ pub fn deposit_msg( /// * `callback_code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn transfer_msg( - recipient: HumanAddr, + recipient: String, amount: Uint128, memo: Option, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::Transfer { recipient, @@ -271,14 +271,14 @@ pub fn transfer_msg( /// * `contract_addr` - address of the contract being called #[allow(clippy::too_many_arguments)] pub fn send_msg( - recipient: HumanAddr, + recipient: String, amount: Uint128, msg: Option, memo: Option, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::Send { recipient, @@ -307,7 +307,7 @@ pub fn send_msg( /// * `contract_addr` - address of the contract being called #[allow(clippy::too_many_arguments)] pub fn send_msg_with_code_hash( - recipient: HumanAddr, + recipient: String, recipient_code_hash: Option, amount: Uint128, msg: Option, @@ -315,7 +315,7 @@ pub fn send_msg_with_code_hash( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::Send { recipient, @@ -341,7 +341,7 @@ pub fn batch_transfer_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::BatchTransfer { actions, padding }.to_cosmos_msg( block_size, @@ -364,7 +364,7 @@ pub fn batch_send_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::BatchSend { actions, padding }.to_cosmos_msg( block_size, @@ -390,7 +390,7 @@ pub fn burn_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::Burn { amount, @@ -413,7 +413,7 @@ pub fn create_viewing_key_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::CreateViewingKey { entropy, padding }.to_cosmos_msg( block_size, @@ -437,7 +437,7 @@ pub fn register_receive_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::RegisterReceive { code_hash: your_contracts_code_hash, @@ -460,7 +460,7 @@ pub fn set_viewing_key_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::SetViewingKey { key, padding }.to_cosmos_msg( block_size, @@ -482,13 +482,13 @@ pub fn set_viewing_key_msg( /// * `callback_code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn increase_allowance_msg( - spender: HumanAddr, + spender: String, amount: Uint128, expiration: Option, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::IncreaseAllowance { spender, @@ -511,13 +511,13 @@ pub fn increase_allowance_msg( /// * `callback_code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn decrease_allowance_msg( - spender: HumanAddr, + spender: String, amount: Uint128, expiration: Option, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::DecreaseAllowance { spender, @@ -542,14 +542,14 @@ pub fn decrease_allowance_msg( /// * `contract_addr` - address of the contract being called #[allow(clippy::too_many_arguments)] pub fn transfer_from_msg( - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, amount: Uint128, memo: Option, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::TransferFrom { owner, @@ -577,15 +577,15 @@ pub fn transfer_from_msg( /// * `contract_addr` - address of the contract being called #[allow(clippy::too_many_arguments)] pub fn send_from_msg( - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, amount: Uint128, msg: Option, memo: Option, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::SendFrom { owner, @@ -616,8 +616,8 @@ pub fn send_from_msg( /// * `contract_addr` - address of the contract being called #[allow(clippy::too_many_arguments)] pub fn send_from_msg_with_code_hash( - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, recipient_code_hash: Option, amount: Uint128, msg: Option, @@ -625,7 +625,7 @@ pub fn send_from_msg_with_code_hash( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::SendFrom { owner, @@ -652,7 +652,7 @@ pub fn batch_transfer_from_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::BatchTransferFrom { actions, padding }.to_cosmos_msg( block_size, @@ -675,7 +675,7 @@ pub fn batch_send_from_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::BatchSendFrom { actions, padding }.to_cosmos_msg( block_size, @@ -697,13 +697,13 @@ pub fn batch_send_from_msg( /// * `callback_code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn burn_from_msg( - owner: HumanAddr, + owner: String, amount: Uint128, memo: Option, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::BurnFrom { owner, @@ -727,7 +727,7 @@ pub fn batch_burn_from_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::BatchBurnFrom { actions, padding }.to_cosmos_msg( block_size, @@ -749,13 +749,13 @@ pub fn batch_burn_from_msg( /// * `callback_code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn mint_msg( - recipient: HumanAddr, + recipient: String, amount: Uint128, memo: Option, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::Mint { recipient, @@ -779,7 +779,7 @@ pub fn batch_mint_msg( padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::BatchMint { actions, padding }.to_cosmos_msg( block_size, @@ -799,11 +799,11 @@ pub fn batch_mint_msg( /// * `callback_code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn add_minters_msg( - minters: Vec, + minters: Vec, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::AddMinters { minters, padding }.to_cosmos_msg( block_size, @@ -823,11 +823,11 @@ pub fn add_minters_msg( /// * `callback_code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn remove_minters_msg( - minters: Vec, + minters: Vec, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::RemoveMinters { minters, padding }.to_cosmos_msg( block_size, @@ -847,11 +847,11 @@ pub fn remove_minters_msg( /// * `callback_code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn set_minters_msg( - minters: Vec, + minters: Vec, padding: Option, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { HandleMsg::SetMinters { minters, padding }.to_cosmos_msg( block_size, diff --git a/packages/snip20/src/query.rs b/packages/snip20/src/query.rs index c8046a7..339e542 100644 --- a/packages/snip20/src/query.rs +++ b/packages/snip20/src/query.rs @@ -3,7 +3,8 @@ use schemars::JsonSchema; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use cosmwasm_std::{ - to_binary, Coin, HumanAddr, Querier, QueryRequest, StdError, StdResult, Uint128, WasmQuery, + to_binary, Coin, CustomQuery, QuerierWrapper, QueryRequest, StdError, StdResult, Uint128, + WasmQuery, }; use secret_toolkit_utils::space_pad; @@ -52,8 +53,8 @@ pub struct ExchangeRate { /// Allowance response #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Allowance { - pub spender: HumanAddr, - pub owner: HumanAddr, + pub spender: String, + pub owner: String, pub allowance: Uint128, #[serde(skip_serializing_if = "Option::is_none")] pub expiration: Option, @@ -69,9 +70,9 @@ pub struct Balance { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Tx { pub id: u64, - pub from: HumanAddr, - pub sender: HumanAddr, - pub receiver: HumanAddr, + pub from: String, + pub sender: String, + pub receiver: String, pub coins: Coin, #[serde(skip_serializing_if = "Option::is_none")] pub memo: Option, @@ -93,17 +94,17 @@ pub struct TransferHistory { #[serde(rename_all = "snake_case")] pub enum TxAction { Transfer { - from: HumanAddr, - sender: HumanAddr, - recipient: HumanAddr, + from: String, + sender: String, + recipient: String, }, Mint { - minter: HumanAddr, - recipient: HumanAddr, + minter: String, + recipient: String, }, Burn { - burner: HumanAddr, - owner: HumanAddr, + burner: String, + owner: String, }, Deposit {}, Redeem {}, @@ -131,7 +132,7 @@ pub struct TransactionHistory { /// Minters response #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Minters { - pub minters: Vec, + pub minters: Vec, } /// SNIP20 queries @@ -143,22 +144,22 @@ pub enum QueryMsg { ContractStatus {}, ExchangeRate {}, Allowance { - owner: HumanAddr, - spender: HumanAddr, + owner: String, + spender: String, key: String, }, Balance { - address: HumanAddr, + address: String, key: String, }, TransferHistory { - address: HumanAddr, + address: String, key: String, page: Option, page_size: u32, }, TransactionHistory { - address: HumanAddr, + address: String, key: String, page: Option, page_size: u32, @@ -191,12 +192,12 @@ impl QueryMsg { /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried - pub fn query( + pub fn query<'a, C: CustomQuery, T: DeserializeOwned>( &self, - querier: &Q, + querier: QuerierWrapper<'a, C>, mut block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { // can not have block size of 0 if block_size == 0 { @@ -207,7 +208,7 @@ impl QueryMsg { querier .query(&QueryRequest::Wasm(WasmQuery::Smart { contract_addr, - callback_code_hash, + code_hash, msg, })) .map_err(|err| { @@ -221,8 +222,8 @@ impl QueryMsg { #[serde(rename_all = "snake_case")] pub enum AuthenticatedQueryResponse { Allowance { - spender: HumanAddr, - owner: HumanAddr, + spender: String, + owner: String, allowance: Uint128, expiration: Option, }, @@ -279,11 +280,11 @@ pub struct MintersResponse { /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn token_info_query( - querier: &Q, +pub fn token_info_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { let answer: TokenInfoResponse = QueryMsg::TokenInfo {}.query(querier, block_size, callback_code_hash, contract_addr)?; @@ -298,11 +299,11 @@ pub fn token_info_query( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn token_config_query( - querier: &Q, +pub fn token_config_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { let answer: TokenConfigResponse = QueryMsg::TokenConfig {}.query(querier, block_size, callback_code_hash, contract_addr)?; @@ -317,11 +318,11 @@ pub fn token_config_query( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn contract_status_query( - querier: &Q, +pub fn contract_status_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { let answer: ContractStatusResponse = QueryMsg::ContractStatus {}.query( querier, @@ -340,11 +341,11 @@ pub fn contract_status_query( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn exchange_rate_query( - querier: &Q, +pub fn exchange_rate_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { let answer: ExchangeRateResponse = QueryMsg::ExchangeRate {}.query(querier, block_size, callback_code_hash, contract_addr)?; @@ -363,14 +364,14 @@ pub fn exchange_rate_query( /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn allowance_query( - querier: &Q, - owner: HumanAddr, - spender: HumanAddr, +pub fn allowance_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, + owner: String, + spender: String, key: String, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { let answer: AuthenticatedQueryResponse = QueryMsg::Allowance { owner, @@ -390,7 +391,9 @@ pub fn allowance_query( allowance, expiration, }), - AuthenticatedQueryResponse::ViewingKeyError { .. } => Err(StdError::unauthorized()), + AuthenticatedQueryResponse::ViewingKeyError { .. } => { + Err(StdError::generic_err("unaithorized")) + } _ => Err(StdError::generic_err("Invalid Allowance query response")), } } @@ -405,13 +408,13 @@ pub fn allowance_query( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn balance_query( - querier: &Q, - address: HumanAddr, +pub fn balance_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, + address: String, key: String, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { let answer: AuthenticatedQueryResponse = QueryMsg::Balance { address, key }.query( querier, @@ -421,7 +424,9 @@ pub fn balance_query( )?; match answer { AuthenticatedQueryResponse::Balance { amount } => Ok(Balance { amount }), - AuthenticatedQueryResponse::ViewingKeyError { .. } => Err(StdError::unauthorized()), + AuthenticatedQueryResponse::ViewingKeyError { .. } => { + Err(StdError::generic_err("unaithorized")) + } _ => Err(StdError::generic_err("Invalid Balance query response")), } } @@ -439,15 +444,15 @@ pub fn balance_query( /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn transfer_history_query( - querier: &Q, - address: HumanAddr, +pub fn transfer_history_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, + address: String, key: String, page: Option, page_size: u32, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { let answer: AuthenticatedQueryResponse = QueryMsg::TransferHistory { address, @@ -460,7 +465,9 @@ pub fn transfer_history_query( AuthenticatedQueryResponse::TransferHistory { txs, total } => { Ok(TransferHistory { txs, total }) } - AuthenticatedQueryResponse::ViewingKeyError { .. } => Err(StdError::unauthorized()), + AuthenticatedQueryResponse::ViewingKeyError { .. } => { + Err(StdError::generic_err("unaithorized")) + } _ => Err(StdError::generic_err( "Invalid TransferHistory query response", )), @@ -480,15 +487,15 @@ pub fn transfer_history_query( /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn transaction_history_query( - querier: &Q, - address: HumanAddr, +pub fn transaction_history_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, + address: String, key: String, page: Option, page_size: u32, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { let answer: AuthenticatedQueryResponse = QueryMsg::TransactionHistory { address, @@ -501,7 +508,9 @@ pub fn transaction_history_query( AuthenticatedQueryResponse::TransactionHistory { txs, total } => { Ok(TransactionHistory { txs, total }) } - AuthenticatedQueryResponse::ViewingKeyError { .. } => Err(StdError::unauthorized()), + AuthenticatedQueryResponse::ViewingKeyError { .. } => { + Err(StdError::generic_err("unaithorized")) + } _ => Err(StdError::generic_err( "Invalid TransactionHistory query response", )), @@ -516,11 +525,11 @@ pub fn transaction_history_query( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn minters_query( - querier: &Q, +pub fn minters_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, block_size: usize, callback_code_hash: String, - contract_addr: HumanAddr, + contract_addr: String, ) -> StdResult { let answer: MintersResponse = QueryMsg::Minters {}.query(querier, block_size, callback_code_hash, contract_addr)?; From 460f97bb0713993a2451072229206a9aed4b141a Mon Sep 17 00:00:00 2001 From: TomL94 Date: Mon, 1 Aug 2022 15:05:38 +0300 Subject: [PATCH 04/37] snip721 --- Cargo.toml | 2 +- packages/snip721/Cargo.toml | 4 +- packages/snip721/src/expiration.rs | 9 +- packages/snip721/src/handle.rs | 486 ++++++++--------- packages/snip721/src/query.rs | 846 +++++++++++++++-------------- 5 files changed, 701 insertions(+), 646 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7c5ab11..44205c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["packages/storage", "packages/toolkit", "packages/serialization", "packages/crypto"] +members = ["packages/storage", "packages/toolkit", "packages/serialization", "packages/crypto", "packages/snip20", "packages/snip721"] # Since `secret-toolkit` depends on all the other packages, this should make `cargo-check` a bit quicker # as it won't have to check all the other packages twice. default-members = ["packages/toolkit"] diff --git a/packages/snip721/Cargo.toml b/packages/snip721/Cargo.toml index 01aee26..a5bc93f 100644 --- a/packages/snip721/Cargo.toml +++ b/packages/snip721/Cargo.toml @@ -15,6 +15,6 @@ all-features = true [dependencies] serde = "1.0" -schemars = "0.7" -cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10" } +schemars = "0.8.1" +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } secret-toolkit-utils = { version = "0.3", path = "../utils" } diff --git a/packages/snip721/src/expiration.rs b/packages/snip721/src/expiration.rs index 263fb78..a376af3 100644 --- a/packages/snip721/src/expiration.rs +++ b/packages/snip721/src/expiration.rs @@ -42,7 +42,8 @@ impl Expiration { pub fn is_expired(&self, block: &BlockInfo) -> bool { match self { Expiration::AtHeight(height) => block.height >= *height, - Expiration::AtTime(time) => block.time >= *time, + // When snip721 will be migrated, `time` might be a Timestamp. For now, just keeping it compatible + Expiration::AtTime(time) => block.time.seconds() >= *time, Expiration::Never => false, } } @@ -50,19 +51,21 @@ impl Expiration { #[cfg(test)] mod test { + use cosmwasm_std::Timestamp; + use super::*; #[test] fn test_expiration() { let block_h1000_t1000000 = BlockInfo { height: 1000, - time: 1000000, + time: Timestamp::from_seconds(1000000), chain_id: "test".to_string(), }; let block_h2000_t2000000 = BlockInfo { height: 2000, - time: 2000000, + time: Timestamp::from_seconds(2000000), chain_id: "test".to_string(), }; let exp_h1000 = Expiration::AtHeight(1000); diff --git a/packages/snip721/src/handle.rs b/packages/snip721/src/handle.rs index 431715e..66fc8fc 100644 --- a/packages/snip721/src/handle.rs +++ b/packages/snip721/src/handle.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{to_binary, Binary, Coin, CosmosMsg, HumanAddr, StdResult, Uint128, WasmMsg}; +use cosmwasm_std::{to_binary, Binary, Coin, CosmosMsg, StdResult, Uint128, WasmMsg}; use crate::expiration::Expiration; use crate::metadata::Metadata; @@ -37,7 +37,7 @@ pub struct Mint { /// optional token id. if omitted, use current token index pub token_id: Option, /// optional owner address. if omitted, owned by the message sender - pub owner: Option, + pub owner: Option, /// optional public metadata that can be seen by everyone pub public_metadata: Option, /// optional private metadata that can only be seen by the owner and whitelist @@ -59,7 +59,7 @@ pub struct Burn { #[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] pub struct Transfer { /// recipient of the transferred tokens - pub recipient: HumanAddr, + pub recipient: String, /// tokens being transferred pub token_ids: Vec, /// optional memo for the tx @@ -70,7 +70,7 @@ pub struct Transfer { #[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] pub struct Send { /// recipient of the sent tokens - pub contract: HumanAddr, + pub contract: String, /// tokens being sent pub token_ids: Vec, /// optional message to send with the (Batch)RecieveNft callback @@ -89,7 +89,7 @@ pub enum HandleMsg { /// transfer a token TransferNft { /// recipient of the transfer - recipient: HumanAddr, + recipient: String, /// id of the token to transfer token_id: String, /// optional memo for the tx @@ -100,7 +100,7 @@ pub enum HandleMsg { /// send a token and call receiving contract's (Batch)ReceiveNft SendNft { /// address to send the token to - contract: HumanAddr, + contract: String, /// id of the token to send token_id: String, /// optional message to send with the (Batch)RecieveNft callback @@ -115,7 +115,7 @@ pub enum HandleMsg { /// you are an operator, you can only use Approve Approve { /// address being granted the permission - spender: HumanAddr, + spender: String, /// id of the token that the spender can transfer token_id: String, /// optional expiration for this approval @@ -129,7 +129,7 @@ pub enum HandleMsg { /// of another operator Revoke { /// address whose permission is revoked - spender: HumanAddr, + spender: String, /// id of the token that the spender can no longer transfer token_id: String, /// optional message length padding @@ -139,7 +139,7 @@ pub enum HandleMsg { /// gives the operator permission to transfer all of the message sender's tokens ApproveAll { /// address being granted permission to transfer - operator: HumanAddr, + operator: String, /// optional expiration for this approval expires: Option, /// optional message length padding @@ -149,7 +149,7 @@ pub enum HandleMsg { /// revokes the operator's permission to transfer any of the message sender's tokens RevokeAll { /// address whose permissions are revoked - operator: HumanAddr, + operator: String, /// optional message length padding padding: Option, }, @@ -157,7 +157,7 @@ pub enum HandleMsg { /// that are omitted will keep the current permission setting for that whitelist address SetWhitelistedApproval { /// address being granted/revoked permission - address: HumanAddr, + address: String, /// optional token id to apply approval/revocation to token_id: Option, /// optional permission level for viewing the owner @@ -201,7 +201,7 @@ pub enum HandleMsg { /// optional token id. if omitted, uses current token index token_id: Option, /// optional owner address. if omitted, owned by the message sender - owner: Option, + owner: Option, /// optional public metadata that can be seen by everyone public_metadata: Option, /// optional private metadata that can only be seen by the owner and whitelist @@ -214,21 +214,21 @@ pub enum HandleMsg { /// add addresses with minting authority AddMinters { /// list of addresses that can now mint - minters: Vec, + minters: Vec, /// optional message length padding padding: Option, }, /// revoke minting authority from addresses RemoveMinters { /// list of addresses no longer allowed to mint - minters: Vec, + minters: Vec, /// optional message length padding padding: Option, }, /// define list of addresses with minting authority SetMinters { /// list of addresses with minting authority - minters: Vec, + minters: Vec, /// optional message length padding padding: Option, }, @@ -324,7 +324,7 @@ impl HandleMsg { /// # Arguments /// /// * `block_size` - pad the message to blocks of this size - /// * `callback_code_hash` - String holding the code hash of the contract being called + /// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called /// * `send_amount` - Optional Uint128 amount of native coin to send with the callback message /// NOTE: No SNIP721 messages send native coin, but the parameter is @@ -332,8 +332,8 @@ impl HandleMsg { pub fn to_cosmos_msg( &self, mut block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, send_amount: Option, ) -> StdResult { // can not have block size of 0 @@ -342,9 +342,9 @@ impl HandleMsg { } let mut msg = to_binary(self)?; space_pad(&mut msg.0, block_size); - let mut send = Vec::new(); + let mut funds = Vec::new(); if let Some(amount) = send_amount { - send.push(Coin { + funds.push(Coin { amount, denom: String::from("uscrt"), }); @@ -352,8 +352,8 @@ impl HandleMsg { let execute = WasmMsg::Execute { msg, contract_addr, - callback_code_hash, - send, + code_hash, + funds, }; Ok(execute.into()) } @@ -372,16 +372,16 @@ impl HandleMsg { /// * `memo` - Optional String memo for the tx /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn transfer_nft_msg( - recipient: HumanAddr, + recipient: String, token_id: String, memo: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::TransferNft { recipient, @@ -389,7 +389,7 @@ pub fn transfer_nft_msg( memo, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } /// Returns a StdResult used to execute [`SendNft`](HandleMsg::SendNft) @@ -404,18 +404,18 @@ pub fn transfer_nft_msg( /// * `memo` - Optional String memo for the tx /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called #[allow(clippy::too_many_arguments)] pub fn send_nft_msg( - contract: HumanAddr, + contract: String, token_id: String, msg: Option, memo: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::SendNft { contract, @@ -424,7 +424,7 @@ pub fn send_nft_msg( memo, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } /// Returns a StdResult used to execute [`Approve`](HandleMsg::Approve) @@ -436,16 +436,16 @@ pub fn send_nft_msg( /// * `expires` - Optional Expiration of this approval /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn approve_msg( - spender: HumanAddr, + spender: String, token_id: String, expires: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::Approve { spender, @@ -453,7 +453,7 @@ pub fn approve_msg( expires, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } /// Returns a StdResult used to execute [`Revoke`](HandleMsg::Revoke) @@ -464,22 +464,22 @@ pub fn approve_msg( /// * `token_id` - ID String of the token that can no longer be transferred /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn revoke_msg( - spender: HumanAddr, + spender: String, token_id: String, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::Revoke { spender, token_id, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } /// Returns a StdResult used to execute [`ApproveAll`](HandleMsg::ApproveAll) @@ -490,22 +490,22 @@ pub fn revoke_msg( /// * `expires` - Optional Expiration of this approval /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn approve_all_msg( - operator: HumanAddr, + operator: String, expires: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::ApproveAll { operator, expires, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } /// Returns a StdResult used to execute [`RevokeAll`](HandleMsg::RevokeAll) @@ -515,18 +515,18 @@ pub fn approve_all_msg( /// * `operator` - the address whose permission to transfer tokens is being revoked /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn revoke_all_msg( - operator: HumanAddr, + operator: String, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::RevokeAll { operator, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -544,11 +544,11 @@ pub fn revoke_all_msg( /// * `expires` - Optional Expiration of any approvals in this message /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called #[allow(clippy::too_many_arguments)] pub fn set_whitelisted_approval_msg( - address: HumanAddr, + address: String, token_id: Option, view_owner: Option, view_private_metadata: Option, @@ -556,8 +556,8 @@ pub fn set_whitelisted_approval_msg( expires: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::SetWhitelistedApproval { address, @@ -568,7 +568,7 @@ pub fn set_whitelisted_approval_msg( expires, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } /// Returns a StdResult used to execute [`RegisterReceiveNft`](HandleMsg::RegisterReceiveNft) @@ -580,22 +580,22 @@ pub fn set_whitelisted_approval_msg( /// implements BatchReceiveNft. Defaults to false if omitted /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn register_receive_nft_msg( your_contracts_code_hash: String, also_implements_batch_receive_nft: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::RegisterReceiveNft { code_hash: your_contracts_code_hash, also_implements_batch_receive_nft, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } /// Returns a StdResult used to execute [`SetViewingKey`](HandleMsg::SetViewingKey) @@ -605,18 +605,18 @@ pub fn register_receive_nft_msg( /// * `key` - String holding the authentication key used for later queries /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn set_viewing_key_msg( key: String, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::SetViewingKey { key, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -640,19 +640,19 @@ pub fn set_viewing_key_msg( /// * `memo` - Optional String memo for the tx /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called #[allow(clippy::too_many_arguments)] pub fn mint_nft_msg( token_id: Option, - owner: Option, + owner: Option, public_metadata: Option, private_metadata: Option, memo: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::MintNft { token_id, @@ -662,7 +662,7 @@ pub fn mint_nft_msg( memo, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } /// Returns a StdResult used to execute [`AddMinters`](HandleMsg::AddMinters) @@ -672,18 +672,18 @@ pub fn mint_nft_msg( /// * `minters` - list of new addresses that will be allowed to mint /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn add_minters_msg( - minters: Vec, + minters: Vec, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::AddMinters { minters, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -696,18 +696,18 @@ pub fn add_minters_msg( /// * `minters` - list of addresses that are no longer allowed to mint /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn remove_minters_msg( - minters: Vec, + minters: Vec, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::RemoveMinters { minters, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -720,18 +720,18 @@ pub fn remove_minters_msg( /// * `minters` - list of the only addresses that are allowed to mint /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn set_minters_msg( - minters: Vec, + minters: Vec, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::SetMinters { minters, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -746,7 +746,7 @@ pub fn set_minters_msg( /// * `private_metadata` - optional new Metadata that only the owner and whitelist can view /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn set_metadata_msg( token_id: String, @@ -754,8 +754,8 @@ pub fn set_metadata_msg( private_metadata: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::SetMetadata { token_id, @@ -763,7 +763,7 @@ pub fn set_metadata_msg( private_metadata, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } // @@ -777,18 +777,18 @@ pub fn set_metadata_msg( /// * `mints` - list of mint operations to perform /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn batch_mint_nft_msg( mints: Vec, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::BatchMintNft { mints, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -801,18 +801,18 @@ pub fn batch_mint_nft_msg( /// * `transfers` - list of Transfers to perform /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn batch_transfer_nft_msg( transfers: Vec, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::BatchTransferNft { transfers, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -825,18 +825,18 @@ pub fn batch_transfer_nft_msg( /// * `sends` - list of Sends to perform /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn batch_send_nft_msg( sends: Vec, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::BatchSendNft { sends, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -854,22 +854,22 @@ pub fn batch_send_nft_msg( /// * `memo` - Optional String memo for the tx /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn burn_nft_msg( token_id: String, memo: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::BurnNft { token_id, memo, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } /// Returns a StdResult used to execute [`BatchBurnNft`](HandleMsg::BatchBurnNft) @@ -879,18 +879,18 @@ pub fn burn_nft_msg( /// * `burns` - list of Burns to perform /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn batch_burn_nft_msg( burns: Vec, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::BatchBurnNft { burns, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -910,7 +910,7 @@ pub fn batch_burn_nft_msg( /// * `expires` - Optional Expiration of any approvals in this message /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called #[allow(clippy::too_many_arguments)] pub fn set_global_approval_msg( @@ -920,8 +920,8 @@ pub fn set_global_approval_msg( expires: Option, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::SetGlobalApproval { token_id, @@ -930,7 +930,7 @@ pub fn set_global_approval_msg( expires, padding, } - .to_cosmos_msg(block_size, callback_code_hash, contract_addr, None) + .to_cosmos_msg(block_size, code_hash, contract_addr, None) } // @@ -944,18 +944,18 @@ pub fn set_global_approval_msg( /// * `token_id` - ID String of the token to unwrap /// * `padding` - Optional String used as padding if you don't want to use block padding /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being called +/// * `code_hash` - String holding the code hash of the contract being called /// * `contract_addr` - address of the contract being called pub fn reveal_msg( token_id: String, padding: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { HandleMsg::Reveal { token_id, padding }.to_cosmos_msg( block_size, - callback_code_hash, + code_hash, contract_addr, None, ) @@ -969,12 +969,12 @@ mod tests { #[test] fn test_transfer_nft_msg() -> StdResult<()> { - let recipient = HumanAddr("alice".to_string()); + let recipient = "alice".to_string(); let token_id = "NFT1".to_string(); let memo = Some("memo".to_string()); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = transfer_nft_msg( recipient.clone(), @@ -982,7 +982,7 @@ mod tests { memo.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::TransferNft { @@ -995,8 +995,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1004,13 +1004,13 @@ mod tests { #[test] fn test_send_nft_msg() -> StdResult<()> { - let contract = HumanAddr("alice".to_string()); - let recipient = HumanAddr("bob".to_string()); + let contract = "alice".to_string(); + let recipient = "bob".to_string(); let token_id = "NFT1".to_string(); let memo = Some("memo".to_string()); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); // just using an arbitrary msg let send_msg = Some(to_binary(&HandleMsg::TransferNft { recipient, @@ -1025,7 +1025,7 @@ mod tests { memo.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::SendNft { @@ -1039,8 +1039,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1048,12 +1048,12 @@ mod tests { #[test] fn test_approve_msg() -> StdResult<()> { - let spender = HumanAddr("alice".to_string()); + let spender = "alice".to_string(); let token_id = "NFT1".to_string(); let expires = Some(Expiration::AtHeight(1000000)); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = approve_msg( spender.clone(), @@ -1061,7 +1061,7 @@ mod tests { expires.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::Approve { @@ -1074,8 +1074,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1083,18 +1083,18 @@ mod tests { #[test] fn test_revoke_msg() -> StdResult<()> { - let spender = HumanAddr("alice".to_string()); + let spender = "alice".to_string(); let token_id = "NFT1".to_string(); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = revoke_msg( spender.clone(), token_id.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::Revoke { @@ -1106,8 +1106,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1115,18 +1115,18 @@ mod tests { #[test] fn test_approve_all_msg() -> StdResult<()> { - let operator = HumanAddr("alice".to_string()); + let operator = "alice".to_string(); let expires = Some(Expiration::AtHeight(1000000)); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = approve_all_msg( operator.clone(), expires.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::ApproveAll { @@ -1138,8 +1138,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1147,16 +1147,16 @@ mod tests { #[test] fn test_revoke_all_msg() -> StdResult<()> { - let operator = HumanAddr("alice".to_string()); + let operator = "alice".to_string(); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = revoke_all_msg( operator.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::RevokeAll { operator, padding })?; @@ -1164,8 +1164,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1173,15 +1173,15 @@ mod tests { #[test] fn test_set_whitelisted_approval_msg() -> StdResult<()> { - let address = HumanAddr("alice".to_string()); + let address = "alice".to_string(); let token_id = Some("NFT1".to_string()); let view_owner = Some(AccessLevel::All); let view_private_metadata = None; let transfer = Some(AccessLevel::RevokeToken); let expires = Some(Expiration::AtTime(1000000000)); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = set_whitelisted_approval_msg( address.clone(), @@ -1192,7 +1192,7 @@ mod tests { expires.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::SetWhitelistedApproval { @@ -1208,8 +1208,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1221,7 +1221,7 @@ mod tests { let also_implements_batch_receive_nft = Some(true); let padding = Some("padding".to_string()); let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let contract_addr = "contract".to_string(); let test_msg = register_receive_nft_msg( code_hash.clone(), @@ -1240,8 +1240,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash: callback_code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1251,14 +1251,14 @@ mod tests { fn test_set_viewing_key_msg() -> StdResult<()> { let key = "key".to_string(); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = set_viewing_key_msg( key.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::SetViewingKey { key, padding })?; @@ -1266,8 +1266,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1275,7 +1275,7 @@ mod tests { #[test] fn test_mint_nft_msg() -> StdResult<()> { - let owner = Some(HumanAddr("alice".to_string())); + let owner = Some("alice".to_string()); let token_id = Some("NFT1".to_string()); let public_metadata = Some(Metadata { token_uri: Some("token uri".to_string()), @@ -1321,8 +1321,8 @@ mod tests { }); let memo = Some("memo".to_string()); let padding = None; - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = mint_nft_msg( token_id.clone(), @@ -1332,7 +1332,7 @@ mod tests { memo.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::MintNft { @@ -1347,8 +1347,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1356,16 +1356,16 @@ mod tests { #[test] fn test_add_minters_msg() -> StdResult<()> { - let minters = vec![HumanAddr("alice".to_string()), HumanAddr("bob".to_string())]; + let minters = vec!["alice".to_string(), "bob".to_string()]; let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = add_minters_msg( minters.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::AddMinters { minters, padding })?; @@ -1373,8 +1373,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1383,19 +1383,19 @@ mod tests { #[test] fn test_remove_minters_msg() -> StdResult<()> { let minters = vec![ - HumanAddr("alice".to_string()), - HumanAddr("bob".to_string()), - HumanAddr("charlie".to_string()), + "alice".to_string(), + "bob".to_string(), + "charlie".to_string(), ]; let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = remove_minters_msg( minters.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::RemoveMinters { minters, padding })?; @@ -1403,8 +1403,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1413,19 +1413,19 @@ mod tests { #[test] fn test_set_minters_msg() -> StdResult<()> { let minters = vec![ - HumanAddr("alice".to_string()), - HumanAddr("bob".to_string()), - HumanAddr("charlie".to_string()), + "alice".to_string(), + "bob".to_string(), + "charlie".to_string(), ]; let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = set_minters_msg( minters.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::SetMinters { minters, padding })?; @@ -1433,8 +1433,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1486,8 +1486,8 @@ mod tests { }), }); let padding = None; - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = set_metadata_msg( token_id.clone(), @@ -1495,7 +1495,7 @@ mod tests { private_metadata.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::SetMetadata { @@ -1508,8 +1508,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1520,7 +1520,7 @@ mod tests { let mints = vec![ Mint { token_id: None, - owner: Some(HumanAddr("alice".to_string())), + owner: Some("alice".to_string()), public_metadata: Some(Metadata { token_uri: Some("token uri".to_string()), extension: Some(Extension { @@ -1594,7 +1594,7 @@ mod tests { }, Mint { token_id: Some("NFT3".to_string()), - owner: Some(HumanAddr("bob".to_string())), + owner: Some("bob".to_string()), public_metadata: None, private_metadata: Some(Metadata { token_uri: Some("token uri3".to_string()), @@ -1621,14 +1621,14 @@ mod tests { }, ]; let padding = None; - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = batch_mint_nft_msg( mints.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::BatchMintNft { mints, padding })?; @@ -1636,8 +1636,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1647,25 +1647,25 @@ mod tests { fn test_batch_transfer_nft_msg() -> StdResult<()> { let transfers = vec![ Transfer { - recipient: HumanAddr("alice".to_string()), + recipient: "alice".to_string(), token_ids: vec!["NFT1".to_string()], memo: Some("memo 1".to_string()), }, Transfer { - recipient: HumanAddr("bob".to_string()), + recipient: "bob".to_string(), token_ids: vec!["NFT2".to_string(), "NFT3".to_string(), "NFT4".to_string()], memo: None, }, ]; let padding = None; - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = batch_transfer_nft_msg( transfers.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::BatchTransferNft { transfers, padding })?; @@ -1673,8 +1673,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1684,10 +1684,10 @@ mod tests { fn test_batch_send_nft_msg() -> StdResult<()> { let sends = vec![ Send { - contract: HumanAddr("alice".to_string()), + contract: "alice".to_string(), token_ids: vec!["NFT1".to_string()], msg: Some(to_binary(&HandleMsg::TransferNft { - recipient: HumanAddr("bob".to_string()), + recipient: "bob".to_string(), token_id: "NFT1".to_string(), memo: Some("send msg memo".to_string()), padding: None, @@ -1695,21 +1695,21 @@ mod tests { memo: Some("memo 1".to_string()), }, Send { - contract: HumanAddr("bob".to_string()), + contract: "bob".to_string(), token_ids: vec!["NFT2".to_string(), "NFT3".to_string(), "NFT4".to_string()], msg: None, memo: None, }, ]; let padding = None; - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = batch_send_nft_msg( sends.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::BatchSendNft { sends, padding })?; @@ -1717,8 +1717,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1729,15 +1729,15 @@ mod tests { let token_id = "NFT1".to_string(); let memo = Some("memo".to_string()); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = burn_nft_msg( token_id.clone(), memo.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::BurnNft { @@ -1749,8 +1749,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1769,14 +1769,14 @@ mod tests { }, ]; let padding = None; - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = batch_burn_nft_msg( burns.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::BatchBurnNft { burns, padding })?; @@ -1784,8 +1784,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1798,8 +1798,8 @@ mod tests { let view_private_metadata = None; let expires = Some(Expiration::AtTime(1000000000)); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = set_global_approval_msg( token_id.clone(), @@ -1808,7 +1808,7 @@ mod tests { expires.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::SetGlobalApproval { @@ -1822,8 +1822,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) @@ -1833,14 +1833,14 @@ mod tests { fn test_reveal_msg() -> StdResult<()> { let token_id = "NFT1".to_string(); let padding = Some("padding".to_string()); - let callback_code_hash = "code hash".to_string(); - let contract_addr = HumanAddr("contract".to_string()); + let code_hash = "code hash".to_string(); + let contract_addr = "contract".to_string(); let test_msg = reveal_msg( token_id.clone(), padding.clone(), 256usize, - callback_code_hash.clone(), + code_hash.clone(), contract_addr.clone(), )?; let mut msg = to_binary(&HandleMsg::Reveal { token_id, padding })?; @@ -1848,8 +1848,8 @@ mod tests { let expected_msg = CosmosMsg::Wasm(WasmMsg::Execute { msg: Binary(msg.to_vec()), contract_addr, - callback_code_hash, - send: vec![], + code_hash, + funds: vec![], }); assert_eq!(test_msg, expected_msg); Ok(()) diff --git a/packages/snip721/src/query.rs b/packages/snip721/src/query.rs index 42a89be..189efe0 100644 --- a/packages/snip721/src/query.rs +++ b/packages/snip721/src/query.rs @@ -2,7 +2,9 @@ use core::fmt; use schemars::JsonSchema; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use cosmwasm_std::{to_binary, HumanAddr, Querier, QueryRequest, StdError, StdResult, WasmQuery}; +use cosmwasm_std::{ + to_binary, CustomQuery, QuerierWrapper, QueryRequest, StdError, StdResult, WasmQuery, +}; use crate::expiration::Expiration; use crate::metadata::Metadata; @@ -16,7 +18,7 @@ use secret_toolkit_utils::space_pad; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct ViewerInfo { /// querying address - pub address: HumanAddr, + pub address: String, /// authentication key string pub viewing_key: String, } @@ -61,7 +63,7 @@ pub struct TokenList { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Cw721Approval { /// address that can transfer the token - pub spender: HumanAddr, + pub spender: String, /// expiration of this approval pub expires: Expiration, } @@ -75,7 +77,7 @@ pub struct Cw721Approval { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct OwnerOf { /// Owner of the token if permitted to view it - pub owner: Option, + pub owner: Option, /// list of addresses approved to transfer this token pub approvals: Vec, } @@ -95,7 +97,7 @@ pub struct AllNftInfo { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Snip721Approval { /// whitelisted address - pub address: HumanAddr, + pub address: String, /// optional expiration if the address has view owner permission pub view_owner_expiration: Option, /// optional expiration if the address has view private metadata permission @@ -112,7 +114,7 @@ pub struct Snip721Approval { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct NftDossier { /// owner of the token if permitted to view it - pub owner: Option, + pub owner: Option, /// the token's public metadata pub public_metadata: Option, /// the token's private metadata if permitted to view it @@ -188,25 +190,25 @@ pub enum TxAction { /// transferred token ownership Transfer { /// previous owner - from: HumanAddr, + from: String, /// optional sender if not owner - sender: Option, + sender: Option, /// new owner - recipient: HumanAddr, + recipient: String, }, /// minted new token Mint { /// minter's address - minter: HumanAddr, + minter: String, /// token's first owner - recipient: HumanAddr, + recipient: String, }, /// burned a token Burn { /// previous owner - owner: HumanAddr, + owner: String, /// burner's address if not owner - burner: Option, + burner: Option, }, } @@ -249,7 +251,7 @@ pub struct TransactionHistory { /// display the list of authorized minters #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Minters { - pub minters: Vec, + pub minters: Vec, } /// response of [`IsUnwrapped`](QueryMsg::IsUnwrapped) @@ -352,7 +354,7 @@ pub enum QueryMsg { /// CW-721 compliance, however, approvals are private on secret network, so only the /// owner's viewing key will authorize the ability to see the list of operators ApprovedForAll { - owner: HumanAddr, + owner: String, /// optional viewing key to authenticate this query. It is "optional" only in the /// sense that a CW721 query does not have this field. However, not providing the /// key will always result in an empty list @@ -364,7 +366,7 @@ pub enum QueryMsg { /// list all the inventory-wide [`Approvals`](Snip721Approval) in place for the specified address if given the /// the correct viewing key for the address InventoryApprovals { - address: HumanAddr, + address: String, /// the viewing key viewing_key: String, /// optionally include expired [`Approvals`](Snip721Approval) in the response list. If ommitted or @@ -374,9 +376,9 @@ pub enum QueryMsg { /// displays a list of all the tokens belonging to the input owner in which the viewer /// has view_owner permission Tokens { - owner: HumanAddr, + owner: String, /// optional address of the querier if different from the owner - viewer: Option, + viewer: Option, /// optional viewing key viewing_key: Option, /// optionally display only token ids that come after the input String in @@ -388,7 +390,7 @@ pub enum QueryMsg { /// display the transaction history for the specified address in reverse /// chronological order TransactionHistory { - address: HumanAddr, + address: String, /// viewing key viewing_key: String, /// optional page to display @@ -409,7 +411,7 @@ pub enum QueryMsg { /// list of tokens to verify approval for token_ids: Vec, /// address that has approval - address: HumanAddr, + address: String, /// viewing key viewing_key: String, }, @@ -445,14 +447,14 @@ impl QueryMsg { /// /// * `querier` - a reference to the Querier dependency of the querying contract /// * `block_size` - pad the message to blocks of this size - /// * `callback_code_hash` - String holding the code hash of the contract being queried + /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried - pub fn query( + pub fn query<'a, C: CustomQuery, T: DeserializeOwned>( &self, - querier: &Q, + querier: QuerierWrapper<'a, C>, mut block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { // can not have block size of 0 if block_size == 0 { @@ -463,7 +465,7 @@ impl QueryMsg { querier .query(&QueryRequest::Wasm(WasmQuery::Smart { contract_addr, - callback_code_hash, + code_hash, msg, })) .map_err(|err| { @@ -568,16 +570,16 @@ pub struct VerifyTransferApprovalResponse { /// /// * `querier` - a reference to the Querier dependency of the querying contract /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn contract_info_query( - querier: &Q, +pub fn contract_info_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: ContractInfoResponse = - QueryMsg::ContractInfo {}.query(querier, block_size, callback_code_hash, contract_addr)?; + QueryMsg::ContractInfo {}.query(querier, block_size, code_hash, contract_addr)?; Ok(answer.contract_info) } @@ -588,21 +590,17 @@ pub fn contract_info_query( /// * `querier` - a reference to the Querier dependency of the querying contract /// * `viewer` - Optional ViewerInfo holding the address and viewing key of the querier /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn num_tokens_query( - querier: &Q, +pub fn num_tokens_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, viewer: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { - let answer: NumTokensResponse = QueryMsg::NumTokens { viewer }.query( - querier, - block_size, - callback_code_hash, - contract_addr, - )?; + let answer: NumTokensResponse = + QueryMsg::NumTokens { viewer }.query(querier, block_size, code_hash, contract_addr)?; Ok(answer.num_tokens) } @@ -616,23 +614,23 @@ pub fn num_tokens_query( /// lexicographical order /// * `limit` - Optional u32 number of token ids to display /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn all_tokens_query( - querier: &Q, +pub fn all_tokens_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, viewer: Option, start_after: Option, limit: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: TokenListResponse = QueryMsg::AllTokens { viewer, start_after, limit, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.token_list) } @@ -647,23 +645,23 @@ pub fn all_tokens_query( /// ommitted or false, expired Approvals will be filtered out of /// the response /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn owner_of_query( - querier: &Q, +pub fn owner_of_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, token_id: String, viewer: Option, include_expired: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: OwnerOfResponse = QueryMsg::OwnerOf { token_id, viewer, include_expired, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.owner_of) } @@ -674,21 +672,17 @@ pub fn owner_of_query( /// * `querier` - a reference to the Querier dependency of the querying contract /// * `token_id` - ID of the token whose info is being requested /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn nft_info_query( - querier: &Q, +pub fn nft_info_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, token_id: String, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { - let answer: NftInfoResponse = QueryMsg::NftInfo { token_id }.query( - querier, - block_size, - callback_code_hash, - contract_addr, - )?; + let answer: NftInfoResponse = + QueryMsg::NftInfo { token_id }.query(querier, block_size, code_hash, contract_addr)?; Ok(answer.nft_info) } @@ -703,23 +697,23 @@ pub fn nft_info_query( /// ommitted or false, expired Approvals will be filtered out of /// the response /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn all_nft_info_query( - querier: &Q, +pub fn all_nft_info_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, token_id: String, viewer: Option, include_expired: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: AllNftInfoResponse = QueryMsg::AllNftInfo { token_id, viewer, include_expired, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.all_nft_info) } @@ -731,20 +725,20 @@ pub fn all_nft_info_query( /// * `token_id` - ID of the token whose info is being requested /// * `viewer` - Optional ViewerInfo holding the address and viewing key of the querier /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn private_metadata_query( - querier: &Q, +pub fn private_metadata_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, token_id: String, viewer: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: PrivateMetadataResponse = QueryMsg::PrivateMetadata { token_id, viewer }.query( querier, block_size, - callback_code_hash, + code_hash, contract_addr, )?; Ok(answer.private_metadata) @@ -761,23 +755,23 @@ pub fn private_metadata_query( /// ommitted or false, expired Approvals will be filtered out of /// the response /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn nft_dossier_query( - querier: &Q, +pub fn nft_dossier_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, token_id: String, viewer: Option, include_expired: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: NftDossierResponse = QueryMsg::NftDossier { token_id, viewer, include_expired, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.nft_dossier) } @@ -792,23 +786,23 @@ pub fn nft_dossier_query( /// ommitted or false, expired Approvals will be filtered out of /// the response /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn token_approvals_query( - querier: &Q, +pub fn token_approvals_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, token_id: String, viewing_key: String, include_expired: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: TokenApprovalsResponse = QueryMsg::TokenApprovals { token_id, viewing_key, include_expired, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.token_approvals) } @@ -823,23 +817,23 @@ pub fn token_approvals_query( /// ommitted or false, expired Approvals will be filtered out of /// the response /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn approved_for_all_query( - querier: &Q, - owner: HumanAddr, +pub fn approved_for_all_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, + owner: String, viewing_key: Option, include_expired: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: ApprovedForAllResponse = QueryMsg::ApprovedForAll { owner, viewing_key, include_expired, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.approved_for_all) } @@ -854,23 +848,23 @@ pub fn approved_for_all_query( /// ommitted or false, expired Approvals will be filtered out of /// the response /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn inventory_approvals_query( - querier: &Q, - address: HumanAddr, +pub fn inventory_approvals_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, + address: String, viewing_key: String, include_expired: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: InventoryApprovalsResponse = QueryMsg::InventoryApprovals { address, viewing_key, include_expired, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.inventory_approvals) } @@ -886,19 +880,19 @@ pub fn inventory_approvals_query( /// lexicographical order /// * `limit` - Optional u32 number of token ids to display /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn tokens_query( - querier: &Q, - owner: HumanAddr, - viewer: Option, +pub fn tokens_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, + owner: String, + viewer: Option, viewing_key: Option, start_after: Option, limit: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: TokenListResponse = QueryMsg::Tokens { owner, @@ -907,7 +901,7 @@ pub fn tokens_query( start_after, limit, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.token_list) } @@ -921,18 +915,18 @@ pub fn tokens_query( /// * `page` - Optional u32 representing the page number of transactions to display /// * `page_size` - Optional u32 number of transactions to return /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn transaction_history_query( - querier: &Q, - address: HumanAddr, +pub fn transaction_history_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, + address: String, viewing_key: String, page: Option, page_size: Option, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: TransactionHistoryResponse = QueryMsg::TransactionHistory { address, @@ -940,7 +934,7 @@ pub fn transaction_history_query( page, page_size, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.transaction_history) } @@ -950,16 +944,16 @@ pub fn transaction_history_query( /// /// * `querier` - a reference to the Querier dependency of the querying contract /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn minters_query( - querier: &Q, +pub fn minters_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: MintersResponse = - QueryMsg::Minters {}.query(querier, block_size, callback_code_hash, contract_addr)?; + QueryMsg::Minters {}.query(querier, block_size, code_hash, contract_addr)?; Ok(answer.minters) } @@ -970,21 +964,17 @@ pub fn minters_query( /// * `querier` - a reference to the Querier dependency of the querying contract /// * `token_id` - ID of the token whose info is being requested /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn is_unwrapped_query( - querier: &Q, +pub fn is_unwrapped_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, token_id: String, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { - let answer: IsUnwrappedResponse = QueryMsg::IsUnwrapped { token_id }.query( - querier, - block_size, - callback_code_hash, - contract_addr, - )?; + let answer: IsUnwrappedResponse = + QueryMsg::IsUnwrapped { token_id }.query(querier, block_size, code_hash, contract_addr)?; Ok(answer.is_unwrapped) } @@ -997,23 +987,23 @@ pub fn is_unwrapped_query( /// * `address` - address that has transfer approval /// * `viewing_key` - String holding the address' viewing key /// * `block_size` - pad the message to blocks of this size -/// * `callback_code_hash` - String holding the code hash of the contract being queried +/// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn verify_transfer_approval_query( - querier: &Q, +pub fn verify_transfer_approval_query<'a, C: CustomQuery>( + querier: QuerierWrapper<'a, C>, token_ids: Vec, - address: HumanAddr, + address: String, viewing_key: String, block_size: usize, - callback_code_hash: String, - contract_addr: HumanAddr, + code_hash: String, + contract_addr: String, ) -> StdResult { let answer: VerifyTransferApprovalResponse = QueryMsg::VerifyTransferApproval { token_ids, address, viewing_key, } - .query(querier, block_size, callback_code_hash, contract_addr)?; + .query(querier, block_size, code_hash, contract_addr)?; Ok(answer.verify_transfer_approval) } @@ -1022,7 +1012,18 @@ mod tests { use crate::{Extension, Trait}; use super::*; - use cosmwasm_std::{to_vec, QuerierResult, SystemError}; + use cosmwasm_std::{ + to_vec, ContractResult, Empty, Querier, QuerierResult, SystemError, SystemResult, + }; + + macro_rules! try_querier_result { + ($result: expr) => { + match $result { + std::result::Result::Ok(ok) => ok, + std::result::Result::Err(err) => return cosmwasm_std::QuerierResult::Err(err), + } + }; + } #[test] fn test_contract_info_query() -> StdResult<()> { @@ -1030,17 +1031,20 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { - let mut expected_msg = - to_binary(&QueryMsg::ContractInfo {}).map_err(|_e| SystemError::Unknown {})?; + let mut expected_msg = try_querier_result!( + to_binary(&QueryMsg::ContractInfo {}).map_err(|_e| SystemError::Unknown {}) + ); + space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = ContractInfoResponse { contract_info: ContractInfo { @@ -1048,12 +1052,14 @@ mod tests { symbol: "NFTS".to_string(), }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let expected_response = ContractInfo { @@ -1061,7 +1067,7 @@ mod tests { symbol: "NFTS".to_string(), }; - let response = contract_info_query(&querier, 256usize, hash, address)?; + let response = contract_info_query(querier, 256usize, hash, address)?; assert_eq!(response, expected_response); Ok(()) @@ -1074,42 +1080,46 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); - let mut expected_msg = to_binary(&QueryMsg::NumTokens { viewer }) - .map_err(|_e| SystemError::Unknown {})?; + let mut expected_msg = + try_querier_result!(to_binary(&QueryMsg::NumTokens { viewer }) + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = NumTokensResponse { num_tokens: NumTokens { count: 32 }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); let expected_response = NumTokens { count: 32 }; - let response = num_tokens_query(&querier, viewer, 256usize, hash, address)?; + let response = num_tokens_query(querier, viewer, 256usize, hash, address)?; assert_eq!(response, expected_response); Ok(()) @@ -1122,27 +1132,28 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); let start_after = Some("NFT1".to_string()); let limit = None; - let mut expected_msg = to_binary(&QueryMsg::AllTokens { + let mut expected_msg = try_querier_result!(to_binary(&QueryMsg::AllTokens { viewer, start_after, limit, }) - .map_err(|_e| SystemError::Unknown {})?; + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = TokenListResponse { @@ -1150,16 +1161,18 @@ mod tests { tokens: vec!["NFT2".to_string(), "NFT3".to_string(), "NFT4".to_string()], }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); let start_after = Some("NFT1".to_string()); @@ -1169,15 +1182,8 @@ mod tests { tokens: vec!["NFT2".to_string(), "NFT3".to_string(), "NFT4".to_string()], }; - let response = all_tokens_query( - &querier, - viewer, - start_after, - limit, - 256usize, - hash, - address, - )?; + let response = + all_tokens_query(querier, viewer, start_after, limit, 256usize, hash, address)?; assert_eq!(response, expected_response); Ok(()) @@ -1190,75 +1196,78 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); let token_id = "NFT1".to_string(); let include_expired = Some(true); - let mut expected_msg = to_binary(&QueryMsg::OwnerOf { + let mut expected_msg = try_querier_result!(to_binary(&QueryMsg::OwnerOf { token_id, viewer, include_expired, }) - .map_err(|_e| SystemError::Unknown {})?; + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = OwnerOfResponse { owner_of: OwnerOf { - owner: Some(HumanAddr("alice".to_string())), + owner: Some("alice".to_string()), approvals: vec![ Cw721Approval { - spender: HumanAddr("bob".to_string()), + spender: "bob".to_string(), expires: Expiration::Never, }, Cw721Approval { - spender: HumanAddr("charlie".to_string()), + spender: "charlie".to_string(), expires: Expiration::AtHeight(1000000), }, ], }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); let token_id = "NFT1".to_string(); let include_expired = Some(true); let expected_response = OwnerOf { - owner: Some(HumanAddr("alice".to_string())), + owner: Some("alice".to_string()), approvals: vec![ Cw721Approval { - spender: HumanAddr("bob".to_string()), + spender: "bob".to_string(), expires: Expiration::Never, }, Cw721Approval { - spender: HumanAddr("charlie".to_string()), + spender: "charlie".to_string(), expires: Expiration::AtHeight(1000000), }, ], }; let response = owner_of_query( - &querier, + querier, token_id, viewer, include_expired, @@ -1278,18 +1287,20 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let token_id = "NFT1".to_string(); - let mut expected_msg = to_binary(&QueryMsg::NftInfo { token_id }) - .map_err(|_e| SystemError::Unknown {})?; + let mut expected_msg = + try_querier_result!(to_binary(&QueryMsg::NftInfo { token_id }) + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = NftInfoResponse { @@ -1315,12 +1326,14 @@ mod tests { }), }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let token_id = "NFT1".to_string(); @@ -1347,7 +1360,7 @@ mod tests { }), }; - let response = nft_info_query(&querier, token_id, 256usize, hash, address)?; + let response = nft_info_query(querier, token_id, 256usize, hash, address)?; assert_eq!(response, expected_response); Ok(()) @@ -1360,40 +1373,41 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); let token_id = "NFT1".to_string(); let include_expired = Some(true); - let mut expected_msg = to_binary(&QueryMsg::AllNftInfo { + let mut expected_msg = try_querier_result!(to_binary(&QueryMsg::AllNftInfo { token_id, viewer, include_expired, }) - .map_err(|_e| SystemError::Unknown {})?; + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = AllNftInfoResponse { all_nft_info: AllNftInfo { access: OwnerOf { - owner: Some(HumanAddr("alice".to_string())), + owner: Some("alice".to_string()), approvals: vec![ Cw721Approval { - spender: HumanAddr("bob".to_string()), + spender: "bob".to_string(), expires: Expiration::Never, }, Cw721Approval { - spender: HumanAddr("charlie".to_string()), + spender: "charlie".to_string(), expires: Expiration::AtHeight(1000000), }, ], @@ -1421,16 +1435,18 @@ mod tests { }), }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); let token_id = "NFT1".to_string(); @@ -1438,14 +1454,14 @@ mod tests { let expected_response = AllNftInfo { access: OwnerOf { - owner: Some(HumanAddr("alice".to_string())), + owner: Some("alice".to_string()), approvals: vec![ Cw721Approval { - spender: HumanAddr("bob".to_string()), + spender: "bob".to_string(), expires: Expiration::Never, }, Cw721Approval { - spender: HumanAddr("charlie".to_string()), + spender: "charlie".to_string(), expires: Expiration::AtHeight(1000000), }, ], @@ -1474,7 +1490,7 @@ mod tests { }; let response = all_nft_info_query( - &querier, + querier, token_id, viewer, include_expired, @@ -1495,21 +1511,23 @@ mod tests { fn raw_query(&self, request: &[u8]) -> QuerierResult { let token_id = "NFT1".to_string(); let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); - let mut expected_msg = to_binary(&QueryMsg::PrivateMetadata { token_id, viewer }) - .map_err(|_e| SystemError::Unknown {})?; + let mut expected_msg = + try_querier_result!(to_binary(&QueryMsg::PrivateMetadata { token_id, viewer }) + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = PrivateMetadataResponse { @@ -1535,17 +1553,19 @@ mod tests { }), }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let token_id = "NFT1".to_string(); let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); @@ -1571,7 +1591,7 @@ mod tests { }), }; - let response = private_metadata_query(&querier, token_id, viewer, 256usize, hash, address)?; + let response = private_metadata_query(querier, token_id, viewer, 256usize, hash, address)?; assert_eq!(response, expected_response); Ok(()) @@ -1584,32 +1604,33 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); let token_id = "NFT1".to_string(); let include_expired = Some(true); - let mut expected_msg = to_binary(&QueryMsg::NftDossier { + let mut expected_msg = try_querier_result!(to_binary(&QueryMsg::NftDossier { token_id, viewer, include_expired, }) - .map_err(|_e| SystemError::Unknown {})?; + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = NftDossierResponse { nft_dossier: NftDossier { - owner: Some(HumanAddr("alice".to_string())), + owner: Some("alice".to_string()), public_metadata: Some(Metadata { token_uri: Some("token uri2".to_string()), extension: Some(Extension { @@ -1639,13 +1660,13 @@ mod tests { private_metadata_is_public_expiration: None, token_approvals: Some(vec![ Snip721Approval { - address: HumanAddr("bob".to_string()), + address: "bob".to_string(), view_owner_expiration: None, view_private_metadata_expiration: Some(Expiration::AtTime(1000000)), transfer_expiration: Some(Expiration::AtHeight(10000)), }, Snip721Approval { - address: HumanAddr("charlie".to_string()), + address: "charlie".to_string(), view_owner_expiration: Some(Expiration::Never), view_private_metadata_expiration: None, transfer_expiration: None, @@ -1654,23 +1675,25 @@ mod tests { inventory_approvals: None, }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let viewer = Some(ViewerInfo { - address: HumanAddr("alice".to_string()), + address: "alice".to_string(), viewing_key: "key".to_string(), }); let token_id = "NFT1".to_string(); let include_expired = Some(true); let expected_response = NftDossier { - owner: Some(HumanAddr("alice".to_string())), + owner: Some("alice".to_string()), public_metadata: Some(Metadata { token_uri: Some("token uri2".to_string()), extension: Some(Extension { @@ -1700,13 +1723,13 @@ mod tests { private_metadata_is_public_expiration: None, token_approvals: Some(vec![ Snip721Approval { - address: HumanAddr("bob".to_string()), + address: "bob".to_string(), view_owner_expiration: None, view_private_metadata_expiration: Some(Expiration::AtTime(1000000)), transfer_expiration: Some(Expiration::AtHeight(10000)), }, Snip721Approval { - address: HumanAddr("charlie".to_string()), + address: "charlie".to_string(), view_owner_expiration: Some(Expiration::Never), view_private_metadata_expiration: None, transfer_expiration: None, @@ -1716,7 +1739,7 @@ mod tests { }; let response = nft_dossier_query( - &querier, + querier, token_id, viewer, include_expired, @@ -1738,22 +1761,23 @@ mod tests { let viewing_key = "key".to_string(); let token_id = "NFT1".to_string(); let include_expired = None; - let mut expected_msg = to_binary(&QueryMsg::TokenApprovals { + let mut expected_msg = try_querier_result!(to_binary(&QueryMsg::TokenApprovals { token_id, viewing_key, include_expired, }) - .map_err(|_e| SystemError::Unknown {})?; + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = TokenApprovalsResponse { @@ -1764,13 +1788,13 @@ mod tests { private_metadata_is_public_expiration: None, token_approvals: vec![ Snip721Approval { - address: HumanAddr("bob".to_string()), + address: "bob".to_string(), view_owner_expiration: None, view_private_metadata_expiration: Some(Expiration::AtTime(1000000)), transfer_expiration: Some(Expiration::AtHeight(10000)), }, Snip721Approval { - address: HumanAddr("charlie".to_string()), + address: "charlie".to_string(), view_owner_expiration: Some(Expiration::Never), view_private_metadata_expiration: None, transfer_expiration: None, @@ -1778,12 +1802,14 @@ mod tests { ], }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let viewing_key = "key".to_string(); @@ -1797,13 +1823,13 @@ mod tests { private_metadata_is_public_expiration: None, token_approvals: vec![ Snip721Approval { - address: HumanAddr("bob".to_string()), + address: "bob".to_string(), view_owner_expiration: None, view_private_metadata_expiration: Some(Expiration::AtTime(1000000)), transfer_expiration: Some(Expiration::AtHeight(10000)), }, Snip721Approval { - address: HumanAddr("charlie".to_string()), + address: "charlie".to_string(), view_owner_expiration: Some(Expiration::Never), view_private_metadata_expiration: None, transfer_expiration: None, @@ -1812,7 +1838,7 @@ mod tests { }; let response = token_approvals_query( - &querier, + querier, token_id, viewing_key, include_expired, @@ -1832,67 +1858,70 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let viewing_key = Some("key".to_string()); - let owner = HumanAddr("alice".to_string()); + let owner = "alice".to_string(); let include_expired = None; - let mut expected_msg = to_binary(&QueryMsg::ApprovedForAll { + let mut expected_msg = try_querier_result!(to_binary(&QueryMsg::ApprovedForAll { owner, viewing_key, include_expired, }) - .map_err(|_e| SystemError::Unknown {})?; + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = ApprovedForAllResponse { approved_for_all: ApprovedForAll { operators: vec![ Cw721Approval { - spender: HumanAddr("bob".to_string()), + spender: "bob".to_string(), expires: Expiration::Never, }, Cw721Approval { - spender: HumanAddr("charlie".to_string()), + spender: "charlie".to_string(), expires: Expiration::AtHeight(1000000), }, ], }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let viewing_key = Some("key".to_string()); - let owner = HumanAddr("alice".to_string()); + let owner = "alice".to_string(); let include_expired = None; let expected_response = ApprovedForAll { operators: vec![ Cw721Approval { - spender: HumanAddr("bob".to_string()), + spender: "bob".to_string(), expires: Expiration::Never, }, Cw721Approval { - spender: HumanAddr("charlie".to_string()), + spender: "charlie".to_string(), expires: Expiration::AtHeight(1000000), }, ], }; let response = approved_for_all_query( - &querier, + querier, owner, viewing_key, include_expired, @@ -1912,24 +1941,26 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let viewing_key = "key".to_string(); - let address = HumanAddr("alice".to_string()); + let address = "alice".to_string(); let include_expired = None; - let mut expected_msg = to_binary(&QueryMsg::InventoryApprovals { - address, - viewing_key, - include_expired, - }) - .map_err(|_e| SystemError::Unknown {})?; + let mut expected_msg = + try_querier_result!(to_binary(&QueryMsg::InventoryApprovals { + address, + viewing_key, + include_expired, + }) + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = InventoryApprovalsResponse { @@ -1940,13 +1971,13 @@ mod tests { private_metadata_is_public_expiration: None, inventory_approvals: vec![ Snip721Approval { - address: HumanAddr("bob".to_string()), + address: "bob".to_string(), view_owner_expiration: None, view_private_metadata_expiration: Some(Expiration::AtTime(1000000)), transfer_expiration: Some(Expiration::AtHeight(10000)), }, Snip721Approval { - address: HumanAddr("charlie".to_string()), + address: "charlie".to_string(), view_owner_expiration: Some(Expiration::Never), view_private_metadata_expiration: None, transfer_expiration: None, @@ -1954,16 +1985,18 @@ mod tests { ], }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let contract_address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let contract_address = "contract".to_string(); let hash = "code hash".to_string(); let viewing_key = "key".to_string(); - let address = HumanAddr("alice".to_string()); + let address = "alice".to_string(); let include_expired = None; let expected_response = InventoryApprovals { @@ -1973,13 +2006,13 @@ mod tests { private_metadata_is_public_expiration: None, inventory_approvals: vec![ Snip721Approval { - address: HumanAddr("bob".to_string()), + address: "bob".to_string(), view_owner_expiration: None, view_private_metadata_expiration: Some(Expiration::AtTime(1000000)), transfer_expiration: Some(Expiration::AtHeight(10000)), }, Snip721Approval { - address: HumanAddr("charlie".to_string()), + address: "charlie".to_string(), view_owner_expiration: Some(Expiration::Never), view_private_metadata_expiration: None, transfer_expiration: None, @@ -1988,7 +2021,7 @@ mod tests { }; let response = inventory_approvals_query( - &querier, + querier, address, viewing_key, include_expired, @@ -2007,29 +2040,30 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { - let owner = HumanAddr("alice".to_string()); - let viewer = Some(HumanAddr("bob".to_string())); + let owner = "alice".to_string(); + let viewer = Some("bob".to_string()); let viewing_key = Some("key".to_string()); let start_after = Some("NFT1".to_string()); let limit = Some(33); - let mut expected_msg = to_binary(&QueryMsg::Tokens { + let mut expected_msg = try_querier_result!(to_binary(&QueryMsg::Tokens { owner, viewer, viewing_key, start_after, limit, }) - .map_err(|_e| SystemError::Unknown {})?; + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = TokenListResponse { @@ -2037,16 +2071,18 @@ mod tests { tokens: vec!["NFT2".to_string(), "NFT3".to_string(), "NFT4".to_string()], }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); - let owner = HumanAddr("alice".to_string()); - let viewer = Some(HumanAddr("bob".to_string())); + let owner = "alice".to_string(); + let viewer = Some("bob".to_string()); let viewing_key = Some("key".to_string()); let start_after = Some("NFT1".to_string()); let limit = Some(33); @@ -2056,7 +2092,7 @@ mod tests { }; let response = tokens_query( - &querier, + querier, owner, viewer, viewing_key, @@ -2077,27 +2113,29 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { - let address = HumanAddr("alice".to_string()); + let address = "alice".to_string(); let viewing_key = "key".to_string(); let page = Some(2); let page_size = None; - let mut expected_msg = to_binary(&QueryMsg::TransactionHistory { - address, - viewing_key, - page, - page_size, - }) - .map_err(|_e| SystemError::Unknown {})?; + let mut expected_msg = + try_querier_result!(to_binary(&QueryMsg::TransactionHistory { + address, + viewing_key, + page, + page_size, + }) + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = TransactionHistoryResponse { @@ -2110,8 +2148,8 @@ mod tests { block_time: 2000000000, token_id: "NFT3".to_string(), action: TxAction::Burn { - owner: HumanAddr("alice".to_string()), - burner: Some(HumanAddr("bob".to_string())), + owner: "alice".to_string(), + burner: Some("bob".to_string()), }, memo: None, }, @@ -2121,9 +2159,9 @@ mod tests { block_time: 1900000000, token_id: "NFT2".to_string(), action: TxAction::Transfer { - from: HumanAddr("alice".to_string()), + from: "alice".to_string(), sender: None, - recipient: HumanAddr("bob".to_string()), + recipient: "bob".to_string(), }, memo: Some("xfer memo".to_string()), }, @@ -2133,23 +2171,25 @@ mod tests { block_time: 1800000000, token_id: "NFT1".to_string(), action: TxAction::Mint { - minter: HumanAddr("admin".to_string()), - recipient: HumanAddr("alice".to_string()), + minter: "admin".to_string(), + recipient: "alice".to_string(), }, memo: None, }, ], }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let contract_address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let contract_address = "contract".to_string(); let hash = "code hash".to_string(); - let address = HumanAddr("alice".to_string()); + let address = "alice".to_string(); let viewing_key = "key".to_string(); let page = Some(2); let page_size = None; @@ -2163,8 +2203,8 @@ mod tests { block_time: 2000000000, token_id: "NFT3".to_string(), action: TxAction::Burn { - owner: HumanAddr("alice".to_string()), - burner: Some(HumanAddr("bob".to_string())), + owner: "alice".to_string(), + burner: Some("bob".to_string()), }, memo: None, }, @@ -2174,9 +2214,9 @@ mod tests { block_time: 1900000000, token_id: "NFT2".to_string(), action: TxAction::Transfer { - from: HumanAddr("alice".to_string()), + from: "alice".to_string(), sender: None, - recipient: HumanAddr("bob".to_string()), + recipient: "bob".to_string(), }, memo: Some("xfer memo".to_string()), }, @@ -2186,8 +2226,8 @@ mod tests { block_time: 1800000000, token_id: "NFT1".to_string(), action: TxAction::Mint { - minter: HumanAddr("admin".to_string()), - recipient: HumanAddr("alice".to_string()), + minter: "admin".to_string(), + recipient: "alice".to_string(), }, memo: None, }, @@ -2195,7 +2235,7 @@ mod tests { }; let response = transaction_history_query( - &querier, + querier, address, viewing_key, page, @@ -2215,46 +2255,50 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { - let mut expected_msg = - to_binary(&QueryMsg::Minters {}).map_err(|_e| SystemError::Unknown {})?; + let mut expected_msg = try_querier_result!( + to_binary(&QueryMsg::Minters {}).map_err(|_e| SystemError::Unknown {}) + ); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = MintersResponse { minters: Minters { minters: vec![ - HumanAddr("alice".to_string()), - HumanAddr("bob".to_string()), - HumanAddr("charlie".to_string()), + "alice".to_string(), + "bob".to_string(), + "charlie".to_string(), ], }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let expected_response = Minters { minters: vec![ - HumanAddr("alice".to_string()), - HumanAddr("bob".to_string()), - HumanAddr("charlie".to_string()), + "alice".to_string(), + "bob".to_string(), + "charlie".to_string(), ], }; - let response = minters_query(&querier, 256usize, hash, address)?; + let response = minters_query(querier, 256usize, hash, address)?; assert_eq!(response, expected_response); Ok(()) @@ -2267,18 +2311,20 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let token_id = "NFT1".to_string(); - let mut expected_msg = to_binary(&QueryMsg::IsUnwrapped { token_id }) - .map_err(|_e| SystemError::Unknown {})?; + let mut expected_msg = + try_querier_result!(to_binary(&QueryMsg::IsUnwrapped { token_id }) + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = IsUnwrappedResponse { @@ -2286,12 +2332,14 @@ mod tests { token_is_unwrapped: false, }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "contract".to_string(); let hash = "code hash".to_string(); let token_id = "NFT1".to_string(); @@ -2300,7 +2348,7 @@ mod tests { token_is_unwrapped: false, }; - let response = is_unwrapped_query(&querier, token_id, 256usize, hash, address)?; + let response = is_unwrapped_query(querier, token_id, 256usize, hash, address)?; assert_eq!(response, expected_response); Ok(()) @@ -2313,25 +2361,27 @@ mod tests { impl Querier for MyMockQuerier { fn raw_query(&self, request: &[u8]) -> QuerierResult { let token_ids = vec!["NFT1".to_string(), "NFT2".to_string(), "NFT3".to_string()]; - let address = HumanAddr("alice".to_string()); + let address = "alice".to_string(); let viewing_key = "key".to_string(); - let mut expected_msg = to_binary(&QueryMsg::VerifyTransferApproval { - token_ids, - address, - viewing_key, - }) - .map_err(|_e| SystemError::Unknown {})?; + let mut expected_msg = + try_querier_result!(to_binary(&QueryMsg::VerifyTransferApproval { + token_ids, + address, + viewing_key, + }) + .map_err(|_e| SystemError::Unknown {})); space_pad(&mut expected_msg.0, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("contract".to_string()), - callback_code_hash: "code hash".to_string(), + contract_addr: "contract".to_string(), + code_hash: "code hash".to_string(), msg: expected_msg, }); - let test_req: &[u8] = - &to_vec(&expected_request).map_err(|_e| SystemError::Unknown {})?; + let test_req: &[u8] = &try_querier_result!( + to_vec(&expected_request).map_err(|_e| SystemError::Unknown {}) + ); assert_eq!(request, test_req); let response = VerifyTransferApprovalResponse { @@ -2340,16 +2390,18 @@ mod tests { first_unapproved_token: Some("NFT3".to_string()), }, }; - Ok(to_binary(&response)) + let response = + try_querier_result!(to_binary(&response).map_err(|_e| SystemError::Unknown {})); + SystemResult::Ok(ContractResult::Ok(response)) } } - let querier = MyMockQuerier {}; - let contract_address = HumanAddr("contract".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let contract_address = "contract".to_string(); let hash = "code hash".to_string(); let token_ids = vec!["NFT1".to_string(), "NFT2".to_string(), "NFT3".to_string()]; - let address = HumanAddr("alice".to_string()); + let address = "alice".to_string(); let viewing_key = "key".to_string(); let expected_response = VerifyTransferApproval { @@ -2358,7 +2410,7 @@ mod tests { }; let response = verify_transfer_approval_query( - &querier, + querier, token_ids, address, viewing_key, From 11213b77c602da3b5b2845eab89a288accfbbce5 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Mon, 1 Aug 2022 18:41:44 +0300 Subject: [PATCH 05/37] Update `packages/permit` --- Cargo.toml | 2 +- packages/permit/Cargo.toml | 4 ++-- packages/permit/src/funcs.rs | 34 ++++++++++++++++++++++++---------- packages/permit/src/state.rs | 6 +++--- packages/permit/src/structs.rs | 10 +++++----- 5 files changed, 35 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 44205c0..0109947 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["packages/storage", "packages/toolkit", "packages/serialization", "packages/crypto", "packages/snip20", "packages/snip721"] +members = ["packages/storage", "packages/toolkit", "packages/serialization", "packages/crypto", "packages/snip20", "packages/snip721", "packages/permit"] # Since `secret-toolkit` depends on all the other packages, this should make `cargo-check` a bit quicker # as it won't have to check all the other packages twice. default-members = ["packages/toolkit"] diff --git a/packages/permit/Cargo.toml b/packages/permit/Cargo.toml index 9bdeaf0..01e077a 100644 --- a/packages/permit/Cargo.toml +++ b/packages/permit/Cargo.toml @@ -14,11 +14,11 @@ keywords = ["secret-network", "secret-contracts", "secret-toolkit"] all-features = true [dependencies] -cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1" } +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } serde = "1.0" ripemd160 = { version = "0.9.1", default-features = false } -schemars = "0.7" +schemars = "0.8.1" bech32 = "0.8.1" remain = "0.2.2" secret-toolkit-crypto = { version = "0.3.0", path = "../crypto", features=["hash"] } diff --git a/packages/permit/src/funcs.rs b/packages/permit/src/funcs.rs index d6fbf6a..838d792 100644 --- a/packages/permit/src/funcs.rs +++ b/packages/permit/src/funcs.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - to_binary, Api, Binary, CanonicalAddr, Extern, HumanAddr, Querier, StdError, StdResult, Storage, + to_binary, Api, Binary, CanonicalAddr, Deps, Querier, StdError, StdResult, Storage, }; use ripemd160::{Digest, Ripemd160}; @@ -8,10 +8,10 @@ use bech32::{ToBase32, Variant}; use secret_toolkit_crypto::sha_256; pub fn validate( - deps: &Extern, + deps: Deps, storage_prefix: &str, permit: &Permit, - current_token_address: HumanAddr, + current_token_address: String, hrp: Option<&str>, ) -> StdResult { let account_hrp = hrp.unwrap_or("secret"); @@ -38,9 +38,9 @@ pub fn validate( // Validate permit_name let permit_name = &permit.params.permit_name; let is_permit_revoked = RevokedPermits::is_permit_revoked( - &deps.storage, + deps.storage, storage_prefix, - &HumanAddr(account.clone()), + &account.clone(), permit_name, ); if is_permit_revoked { @@ -79,15 +79,15 @@ pub fn pubkey_to_account(pubkey: &Binary) -> CanonicalAddr { mod tests { use super::*; use crate::{PermitParams, PermitSignature, PubKey, TokenPermissions}; - use cosmwasm_std::testing::mock_dependencies; + use cosmwasm_std::testing::{mock_dependencies, MockApi, MockQuerier, MockStorage}; #[test] fn test_verify_permit() { - let deps = mock_dependencies(20, &[]); + let deps = mock_dependencies(); //{"permit": {"params":{"chain_id":"pulsar-2","permit_name":"memo_secret1rf03820fp8gngzg2w02vd30ns78qkc8rg8dxaq","allowed_tokens":["secret1rf03820fp8gngzg2w02vd30ns78qkc8rg8dxaq"],"permissions":["history"]},"signature":{"pub_key":{"type":"tendermint/PubKeySecp256k1","value":"A5M49l32ZrV+SDsPnoRv8fH7ivNC4gEX9prvd4RwvRaL"},"signature":"hw/Mo3ZZYu1pEiDdymElFkuCuJzg9soDHw+4DxK7cL9rafiyykh7VynS+guotRAKXhfYMwCiyWmiznc6R+UlsQ=="}}} - let token = HumanAddr("secret1rf03820fp8gngzg2w02vd30ns78qkc8rg8dxaq".to_string()); + let token = "secret1rf03820fp8gngzg2w02vd30ns78qkc8rg8dxaq".to_string(); let permit: Permit = Permit{ params: PermitParams { @@ -105,14 +105,28 @@ mod tests { } }; - let address = validate(&deps, "test", &permit, token.clone(), Some("secret")).unwrap(); + let address = validate::<_, MockStorage, MockApi, MockQuerier>( + deps.as_ref(), + "test", + &permit, + token.clone(), + Some("secret"), + ) + .unwrap(); assert_eq!( address, "secret1399pyvvk3hvwgxwt3udkslsc5jl3rqv4yshfrl".to_string() ); - let address = validate(&deps, "test", &permit, token, Some("cosmos")).unwrap(); + let address = validate::<_, MockStorage, MockApi, MockQuerier>( + deps.as_ref(), + "test", + &permit, + token, + Some("cosmos"), + ) + .unwrap(); assert_eq!( address, diff --git a/packages/permit/src/state.rs b/packages/permit/src/state.rs index fd9df80..af853c3 100644 --- a/packages/permit/src/state.rs +++ b/packages/permit/src/state.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{HumanAddr, Storage}; +use cosmwasm_std::Storage; pub struct RevokedPermits; @@ -6,7 +6,7 @@ impl RevokedPermits { pub fn is_permit_revoked( storgae: &dyn Storage, storage_prefix: &str, - account: &HumanAddr, + account: &String, permit_name: &str, ) -> bool { let storage_key = storage_prefix.to_string() + &account.to_string() + permit_name; @@ -17,7 +17,7 @@ impl RevokedPermits { pub fn revoke_permit( storage: &mut dyn Storage, storage_prefix: &str, - account: &HumanAddr, + account: &String, permit_name: &str, ) { let storage_key = storage_prefix.to_string() + &account.to_string() + permit_name; diff --git a/packages/permit/src/structs.rs b/packages/permit/src/structs.rs index fc9f387..f395424 100644 --- a/packages/permit/src/structs.rs +++ b/packages/permit/src/structs.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::pubkey_to_account; -use cosmwasm_std::{Binary, CanonicalAddr, HumanAddr, Uint128}; +use cosmwasm_std::{Binary, CanonicalAddr, Uint128}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -15,7 +15,7 @@ pub struct Permit { } impl Permit { - pub fn check_token(&self, token: &HumanAddr) -> bool { + pub fn check_token(&self, token: &String) -> bool { self.params.allowed_tokens.contains(token) } @@ -27,7 +27,7 @@ impl Permit { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct PermitParams { - pub allowed_tokens: Vec, + pub allowed_tokens: Vec, pub permit_name: String, pub chain_id: String, #[serde(bound = "")] @@ -102,7 +102,7 @@ impl Fee { pub fn new() -> Self { Self { amount: vec![Coin::new()], - gas: Uint128(1), + gas: Uint128::new(1), } } } @@ -161,7 +161,7 @@ impl PermitMsg { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct PermitContent { - pub allowed_tokens: Vec, + pub allowed_tokens: Vec, #[serde(bound = "")] pub permissions: Vec, pub permit_name: String, From af71c80d103c474b6e6d816f8b9387f0cb33d663 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Tue, 2 Aug 2022 16:35:40 +0300 Subject: [PATCH 06/37] Fixed `packages/utils` --- Cargo.toml | 2 +- packages/utils/Cargo.toml | 6 +- packages/utils/src/calls.rs | 94 +++++++------ packages/utils/src/feature_toggle.rs | 196 ++++++++++++--------------- packages/utils/src/padding.rs | 18 +-- packages/utils/src/types.rs | 3 +- 6 files changed, 150 insertions(+), 169 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0109947..d1f1800 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["packages/storage", "packages/toolkit", "packages/serialization", "packages/crypto", "packages/snip20", "packages/snip721", "packages/permit"] +members = ["packages/storage", "packages/toolkit", "packages/serialization", "packages/crypto", "packages/snip20", "packages/snip721", "packages/permit", "packages/utils"] # Since `secret-toolkit` depends on all the other packages, this should make `cargo-check` a bit quicker # as it won't have to check all the other packages twice. default-members = ["packages/toolkit"] diff --git a/packages/utils/Cargo.toml b/packages/utils/Cargo.toml index 49ad01f..7187271 100644 --- a/packages/utils/Cargo.toml +++ b/packages/utils/Cargo.toml @@ -15,6 +15,6 @@ all-features = true [dependencies] serde = "1.0" -schemars = "0.7" -cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10" } -cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10"} +schemars = "0.8.1" +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } diff --git a/packages/utils/src/calls.rs b/packages/utils/src/calls.rs index 5f94321..8babc4c 100755 --- a/packages/utils/src/calls.rs +++ b/packages/utils/src/calls.rs @@ -1,8 +1,8 @@ use serde::{de::DeserializeOwned, Serialize}; use cosmwasm_std::{ - to_binary, Coin, CosmosMsg, HumanAddr, Querier, QueryRequest, StdResult, Uint128, WasmMsg, - WasmQuery, + to_binary, Coin, CosmosMsg, CustomQuery, QuerierWrapper, QueryRequest, StdResult, Uint128, + WasmMsg, WasmQuery, }; use super::space_pad; @@ -25,14 +25,14 @@ pub trait InitCallback: Serialize { /// /// * `label` - String holding the label for the new contract instance /// * `code_id` - code ID of the contract to be instantiated - /// * `callback_code_hash` - String holding the code hash of the contract to be instantiated - /// * `send_amount` - Optional Uint128 amount of native coin to send with instantiation message + /// * `code_hash` - String holding the code hash of the contract to be instantiated + /// * `funds_amount` - Optional Uint128 amount of native coin to send with instantiation message fn to_cosmos_msg( &self, label: String, code_id: u64, - callback_code_hash: String, - send_amount: Option, + code_hash: String, + funds_amount: Option, ) -> StdResult { let mut msg = to_binary(self)?; // can not have 0 block size @@ -42,9 +42,9 @@ pub trait InitCallback: Serialize { Self::BLOCK_SIZE }; space_pad(&mut msg.0, padding); - let mut send = Vec::new(); - if let Some(amount) = send_amount { - send.push(Coin { + let mut funds = Vec::new(); + if let Some(amount) = funds_amount { + funds.push(Coin { amount, denom: String::from("uscrt"), }); @@ -52,8 +52,8 @@ pub trait InitCallback: Serialize { let init = WasmMsg::Instantiate { code_id, msg, - callback_code_hash, - send, + code_hash, + funds, label, }; Ok(init.into()) @@ -76,14 +76,14 @@ pub trait HandleCallback: Serialize { /// /// # Arguments /// - /// * `callback_code_hash` - String holding the code hash of the contract to be executed + /// * `code_hash` - String holding the code hash of the contract to be executed /// * `contract_addr` - address of the contract being called - /// * `send_amount` - Optional Uint128 amount of native coin to send with the handle message + /// * `funds_amount` - Optional Uint128 amount of native coin to send with the handle message fn to_cosmos_msg( &self, - callback_code_hash: String, - contract_addr: HumanAddr, - send_amount: Option, + code_hash: String, + contract_addr: String, + funds_amount: Option, ) -> StdResult { let mut msg = to_binary(self)?; // can not have 0 block size @@ -93,9 +93,9 @@ pub trait HandleCallback: Serialize { Self::BLOCK_SIZE }; space_pad(&mut msg.0, padding); - let mut send = Vec::new(); - if let Some(amount) = send_amount { - send.push(Coin { + let mut funds = Vec::new(); + if let Some(amount) = funds_amount { + funds.push(Coin { amount, denom: String::from("uscrt"), }); @@ -103,8 +103,8 @@ pub trait HandleCallback: Serialize { let execute = WasmMsg::Execute { msg, contract_addr, - callback_code_hash, - send, + code_hash, + funds, }; Ok(execute.into()) } @@ -127,11 +127,11 @@ pub trait Query: Serialize { /// * `querier` - a reference to the Querier dependency of the querying contract /// * `callback_code_hash` - String holding the code hash of the contract to be queried /// * `contract_addr` - address of the contract being queried - fn query( + fn query<'a, C: CustomQuery, T: DeserializeOwned>( &self, - querier: &Q, - callback_code_hash: String, - contract_addr: HumanAddr, + querier: QuerierWrapper<'a, C>, + code_hash: String, + contract_addr: String, ) -> StdResult { let mut msg = to_binary(self)?; // can not have 0 block size @@ -143,7 +143,7 @@ pub trait Query: Serialize { space_pad(&mut msg.0, padding); querier.query(&QueryRequest::Wasm(WasmQuery::Smart { contract_addr, - callback_code_hash, + code_hash, msg, })) } @@ -152,7 +152,9 @@ pub trait Query: Serialize { #[cfg(test)] mod tests { use super::*; - use cosmwasm_std::{to_vec, Binary, Querier, QuerierResult}; + use cosmwasm_std::{ + to_vec, Binary, ContractResult, Empty, Querier, QuerierResult, SystemError, SystemResult, + }; use serde::Deserialize; #[derive(Serialize)] @@ -186,9 +188,9 @@ mod tests { #[test] fn test_handle_callback_implementation_works() -> StdResult<()> { - let address = HumanAddr("secret1xyzasdf".to_string()); + let address = "secret1xyzasdf".to_string(); let hash = "asdf".to_string(); - let amount = Uint128(1234); + let amount = Uint128::new(1234); let cosmos_message: CosmosMsg = FooHandle::Var1 { f1: 1, f2: 2 }.to_cosmos_msg( hash.clone(), @@ -199,16 +201,16 @@ mod tests { match cosmos_message { CosmosMsg::Wasm(WasmMsg::Execute { contract_addr, - callback_code_hash, + code_hash, msg, - send, + funds, }) => { assert_eq!(contract_addr, address); - assert_eq!(callback_code_hash, hash); + assert_eq!(code_hash, hash); let mut expected_msg = r#"{"Var1":{"f1":1,"f2":2}}"#.as_bytes().to_vec(); space_pad(&mut expected_msg, 256); assert_eq!(msg.0, expected_msg); - assert_eq!(send, vec![Coin::new(amount.0, "uscrt")]) + assert_eq!(funds, vec![Coin::new(amount.u128(), "uscrt")]) } other => panic!("unexpected CosmosMsg variant: {:?}", other), }; @@ -221,7 +223,7 @@ mod tests { let lbl = "testlabel".to_string(); let id = 17u64; let hash = "asdf".to_string(); - let amount = Uint128(1234); + let amount = Uint128::new(1234); let cosmos_message: CosmosMsg = FooInit { f1: 1, f2: 2 }.to_cosmos_msg(lbl.clone(), id, hash.clone(), Some(amount))?; @@ -230,16 +232,16 @@ mod tests { CosmosMsg::Wasm(WasmMsg::Instantiate { code_id, msg, - callback_code_hash, - send, + code_hash, + funds, label, }) => { assert_eq!(code_id, id); let mut expected_msg = r#"{"f1":1,"f2":2}"#.as_bytes().to_vec(); space_pad(&mut expected_msg, 256); assert_eq!(msg.0, expected_msg); - assert_eq!(callback_code_hash, hash); - assert_eq!(send, vec![Coin::new(amount.0, "uscrt")]); + assert_eq!(code_hash, hash); + assert_eq!(funds, vec![Coin::new(amount.u128(), "uscrt")]); assert_eq!(label, lbl) } other => panic!("unexpected CosmosMsg variant: {:?}", other), @@ -264,22 +266,26 @@ mod tests { space_pad(&mut expected_msg, 256); let expected_request: QueryRequest = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: HumanAddr("secret1xyzasdf".to_string()), - callback_code_hash: "asdf".to_string(), + contract_addr: "secret1xyzasdf".to_string(), + code_hash: "asdf".to_string(), msg: Binary(expected_msg), }); let test_req: &[u8] = &to_vec(&expected_request).unwrap(); assert_eq!(request, test_req); - Ok(to_binary(&QueryResponse { bar1: 1, bar2: 2 })) + let response = match to_binary(&QueryResponse { bar1: 1, bar2: 2 }) { + Ok(response) => ContractResult::Ok(response), + Err(_e) => return SystemResult::Err(SystemError::Unknown {}), + }; + SystemResult::Ok(response) } } - let querier = MyMockQuerier {}; - let address = HumanAddr("secret1xyzasdf".to_string()); + let querier = QuerierWrapper::::new(&MyMockQuerier {}); + let address = "secret1xyzasdf".to_string(); let hash = "asdf".to_string(); let response: QueryResponse = - FooQuery::Query1 { f1: 1, f2: 2 }.query(&querier, hash, address)?; + FooQuery::Query1 { f1: 1, f2: 2 }.query(querier, hash, address)?; assert_eq!(response, QueryResponse { bar1: 1, bar2: 2 }); Ok(()) diff --git a/packages/utils/src/feature_toggle.rs b/packages/utils/src/feature_toggle.rs index 60912eb..798960e 100644 --- a/packages/utils/src/feature_toggle.rs +++ b/packages/utils/src/feature_toggle.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ - to_binary, to_vec, Api, Env, Extern, HandleResponse, HandleResult, HumanAddr, Querier, - QueryResult, ReadonlyStorage, StdError, StdResult, Storage, + to_binary, to_vec, Addr, Binary, Deps, DepsMut, MessageInfo, Response, StdError, StdResult, + Storage, }; use cosmwasm_storage::{Bucket, ReadonlyBucket}; use schemars::JsonSchema; @@ -19,10 +19,10 @@ impl FeatureToggleTrait for FeatureToggle { pub trait FeatureToggleTrait { const STORAGE_KEY: &'static [u8]; - fn init_features( - storage: &mut S, + fn init_features<'a, T: Serialize>( + storage: &'a mut dyn Storage, feature_statuses: Vec>, - pausers: Vec, + pausers: Vec, ) -> StdResult<()> { for fs in feature_statuses { Self::set_feature_status(storage, &fs.feature, fs.status)?; @@ -35,8 +35,8 @@ pub trait FeatureToggleTrait { Ok(()) } - fn require_not_paused( - storage: &S, + fn require_not_paused<'a, T: Serialize>( + storage: &'a dyn Storage, features: Vec, ) -> StdResult<()> { for feature in features { @@ -63,7 +63,7 @@ pub trait FeatureToggleTrait { Ok(()) } - fn pause(storage: &mut S, features: Vec) -> StdResult<()> { + fn pause<'a, T: Serialize>(storage: &'a mut dyn Storage, features: Vec) -> StdResult<()> { for f in features { Self::set_feature_status(storage, &f, Status::Paused)?; } @@ -71,7 +71,7 @@ pub trait FeatureToggleTrait { Ok(()) } - fn unpause(storage: &mut S, features: Vec) -> StdResult<()> { + fn unpause<'a, T: Serialize>(storage: &'a mut dyn Storage, features: Vec) -> StdResult<()> { for f in features { Self::set_feature_status(storage, &f, Status::NotPaused)?; } @@ -79,122 +79,97 @@ pub trait FeatureToggleTrait { Ok(()) } - fn is_pauser(storage: &S, key: &HumanAddr) -> StdResult { - let feature_store: ReadonlyBucket = - ReadonlyBucket::multilevel(&[Self::STORAGE_KEY, PREFIX_PAUSERS], storage); - feature_store - .may_load(key.0.as_bytes()) - .map(|p| p.is_some()) + fn is_pauser<'a>(storage: &'a dyn Storage, key: &Addr) -> StdResult { + let feature_store: ReadonlyBucket = + ReadonlyBucket::multilevel(storage, &[Self::STORAGE_KEY, PREFIX_PAUSERS]); + feature_store.may_load(key.as_bytes()).map(|p| p.is_some()) } - fn set_pauser(storage: &mut S, key: &HumanAddr) -> StdResult<()> { - let mut feature_store = Bucket::multilevel(&[Self::STORAGE_KEY, PREFIX_PAUSERS], storage); - feature_store.save(key.0.as_bytes(), &true /* value is insignificant */) + fn set_pauser<'a>(storage: &'a mut dyn Storage, key: &Addr) -> StdResult<()> { + let mut feature_store = Bucket::multilevel(storage, &[Self::STORAGE_KEY, PREFIX_PAUSERS]); + feature_store.save(key.as_bytes(), &true /* value is insignificant */) } - fn remove_pauser(storage: &mut S, key: &HumanAddr) { - let mut feature_store: Bucket = - Bucket::multilevel(&[Self::STORAGE_KEY, PREFIX_PAUSERS], storage); - feature_store.remove(key.0.as_bytes()) + fn remove_pauser<'a>(storage: &'a mut dyn Storage, key: &Addr) { + let mut feature_store: Bucket = + Bucket::multilevel(storage, &[Self::STORAGE_KEY, PREFIX_PAUSERS]); + feature_store.remove(key.as_bytes()) } - fn get_feature_status( - storage: &S, + fn get_feature_status<'a, T: Serialize>( + storage: &'a dyn Storage, key: &T, ) -> StdResult> { let feature_store = - ReadonlyBucket::multilevel(&[Self::STORAGE_KEY, PREFIX_FEATURES], storage); + ReadonlyBucket::multilevel(storage, &[Self::STORAGE_KEY, PREFIX_FEATURES]); feature_store.may_load(&cosmwasm_std::to_vec(&key)?) } - fn set_feature_status( - storage: &mut S, + fn set_feature_status<'a, T: Serialize>( + storage: &'a mut dyn Storage, key: &T, item: Status, ) -> StdResult<()> { - let mut feature_store = Bucket::multilevel(&[Self::STORAGE_KEY, PREFIX_FEATURES], storage); + let mut feature_store = Bucket::multilevel(storage, &[Self::STORAGE_KEY, PREFIX_FEATURES]); feature_store.save(&cosmwasm_std::to_vec(&key)?, &item) } - fn handle_pause( - deps: &mut Extern, - env: &Env, + fn handle_pause( + deps: DepsMut, + info: &MessageInfo, features: Vec, - ) -> HandleResult { - if !Self::is_pauser(&deps.storage, &env.message.sender)? { - return Err(StdError::unauthorized()); + ) -> StdResult { + if !Self::is_pauser(deps.storage, &info.sender)? { + return Err(StdError::generic_err("unauthorized")); } - Self::pause(&mut deps.storage, features)?; + Self::pause(deps.storage, features)?; - Ok(HandleResponse { - messages: vec![], - log: vec![], - data: Some(to_binary(&HandleAnswer::Pause { - status: ResponseStatus::Success, - })?), - }) + Ok(Response::new().set_data(to_binary(&HandleAnswer::Pause { + status: ResponseStatus::Success, + })?)) } - fn handle_unpause( - deps: &mut Extern, - env: &Env, + fn handle_unpause( + deps: DepsMut, + info: &MessageInfo, features: Vec, - ) -> HandleResult { - if !Self::is_pauser(&deps.storage, &env.message.sender)? { - return Err(StdError::unauthorized()); + ) -> StdResult { + if !Self::is_pauser(deps.storage, &info.sender)? { + return Err(StdError::generic_err("unauthorized")); } - Self::unpause(&mut deps.storage, features)?; + Self::unpause(deps.storage, features)?; - Ok(HandleResponse { - messages: vec![], - log: vec![], - data: Some(to_binary(&HandleAnswer::Unpause { - status: ResponseStatus::Success, - })?), - }) + Ok(Response::new().set_data(to_binary(&HandleAnswer::Unpause { + status: ResponseStatus::Success, + })?)) } - fn handle_set_pauser( - deps: &mut Extern, - _env: &Env, - address: HumanAddr, - ) -> HandleResult { - Self::set_pauser(&mut deps.storage, &address)?; - - Ok(HandleResponse { - messages: vec![], - log: vec![], - data: Some(to_binary(&HandleAnswer::SetPauser { + fn handle_set_pauser(deps: DepsMut, address: Addr) -> StdResult { + Self::set_pauser(deps.storage, &address)?; + + Ok( + Response::new().set_data(to_binary(&HandleAnswer::SetPauser { status: ResponseStatus::Success, })?), - }) + ) } - fn handle_remove_pauser( - deps: &mut Extern, - _env: &Env, - address: HumanAddr, - ) -> HandleResult { - Self::remove_pauser(&mut deps.storage, &address); - - Ok(HandleResponse { - messages: vec![], - log: vec![], - data: Some(to_binary(&HandleAnswer::RemovePauser { + fn handle_remove_pauser(deps: DepsMut, address: Addr) -> StdResult { + Self::remove_pauser(deps.storage, &address); + + Ok( + Response::new().set_data(to_binary(&HandleAnswer::RemovePauser { status: ResponseStatus::Success, })?), - }) + ) } - fn query_status( - deps: &Extern, - features: Vec, - ) -> QueryResult { + fn query_status(deps: Deps, features: Vec) -> StdResult { let mut status = Vec::with_capacity(features.len()); for feature in features { - match Self::get_feature_status(&deps.storage, &feature)? { + match Self::get_feature_status(deps.storage, &feature)? { None => { return Err(StdError::generic_err(format!( "invalid feature: {} does not exist", @@ -208,11 +183,8 @@ pub trait FeatureToggleTrait { to_binary(&FeatureToggleQueryAnswer::Status { features: status }) } - fn query_is_pauser( - deps: &Extern, - address: HumanAddr, - ) -> QueryResult { - let is_pauser = Self::is_pauser(&deps.storage, &address)?; + fn query_is_pauser(deps: Deps, address: Addr) -> StdResult { + let is_pauser = Self::is_pauser(deps.storage, &address)?; to_binary(&FeatureToggleQueryAnswer::<()>::IsPauser { is_pauser }) } @@ -242,10 +214,10 @@ pub enum FeatureToggleHandleMsg { features: Vec, }, SetPauser { - address: HumanAddr, + address: String, }, RemovePauser { - address: HumanAddr, + address: String, }, } @@ -273,7 +245,7 @@ pub enum FeatureToggleQueryMsg { features: Vec, }, IsPauser { - address: HumanAddr, + address: String, }, } @@ -296,8 +268,8 @@ mod tests { FeatureStatus, FeatureToggle, FeatureToggleHandleMsg, FeatureToggleQueryMsg, FeatureToggleTrait, HandleAnswer, ResponseStatus, Status, }; - use cosmwasm_std::testing::{mock_dependencies, mock_env, MockStorage}; - use cosmwasm_std::{from_binary, HumanAddr, MemoryStorage, StdError, StdResult}; + use cosmwasm_std::testing::{mock_dependencies, mock_info, MockStorage}; + use cosmwasm_std::{from_binary, Addr, MemoryStorage, StdError, StdResult}; fn init_features(storage: &mut MemoryStorage) -> StdResult<()> { FeatureToggle::init_features( @@ -316,7 +288,7 @@ mod tests { status: Status::Paused, }, ], - vec![HumanAddr("alice".to_string())], + vec![Addr::unchecked("alice".to_string())], ) } @@ -343,11 +315,11 @@ mod tests { ); assert_eq!( - FeatureToggle::is_pauser(&storage, &HumanAddr("alice".to_string()))?, + FeatureToggle::is_pauser(&storage, &Addr::unchecked("alice".to_string()))?, true ); assert_eq!( - FeatureToggle::is_pauser(&storage, &HumanAddr("bob".to_string()))?, + FeatureToggle::is_pauser(&storage, &Addr::unchecked("bob".to_string()))?, false ); @@ -370,16 +342,17 @@ mod tests { #[test] fn test_handle_unpause() -> StdResult<()> { - let mut deps = mock_dependencies(20, &[]); + let mut deps = mock_dependencies(); init_features(&mut deps.storage)?; - let env = mock_env("non-pauser", &[]); - let error = FeatureToggle::handle_unpause(&mut deps, &env, vec!["Feature3".to_string()]); - assert_eq!(error, Err(StdError::unauthorized())); + let info = mock_info("non-pauser", &[]); + let error = + FeatureToggle::handle_unpause(deps.as_mut(), &info, vec!["Feature3".to_string()]); + assert_eq!(error, Err(StdError::generic_err("unauthorized"))); - let env = mock_env("alice", &[]); + let info = mock_info("alice", &[]); let response = - FeatureToggle::handle_unpause(&mut deps, &env, vec!["Feature3".to_string()])?; + FeatureToggle::handle_unpause(deps.as_mut(), &info, vec!["Feature3".to_string()])?; let answer: HandleAnswer = from_binary(&response.data.unwrap())?; assert_eq!( @@ -407,15 +380,16 @@ mod tests { #[test] fn test_handle_pause() -> StdResult<()> { - let mut deps = mock_dependencies(20, &[]); + let mut deps = mock_dependencies(); init_features(&mut deps.storage)?; - let env = mock_env("non-pauser", &[]); - let error = FeatureToggle::handle_pause(&mut deps, &env, vec!["Feature2".to_string()]); - assert_eq!(error, Err(StdError::unauthorized())); + let info = mock_info("non-pauser", &[]); + let error = FeatureToggle::handle_pause(deps.as_mut(), &info, vec!["Feature2".to_string()]); + assert_eq!(error, Err(StdError::generic_err("unauthorized"))); - let env = mock_env("alice", &[]); - let response = FeatureToggle::handle_pause(&mut deps, &env, vec!["Feature2".to_string()])?; + let info = mock_info("alice", &[]); + let response = + FeatureToggle::handle_pause(deps.as_mut(), &info, vec!["Feature2".to_string()])?; let answer: HandleAnswer = from_binary(&response.data.unwrap())?; assert_eq!( @@ -451,7 +425,7 @@ mod tests { let mut storage = MockStorage::new(); init_features(&mut storage)?; - let bob = HumanAddr("bob".to_string()); + let bob = Addr::unchecked("bob".to_string()); FeatureToggle::set_pauser(&mut storage, &bob)?; assert!( diff --git a/packages/utils/src/padding.rs b/packages/utils/src/padding.rs index b7c3817..2b37dbf 100644 --- a/packages/utils/src/padding.rs +++ b/packages/utils/src/padding.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{HandleResult, QueryResult}; +use cosmwasm_std::{Binary, Response, StdResult}; /// Take a Vec and pad it up to a multiple of `block_size`, using spaces at the end. pub fn space_pad(message: &mut Vec, block_size: usize) -> &mut Vec { @@ -14,11 +14,13 @@ pub fn space_pad(message: &mut Vec, block_size: usize) -> &mut Vec { message } -/// Pad the data and logs in a `HandleResult` to the block size, with spaces. -// The big `where` clause is based on the `where` clause of `HandleResponse`. +/// Pad the data and logs in a `StdResult` to the block size, with spaces. // Users don't need to care about it as the type `T` has a default, and will // always be known in the context of the caller. -pub fn pad_handle_result(response: HandleResult, block_size: usize) -> HandleResult +pub fn pad_handle_result( + response: StdResult>, + block_size: usize, +) -> StdResult> where T: Clone + std::fmt::Debug + PartialEq + schemars::JsonSchema, { @@ -27,18 +29,18 @@ where space_pad(&mut data.0, block_size); data }); - for log in &mut response.log { + for attribute in &mut response.attributes { // Safety: These two are safe because we know the characters that // `space_pad` appends are valid UTF-8 - unsafe { space_pad(log.key.as_mut_vec(), block_size) }; - unsafe { space_pad(log.value.as_mut_vec(), block_size) }; + unsafe { space_pad(attribute.key.as_mut_vec(), block_size) }; + unsafe { space_pad(attribute.value.as_mut_vec(), block_size) }; } response }) } /// Pad a `QueryResult` with spaces -pub fn pad_query_result(response: QueryResult, block_size: usize) -> QueryResult { +pub fn pad_query_result(response: StdResult, block_size: usize) -> StdResult { response.map(|mut response| { space_pad(&mut response.0, block_size); response diff --git a/packages/utils/src/types.rs b/packages/utils/src/types.rs index 608fabd..f9e2149 100644 --- a/packages/utils/src/types.rs +++ b/packages/utils/src/types.rs @@ -1,9 +1,8 @@ -use cosmwasm_std::HumanAddr; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone, JsonSchema)] pub struct Contract { - pub address: HumanAddr, + pub address: String, pub hash: String, } From 02fa4472c1569b9bb1528a16cadc0339ebcdf83c Mon Sep 17 00:00:00 2001 From: TomL94 Date: Tue, 2 Aug 2022 18:12:08 +0300 Subject: [PATCH 07/37] Fix `packages/incubator`, clippy --- Cargo.toml | 2 +- packages/incubator/Cargo.toml | 5 +- packages/incubator/src/cashmap.rs | 98 +++++++++----------- packages/incubator/src/generational_store.rs | 88 ++++++++---------- packages/incubator/src/maxheap.rs | 50 +++++----- packages/permit/src/funcs.rs | 8 +- packages/permit/src/state.rs | 8 +- packages/permit/src/structs.rs | 4 +- packages/snip20/src/query.rs | 40 ++++---- packages/snip721/src/handle.rs | 4 +- packages/snip721/src/query.rs | 68 +++++++------- packages/utils/src/calls.rs | 4 +- packages/utils/src/feature_toggle.rs | 27 +++--- 13 files changed, 191 insertions(+), 215 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d1f1800..5eafb8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["packages/storage", "packages/toolkit", "packages/serialization", "packages/crypto", "packages/snip20", "packages/snip721", "packages/permit", "packages/utils"] +members = ["packages/*"] # Since `secret-toolkit` depends on all the other packages, this should make `cargo-check` a bit quicker # as it won't have to check all the other packages twice. default-members = ["packages/toolkit"] diff --git a/packages/incubator/Cargo.toml b/packages/incubator/Cargo.toml index b3e5b09..ab1a44f 100644 --- a/packages/incubator/Cargo.toml +++ b/packages/incubator/Cargo.toml @@ -15,11 +15,12 @@ all-features = true [dependencies] serde = { version = "1.0", optional = true } -cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10", optional = true } -cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10", optional = true } +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret", optional = true } +cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret", optional = true } secret-toolkit-serialization = { version = "0.3", path = "../serialization", optional = true } [features] +default = ["cashmap", "generational-store", "maxheap"] cashmap = ["cosmwasm-storage", "serde", "secret-toolkit-serialization", "cosmwasm-std"] generational-store = ["secret-toolkit-serialization", "serde", "cosmwasm-std"] maxheap = ["secret-toolkit-serialization", "serde", "cosmwasm-std"] diff --git a/packages/incubator/src/cashmap.rs b/packages/incubator/src/cashmap.rs index 8c5b947..4ea1cc2 100644 --- a/packages/incubator/src/cashmap.rs +++ b/packages/incubator/src/cashmap.rs @@ -6,7 +6,7 @@ use std::marker::PhantomData; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use cosmwasm_std::{ReadonlyStorage, StdError, StdResult, Storage}; +use cosmwasm_std::{StdError, StdResult, Storage}; use cosmwasm_storage::{PrefixedStorage, ReadonlyPrefixedStorage}; use secret_toolkit_serialization::{Bincode2, Serde}; @@ -46,37 +46,33 @@ pub struct InternalItem meta_data: MetaData, } -pub struct CashMap<'a, T, S, Ser = Bincode2> +pub struct CashMap<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { - storage: &'a mut S, + storage: &'a mut dyn Storage, item_type: PhantomData<*const InternalItem>, serialization_type: PhantomData<*const Ser>, prefix: Option>, } -impl<'a, T, S> CashMap<'a, T, S, Bincode2> +impl<'a, T> CashMap<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, { - pub fn init(name: &[u8], storage: &'a mut S) -> Self { + pub fn init(name: &[u8], storage: &'a mut dyn Storage) -> Self { Self::attach_with_serialization(storage, Bincode2, Some(name.to_vec())) } - pub fn attach(storage: &'a mut S) -> Self { + pub fn attach(storage: &'a mut dyn Storage) -> Self { Self::attach_with_serialization(storage, Bincode2, None) } } -impl<'a, T, S, Ser> CashMap<'a, T, S, Ser> +impl<'a, T, Ser> CashMap<'a, T, Ser> where T: Serialize + DeserializeOwned, - // K: Hash + Eq + ?Sized, - S: Storage, Ser: Serde, { pub fn is_empty(&self) -> bool { @@ -89,7 +85,7 @@ where /// This method allows customization of the serialization, in case we want to force /// something other than Bincode2, which has it's drawbacks (such as Enums fucking up) pub fn attach_with_serialization( - storage: &'a mut S, + storage: &'a mut dyn Storage, _serialization: Ser, prefix: Option>, ) -> Self { @@ -293,7 +289,7 @@ where #[allow(clippy::ptr_arg)] fn store_indexes(&mut self, index: u32, indexes: &Vec) -> StdResult<()> { if let Some(prefix) = &self.prefix { - let mut store = PrefixedStorage::new(prefix, self.storage); + let mut store = PrefixedStorage::new(self.storage, prefix); store.set( &[INDEXES, index.to_be_bytes().to_vec().as_slice()].concat(), &Ser::serialize(indexes)?, @@ -310,7 +306,7 @@ where // unused - we just set deleted = true fn remove_from_store(&mut self, key: &[u8]) -> StdResult<()> { if let Some(prefix) = &self.prefix { - let mut store = PrefixedStorage::new(prefix, self.storage); + let mut store = PrefixedStorage::new(self.storage, prefix); store.remove(key) } else { self.storage.remove(key) @@ -320,7 +316,7 @@ where fn store(&mut self, key: &[u8], item: &InternalItem) -> StdResult<()> { if let Some(prefix) = &self.prefix { - let mut store = PrefixedStorage::new(prefix, self.storage); + let mut store = PrefixedStorage::new(self.storage, prefix); store.set(key, &Ser::serialize(item)?) } else { self.storage.set(key, &Ser::serialize(item)?) @@ -329,7 +325,7 @@ where Ok(()) } - fn as_readonly(&self) -> ReadOnlyCashMap { + fn as_readonly(&self) -> ReadOnlyCashMap { ReadOnlyCashMap { storage: self.storage, item_type: self.item_type, @@ -340,7 +336,7 @@ where fn set_length(&mut self, length: u32) -> StdResult<()> { if let Some(prefix) = &self.prefix { - let mut store = PrefixedStorage::new(prefix, self.storage); + let mut store = PrefixedStorage::new(self.storage, prefix); store.set(MAP_LENGTH, &Ser::serialize(&length.to_be_bytes())?) } else { self.storage @@ -356,40 +352,37 @@ where } /// basically this is used in queries -pub struct ReadOnlyCashMap<'a, T, S, Ser = Bincode2> +pub struct ReadOnlyCashMap<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { - storage: &'a S, + storage: &'a dyn Storage, item_type: PhantomData<*const InternalItem>, serialization_type: PhantomData<*const Ser>, prefix: Option>, } -impl<'a, T, S> ReadOnlyCashMap<'a, T, S, Bincode2> +impl<'a, T> ReadOnlyCashMap<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, { - pub fn init(name: &[u8], storage: &'a S) -> Self { + pub fn init(name: &[u8], storage: &'a dyn Storage) -> Self { Self::attach_with_serialization(storage, Bincode2, Some(name.to_vec())) } - pub fn attach(storage: &'a S) -> Self { + pub fn attach(storage: &'a dyn Storage) -> Self { Self::attach_with_serialization(storage, Bincode2, None) } } -impl<'a, T, S, Ser> ReadOnlyCashMap<'a, T, S, Ser> +impl<'a, T, Ser> ReadOnlyCashMap<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { pub fn attach_with_serialization( - storage: &'a S, + storage: &'a dyn Storage, _serialization: Ser, prefix: Option>, ) -> Self { @@ -479,7 +472,7 @@ where pub fn len(&self) -> u32 { let maybe_serialized = if let Some(prefix) = &self.prefix { - let store = ReadonlyPrefixedStorage::new(prefix, self.storage); + let store = ReadonlyPrefixedStorage::new(self.storage, prefix); store.get(MAP_LENGTH) } else { self.storage.get(MAP_LENGTH) @@ -505,7 +498,6 @@ where if start_pos > max_size { return Err(StdError::NotFound { kind: "Out of bounds".to_string(), - backtrace: None, }); } else if end_pos >= max_size { end_pos = max_size - 1; @@ -560,7 +552,7 @@ where pub fn get_indexes(&self, index: u32) -> Vec { let maybe_serialized = if let Some(prefix) = &self.prefix { - let store = ReadonlyPrefixedStorage::new(prefix, self.storage); + let store = ReadonlyPrefixedStorage::new(self.storage, prefix); store.get(&[INDEXES, index.to_be_bytes().to_vec().as_slice()].concat()) } else { self.storage @@ -617,7 +609,7 @@ where fn _prefix_load(&self, hash: &u64) -> StdResult> { let serialized = if let Some(prefix) = &self.prefix { - let store = ReadonlyPrefixedStorage::new(prefix, self.storage); + let store = ReadonlyPrefixedStorage::new(self.storage, prefix); store.get(&hash.to_be_bytes()) } else { self.storage.get(&hash.to_be_bytes()) @@ -642,7 +634,7 @@ where hasher.finish() } - pub fn iter(&self) -> Iter<'a, T, S, Ser> { + pub fn iter(&self) -> Iter<'a, T, Ser> { Iter { storage: Self::clone(self), start: 0, @@ -652,21 +644,19 @@ where } /// An iterator over the contents of the append store. -pub struct Iter<'a, T, S, Ser> +pub struct Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { - storage: ReadOnlyCashMap<'a, T, S, Ser>, + storage: ReadOnlyCashMap<'a, T, Ser>, start: u32, end: u32, } -impl<'a, T, S, Ser> Iterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> Iterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { type Item = T; @@ -702,16 +692,15 @@ where } } -impl<'a, T, S, Ser> IntoIterator for ReadOnlyCashMap<'a, T, S, Ser> +impl<'a, T, Ser> IntoIterator for ReadOnlyCashMap<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { type Item = T; - type IntoIter = Iter<'a, T, S, Ser>; + type IntoIter = Iter<'a, T, Ser>; - fn into_iter(self) -> Iter<'a, T, S, Ser> { + fn into_iter(self) -> Iter<'a, T, Ser> { let end = self.len(); Iter { storage: self, @@ -722,10 +711,9 @@ where } // Manual `Clone` implementation because the default one tries to clone the Storage?? -impl<'a, T, S, Ser> Clone for ReadOnlyCashMap<'a, T, S, Ser> +impl<'a, T, Ser> Clone for ReadOnlyCashMap<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { fn clone(&self) -> Self { @@ -819,7 +807,7 @@ mod tests { #[test] fn test_hashmap_paging_prefixed() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut prefixed = PrefixedStorage::new(b"test", &mut storage); + let mut prefixed = PrefixedStorage::new(&mut storage, b"test"); let mut cashmap = CashMap::init(b"yo", &mut prefixed); let page_size = 50; @@ -1005,7 +993,7 @@ mod tests { #[test] fn test_hashmap_overwrite_prefixed() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut prefixed = PrefixedStorage::new(b"test", &mut storage); + let mut prefixed = PrefixedStorage::new(&mut storage, b"test"); let mut hashmap = CashMap::init(b"yo", &mut prefixed); let foo1 = Foo { @@ -1064,11 +1052,12 @@ mod tests { // Try to load it with the wrong format let typed_store = - ReadOnlyCashMap::::attach_with_serialization(&storage, Json, None); + ReadOnlyCashMap::::attach_with_serialization(&storage, Json, None); match typed_store.load(b"key2") { - Err(StdError::ParseErr { target, msg, .. }) - if target == "secret_toolkit_incubator::cashmap::InternalItem" - && msg == "Invalid type" => {} + Err(StdError::ParseErr { + target_type, msg, .. + }) if target_type == "secret_toolkit_incubator::cashmap::InternalItem" + && msg == "Invalid type" => {} other => panic!("unexpected value: {:?}", other), } @@ -1111,15 +1100,16 @@ mod tests { assert!(cmap.get(b"key3").is_none()); // Try to load it with the wrong format - let typed_store = ReadOnlyCashMap::::attach_with_serialization( + let typed_store = ReadOnlyCashMap::::attach_with_serialization( &storage, Json, Some(b"yo".to_vec()), ); match typed_store.load(b"key2") { - Err(StdError::ParseErr { target, msg, .. }) - if target == "secret_toolkit_incubator::cashmap::InternalItem" - && msg == "Invalid type" => {} + Err(StdError::ParseErr { + target_type, msg, .. + }) if target_type == "secret_toolkit_incubator::cashmap::InternalItem" + && msg == "Invalid type" => {} other => panic!("unexpected value: {:?}", other), } @@ -1167,7 +1157,7 @@ mod tests { #[test] fn test_cashmap_length_prefixed() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut prefixed = PrefixedStorage::new(b"test", &mut storage); + let mut prefixed = PrefixedStorage::new(&mut storage, b"test"); let mut cmap = CashMap::init(b"yo", &mut prefixed); let foo1 = Foo { diff --git a/packages/incubator/src/generational_store.rs b/packages/incubator/src/generational_store.rs index dc934aa..cc8bc95 100644 --- a/packages/incubator/src/generational_store.rs +++ b/packages/incubator/src/generational_store.rs @@ -18,7 +18,7 @@ use std::marker::PhantomData; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use cosmwasm_std::{ReadonlyStorage, StdError, StdResult, Storage}; +use cosmwasm_std::{StdError, StdResult, Storage}; use secret_toolkit_serialization::{Bincode2, Serde}; @@ -82,14 +82,12 @@ pub struct StoredOccupiedEntry { // Mutable generational index store /// A type allowing both reads from and writes to the generational store. -#[derive(Debug)] -pub struct GenerationalStoreMut<'a, T, S, Ser = Bincode2> +pub struct GenerationalStoreMut<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { - storage: &'a mut S, + storage: &'a mut dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, len: u32, @@ -99,16 +97,15 @@ where capacity: u32, } -impl<'a, T, S> GenerationalStoreMut<'a, T, S, Bincode2> +impl<'a, T> GenerationalStoreMut<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, { /// Try to use the provided storage as an GenerationalStore. If it doesn't seem to be one, then /// initialize it as one. /// /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create(storage: &'a mut S) -> StdResult { + pub fn attach_or_create(storage: &'a mut dyn Storage) -> StdResult { GenerationalStoreMut::attach_or_create_with_serialization(storage, Bincode2) } @@ -116,22 +113,24 @@ where /// /// Returns None if the provided storage doesn't seem like an GenerationalStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a mut S) -> Option> { + pub fn attach(storage: &'a mut dyn Storage) -> Option> { GenerationalStoreMut::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> GenerationalStoreMut<'a, T, S, Ser> +impl<'a, T, Ser> GenerationalStoreMut<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { /// Try to use the provided storage as an GenerationalStore. If it doesn't seem to be one, then /// initialize it as one. This method allows choosing the serialization format you want to use. /// /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create_with_serialization(storage: &'a mut S, _ser: Ser) -> StdResult { + pub fn attach_or_create_with_serialization( + storage: &'a mut dyn Storage, + _ser: Ser, + ) -> StdResult { let len_vec = storage.get(LEN_KEY); let generation_vec = storage.get(GENERATION_KEY); let free_list_head_vec = storage.get(FREE_LIST_HEAD_KEY); @@ -172,7 +171,10 @@ where /// /// Returns None if the provided storage doesn't seem like an GenerationalStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization(storage: &'a mut S, _ser: Ser) -> Option> { + pub fn attach_with_serialization( + storage: &'a mut dyn Storage, + _ser: Ser, + ) -> Option> { let len_vec = storage.get(LEN_KEY)?; let generation_vec = storage.get(GENERATION_KEY)?; let free_list_head_vec = storage.get(FREE_LIST_HEAD_KEY)?; @@ -187,7 +189,7 @@ where } fn new( - storage: &'a mut S, + storage: &'a mut dyn Storage, len_vec: &[u8], generation_vec: &[u8], free_list_head_vec: &[u8], @@ -351,16 +353,16 @@ where self.len == 0 } - pub fn storage(&mut self) -> &mut S { + pub fn storage(&'a mut self) -> &'a mut dyn Storage { self.storage } - pub fn readonly_storage(&self) -> &S { + pub fn readonly_storage(&'a self) -> &'a dyn Storage { self.storage } /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter { self.as_readonly().iter() } @@ -437,7 +439,7 @@ where } /// Gain access to the implementation of the immutable methods - fn as_readonly(&self) -> GenerationalStore { + fn as_readonly(&self) -> GenerationalStore { GenerationalStore { storage: self.storage, item_type: self.item_type, @@ -453,14 +455,12 @@ where // Readonly generational index store /// A type allowing only reads from an append store. useful in the context_, u8 of queries. -#[derive(Debug)] -pub struct GenerationalStore<'a, T, S, Ser = Bincode2> +pub struct GenerationalStore<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { - storage: &'a S, + storage: &'a dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, len: u32, @@ -469,24 +469,22 @@ where capacity: u32, } -impl<'a, T, S> GenerationalStore<'a, T, S, Bincode2> +impl<'a, T> GenerationalStore<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, { /// Try to use the provided storage as an GenerationalStore. /// /// Returns None if the provided storage doesn't seem like an GenerationalStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a S) -> Option> { + pub fn attach(storage: &'a dyn Storage) -> Option> { GenerationalStore::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> GenerationalStore<'a, T, S, Ser> +impl<'a, T, Ser> GenerationalStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { /// Try to use the provided storage as an GenerationalStore. @@ -494,7 +492,10 @@ where /// /// Returns None if the provided storage doesn't seem like an GenerationalStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization(storage: &'a S, _ser: Ser) -> Option> { + pub fn attach_with_serialization( + storage: &'a dyn Storage, + _ser: Ser, + ) -> Option> { let len_vec = storage.get(LEN_KEY)?; let generation_vec = storage.get(GENERATION_KEY)?; let free_list_head_vec = storage.get(FREE_LIST_HEAD_KEY)?; @@ -509,7 +510,7 @@ where } fn new( - storage: &'a S, + storage: &'a dyn Storage, len_vec: Vec, generation_vec: Vec, free_list_head_vec: Vec, @@ -562,12 +563,12 @@ where self.capacity } - pub fn readonly_storage(&self) -> &S { + pub fn readonly_storage(&self) -> &'a dyn Storage { self.storage } /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter<'a, T, S, Ser> { + pub fn iter(&self) -> Iter<'a, T, Ser> { Iter { storage: GenerationalStore::clone(self), start: 0, @@ -638,10 +639,9 @@ where } } -impl<'a, T, S, Ser> IntoIterator for GenerationalStore<'a, T, S, Ser> +impl<'a, T, Ser> IntoIterator for GenerationalStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { type Item = (Option, Entry); @@ -649,9 +649,9 @@ where // alternate version, see below //type Item = (Index, T); - type IntoIter = Iter<'a, T, S, Ser>; + type IntoIter = Iter<'a, T, Ser>; - fn into_iter(self) -> Iter<'a, T, S, Ser> { + fn into_iter(self) -> Iter<'a, T, Ser> { let end = self.len; Iter { storage: self, @@ -662,10 +662,9 @@ where } // Manual `Clone` implementation because the default one tries to clone the Storage?? -impl<'a, T, S, Ser> Clone for GenerationalStore<'a, T, S, Ser> +impl<'a, T, Ser> Clone for GenerationalStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { fn clone(&self) -> Self { @@ -684,22 +683,19 @@ where // Owning iterator /// An iterator over the contents of the generational store. -#[derive(Debug)] -pub struct Iter<'a, T, S, Ser> +pub struct Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { - storage: GenerationalStore<'a, T, S, Ser>, + storage: GenerationalStore<'a, T, Ser>, start: u32, end: u32, } -impl<'a, T, S, Ser> Iterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> Iterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { type Item = (Option, Entry); @@ -785,10 +781,9 @@ where } } -impl<'a, T, S, Ser> DoubleEndedIterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> DoubleEndedIterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -825,10 +820,9 @@ where } // This enables writing `append_store.iter().skip(n).rev()` -impl<'a, T, S, Ser> ExactSizeIterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> ExactSizeIterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { } diff --git a/packages/incubator/src/maxheap.rs b/packages/incubator/src/maxheap.rs index a3cb127..afcc31f 100644 --- a/packages/incubator/src/maxheap.rs +++ b/packages/incubator/src/maxheap.rs @@ -11,7 +11,7 @@ use std::marker::PhantomData; use serde::{de::DeserializeOwned, Serialize}; use std::cmp::PartialOrd; -use cosmwasm_std::{ReadonlyStorage, StdError, StdResult, Storage}; +use cosmwasm_std::{StdError, StdResult, Storage}; use secret_toolkit_serialization::{Bincode2, Serde}; @@ -244,7 +244,7 @@ where } /// Gain access to the implementation of the immutable methods - fn as_readonly(&self) -> MaxHeapStore { + fn as_readonly(&self) -> MaxHeapStore { MaxHeapStore { storage: self.storage, item_type: self.item_type, @@ -257,37 +257,33 @@ where // Readonly maxheap store /// A type allowing only reads from an max heap store. useful in the context of queries. -#[derive(Debug)] -pub struct MaxHeapStore<'a, T, S, Ser = Bincode2> +pub struct MaxHeapStore<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned + PartialOrd, - S: ReadonlyStorage, Ser: Serde, { - storage: &'a S, + storage: &'a dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, len: u32, } -impl<'a, T, S> MaxHeapStore<'a, T, S, Bincode2> +impl<'a, T> MaxHeapStore<'a, T, Bincode2> where T: Serialize + DeserializeOwned + PartialOrd, - S: ReadonlyStorage, { /// Try to use the provided storage as a MaxHeapStore. /// /// Returns None if the provided storage doesn't seem like a MaxHeapStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a S) -> Option> { + pub fn attach(storage: &'a dyn Storage) -> Option> { MaxHeapStore::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> MaxHeapStore<'a, T, S, Ser> +impl<'a, T, Ser> MaxHeapStore<'a, T, Ser> where T: Serialize + DeserializeOwned + PartialOrd, - S: ReadonlyStorage, Ser: Serde, { /// Try to use the provided storage as an MaxHeapStore. @@ -295,12 +291,15 @@ where /// /// Returns None if the provided storage doesn't seem like an MaxHeapStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization(storage: &'a S, _ser: Ser) -> Option> { + pub fn attach_with_serialization( + storage: &'a dyn Storage, + _ser: Ser, + ) -> Option> { let len_vec = storage.get(LEN_KEY)?; Some(MaxHeapStore::new(storage, len_vec)) } - fn new(storage: &'a S, len_vec: Vec) -> StdResult { + fn new(storage: &'a dyn Storage, len_vec: Vec) -> StdResult { let len_array = len_vec .as_slice() .try_into() @@ -323,7 +322,7 @@ where self.len == 0 } - pub fn readonly_storage(&self) -> &S { + pub fn readonly_storage(&self) -> &'a dyn Storage { self.storage } @@ -356,7 +355,6 @@ mod tests { use cosmwasm_std::testing::MockStorage; use serde::Deserialize; - use cosmwasm_std::HumanAddr; use secret_toolkit_serialization::Json; use std::cmp::Ordering; @@ -389,7 +387,7 @@ mod tests { fn test_custom_ord() -> StdResult<()> { #[derive(Serialize, Deserialize, Clone, Debug, Eq)] pub struct Tx { - address: HumanAddr, + address: String, amount: u128, } @@ -415,58 +413,58 @@ mod tests { let mut heap_store = MaxHeapStoreMut::attach_or_create(&mut storage)?; heap_store.insert(&Tx { - address: HumanAddr("address1".to_string()), + address: "address1".to_string(), amount: 200, })?; heap_store.insert(&Tx { - address: HumanAddr("address2".to_string()), + address: "address2".to_string(), amount: 100, })?; heap_store.insert(&Tx { - address: HumanAddr("address3".to_string()), + address: "address3".to_string(), amount: 400, })?; heap_store.insert(&Tx { - address: HumanAddr("address4".to_string()), + address: "address4".to_string(), amount: 300, })?; heap_store.insert(&Tx { - address: HumanAddr("address5".to_string()), + address: "address5".to_string(), amount: 50, })?; assert_eq!( heap_store.remove(), Ok(Tx { - address: HumanAddr("address3".to_string()), + address: "address3".to_string(), amount: 400, }) ); assert_eq!( heap_store.remove(), Ok(Tx { - address: HumanAddr("address4".to_string()), + address: "address4".to_string(), amount: 300, }) ); assert_eq!( heap_store.remove(), Ok(Tx { - address: HumanAddr("address1".to_string()), + address: "address1".to_string(), amount: 200, }) ); assert_eq!( heap_store.remove(), Ok(Tx { - address: HumanAddr("address2".to_string()), + address: "address2".to_string(), amount: 100, }) ); assert_eq!( heap_store.remove(), Ok(Tx { - address: HumanAddr("address5".to_string()), + address: "address5".to_string(), amount: 50, }) ); diff --git a/packages/permit/src/funcs.rs b/packages/permit/src/funcs.rs index 838d792..1bb0f98 100644 --- a/packages/permit/src/funcs.rs +++ b/packages/permit/src/funcs.rs @@ -37,12 +37,8 @@ pub fn validate( // Validate permit_name let permit_name = &permit.params.permit_name; - let is_permit_revoked = RevokedPermits::is_permit_revoked( - deps.storage, - storage_prefix, - &account.clone(), - permit_name, - ); + let is_permit_revoked = + RevokedPermits::is_permit_revoked(deps.storage, storage_prefix, &account, permit_name); if is_permit_revoked { return Err(StdError::generic_err(format!( "Permit {:?} was revoked by account {:?}", diff --git a/packages/permit/src/state.rs b/packages/permit/src/state.rs index af853c3..cd35daf 100644 --- a/packages/permit/src/state.rs +++ b/packages/permit/src/state.rs @@ -6,10 +6,10 @@ impl RevokedPermits { pub fn is_permit_revoked( storgae: &dyn Storage, storage_prefix: &str, - account: &String, + account: &str, permit_name: &str, ) -> bool { - let storage_key = storage_prefix.to_string() + &account.to_string() + permit_name; + let storage_key = storage_prefix.to_string() + account + permit_name; storgae.get(storage_key.as_bytes()).is_some() } @@ -17,10 +17,10 @@ impl RevokedPermits { pub fn revoke_permit( storage: &mut dyn Storage, storage_prefix: &str, - account: &String, + account: &str, permit_name: &str, ) { - let storage_key = storage_prefix.to_string() + &account.to_string() + permit_name; + let storage_key = storage_prefix.to_string() + account + permit_name; storage.set(storage_key.as_bytes(), &[]) } diff --git a/packages/permit/src/structs.rs b/packages/permit/src/structs.rs index f395424..2cfbb2a 100644 --- a/packages/permit/src/structs.rs +++ b/packages/permit/src/structs.rs @@ -15,8 +15,8 @@ pub struct Permit { } impl Permit { - pub fn check_token(&self, token: &String) -> bool { - self.params.allowed_tokens.contains(token) + pub fn check_token(&self, token: &str) -> bool { + self.params.allowed_tokens.contains(&token.to_string()) } pub fn check_permission(&self, permission: &Permission) -> bool { diff --git a/packages/snip20/src/query.rs b/packages/snip20/src/query.rs index 339e542..171e561 100644 --- a/packages/snip20/src/query.rs +++ b/packages/snip20/src/query.rs @@ -192,9 +192,9 @@ impl QueryMsg { /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried - pub fn query<'a, C: CustomQuery, T: DeserializeOwned>( + pub fn query( &self, - querier: QuerierWrapper<'a, C>, + querier: QuerierWrapper, mut block_size: usize, code_hash: String, contract_addr: String, @@ -280,8 +280,8 @@ pub struct MintersResponse { /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn token_info_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn token_info_query( + querier: QuerierWrapper, block_size: usize, callback_code_hash: String, contract_addr: String, @@ -299,8 +299,8 @@ pub fn token_info_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn token_config_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn token_config_query( + querier: QuerierWrapper, block_size: usize, callback_code_hash: String, contract_addr: String, @@ -318,8 +318,8 @@ pub fn token_config_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn contract_status_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn contract_status_query( + querier: QuerierWrapper, block_size: usize, callback_code_hash: String, contract_addr: String, @@ -341,8 +341,8 @@ pub fn contract_status_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn exchange_rate_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn exchange_rate_query( + querier: QuerierWrapper, block_size: usize, callback_code_hash: String, contract_addr: String, @@ -364,8 +364,8 @@ pub fn exchange_rate_query<'a, C: CustomQuery>( /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn allowance_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn allowance_query( + querier: QuerierWrapper, owner: String, spender: String, key: String, @@ -408,8 +408,8 @@ pub fn allowance_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn balance_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn balance_query( + querier: QuerierWrapper, address: String, key: String, block_size: usize, @@ -444,8 +444,8 @@ pub fn balance_query<'a, C: CustomQuery>( /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn transfer_history_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn transfer_history_query( + querier: QuerierWrapper, address: String, key: String, page: Option, @@ -487,8 +487,8 @@ pub fn transfer_history_query<'a, C: CustomQuery>( /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn transaction_history_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn transaction_history_query( + querier: QuerierWrapper, address: String, key: String, page: Option, @@ -525,8 +525,8 @@ pub fn transaction_history_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `callback_code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn minters_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn minters_query( + querier: QuerierWrapper, block_size: usize, callback_code_hash: String, contract_addr: String, diff --git a/packages/snip721/src/handle.rs b/packages/snip721/src/handle.rs index 66fc8fc..6ae97cb 100644 --- a/packages/snip721/src/handle.rs +++ b/packages/snip721/src/handle.rs @@ -1225,7 +1225,7 @@ mod tests { let test_msg = register_receive_nft_msg( code_hash.clone(), - also_implements_batch_receive_nft.clone(), + also_implements_batch_receive_nft, padding.clone(), 256usize, callback_code_hash.clone(), @@ -1805,7 +1805,7 @@ mod tests { token_id.clone(), view_owner.clone(), view_private_metadata.clone(), - expires.clone(), + expires, padding.clone(), 256usize, code_hash.clone(), diff --git a/packages/snip721/src/query.rs b/packages/snip721/src/query.rs index 189efe0..fea5c1f 100644 --- a/packages/snip721/src/query.rs +++ b/packages/snip721/src/query.rs @@ -449,9 +449,9 @@ impl QueryMsg { /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried - pub fn query<'a, C: CustomQuery, T: DeserializeOwned>( + pub fn query( &self, - querier: QuerierWrapper<'a, C>, + querier: QuerierWrapper, mut block_size: usize, code_hash: String, contract_addr: String, @@ -572,8 +572,8 @@ pub struct VerifyTransferApprovalResponse { /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn contract_info_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn contract_info_query( + querier: QuerierWrapper, block_size: usize, code_hash: String, contract_addr: String, @@ -592,8 +592,8 @@ pub fn contract_info_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn num_tokens_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn num_tokens_query( + querier: QuerierWrapper, viewer: Option, block_size: usize, code_hash: String, @@ -616,8 +616,8 @@ pub fn num_tokens_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn all_tokens_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn all_tokens_query( + querier: QuerierWrapper, viewer: Option, start_after: Option, limit: Option, @@ -647,8 +647,8 @@ pub fn all_tokens_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn owner_of_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn owner_of_query( + querier: QuerierWrapper, token_id: String, viewer: Option, include_expired: Option, @@ -674,8 +674,8 @@ pub fn owner_of_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn nft_info_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn nft_info_query( + querier: QuerierWrapper, token_id: String, block_size: usize, code_hash: String, @@ -699,8 +699,8 @@ pub fn nft_info_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn all_nft_info_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn all_nft_info_query( + querier: QuerierWrapper, token_id: String, viewer: Option, include_expired: Option, @@ -727,8 +727,8 @@ pub fn all_nft_info_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn private_metadata_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn private_metadata_query( + querier: QuerierWrapper, token_id: String, viewer: Option, block_size: usize, @@ -757,8 +757,8 @@ pub fn private_metadata_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn nft_dossier_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn nft_dossier_query( + querier: QuerierWrapper, token_id: String, viewer: Option, include_expired: Option, @@ -788,8 +788,8 @@ pub fn nft_dossier_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn token_approvals_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn token_approvals_query( + querier: QuerierWrapper, token_id: String, viewing_key: String, include_expired: Option, @@ -819,8 +819,8 @@ pub fn token_approvals_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn approved_for_all_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn approved_for_all_query( + querier: QuerierWrapper, owner: String, viewing_key: Option, include_expired: Option, @@ -850,8 +850,8 @@ pub fn approved_for_all_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn inventory_approvals_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn inventory_approvals_query( + querier: QuerierWrapper, address: String, viewing_key: String, include_expired: Option, @@ -883,8 +883,8 @@ pub fn inventory_approvals_query<'a, C: CustomQuery>( /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn tokens_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn tokens_query( + querier: QuerierWrapper, owner: String, viewer: Option, viewing_key: Option, @@ -918,8 +918,8 @@ pub fn tokens_query<'a, C: CustomQuery>( /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried #[allow(clippy::too_many_arguments)] -pub fn transaction_history_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn transaction_history_query( + querier: QuerierWrapper, address: String, viewing_key: String, page: Option, @@ -946,8 +946,8 @@ pub fn transaction_history_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn minters_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn minters_query( + querier: QuerierWrapper, block_size: usize, code_hash: String, contract_addr: String, @@ -966,8 +966,8 @@ pub fn minters_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn is_unwrapped_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn is_unwrapped_query( + querier: QuerierWrapper, token_id: String, block_size: usize, code_hash: String, @@ -989,8 +989,8 @@ pub fn is_unwrapped_query<'a, C: CustomQuery>( /// * `block_size` - pad the message to blocks of this size /// * `code_hash` - String holding the code hash of the contract being queried /// * `contract_addr` - address of the contract being queried -pub fn verify_transfer_approval_query<'a, C: CustomQuery>( - querier: QuerierWrapper<'a, C>, +pub fn verify_transfer_approval_query( + querier: QuerierWrapper, token_ids: Vec, address: String, viewing_key: String, diff --git a/packages/utils/src/calls.rs b/packages/utils/src/calls.rs index 8babc4c..b4de5a3 100755 --- a/packages/utils/src/calls.rs +++ b/packages/utils/src/calls.rs @@ -127,9 +127,9 @@ pub trait Query: Serialize { /// * `querier` - a reference to the Querier dependency of the querying contract /// * `callback_code_hash` - String holding the code hash of the contract to be queried /// * `contract_addr` - address of the contract being queried - fn query<'a, C: CustomQuery, T: DeserializeOwned>( + fn query( &self, - querier: QuerierWrapper<'a, C>, + querier: QuerierWrapper, code_hash: String, contract_addr: String, ) -> StdResult { diff --git a/packages/utils/src/feature_toggle.rs b/packages/utils/src/feature_toggle.rs index 798960e..5ee85cc 100644 --- a/packages/utils/src/feature_toggle.rs +++ b/packages/utils/src/feature_toggle.rs @@ -19,8 +19,8 @@ impl FeatureToggleTrait for FeatureToggle { pub trait FeatureToggleTrait { const STORAGE_KEY: &'static [u8]; - fn init_features<'a, T: Serialize>( - storage: &'a mut dyn Storage, + fn init_features( + storage: &mut dyn Storage, feature_statuses: Vec>, pausers: Vec, ) -> StdResult<()> { @@ -35,10 +35,7 @@ pub trait FeatureToggleTrait { Ok(()) } - fn require_not_paused<'a, T: Serialize>( - storage: &'a dyn Storage, - features: Vec, - ) -> StdResult<()> { + fn require_not_paused(storage: &dyn Storage, features: Vec) -> StdResult<()> { for feature in features { let status = Self::get_feature_status(storage, &feature)?; match status { @@ -63,7 +60,7 @@ pub trait FeatureToggleTrait { Ok(()) } - fn pause<'a, T: Serialize>(storage: &'a mut dyn Storage, features: Vec) -> StdResult<()> { + fn pause(storage: &mut dyn Storage, features: Vec) -> StdResult<()> { for f in features { Self::set_feature_status(storage, &f, Status::Paused)?; } @@ -71,7 +68,7 @@ pub trait FeatureToggleTrait { Ok(()) } - fn unpause<'a, T: Serialize>(storage: &'a mut dyn Storage, features: Vec) -> StdResult<()> { + fn unpause(storage: &mut dyn Storage, features: Vec) -> StdResult<()> { for f in features { Self::set_feature_status(storage, &f, Status::NotPaused)?; } @@ -79,25 +76,25 @@ pub trait FeatureToggleTrait { Ok(()) } - fn is_pauser<'a>(storage: &'a dyn Storage, key: &Addr) -> StdResult { + fn is_pauser(storage: &dyn Storage, key: &Addr) -> StdResult { let feature_store: ReadonlyBucket = ReadonlyBucket::multilevel(storage, &[Self::STORAGE_KEY, PREFIX_PAUSERS]); feature_store.may_load(key.as_bytes()).map(|p| p.is_some()) } - fn set_pauser<'a>(storage: &'a mut dyn Storage, key: &Addr) -> StdResult<()> { + fn set_pauser(storage: &mut dyn Storage, key: &Addr) -> StdResult<()> { let mut feature_store = Bucket::multilevel(storage, &[Self::STORAGE_KEY, PREFIX_PAUSERS]); feature_store.save(key.as_bytes(), &true /* value is insignificant */) } - fn remove_pauser<'a>(storage: &'a mut dyn Storage, key: &Addr) { + fn remove_pauser(storage: &mut dyn Storage, key: &Addr) { let mut feature_store: Bucket = Bucket::multilevel(storage, &[Self::STORAGE_KEY, PREFIX_PAUSERS]); feature_store.remove(key.as_bytes()) } - fn get_feature_status<'a, T: Serialize>( - storage: &'a dyn Storage, + fn get_feature_status( + storage: &dyn Storage, key: &T, ) -> StdResult> { let feature_store = @@ -105,8 +102,8 @@ pub trait FeatureToggleTrait { feature_store.may_load(&cosmwasm_std::to_vec(&key)?) } - fn set_feature_status<'a, T: Serialize>( - storage: &'a mut dyn Storage, + fn set_feature_status( + storage: &mut dyn Storage, key: &T, item: Status, ) -> StdResult<()> { From 4e45199a25a8f041a1ad785262a60532d1d45de8 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Tue, 2 Aug 2022 18:13:44 +0300 Subject: [PATCH 08/37] CI clippy all features --- .github/workflows/Static.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Static.yml b/.github/workflows/Static.yml index ca488fb..00aad69 100644 --- a/.github/workflows/Static.yml +++ b/.github/workflows/Static.yml @@ -13,7 +13,7 @@ jobs: rust: [stable] make: - name: Clippy - task: "cargo clippy" + task: "cargo clippy --all --all-features" - name: Unit tests task: "cargo test --all --all-features" include: From 122e9fc3e27c7ecb2fffc453bb110c5f783d24d4 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Wed, 3 Aug 2022 16:25:31 +0300 Subject: [PATCH 09/37] Fix rest of `packages/storage` - TypedStore, DequeStore --- packages/storage/src/deque_store.rs | 88 ++++++++++++++--------------- packages/storage/src/lib.rs | 8 +-- packages/storage/src/typed_store.rs | 41 ++++++-------- 3 files changed, 63 insertions(+), 74 deletions(-) diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 40d0e0d..d107fc1 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -8,7 +8,7 @@ use std::{convert::TryInto, marker::PhantomData}; use serde::{de::DeserializeOwned, Serialize}; -use cosmwasm_std::{ReadonlyStorage, StdError, StdResult, Storage}; +use cosmwasm_std::{StdError, StdResult, Storage}; use secret_toolkit_serialization::{Bincode2, Serde}; @@ -17,30 +17,27 @@ const OFFSET_KEY: &[u8] = b"off"; // Mutable deque_store /// A type allowing both reads from and writes to the deque store at a given storage location. -#[derive(Debug)] -pub struct DequeStoreMut<'a, T, S, Ser = Bincode2> +pub struct DequeStoreMut<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { - storage: &'a mut S, + storage: &'a mut dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, len: u32, off: u32, } -impl<'a, T, S> DequeStoreMut<'a, T, S, Bincode2> +impl<'a, T> DequeStoreMut<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, { /// Try to use the provided storage as an DequeStore. If it doesn't seem to be one, then /// initialize it as one. /// /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create(storage: &'a mut S) -> StdResult { + pub fn attach_or_create(storage: &'a mut dyn Storage) -> StdResult { DequeStoreMut::attach_or_create_with_serialization(storage, Bincode2) } @@ -48,22 +45,24 @@ where /// /// Returns None if the provided storage doesn't seem like an DequeStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a mut S) -> Option> { + pub fn attach(storage: &'a mut dyn Storage) -> Option> { DequeStoreMut::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> DequeStoreMut<'a, T, S, Ser> +impl<'a, T, Ser> DequeStoreMut<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { /// Try to use the provided storage as an DequeStore. If it doesn't seem to be one, then /// initialize it as one. This method allows choosing the serialization format you want to use. /// /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create_with_serialization(storage: &'a mut S, _ser: Ser) -> StdResult { + pub fn attach_or_create_with_serialization( + storage: &'a mut dyn Storage, + _ser: Ser, + ) -> StdResult { if let (Some(len_vec), Some(off_vec)) = (storage.get(LEN_KEY), (storage.get(OFFSET_KEY))) { Self::new(storage, &len_vec, &off_vec) } else { @@ -80,13 +79,16 @@ where /// /// Returns None if the provided storage doesn't seem like an DequeStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization(storage: &'a mut S, _ser: Ser) -> Option> { + pub fn attach_with_serialization( + storage: &'a mut dyn Storage, + _ser: Ser, + ) -> Option> { let len_vec = storage.get(LEN_KEY)?; let off_vec = storage.get(OFFSET_KEY)?; Some(Self::new(storage, &len_vec, &off_vec)) } - fn new(storage: &'a mut S, len_vec: &[u8], off_vec: &[u8]) -> StdResult { + fn new(storage: &'a mut dyn Storage, len_vec: &[u8], off_vec: &[u8]) -> StdResult { let len_array = len_vec .try_into() .map_err(|err| StdError::parse_err("u32", err))?; @@ -113,16 +115,16 @@ where self.len == 0 } - pub fn storage(&mut self) -> &mut S { + pub fn storage(&mut self) -> &mut dyn Storage { self.storage } - pub fn readonly_storage(&self) -> &S { + pub fn readonly_storage(&self) -> &dyn Storage { self.storage } /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter { self.as_readonly().iter() } @@ -256,7 +258,7 @@ where } /// Gain access to the implementation of the immutable methods - fn as_readonly(&self) -> DequeStore { + fn as_readonly(&self) -> DequeStore { DequeStore { storage: self.storage, item_type: self.item_type, @@ -270,38 +272,34 @@ where // Readonly deque-store /// A type allowing only reads from an deque store. useful in the context_, u8 of queries. -#[derive(Debug)] -pub struct DequeStore<'a, T, S, Ser = Bincode2> +pub struct DequeStore<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { - storage: &'a S, + storage: &'a dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, len: u32, off: u32, } -impl<'a, T, S> DequeStore<'a, T, S, Bincode2> +impl<'a, T> DequeStore<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, { /// Try to use the provided storage as an DequeStore. /// /// Returns None if the provided storage doesn't seem like an DequeStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a S) -> Option> { + pub fn attach(storage: &'a dyn Storage) -> Option> { DequeStore::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> DequeStore<'a, T, S, Ser> +impl<'a, T, Ser> DequeStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { /// Try to use the provided storage as an DequeStore. @@ -309,13 +307,16 @@ where /// /// Returns None if the provided storage doesn't seem like an DequeStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization(storage: &'a S, _ser: Ser) -> Option> { + pub fn attach_with_serialization( + storage: &'a dyn Storage, + _ser: Ser, + ) -> Option> { let len_vec = storage.get(LEN_KEY)?; let off_vec = storage.get(OFFSET_KEY)?; Some(DequeStore::new(storage, len_vec, off_vec)) } - fn new(storage: &'a S, len_vec: Vec, off_vec: Vec) -> StdResult { + fn new(storage: &'a dyn Storage, len_vec: Vec, off_vec: Vec) -> StdResult { let len_array = len_vec .as_slice() .try_into() @@ -344,12 +345,12 @@ where self.len == 0 } - pub fn readonly_storage(&self) -> &S { + pub fn readonly_storage(&self) -> &dyn Storage { self.storage } /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter<'a, T, S, Ser> { + pub fn iter(&self) -> Iter<'a, T, Ser> { Iter { storage: DequeStore::clone(self), start: 0_u32, @@ -382,16 +383,15 @@ where } } -impl<'a, T, S, Ser> IntoIterator for DequeStore<'a, T, S, Ser> +impl<'a, T, Ser> IntoIterator for DequeStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { type Item = StdResult; - type IntoIter = Iter<'a, T, S, Ser>; + type IntoIter = Iter<'a, T, Ser>; - fn into_iter(self) -> Iter<'a, T, S, Ser> { + fn into_iter(self) -> Iter<'a, T, Ser> { let end = self.len; Iter { storage: self, @@ -402,10 +402,9 @@ where } // Manual `Clone` implementation because the default one tries to clone the Storage?? -impl<'a, T, S, Ser> Clone for DequeStore<'a, T, S, Ser> +impl<'a, T, Ser> Clone for DequeStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { fn clone(&self) -> Self { @@ -422,22 +421,19 @@ where // Owning iterator /// An iterator over the contents of the deque store. -#[derive(Debug)] -pub struct Iter<'a, T, S, Ser> +pub struct Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { - storage: DequeStore<'a, T, S, Ser>, + storage: DequeStore<'a, T, Ser>, start: u32, end: u32, } -impl<'a, T, S, Ser> Iterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> Iterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { type Item = StdResult; @@ -469,10 +465,9 @@ where } } -impl<'a, T, S, Ser> DoubleEndedIterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> DoubleEndedIterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -497,10 +492,9 @@ where } // This enables writing `deque_store.iter().skip(n).rev()` -impl<'a, T, S, Ser> ExactSizeIterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> ExactSizeIterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { } diff --git a/packages/storage/src/lib.rs b/packages/storage/src/lib.rs index cb99e83..0bacff8 100644 --- a/packages/storage/src/lib.rs +++ b/packages/storage/src/lib.rs @@ -1,7 +1,7 @@ pub mod append_store; -// pub mod deque_store; -// pub mod typed_store; +pub mod deque_store; +pub mod typed_store; pub use append_store::{AppendStore, AppendStoreMut}; -// pub use deque_store::{DequeStore, DequeStoreMut}; -// pub use typed_store::{TypedStore, TypedStoreMut}; +pub use deque_store::{DequeStore, DequeStoreMut}; +pub use typed_store::{TypedStore, TypedStoreMut}; diff --git a/packages/storage/src/typed_store.rs b/packages/storage/src/typed_store.rs index c8797ca..95ec8df 100644 --- a/packages/storage/src/typed_store.rs +++ b/packages/storage/src/typed_store.rs @@ -3,38 +3,35 @@ use std::marker::PhantomData; use serde::{de::DeserializeOwned, Serialize}; -use cosmwasm_std::{ReadonlyStorage, StdError, StdResult, Storage}; +use cosmwasm_std::{StdError, StdResult, Storage}; use secret_toolkit_serialization::{Bincode2, Serde}; -pub struct TypedStoreMut<'a, T, S, Ser = Bincode2> +pub struct TypedStoreMut<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { - storage: &'a mut S, + storage: &'a mut dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, } -impl<'a, T, S> TypedStoreMut<'a, T, S, Bincode2> +impl<'a, T> TypedStoreMut<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, { - pub fn attach(storage: &'a mut S) -> Self { + pub fn attach(storage: &'a mut dyn Storage) -> Self { Self::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> TypedStoreMut<'a, T, S, Ser> +impl<'a, T, Ser> TypedStoreMut<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { - pub fn attach_with_serialization(storage: &'a mut S, _serialization: Ser) -> Self { + pub fn attach_with_serialization(storage: &'a mut dyn Storage, _serialization: Ser) -> Self { Self { storage, serialization_type: PhantomData, @@ -51,7 +48,7 @@ where self.storage.remove(key); } - fn as_readonly(&self) -> TypedStore { + fn as_readonly(&self) -> TypedStore { TypedStore { storage: self.storage, item_type: self.item_type, @@ -68,34 +65,31 @@ where } } -pub struct TypedStore<'a, T, S, Ser = Bincode2> +pub struct TypedStore<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { - storage: &'a S, + storage: &'a dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, } -impl<'a, T, S> TypedStore<'a, T, S, Bincode2> +impl<'a, T> TypedStore<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, { - pub fn attach(storage: &'a S) -> Self { + pub fn attach(storage: &'a dyn Storage) -> Self { Self::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> TypedStore<'a, T, S, Ser> +impl<'a, T, Ser> TypedStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: ReadonlyStorage, Ser: Serde, { - pub fn attach_with_serialization(storage: &'a S, _serialization: Ser) -> Self { + pub fn attach_with_serialization(storage: &'a dyn Storage, _serialization: Ser) -> Self { Self { storage, serialization_type: PhantomData, @@ -169,10 +163,11 @@ mod tests { assert!(typed_store_mut.may_load(b"key3")?.is_none()); // Try to load it with the wrong format - let typed_store = TypedStore::::attach_with_serialization(&storage, Json); + let typed_store = TypedStore::::attach_with_serialization(&storage, Json); match typed_store.load(b"key2") { - Err(StdError::ParseErr { target, msg, .. }) - if target == "i32" && msg == "Invalid type" => {} + Err(StdError::ParseErr { + target_type, msg, .. + }) if target_type == "i32" && msg == "Invalid type" => {} other => panic!("unexpected value: {:?}", other), } From 34d56abbf06527db12f8f086e9614442cfb59e7a Mon Sep 17 00:00:00 2001 From: TomL94 Date: Wed, 3 Aug 2022 16:25:48 +0300 Subject: [PATCH 10/37] export all packages --- packages/snip721/src/handle.rs | 4 ++-- packages/toolkit/src/lib.rs | 32 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/snip721/src/handle.rs b/packages/snip721/src/handle.rs index 6ae97cb..66fc8fc 100644 --- a/packages/snip721/src/handle.rs +++ b/packages/snip721/src/handle.rs @@ -1225,7 +1225,7 @@ mod tests { let test_msg = register_receive_nft_msg( code_hash.clone(), - also_implements_batch_receive_nft, + also_implements_batch_receive_nft.clone(), padding.clone(), 256usize, callback_code_hash.clone(), @@ -1805,7 +1805,7 @@ mod tests { token_id.clone(), view_owner.clone(), view_private_metadata.clone(), - expires, + expires.clone(), padding.clone(), 256usize, code_hash.clone(), diff --git a/packages/toolkit/src/lib.rs b/packages/toolkit/src/lib.rs index 7e744cb..2612edb 100644 --- a/packages/toolkit/src/lib.rs +++ b/packages/toolkit/src/lib.rs @@ -1,18 +1,18 @@ -// #[cfg(feature = "crypto")] -// pub use secret_toolkit_crypto as crypto; -// #[cfg(feature = "incubator")] -// pub use secret_toolkit_incubator as incubator; -// #[cfg(feature = "permit")] -// pub use secret_toolkit_permit as permit; -// #[cfg(feature = "serialization")] -// pub use secret_toolkit_serialization as serialization; -// #[cfg(feature = "snip20")] -// pub use secret_toolkit_snip20 as snip20; -// #[cfg(feature = "snip721")] -// pub use secret_toolkit_snip721 as snip721; +#[cfg(feature = "crypto")] +pub use secret_toolkit_crypto as crypto; +#[cfg(feature = "incubator")] +pub use secret_toolkit_incubator as incubator; +#[cfg(feature = "permit")] +pub use secret_toolkit_permit as permit; +#[cfg(feature = "serialization")] +pub use secret_toolkit_serialization as serialization; +#[cfg(feature = "snip20")] +pub use secret_toolkit_snip20 as snip20; +#[cfg(feature = "snip721")] +pub use secret_toolkit_snip721 as snip721; #[cfg(feature = "storage")] pub use secret_toolkit_storage as storage; -// #[cfg(feature = "utils")] -// pub use secret_toolkit_utils as utils; -// #[cfg(feature = "viewing-key")] -// pub use secret_toolkit_viewing_key as viewing_key; +#[cfg(feature = "utils")] +pub use secret_toolkit_utils as utils; +#[cfg(feature = "viewing-key")] +pub use secret_toolkit_viewing_key as viewing_key; From 2615f4e63f68da250f629110e088a626b30866fd Mon Sep 17 00:00:00 2001 From: TomL94 Date: Wed, 3 Aug 2022 16:38:55 +0300 Subject: [PATCH 11/37] Removed unnecessary generics MaxHeap, AppendStore, permit --- packages/incubator/src/maxheap.rs | 32 ++++++----- packages/permit/src/funcs.rs | 19 ++---- packages/storage/src/append_store.rs | 86 +++++++++++++--------------- 3 files changed, 62 insertions(+), 75 deletions(-) diff --git a/packages/incubator/src/maxheap.rs b/packages/incubator/src/maxheap.rs index afcc31f..1c8afac 100644 --- a/packages/incubator/src/maxheap.rs +++ b/packages/incubator/src/maxheap.rs @@ -20,29 +20,26 @@ const LEN_KEY: &[u8] = b"len"; // Mutable maxheap store /// A type allowing both reads from and writes to the maxheap store at a given storage location. -#[derive(Debug)] -pub struct MaxHeapStoreMut<'a, T, S, Ser = Bincode2> +pub struct MaxHeapStoreMut<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned + PartialOrd, - S: Storage, Ser: Serde, { - storage: &'a mut S, + storage: &'a mut dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, len: u32, } -impl<'a, T, S> MaxHeapStoreMut<'a, T, S, Bincode2> +impl<'a, T> MaxHeapStoreMut<'a, T, Bincode2> where T: Serialize + DeserializeOwned + PartialOrd, - S: Storage, { /// Try to use the provided storage as an MaxHeapStore. If it doesn't seem to be one, then /// initialize it as one. /// /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create(storage: &'a mut S) -> StdResult { + pub fn attach_or_create(storage: &'a mut dyn Storage) -> StdResult { MaxHeapStoreMut::attach_or_create_with_serialization(storage, Bincode2) } @@ -50,22 +47,24 @@ where /// /// Returns None if the provided storage doesn't seem like an MaxHeapStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a mut S) -> Option> { + pub fn attach(storage: &'a mut dyn Storage) -> Option> { MaxHeapStoreMut::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> MaxHeapStoreMut<'a, T, S, Ser> +impl<'a, T, Ser> MaxHeapStoreMut<'a, T, Ser> where T: Serialize + DeserializeOwned + PartialOrd, - S: Storage, Ser: Serde, { /// Try to use the provided storage as an MaxHeapStore. If it doesn't seem to be one, then /// initialize it as one. This method allows choosing the serialization format you want to use. /// /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create_with_serialization(storage: &'a mut S, _ser: Ser) -> StdResult { + pub fn attach_or_create_with_serialization( + storage: &'a mut dyn Storage, + _ser: Ser, + ) -> StdResult { if let Some(len_vec) = storage.get(LEN_KEY) { Self::new(storage, &len_vec) } else { @@ -80,12 +79,15 @@ where /// /// Returns None if the provided storage doesn't seem like an MaxHeapStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization(storage: &'a mut S, _ser: Ser) -> Option> { + pub fn attach_with_serialization( + storage: &'a mut dyn Storage, + _ser: Ser, + ) -> Option> { let len_vec = storage.get(LEN_KEY)?; Some(Self::new(storage, &len_vec)) } - fn new(storage: &'a mut S, len_vec: &[u8]) -> StdResult { + fn new(storage: &'a mut dyn Storage, len_vec: &[u8]) -> StdResult { let len_array = len_vec .try_into() .map_err(|err| StdError::parse_err("u32", err))?; @@ -107,11 +109,11 @@ where self.len == 0 } - pub fn storage(&mut self) -> &mut S { + pub fn storage(&mut self) -> &mut dyn Storage { self.storage } - pub fn readonly_storage(&self) -> &S { + pub fn readonly_storage(&self) -> &dyn Storage { self.storage } diff --git a/packages/permit/src/funcs.rs b/packages/permit/src/funcs.rs index 1bb0f98..6cde3b3 100644 --- a/packages/permit/src/funcs.rs +++ b/packages/permit/src/funcs.rs @@ -1,13 +1,11 @@ -use cosmwasm_std::{ - to_binary, Api, Binary, CanonicalAddr, Deps, Querier, StdError, StdResult, Storage, -}; +use cosmwasm_std::{to_binary, Binary, CanonicalAddr, Deps, StdError, StdResult}; use ripemd160::{Digest, Ripemd160}; use crate::{Permissions, Permit, RevokedPermits, SignedPermit}; use bech32::{ToBase32, Variant}; use secret_toolkit_crypto::sha_256; -pub fn validate( +pub fn validate( deps: Deps, storage_prefix: &str, permit: &Permit, @@ -75,7 +73,7 @@ pub fn pubkey_to_account(pubkey: &Binary) -> CanonicalAddr { mod tests { use super::*; use crate::{PermitParams, PermitSignature, PubKey, TokenPermissions}; - use cosmwasm_std::testing::{mock_dependencies, MockApi, MockQuerier, MockStorage}; + use cosmwasm_std::testing::mock_dependencies; #[test] fn test_verify_permit() { @@ -101,7 +99,7 @@ mod tests { } }; - let address = validate::<_, MockStorage, MockApi, MockQuerier>( + let address = validate::<_>( deps.as_ref(), "test", &permit, @@ -115,14 +113,7 @@ mod tests { "secret1399pyvvk3hvwgxwt3udkslsc5jl3rqv4yshfrl".to_string() ); - let address = validate::<_, MockStorage, MockApi, MockQuerier>( - deps.as_ref(), - "test", - &permit, - token, - Some("cosmos"), - ) - .unwrap(); + let address = validate::<_>(deps.as_ref(), "test", &permit, token, Some("cosmos")).unwrap(); assert_eq!( address, diff --git a/packages/storage/src/append_store.rs b/packages/storage/src/append_store.rs index 13b9ca2..6354555 100644 --- a/packages/storage/src/append_store.rs +++ b/packages/storage/src/append_store.rs @@ -17,29 +17,26 @@ const LEN_KEY: &[u8] = b"len"; // Mutable append-store /// A type allowing both reads from and writes to the append store at a given storage location. -#[derive(Debug)] -pub struct AppendStoreMut<'a, T, S, Ser = Bincode2> +pub struct AppendStoreMut<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { - storage: &'a mut S, + storage: &'a mut dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, len: u32, } -impl<'a, T, S> AppendStoreMut<'a, T, S, Bincode2> +impl<'a, T> AppendStoreMut<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, { /// Try to use the provided storage as an AppendStore. If it doesn't seem to be one, then /// initialize it as one. /// /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create(storage: &'a mut S) -> StdResult { + pub fn attach_or_create(storage: &'a mut dyn Storage) -> StdResult { AppendStoreMut::attach_or_create_with_serialization(storage, Bincode2) } @@ -47,22 +44,24 @@ where /// /// Returns None if the provided storage doesn't seem like an AppendStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a mut S) -> Option> { + pub fn attach(storage: &'a mut dyn Storage) -> Option> { AppendStoreMut::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> AppendStoreMut<'a, T, S, Ser> +impl<'a, T, Ser> AppendStoreMut<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { /// Try to use the provided storage as an AppendStore. If it doesn't seem to be one, then /// initialize it as one. This method allows choosing the serialization format you want to use. /// /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create_with_serialization(storage: &'a mut S, _ser: Ser) -> StdResult { + pub fn attach_or_create_with_serialization( + storage: &'a mut dyn Storage, + _ser: Ser, + ) -> StdResult { if let Some(len_vec) = storage.get(LEN_KEY) { Self::new(storage, &len_vec) } else { @@ -77,12 +76,15 @@ where /// /// Returns None if the provided storage doesn't seem like an AppendStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization(storage: &'a mut S, _ser: Ser) -> Option> { + pub fn attach_with_serialization( + storage: &'a mut dyn Storage, + _ser: Ser, + ) -> Option> { let len_vec = storage.get(LEN_KEY)?; Some(Self::new(storage, &len_vec)) } - fn new(storage: &'a mut S, len_vec: &[u8]) -> StdResult { + fn new(storage: &'a mut dyn Storage, len_vec: &[u8]) -> StdResult { let len_array = len_vec .try_into() .map_err(|err| StdError::parse_err("u32", err))?; @@ -104,16 +106,16 @@ where self.len == 0 } - pub fn storage(&mut self) -> &mut S { + pub fn storage(&mut self) -> &mut dyn Storage { self.storage } - pub fn readonly_storage(&self) -> &S { + pub fn readonly_storage(&self) -> &dyn Storage { self.storage } /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter { self.as_readonly().iter() } @@ -178,7 +180,7 @@ where } /// Gain access to the implementation of the immutable methods - fn as_readonly(&self) -> AppendStore { + fn as_readonly(&self) -> AppendStore { AppendStore { storage: self.storage, item_type: self.item_type, @@ -213,37 +215,33 @@ where // Readonly append-store /// A type allowing only reads from an append store. useful in the context_, u8 of queries. -#[derive(Debug)] -pub struct AppendStore<'a, T, S, Ser = Bincode2> +pub struct AppendStore<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { - storage: &'a S, + storage: &'a dyn Storage, item_type: PhantomData<*const T>, serialization_type: PhantomData<*const Ser>, len: u32, } -impl<'a, T, S> AppendStore<'a, T, S, Bincode2> +impl<'a, T> AppendStore<'a, T, Bincode2> where T: Serialize + DeserializeOwned, - S: Storage, { /// Try to use the provided storage as an AppendStore. /// /// Returns None if the provided storage doesn't seem like an AppendStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a S) -> Option> { + pub fn attach(storage: &'a dyn Storage) -> Option> { AppendStore::attach_with_serialization(storage, Bincode2) } } -impl<'a, T, S, Ser> AppendStore<'a, T, S, Ser> +impl<'a, T, Ser> AppendStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { /// Try to use the provided storage as an AppendStore. @@ -251,12 +249,15 @@ where /// /// Returns None if the provided storage doesn't seem like an AppendStore. /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization(storage: &'a S, _ser: Ser) -> Option> { + pub fn attach_with_serialization( + storage: &'a dyn Storage, + _ser: Ser, + ) -> Option> { let len_vec = storage.get(LEN_KEY)?; Some(AppendStore::new(storage, len_vec)) } - fn new(storage: &'a S, len_vec: Vec) -> StdResult { + fn new(storage: &'a dyn Storage, len_vec: Vec) -> StdResult { let len_array = len_vec .as_slice() .try_into() @@ -279,12 +280,12 @@ where self.len == 0 } - pub fn readonly_storage(&self) -> &S { + pub fn readonly_storage(&self) -> &dyn Storage { self.storage } /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter<'a, T, S, Ser> { + pub fn iter(&self) -> Iter<'a, T, Ser> { Iter { storage: AppendStore::clone(self), start: 0, @@ -311,16 +312,15 @@ where } } -impl<'a, T, S, Ser> IntoIterator for AppendStore<'a, T, S, Ser> +impl<'a, T, Ser> IntoIterator for AppendStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { type Item = StdResult; - type IntoIter = Iter<'a, T, S, Ser>; + type IntoIter = Iter<'a, T, Ser>; - fn into_iter(self) -> Iter<'a, T, S, Ser> { + fn into_iter(self) -> Iter<'a, T, Ser> { let end = self.len; Iter { storage: self, @@ -331,10 +331,9 @@ where } // Manual `Clone` implementation because the default one tries to clone the Storage?? -impl<'a, T, S, Ser> Clone for AppendStore<'a, T, S, Ser> +impl<'a, T, Ser> Clone for AppendStore<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { fn clone(&self) -> Self { @@ -350,22 +349,19 @@ where // Owning iterator /// An iterator over the contents of the append store. -#[derive(Debug)] -pub struct Iter<'a, T, S, Ser> +pub struct Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { - storage: AppendStore<'a, T, S, Ser>, + storage: AppendStore<'a, T, Ser>, start: u32, end: u32, } -impl<'a, T, S, Ser> Iterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> Iterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { type Item = StdResult; @@ -397,10 +393,9 @@ where } } -impl<'a, T, S, Ser> DoubleEndedIterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> DoubleEndedIterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -425,10 +420,9 @@ where } // This enables writing `append_store.iter().skip(n).rev()` -impl<'a, T, S, Ser> ExactSizeIterator for Iter<'a, T, S, Ser> +impl<'a, T, Ser> ExactSizeIterator for Iter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { } From ba990c585fbea8b16833e713ab81a8c4ea318d44 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Wed, 3 Aug 2022 16:46:35 +0300 Subject: [PATCH 12/37] Fixed `packages/viewing_key` --- packages/viewing_key/Cargo.toml | 4 +- packages/viewing_key/src/lib.rs | 69 +++++++++++++++++---------------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/packages/viewing_key/Cargo.toml b/packages/viewing_key/Cargo.toml index bd05cd6..5ea822c 100644 --- a/packages/viewing_key/Cargo.toml +++ b/packages/viewing_key/Cargo.toml @@ -18,7 +18,7 @@ serde = "1.0" schemars = "0.7" base64 = "0.11.0" # Same as used by cosmwas-std subtle = { version = "2.2.3", default-features = false } -cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10" } -cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10" } +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } secret-toolkit-crypto = { version = "0.3", path = "../crypto", default-features = false, features = ["hash", "rand"] } secret-toolkit-utils = { version = "0.3", path = "../utils" } diff --git a/packages/viewing_key/src/lib.rs b/packages/viewing_key/src/lib.rs index f5119b0..e893955 100644 --- a/packages/viewing_key/src/lib.rs +++ b/packages/viewing_key/src/lib.rs @@ -2,7 +2,7 @@ extern crate core; use subtle::ConstantTimeEq; -use cosmwasm_std::{Env, HumanAddr, ReadonlyStorage, StdError, StdResult, Storage}; +use cosmwasm_std::{Env, MessageInfo, StdError, StdResult, Storage}; use cosmwasm_storage::{PrefixedStorage, ReadonlyPrefixedStorage}; use secret_toolkit_crypto::{sha_256, Prng, SHA256_HASH_SIZE}; @@ -29,7 +29,7 @@ pub trait ViewingKeyStore { const STORAGE_KEY: &'static [u8]; /// Set the initial prng seed for the store - fn set_seed(storage: &mut S, seed: &[u8]) { + fn set_seed(storage: &mut dyn Storage, seed: &[u8]) { let mut seed_key = Vec::new(); seed_key.extend_from_slice(Self::STORAGE_KEY); seed_key.extend_from_slice(SEED_KEY); @@ -40,10 +40,11 @@ pub trait ViewingKeyStore { /// Create a new viewing key, save it to storage, and return it. /// /// The random entropy should be provided from some external source, such as the user. - fn create( - storage: &mut S, + fn create( + storage: &mut dyn Storage, + info: &MessageInfo, env: &Env, - account: &HumanAddr, + account: &String, entropy: &[u8], ) -> String { let mut seed_key = Vec::with_capacity(Self::STORAGE_KEY.len() + SEED_KEY.len()); @@ -51,10 +52,10 @@ pub trait ViewingKeyStore { seed_key.extend_from_slice(SEED_KEY); let seed = storage.get(&seed_key).unwrap_or_default(); - let (viewing_key, next_seed) = new_viewing_key(env, &seed, entropy); - let mut balance_store = PrefixedStorage::new(Self::STORAGE_KEY, storage); + let (viewing_key, next_seed) = new_viewing_key(info, env, &seed, entropy); + let mut balance_store = PrefixedStorage::new(storage, Self::STORAGE_KEY); let hashed_key = sha_256(viewing_key.as_bytes()); - balance_store.set(account.as_str().as_bytes(), &hashed_key); + balance_store.set(account.as_bytes(), &hashed_key); storage.set(&seed_key, &next_seed); @@ -62,21 +63,14 @@ pub trait ViewingKeyStore { } /// Set a new viewing key based on a predetermined value. - fn set(storage: &mut S, account: &HumanAddr, viewing_key: &str) { - let mut balance_store = PrefixedStorage::new(Self::STORAGE_KEY, storage); - balance_store.set( - account.as_str().as_bytes(), - &sha_256(viewing_key.as_bytes()), - ); + fn set(storage: &mut S, account: &String, viewing_key: &str) { + let mut balance_store = PrefixedStorage::new(storage, Self::STORAGE_KEY); + balance_store.set(account.as_bytes(), &sha_256(viewing_key.as_bytes())); } /// Check if a viewing key matches an account. - fn check( - storage: &S, - account: &HumanAddr, - viewing_key: &str, - ) -> StdResult<()> { - let balance_store = ReadonlyPrefixedStorage::new(Self::STORAGE_KEY, storage); + fn check(storage: &dyn Storage, account: &String, viewing_key: &str) -> StdResult<()> { + let balance_store = ReadonlyPrefixedStorage::new(storage, Self::STORAGE_KEY); let expected_hash = balance_store.get(account.as_str().as_bytes()); let expected_hash = match &expected_hash { Some(hash) => hash.as_slice(), @@ -86,18 +80,23 @@ pub trait ViewingKeyStore { if ct_slice_compare(&key_hash, expected_hash) { Ok(()) } else { - Err(StdError::unauthorized()) + Err(StdError::generic_err("unauthorized")) } } } -fn new_viewing_key(env: &Env, seed: &[u8], entropy: &[u8]) -> (String, [u8; 32]) { +fn new_viewing_key( + info: &MessageInfo, + env: &Env, + seed: &[u8], + entropy: &[u8], +) -> (String, [u8; 32]) { // 16 here represents the lengths in bytes of the block height and time. - let entropy_len = 16 + env.message.sender.len() + entropy.len(); + let entropy_len = 16 + info.sender.to_string().len() + entropy.len(); let mut rng_entropy = Vec::with_capacity(entropy_len); rng_entropy.extend_from_slice(&env.block.height.to_be_bytes()); - rng_entropy.extend_from_slice(&env.block.time.to_be_bytes()); - rng_entropy.extend_from_slice(env.message.sender.0.as_bytes()); + rng_entropy.extend_from_slice(&env.block.time.seconds().to_be_bytes()); + rng_entropy.extend_from_slice(info.sender.as_bytes()); rng_entropy.extend_from_slice(entropy); let mut rng = Prng::new(seed, &rng_entropy); @@ -118,32 +117,34 @@ fn ct_slice_compare(s1: &[u8], s2: &[u8]) -> bool { mod tests { use super::*; - use cosmwasm_std::testing::{mock_dependencies, mock_env}; + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; #[test] fn test_viewing_keys() { - let account = HumanAddr("user-1".to_string()); + let account = "user-1".to_string(); - let mut deps = mock_dependencies(20, &[]); - let env = mock_env(account.as_str(), &[]); + let mut deps = mock_dependencies(); + let env = mock_env(); + let info = mock_info(account.as_str(), &[]); // VK not set yet: let result = ViewingKey::check(&deps.storage, &account, "fake key"); - assert_eq!(result, Err(StdError::unauthorized())); + assert_eq!(result, Err(StdError::generic_err("unauthorized"))); ViewingKey::set_seed(&mut deps.storage, b"seed"); - let viewing_key = ViewingKey::create(&mut deps.storage, &env, &account, b"entropy"); + let viewing_key = ViewingKey::create(&mut deps.storage, &info, &env, &account, b"entropy"); let result = ViewingKey::check(&deps.storage, &account, &viewing_key); assert_eq!(result, Ok(())); // Create a key with the same entropy. Check that it's different - let viewing_key_2 = ViewingKey::create(&mut deps.storage, &env, &account, b"entropy"); + let viewing_key_2 = + ViewingKey::create(&mut deps.storage, &info, &env, &account, b"entropy"); assert_ne!(viewing_key, viewing_key_2); // VK set to another key: let result = ViewingKey::check(&deps.storage, &account, "fake key"); - assert_eq!(result, Err(StdError::unauthorized())); + assert_eq!(result, Err(StdError::generic_err("unauthorized"))); let viewing_key = "custom key"; @@ -154,6 +155,6 @@ mod tests { // VK set to another key: let result = ViewingKey::check(&deps.storage, &account, "fake key"); - assert_eq!(result, Err(StdError::unauthorized())); + assert_eq!(result, Err(StdError::generic_err("unauthorized"))); } } From 5d160b3dcf4734fa0654a4a921281a43677b8487 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Thu, 11 Aug 2022 14:50:19 +0300 Subject: [PATCH 13/37] Added `Code` struct to `types.rs` --- packages/utils/src/types.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/utils/src/types.rs b/packages/utils/src/types.rs index f9e2149..182561b 100644 --- a/packages/utils/src/types.rs +++ b/packages/utils/src/types.rs @@ -6,3 +6,9 @@ pub struct Contract { pub address: String, pub hash: String, } + +#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone, JsonSchema)] +pub struct Code { + pub code_id: u64, + pub hash: String, +} From eae7953cc855f778eedd6cdad338c97c024883b8 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Thu, 11 Aug 2022 14:52:40 +0300 Subject: [PATCH 14/37] clippy warnings --- packages/viewing_key/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/viewing_key/src/lib.rs b/packages/viewing_key/src/lib.rs index e893955..d4bd962 100644 --- a/packages/viewing_key/src/lib.rs +++ b/packages/viewing_key/src/lib.rs @@ -44,7 +44,7 @@ pub trait ViewingKeyStore { storage: &mut dyn Storage, info: &MessageInfo, env: &Env, - account: &String, + account: &str, entropy: &[u8], ) -> String { let mut seed_key = Vec::with_capacity(Self::STORAGE_KEY.len() + SEED_KEY.len()); @@ -63,15 +63,15 @@ pub trait ViewingKeyStore { } /// Set a new viewing key based on a predetermined value. - fn set(storage: &mut S, account: &String, viewing_key: &str) { + fn set(storage: &mut S, account: &str, viewing_key: &str) { let mut balance_store = PrefixedStorage::new(storage, Self::STORAGE_KEY); balance_store.set(account.as_bytes(), &sha_256(viewing_key.as_bytes())); } /// Check if a viewing key matches an account. - fn check(storage: &dyn Storage, account: &String, viewing_key: &str) -> StdResult<()> { + fn check(storage: &dyn Storage, account: &str, viewing_key: &str) -> StdResult<()> { let balance_store = ReadonlyPrefixedStorage::new(storage, Self::STORAGE_KEY); - let expected_hash = balance_store.get(account.as_str().as_bytes()); + let expected_hash = balance_store.get(account.as_bytes()); let expected_hash = match &expected_hash { Some(hash) => hash.as_slice(), None => &[0u8; VIEWING_KEY_SIZE], From cf10e33e06cc74460707240d0cb8bbe94ca4af4b Mon Sep 17 00:00:00 2001 From: TomL94 Date: Tue, 16 Aug 2022 16:53:21 +0300 Subject: [PATCH 15/37] Rename to be clearer --- packages/utils/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/types.rs b/packages/utils/src/types.rs index 182561b..8c28196 100644 --- a/packages/utils/src/types.rs +++ b/packages/utils/src/types.rs @@ -8,7 +8,7 @@ pub struct Contract { } #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone, JsonSchema)] -pub struct Code { +pub struct WasmCode { pub code_id: u64, pub hash: String, } From f0d198b83151775997e0aa9a6c7e77f1076c96b1 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Thu, 18 Aug 2022 16:18:10 +0300 Subject: [PATCH 16/37] add Token to types.rs --- packages/utils/src/types.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/utils/src/types.rs b/packages/utils/src/types.rs index 8c28196..2a0286e 100644 --- a/packages/utils/src/types.rs +++ b/packages/utils/src/types.rs @@ -12,3 +12,10 @@ pub struct WasmCode { pub code_id: u64, pub hash: String, } + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum Token { + Snip20(Contract), + Native(String), +} From 2a346c507f400c2d85bd2170edab757d70e69d52 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 21 Aug 2022 22:46:21 +0300 Subject: [PATCH 17/37] storage v0.4 is updated to cw1.0 this still needs to be tested in a real cw-v1.0 contract --- packages/storage/Readme.md | 285 ++++- packages/storage/src/append_store.rs | 801 ++++++++------ packages/storage/src/deque_store.rs | 830 +++++++-------- packages/storage/src/item.rs | 183 ++++ packages/storage/src/keymap.rs | 1432 ++++++++++++++++++++++++++ packages/storage/src/lib.rs | 11 +- packages/storage/src/typed_store.rs | 176 ---- 7 files changed, 2760 insertions(+), 958 deletions(-) create mode 100644 packages/storage/src/item.rs create mode 100644 packages/storage/src/keymap.rs delete mode 100644 packages/storage/src/typed_store.rs diff --git a/packages/storage/Readme.md b/packages/storage/Readme.md index b656e70..3d784cd 100644 --- a/packages/storage/Readme.md +++ b/packages/storage/Readme.md @@ -1,5 +1,286 @@ # Secret Contract Development Toolkit - Storage Tools -⚠️ This package is a sub-package of the `secret-toolkit` package. Please see its crate page for more context. +⚠️ This package is a cw v1.0 fork of the `secret-toolkit` package. Please see its crate page for more context. You need Rust 1.63+ to compile this package. -This package contains all the tools related to storage access patterns +This package contains many tools related to storage access patterns. This readme file assumes basic familiarity with basic cosmwasm storage, [click here to learn about this](https://docs.scrt.network/secret-network-documentation/development/secret-contracts/storage). + +## **How to Import This Subpackage** + +To import this package, add one of the following lines to your `Cargo.toml` file + +```toml +secret-toolkit = { version = "0.4", default-features = false, features = ["utils", "storage", "serialization"] } +``` + +for the release versions (when it is updated to cosmwasm 1.0), or + +```toml +secret-toolkit = { git = "https://github.com/scrtlabs/secret-toolkit", branch = "cosmwasm-v1.0", default-features = false, features = ["utils", "storage", "serialization"]} +``` + +for the github version. We also import the `serialization` feature in case we want to switch to using Json instead of Bincode2 to serialize/deserialize data. + +## **Storage Objects** + +### **Item** + +This is the simplest storage object in this toolkit. It based on the similarly named Item from cosmwasm-storage-plus. Item allows the user to specify the type of the object being stored and the serialization/deserialization method used to store it (default being Bincode2). **One can think of the Item struct as a wrapper for the storage key.** Note that you want to use Json to serde an enum or any struct that stores an enum (except for the standard Option enum), because Bincode2 somehow uses floats during the deserialization of enums. This is why other cosmwasm chains don't use Bincode2 at all, however, you gain some performance when you can use it. + +#### **Initialize** + +This object is meant to be initialized as a static constant in `state.rs`. However, it would also work perfectly fine if it was initialized during run time with a variable key (in this case though, you'd have to remind it what type of object is stored and its serde). Import it using the following lines: + +```ignore +use secret_toolkit_storage::{Item} +``` + +And initialize it using the following lines: + +```ignore +pub static OWNER: Item = Item::new(b"owner"); +``` + +This uses Bincode2 to serde HumanAddr by default. To specify the Serde algorithm as Json, first import it from `secret-toolkit-serialization` + +```ignore +use secret_toolkit::serialization::{Bincode2, Json}; +``` + +then + +```ignore +pub static SOME_ENUM: Item = Item::new(b"some_enum"); +``` + +#### **Read/Write** + +The way to read/write to/from strorage is to use its methods. These methods are `save`, `load`, `may_load`, `remove`, `update`. Here is an example usecase for each in execution inside `contract.rs`: + +```ignore +// The compiler knows that owner_addr is HumanAddr +let owner_addr = OWNER.load(&deps.storage)?; +``` + +```ignore +OWNER.save(&mut deps.storage, &env.message.sender)?; +``` + +```ignore +// The compiler knows that may_addr is Option +let may_addr = OWNER.may_load(&deps.storage)?; +``` + +```ignore +// The compiler knows that may_addr is Option +let may_addr = OWNER.remove(&mut deps.storage)?; +``` + +```ignore +// The compiler knows that may_addr is Option +let may_addr = OWNER.update(&mut deps.storage, |_x| Ok(env.message.sender))?; +``` + +### **AppendStore** + +AppendStore is meant replicate the functionality of an append list in a cosmwasm efficient manner. The length of the list is stored and used to pop/push items to the list. It also has a method to create a read only iterator. + +This storage object also has the method `remove` to remove a stored object from an arbitrary position in the list, but this can be exteremely inefficient. + +> ❗ Removing a storage object further from the tail gets increasingly inefficient. We recommend you use `pop` and `push` whenever possible. + +The same conventions from `Item` also apply here, that is: + +1. AppendStore has to be told the type of the stored objects. And the serde optionally. +2. Every methods needs it's own reference to `deps.storage`. + +#### **Initialize** + +To import and intialize this storage object as a static constant in `state.rs`, do the following: + +```ignore +use secret_toolkit::storage::{AppendStore} +``` + +```ignore +pub static COUNT_STORE: AppendStore = AppendStore::new(b"count"); +``` + +> ❗ Initializing the object as const instead of static will also work but be less efficient since the variable won't be able to cache length data. + +Often times we need these storage objects to be associated to a user address or some other key that is variable. In this case, you need not initialize a completely new AppendStore inside `contract.rs`. Instead, you can create a new AppendStore by adding a suffix to an already existing AppendStore. This has the benefit of preventing you from having to rewrite the signature of the AppendStore. For example + +```ignore +// The compiler knows that user_count_store is AppendStore +let user_count_store = COUNT_STORE.add_suffix(env.message.sender.to_string().as_bytes()); +``` + +#### **Read/Write** + +The main user facing methods to read/write to AppendStore are `pop`, `push`, `get_len`, `set_at` (which replaces data at a position within the length bound), `clear` (which deletes all data in the storage), `remove` (which removes an item in an arbitrary position, this is very inefficient). An extensive list of examples of these being used can be found inside the unit tests of AppendStore found in `append_store.rs`. + +#### **Iterator** + +AppendStore also implements a readonly iterator feature. This feature is also used to create a paging wrapper method called `paging`. The way you create the iterator is: + +```ignore +let iter = user_count_store.iter(&deps.storage)?; +``` + +More examples can be found in the unit tests. And the paging wrapper is used in the following manner: + +```ignore +let start_page: u32 = 0; +let page_size: u32 = 5; +// The compiler knows that values is Vec +let values = user_count_store.paging(&deps.storage, start_page, page_size)?; +``` + +### **DequeStore** + +This is a storage wrapper based on AppendStore that replicates a double ended list. This storage object allows the user to efficiently pop/push items to either end of the list. + +#### **Init** + +To import and intialize this storage object as a static constant in `state.rs`, do the following: + +```ignore +use secret_toolkit::storage::{DequeStore} +``` + +```ignore +pub static COUNT_STORE: DequeStore = DequeStore::new(b"count"); +``` + +> ❗ Initializing the object as const instead of static will also work but be less efficient since the variable won't be able to cache length data. + +#### **Read/Write** + +The main user facing methods to read/write to DequeStore are `pop_back`, `pop_front`, `push_back`, `push_front`, `get_len`, `get_off`, `set_at` (which replaces data at a position within the length bound), `clear` (which deletes all data in the storage), `remove` (which removes an item in an arbitrary position, this is very inefficient). An extensive list of examples of these being used can be found inside the unit tests of DequeStore found in `deque_store.rs`. + +#### **Iterator** + +This is exactly same as that of AppendStore. + +### **Keymap** + +This hashmap-like storage structure allows the user to use generic typed keys to store objects. Allows iteration with paging over keys and/or items (without guaranteed ordering, although the order of insertion is preserved until you start removing objects). +An example use-case for such a structure is if you want to contain a large amount of votes, deposits, or bets and iterate over them at some time in the future. +Since iterating over large amounts of data at once may be prohibitive, this structure allows you to specify the amount of data that will +be returned in each page. + +#### **Init** + +To import and intialize this storage object as a static constant in `state.rs`, do the following: + +```ignore +use secret_toolkit::storage::{Keymap} +``` + +```ignore +pub static ADDR_VOTE: Keymap = Keymap::new(b"vote"); +pub static BET_STORE: Keymap = Keymap::new(b"vote"); +``` + +> ❗ Initializing the object as const instead of static will also work but be less efficient since the variable won't be able to cache length data. + +You can use Json serde algorithm by changing the signature to `Keymap`, similar to all the other storage objects above. However, keep in mind that the Serde algorthm is used to serde both the stored object (`Uint128`) AND the key (`HumanAddr`). + +If you need to associate a keymap to a user address (or any other variable), then you can also do this using the `.add_suffix` method. + +For example suppose that in your contract, a user can make multiple bets. Then, you'd want a Keymap to be associated to each user. You would achieve this my doing the following during execution in `contract.rs`. + +```ignore +// The compiler knows that user_bet_store is AppendStore +let user_count_store = BET_STORE.add_suffix(env.message.sender.to_string().as_bytes()); +``` + +#### **Read/Write** + +You can find more examples of using keymaps in the unit tests of Keymap in `keymap.rs`. + +To insert, remove, read from the keymap, do the following: + +```ignore +let user_addr: HumanAddr = env.message.sender; + +let foo = Foo { + message: "string one".to_string(), + votes: 1111, +}; + +ADDR_VOTE.insert(&mut deps.storage, &user_addr, &foo)?; +// Compiler knows that this is Foo +let read_foo = ADDR_VOTE.get(&deps.storage, &user_addr).unwrap(); +assert_eq!(read_foo, foo1); +ADDR_VOTE.remove(&mut deps.storage, &user_addr)?; +assert_eq!(ADDR_VOTE.get_len(&deps.storage)?, 0); +``` + +#### **Iterator** + +There are two methods that create an iterator in Keymap. These are `.iter` and `.iter_keys`. `iter_keys` only iterates over the keys whereas `iter` iterates over (key, item) pairs. Needless to say, `.iter_keys` is more efficient as it does not attempt to read the item. + +Keymap also has two paging methods, these are `.paging` and `.paging_keys`. `paging_keys` only paginates keys whereas `iter` iterates over (key, item) pairs. Needless to say, `.iter_keys` is more efficient as it does not attempt to read the item. + +Here are some select examples from the unit tests: + +```ignore +fn test_keymap_iter_keys() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let keymap: Keymap = Keymap::new(b"test"); + let foo1 = Foo { + string: "string one".to_string(), + number: 1111, + }; + let foo2 = Foo { + string: "string two".to_string(), + number: 1111, + }; + + let key1 = "key1".to_string(); + let key2 = "key2".to_string(); + + keymap.insert(&mut storage, &key1, &foo1)?; + keymap.insert(&mut storage, &key2, &foo2)?; + + let mut x = keymap.iter_keys(&storage)?; + let (len, _) = x.size_hint(); + assert_eq!(len, 2); + + assert_eq!(x.next().unwrap()?, key1); + + assert_eq!(x.next().unwrap()?, key2); + + Ok(()) +} +``` + +```ignore +fn test_keymap_iter() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let keymap: Keymap, Foo> = Keymap::new(b"test"); + let foo1 = Foo { + string: "string one".to_string(), + number: 1111, + }; + let foo2 = Foo { + string: "string two".to_string(), + number: 1111, + }; + + keymap.insert(&mut storage, &b"key1".to_vec(), &foo1)?; + keymap.insert(&mut storage, &b"key2".to_vec(), &foo2)?; + + let mut x = keymap.iter(&storage)?; + let (len, _) = x.size_hint(); + assert_eq!(len, 2); + + assert_eq!(x.next().unwrap()?.1, foo1); + + assert_eq!(x.next().unwrap()?.1, foo2); + + Ok(()) +} +``` diff --git a/packages/storage/src/append_store.rs b/packages/storage/src/append_store.rs index 6354555..0e5f793 100644 --- a/packages/storage/src/append_store.rs +++ b/packages/storage/src/append_store.rs @@ -3,8 +3,10 @@ //! //! This is achieved by storing each item in a separate storage entry. A special key is reserved //! for storing the length of the collection so far. +use std::any::type_name; use std::convert::TryInto; use std::marker::PhantomData; +use std::sync::Mutex; use serde::{de::DeserializeOwned, Serialize}; @@ -14,354 +16,260 @@ use secret_toolkit_serialization::{Bincode2, Serde}; const LEN_KEY: &[u8] = b"len"; -// Mutable append-store - -/// A type allowing both reads from and writes to the append store at a given storage location. -pub struct AppendStoreMut<'a, T, Ser = Bincode2> +pub struct AppendStore<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, Ser: Serde, { - storage: &'a mut dyn Storage, - item_type: PhantomData<*const T>, - serialization_type: PhantomData<*const Ser>, - len: u32, + /// prefix of the newly constructed Storage + namespace: &'a [u8], + /// needed if any suffixes were added to the original namespace. + /// therefore it is not necessarily same as the namespace. + prefix: Option>, + length: Mutex>, + item_type: PhantomData, + serialization_type: PhantomData, } -impl<'a, T> AppendStoreMut<'a, T, Bincode2> -where - T: Serialize + DeserializeOwned, -{ - /// Try to use the provided storage as an AppendStore. If it doesn't seem to be one, then - /// initialize it as one. - /// - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create(storage: &'a mut dyn Storage) -> StdResult { - AppendStoreMut::attach_or_create_with_serialization(storage, Bincode2) - } - - /// Try to use the provided storage as an AppendStore. - /// - /// Returns None if the provided storage doesn't seem like an AppendStore. - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a mut dyn Storage) -> Option> { - AppendStoreMut::attach_with_serialization(storage, Bincode2) - } -} - -impl<'a, T, Ser> AppendStoreMut<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - /// Try to use the provided storage as an AppendStore. If it doesn't seem to be one, then - /// initialize it as one. This method allows choosing the serialization format you want to use. - /// - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create_with_serialization( - storage: &'a mut dyn Storage, - _ser: Ser, - ) -> StdResult { - if let Some(len_vec) = storage.get(LEN_KEY) { - Self::new(storage, &len_vec) - } else { - let len_vec = 0_u32.to_be_bytes(); - storage.set(LEN_KEY, &len_vec); - Self::new(storage, &len_vec) - } - } - - /// Try to use the provided storage as an AppendStore. - /// This method allows choosing the serialization format you want to use. - /// - /// Returns None if the provided storage doesn't seem like an AppendStore. - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization( - storage: &'a mut dyn Storage, - _ser: Ser, - ) -> Option> { - let len_vec = storage.get(LEN_KEY)?; - Some(Self::new(storage, &len_vec)) - } - - fn new(storage: &'a mut dyn Storage, len_vec: &[u8]) -> StdResult { - let len_array = len_vec - .try_into() - .map_err(|err| StdError::parse_err("u32", err))?; - let len = u32::from_be_bytes(len_array); - - Ok(Self { - storage, +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { + /// constructor + pub const fn new(prefix: &'a [u8]) -> Self { + Self { + namespace: prefix, + prefix: None, + length: Mutex::new(None), item_type: PhantomData, serialization_type: PhantomData, - len, - }) + } } - - pub fn len(&self) -> u32 { - self.len + /// This is used to produce a new AppendListStorage. This can be used when you want to associate an AppendListStorage to each user + /// and you still get to define the AppendListStorage as a static constant + pub fn add_suffix(&self, suffix: &[u8]) -> Self { + let prefix = if let Some(prefix) = &self.prefix { + [prefix.clone(), suffix.to_vec()].concat() + } else { + [self.namespace.to_vec(), suffix.to_vec()].concat() + }; + Self { + namespace: self.namespace, + prefix: Some(prefix), + length: Mutex::new(None), + item_type: self.item_type, + serialization_type: self.serialization_type, + } } +} - pub fn is_empty(&self) -> bool { - self.len == 0 +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { + /// gets the length from storage, and otherwise sets it to 0 + pub fn get_len(&self, storage: &S) -> StdResult { + let mut may_len = self.length.lock().unwrap(); + match *may_len { + Some(len) => Ok(len), + None => { + let len_key = [self.as_slice(), LEN_KEY].concat(); + if let Some(len_vec) = storage.get(&len_key) { + let len_bytes = len_vec + .as_slice() + .try_into() + .map_err(|err| StdError::parse_err("u32", err))?; + let len = u32::from_be_bytes(len_bytes); + *may_len = Some(len); + Ok(len) + } else { + *may_len = Some(0); + Ok(0) + } + } + } } - - pub fn storage(&mut self) -> &mut dyn Storage { - self.storage + /// checks if the collection has any elements + pub fn is_empty(&self, storage: &S) -> StdResult { + Ok(self.get_len(storage)? == 0) } - - pub fn readonly_storage(&self) -> &dyn Storage { - self.storage + /// gets the element at pos if within bounds + pub fn get_at(&self, storage: &S, pos: u32) -> StdResult { + let len = self.get_len(storage)?; + if pos > len { + return Err(StdError::generic_err("AppendStore access out of bounds")); + } + self.get_at_unchecked(storage, pos) } - - /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter { - self.as_readonly().iter() + /// tries to get the element at pos + fn get_at_unchecked(&self, storage: &S, pos: u32) -> StdResult { + let key = pos.to_be_bytes(); + self.load_impl(storage, &key) } - /// Get the value stored at a given position. - /// - /// # Errors - /// Will return an error if pos is out of bounds or if an item is not found. - pub fn get_at(&self, pos: u32) -> StdResult { - self.as_readonly().get_at(pos) - } + /// Set the length of the collection + fn set_len(&self, storage: &mut S, len: u32) { + let len_key = [self.as_slice(), LEN_KEY].concat(); + storage.set(&len_key, &len.to_be_bytes()); - fn get_at_unchecked(&self, pos: u32) -> StdResult { - self.as_readonly().get_at_unchecked(pos) + let mut may_len = self.length.lock().unwrap(); + *may_len = Some(len); } - - /// Set the value of the item stored at a given position. - /// - /// # Errors - /// Will return an error if the position is out of bounds - pub fn set_at(&mut self, pos: u32, item: &T) -> StdResult<()> { - if pos >= self.len { - return Err(StdError::generic_err("AppendStorage access out of bounds")); + /// Clear the collection + pub fn clear(&self, storage: &mut S) { + self.set_len(storage, 0); + } + /// Replaces data at a position within bounds + pub fn set_at(&self, storage: &mut S, pos: u32, item: &T) -> StdResult<()> { + let len = self.get_len(storage)?; + if pos >= len { + return Err(StdError::generic_err("AppendStore access out of bounds")); } - self.set_at_unchecked(pos, item) + self.set_at_unchecked(storage, pos, item) } - - fn set_at_unchecked(&mut self, pos: u32, item: &T) -> StdResult<()> { - let serialized = Ser::serialize(item)?; - self.storage.set(&pos.to_be_bytes(), &serialized); - Ok(()) + /// Sets data at a given index + fn set_at_unchecked(&self, storage: &mut S, pos: u32, item: &T) -> StdResult<()> { + self.save_impl(storage, &pos.to_be_bytes(), item) } - - /// Append an item to the end of the collection. - /// - /// This operation has a constant cost. - pub fn push(&mut self, item: &T) -> StdResult<()> { - self.set_at_unchecked(self.len, item)?; - self.set_length(self.len + 1); + /// Pushes an item to AppendStorage + pub fn push(&self, storage: &mut S, item: &T) -> StdResult<()> { + let len = self.get_len(storage)?; + self.set_at_unchecked(storage, len, item)?; + self.set_len(storage, len + 1); Ok(()) } - - /// Pop the last item off the collection - pub fn pop(&mut self) -> StdResult { - if let Some(len) = self.len.checked_sub(1) { - let item = self.get_at_unchecked(len); - self.set_length(len); + /// Pops an item from AppendStore + pub fn pop(&self, storage: &mut S) -> StdResult { + if let Some(len) = self.get_len(storage)?.checked_sub(1) { + let item = self.get_at_unchecked(storage, len); + self.set_len(storage, len); item } else { Err(StdError::generic_err("Can not pop from empty AppendStore")) } } + /// Remove an element from the collection at the specified position. + /// + /// Removing the last element has a constant cost. + /// The cost of removing from the middle/start will depend on the proximity to tail of the list. + /// All elements above the specified position will be shifted in storage. + /// + /// Removing an element from the start (head) of the collection + /// has the worst runtime and gas cost. + pub fn remove(&self, storage: &mut S, pos: u32) -> StdResult { + let len = self.get_len(storage)?; - /// Clear the collection - pub fn clear(&mut self) { - self.set_length(0); - } - - /// Set the length of the collection - fn set_length(&mut self, len: u32) { - self.storage.set(LEN_KEY, &len.to_be_bytes()); - self.len = len; - } - - /// Gain access to the implementation of the immutable methods - fn as_readonly(&self) -> AppendStore { - AppendStore { - storage: self.storage, - item_type: self.item_type, - serialization_type: self.serialization_type, - len: self.len, + if pos >= len { + return Err(StdError::generic_err("DequeStorage access out of bounds")); } - } -} - -// Doing this is fundamentally flawed because it would theoretically permanently turn the `&mut S` -// into a `&S`, preventing any further mutation of the entire storage. -// In practice this just gave annoying lifetime errors either here or at `AppendStoreMut::as_readonly`. -/* -impl<'a, T, S> IntoIterator for AppendStoreMut<'a, T, S> -where - T: 'a + Serialize + DeserializeOwned, - S: Storage, -{ - type Item = StdResult; - type IntoIter = Iter<'a, T, S>; + let item = self.get_at_unchecked(storage, pos); - fn into_iter(self) -> Iter<'a, T, S> { - Iter { - storage: self.as_readonly(), - start: 0, - end: self.len, + for i in pos..(len - 1) { + let element_to_shift = self.get_at_unchecked(storage, i + 1)?; + self.set_at_unchecked(storage, i, &element_to_shift)?; } + self.set_len(storage, len - 1); + item + } + /// Returns a readonly iterator + pub fn iter(&self, storage: &'a S) -> StdResult> { + let len = self.get_len(storage)?; + let iter = AppendStoreIter::new(self, storage, 0, len); + Ok(iter) + } + /// does paging with the given parameters + pub fn paging(&self, storage: &S, start_page: u32, size: u32) -> StdResult> { + self.iter(storage)? + .skip((start_page as usize) * (size as usize)) + .take(size as usize) + .collect() } } -*/ - -// Readonly append-store - -/// A type allowing only reads from an append store. useful in the context_, u8 of queries. -pub struct AppendStore<'a, T, Ser = Bincode2> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - storage: &'a dyn Storage, - item_type: PhantomData<*const T>, - serialization_type: PhantomData<*const Ser>, - len: u32, -} -impl<'a, T> AppendStore<'a, T, Bincode2> -where - T: Serialize + DeserializeOwned, -{ - /// Try to use the provided storage as an AppendStore. - /// - /// Returns None if the provided storage doesn't seem like an AppendStore. - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a dyn Storage) -> Option> { - AppendStore::attach_with_serialization(storage, Bincode2) +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for AppendStore<'a, T, Ser> { + fn clone(&self) -> Self { + Self { + namespace: self.namespace.clone(), + prefix: self.prefix.clone(), + length: Mutex::new(None), + item_type: self.item_type.clone(), + serialization_type: self.serialization_type.clone(), + } } } -impl<'a, T, Ser> AppendStore<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - /// Try to use the provided storage as an AppendStore. - /// This method allows choosing the serialization format you want to use. - /// - /// Returns None if the provided storage doesn't seem like an AppendStore. - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization( - storage: &'a dyn Storage, - _ser: Ser, - ) -> Option> { - let len_vec = storage.get(LEN_KEY)?; - Some(AppendStore::new(storage, len_vec)) - } - - fn new(storage: &'a dyn Storage, len_vec: Vec) -> StdResult { - let len_array = len_vec - .as_slice() - .try_into() - .map_err(|err| StdError::parse_err("u32", err))?; - let len = u32::from_be_bytes(len_array); - - Ok(Self { - storage, - item_type: PhantomData, - serialization_type: PhantomData, - len, - }) - } - - pub fn len(&self) -> u32 { - self.len - } - - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - pub fn readonly_storage(&self) -> &dyn Storage { - self.storage - } - - /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter<'a, T, Ser> { - Iter { - storage: AppendStore::clone(self), - start: 0, - end: self.len, +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { + fn as_slice(&self) -> &[u8] { + if let Some(prefix) = &self.prefix { + prefix + } else { + self.namespace } } - /// Get the value stored at a given position. + /// Returns StdResult from retrieving the item with the specified key. Returns a + /// StdError::NotFound if there is no item with that key /// - /// # Errors - /// Will return an error if pos is out of bounds or if an item is not found. - pub fn get_at(&self, pos: u32) -> StdResult { - if pos >= self.len { - return Err(StdError::generic_err("AppendStorage access out of bounds")); - } - self.get_at_unchecked(pos) - } - - fn get_at_unchecked(&self, pos: u32) -> StdResult { - let serialized = self.storage.get(&pos.to_be_bytes()).ok_or_else(|| { - StdError::generic_err(format!("No item in AppendStorage at position {}", pos)) - })?; - Ser::deserialize(&serialized) + /// # Arguments + /// + /// * `storage` - a reference to the storage this item is in + /// * `key` - a byte slice representing the key to access the stored item + fn load_impl(&self, storage: &S, key: &[u8]) -> StdResult { + let prefixed_key = [self.as_slice(), key].concat(); + Ser::deserialize( + &storage + .get(&prefixed_key) + .ok_or(StdError::not_found(type_name::()))?, + ) + } + + /// Returns StdResult<()> resulting from saving an item to storage + /// + /// # Arguments + /// + /// * `storage` - a mutable reference to the storage this item should go to + /// * `key` - a byte slice representing the key to access the stored item + /// * `value` - a reference to the item to store + fn save_impl(&self, storage: &mut S, key: &[u8], value: &T) -> StdResult<()> { + let prefixed_key = [self.as_slice(), key].concat(); + storage.set(&prefixed_key, &Ser::serialize(value)?); + Ok(()) } } -impl<'a, T, Ser> IntoIterator for AppendStore<'a, T, Ser> +/// An iterator over the contents of the append store. +pub struct AppendStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { - type Item = StdResult; - type IntoIter = Iter<'a, T, Ser>; - - fn into_iter(self) -> Iter<'a, T, Ser> { - let end = self.len; - Iter { - storage: self, - start: 0, - end, - } - } + append_store: &'a AppendStore<'a, T, Ser>, + storage: &'a S, + start: u32, + end: u32, } -// Manual `Clone` implementation because the default one tries to clone the Storage?? -impl<'a, T, Ser> Clone for AppendStore<'a, T, Ser> +impl<'a, T, S, Ser> AppendStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { - fn clone(&self) -> Self { + /// constructor + pub fn new( + append_store: &'a AppendStore<'a, T, Ser>, + storage: &'a S, + start: u32, + end: u32, + ) -> Self { Self { - storage: self.storage, - item_type: self.item_type, - serialization_type: self.serialization_type, - len: self.len, + append_store, + storage, + start, + end, } } } -// Owning iterator - -/// An iterator over the contents of the append store. -pub struct Iter<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - storage: AppendStore<'a, T, Ser>, - start: u32, - end: u32, -} - -impl<'a, T, Ser> Iterator for Iter<'a, T, Ser> +impl<'a, T, S, Ser> Iterator for AppendStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { type Item = StdResult; @@ -370,7 +278,7 @@ where if self.start >= self.end { return None; } - let item = self.storage.get_at(self.start); + let item = self.append_store.get_at(self.storage, self.start); self.start += 1; Some(item) } @@ -393,9 +301,10 @@ where } } -impl<'a, T, Ser> DoubleEndedIterator for Iter<'a, T, Ser> +impl<'a, T, S, Ser> DoubleEndedIterator for AppendStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -403,7 +312,7 @@ where return None; } self.end -= 1; - let item = self.storage.get_at(self.end); + let item = self.append_store.get_at(self.storage, self.end); Some(item) } @@ -420,9 +329,10 @@ where } // This enables writing `append_store.iter().skip(n).rev()` -impl<'a, T, Ser> ExactSizeIterator for Iter<'a, T, Ser> +impl<'a, T, S, Ser> ExactSizeIterator for AppendStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { } @@ -438,17 +348,50 @@ mod tests { #[test] fn test_push_pop() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut append_store = AppendStoreMut::attach_or_create(&mut storage)?; - append_store.push(&1234)?; - append_store.push(&2143)?; - append_store.push(&3412)?; - append_store.push(&4321)?; - - assert_eq!(append_store.pop(), Ok(4321)); - assert_eq!(append_store.pop(), Ok(3412)); - assert_eq!(append_store.pop(), Ok(2143)); - assert_eq!(append_store.pop(), Ok(1234)); - assert!(append_store.pop().is_err()); + let append_store: AppendStore = AppendStore::new(b"test"); + append_store.push(&mut storage, &1234)?; + append_store.push(&mut storage, &2143)?; + append_store.push(&mut storage, &3412)?; + append_store.push(&mut storage, &4321)?; + + assert_eq!(append_store.pop(&mut storage), Ok(4321)); + assert_eq!(append_store.pop(&mut storage), Ok(3412)); + assert_eq!(append_store.pop(&mut storage), Ok(2143)); + assert_eq!(append_store.pop(&mut storage), Ok(1234)); + assert!(append_store.pop(&mut storage).is_err()); + + Ok(()) + } + + #[test] + fn test_length() -> StdResult<()> { + let mut storage = MockStorage::new(); + let append_store: AppendStore = AppendStore::new(b"test"); + + assert!(append_store.length.lock().unwrap().eq(&None)); + assert_eq!(append_store.get_len(&mut storage)?, 0); + assert!(append_store.length.lock().unwrap().eq(&Some(0))); + + append_store.push(&mut storage, &1234)?; + append_store.push(&mut storage, &2143)?; + append_store.push(&mut storage, &3412)?; + append_store.push(&mut storage, &4321)?; + assert!(append_store.length.lock().unwrap().eq(&Some(4))); + assert_eq!(append_store.get_len(&mut storage)?, 4); + + assert_eq!(append_store.pop(&mut storage), Ok(4321)); + assert_eq!(append_store.pop(&mut storage), Ok(3412)); + assert!(append_store.length.lock().unwrap().eq(&Some(2))); + assert_eq!(append_store.get_len(&mut storage)?, 2); + + assert_eq!(append_store.pop(&mut storage), Ok(2143)); + assert_eq!(append_store.pop(&mut storage), Ok(1234)); + assert!(append_store.length.lock().unwrap().eq(&Some(0))); + assert_eq!(append_store.get_len(&mut storage)?, 0); + + assert!(append_store.pop(&mut storage).is_err()); + assert!(append_store.length.lock().unwrap().eq(&Some(0))); + assert_eq!(append_store.get_len(&mut storage)?, 0); Ok(()) } @@ -456,21 +399,21 @@ mod tests { #[test] fn test_iterator() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut append_store = AppendStoreMut::attach_or_create(&mut storage)?; - append_store.push(&1234)?; - append_store.push(&2143)?; - append_store.push(&3412)?; - append_store.push(&4321)?; + let append_store: AppendStore = AppendStore::new(b"test"); + append_store.push(&mut storage, &1234)?; + append_store.push(&mut storage, &2143)?; + append_store.push(&mut storage, &3412)?; + append_store.push(&mut storage, &4321)?; // iterate twice to make sure nothing changed - let mut iter = append_store.iter(); + let mut iter = append_store.iter(&storage)?; assert_eq!(iter.next(), Some(Ok(1234))); assert_eq!(iter.next(), Some(Ok(2143))); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), None); - let mut iter = append_store.iter(); + let mut iter = append_store.iter(&storage)?; assert_eq!(iter.next(), Some(Ok(1234))); assert_eq!(iter.next(), Some(Ok(2143))); assert_eq!(iter.next(), Some(Ok(3412))); @@ -478,7 +421,7 @@ mod tests { assert_eq!(iter.next(), None); // make sure our implementation of `nth` doesn't break anything - let mut iter = append_store.iter().skip(2); + let mut iter = append_store.iter(&storage)?.skip(2); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), None); @@ -489,13 +432,13 @@ mod tests { #[test] fn test_reverse_iterator() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut append_store = AppendStoreMut::attach_or_create(&mut storage)?; - append_store.push(&1234)?; - append_store.push(&2143)?; - append_store.push(&3412)?; - append_store.push(&4321)?; + let append_store: AppendStore = AppendStore::new(b"test"); + append_store.push(&mut storage, &1234)?; + append_store.push(&mut storage, &2143)?; + append_store.push(&mut storage, &3412)?; + append_store.push(&mut storage, &4321)?; - let mut iter = append_store.iter().rev(); + let mut iter = append_store.iter(&storage)?.rev(); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), Some(Ok(2143))); @@ -503,7 +446,7 @@ mod tests { assert_eq!(iter.next(), None); // iterate twice to make sure nothing changed - let mut iter = append_store.iter().rev(); + let mut iter = append_store.iter(&storage)?.rev(); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), Some(Ok(2143))); @@ -511,13 +454,13 @@ mod tests { assert_eq!(iter.next(), None); // make sure our implementation of `nth_back` doesn't break anything - let mut iter = append_store.iter().rev().skip(2); + let mut iter = append_store.iter(&storage)?.rev().skip(2); assert_eq!(iter.next(), Some(Ok(2143))); assert_eq!(iter.next(), Some(Ok(1234))); assert_eq!(iter.next(), None); // make sure our implementation of `ExactSizeIterator` works well - let mut iter = append_store.iter().skip(2).rev(); + let mut iter = append_store.iter(&storage)?.skip(2).rev(); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), None); @@ -526,10 +469,121 @@ mod tests { } #[test] - fn test_attach_to_wrong_location() { + fn test_json_push_pop() -> StdResult<()> { + let mut storage = MockStorage::new(); + let append_store: AppendStore = AppendStore::new(b"test"); + append_store.push(&mut storage, &1234)?; + append_store.push(&mut storage, &2143)?; + append_store.push(&mut storage, &3412)?; + append_store.push(&mut storage, &4321)?; + + assert_eq!(append_store.pop(&mut storage), Ok(4321)); + assert_eq!(append_store.pop(&mut storage), Ok(3412)); + assert_eq!(append_store.pop(&mut storage), Ok(2143)); + assert_eq!(append_store.pop(&mut storage), Ok(1234)); + assert!(append_store.pop(&mut storage).is_err()); + + Ok(()) + } + + #[test] + fn test_suffixed_pop() -> StdResult<()> { let mut storage = MockStorage::new(); - assert!(AppendStore::::attach(&storage).is_none()); - assert!(AppendStoreMut::::attach(&mut storage).is_none()); + let suffix: &[u8] = b"test_suffix"; + let original_store: AppendStore = AppendStore::new(b"test"); + let append_store = original_store.add_suffix(suffix); + append_store.push(&mut storage, &1234)?; + append_store.push(&mut storage, &2143)?; + append_store.push(&mut storage, &3412)?; + append_store.push(&mut storage, &4321)?; + + assert_eq!(append_store.pop(&mut storage), Ok(4321)); + assert_eq!(append_store.pop(&mut storage), Ok(3412)); + assert_eq!(append_store.pop(&mut storage), Ok(2143)); + assert_eq!(append_store.pop(&mut storage), Ok(1234)); + assert!(append_store.pop(&mut storage).is_err()); + + Ok(()) + } + + #[test] + fn test_suffixed_reverse_iter() -> StdResult<()> { + let mut storage = MockStorage::new(); + let suffix: &[u8] = b"test_suffix"; + let original_store: AppendStore = AppendStore::new(b"test"); + let append_store = original_store.add_suffix(suffix); + + append_store.push(&mut storage, &1234)?; + append_store.push(&mut storage, &2143)?; + append_store.push(&mut storage, &3412)?; + append_store.push(&mut storage, &4321)?; + + assert_eq!(original_store.get_len(&storage)?, 0); + + let mut iter = append_store.iter(&storage)?.rev(); + assert_eq!(iter.next(), Some(Ok(4321))); + assert_eq!(iter.next(), Some(Ok(3412))); + assert_eq!(iter.next(), Some(Ok(2143))); + assert_eq!(iter.next(), Some(Ok(1234))); + assert_eq!(iter.next(), None); + + // iterate twice to make sure nothing changed + let mut iter = append_store.iter(&storage)?.rev(); + assert_eq!(iter.next(), Some(Ok(4321))); + assert_eq!(iter.next(), Some(Ok(3412))); + assert_eq!(iter.next(), Some(Ok(2143))); + assert_eq!(iter.next(), Some(Ok(1234))); + assert_eq!(iter.next(), None); + + // make sure our implementation of `nth_back` doesn't break anything + let mut iter = append_store.iter(&storage)?.rev().skip(2); + assert_eq!(iter.next(), Some(Ok(2143))); + assert_eq!(iter.next(), Some(Ok(1234))); + assert_eq!(iter.next(), None); + + // make sure our implementation of `ExactSizeIterator` works well + let mut iter = append_store.iter(&storage)?.skip(2).rev(); + assert_eq!(iter.next(), Some(Ok(4321))); + assert_eq!(iter.next(), Some(Ok(3412))); + assert_eq!(iter.next(), None); + + Ok(()) + } + + #[test] + fn test_suffix_iter() -> StdResult<()> { + let mut storage = MockStorage::new(); + let suffix: &[u8] = b"test_suffix"; + let original_store: AppendStore = AppendStore::new(b"test"); + let append_store = original_store.add_suffix(suffix); + + append_store.push(&mut storage, &1234)?; + append_store.push(&mut storage, &2143)?; + append_store.push(&mut storage, &3412)?; + append_store.push(&mut storage, &4321)?; + + // iterate twice to make sure nothing changed + let mut iter = append_store.iter(&storage)?; + assert_eq!(iter.next(), Some(Ok(1234))); + assert_eq!(iter.next(), Some(Ok(2143))); + assert_eq!(iter.next(), Some(Ok(3412))); + assert_eq!(iter.next(), Some(Ok(4321))); + assert_eq!(iter.next(), None); + + let mut iter = append_store.iter(&storage)?; + assert_eq!(iter.next(), Some(Ok(1234))); + assert_eq!(iter.next(), Some(Ok(2143))); + assert_eq!(iter.next(), Some(Ok(3412))); + assert_eq!(iter.next(), Some(Ok(4321))); + assert_eq!(iter.next(), None); + + // make sure our implementation of `nth` doesn't break anything + let mut iter = append_store.iter(&storage)?.skip(2); + assert_eq!(iter.next(), Some(Ok(3412))); + assert_eq!(iter.next(), Some(Ok(4321))); + assert_eq!(iter.next(), None); + + Ok(()) } #[test] @@ -537,20 +591,111 @@ mod tests { // Check the default behavior is Bincode2 let mut storage = MockStorage::new(); - let mut append_store = AppendStoreMut::attach_or_create(&mut storage)?; - append_store.push(&1234)?; + let append_store: AppendStore = AppendStore::new(b"test"); + append_store.push(&mut storage, &1234)?; - let bytes = append_store.readonly_storage().get(&0_u32.to_be_bytes()); + let key = [append_store.as_slice(), &0_u32.to_be_bytes()].concat(); + let bytes = storage.get(&key); assert_eq!(bytes, Some(vec![210, 4, 0, 0])); // Check that overriding the serializer with Json works let mut storage = MockStorage::new(); - let mut append_store = - AppendStoreMut::attach_or_create_with_serialization(&mut storage, Json)?; - append_store.push(&1234)?; - let bytes = append_store.readonly_storage().get(&0_u32.to_be_bytes()); + let json_append_store: AppendStore = AppendStore::new(b"test2"); + json_append_store.push(&mut storage, &1234)?; + + let key = [json_append_store.as_slice(), &0_u32.to_be_bytes()].concat(); + let bytes = storage.get(&key); assert_eq!(bytes, Some(b"1234".to_vec())); Ok(()) } + + #[test] + fn test_removes() -> StdResult<()> { + let mut storage = MockStorage::new(); + let deque_store: AppendStore = AppendStore::new(b"test"); + deque_store.push(&mut storage, &1)?; + deque_store.push(&mut storage, &2)?; + deque_store.push(&mut storage, &3)?; + deque_store.push(&mut storage, &4)?; + deque_store.push(&mut storage, &5)?; + deque_store.push(&mut storage, &6)?; + deque_store.push(&mut storage, &7)?; + deque_store.push(&mut storage, &8)?; + + assert!(deque_store.remove(&mut storage, 8).is_err()); + assert!(deque_store.remove(&mut storage, 9).is_err()); + + assert_eq!(deque_store.remove(&mut storage, 7), Ok(8)); + assert_eq!(deque_store.get_at(&storage, 6), Ok(7)); + assert_eq!(deque_store.get_at(&storage, 5), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 3), Ok(4)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 6), Ok(7)); + assert_eq!(deque_store.get_at(&storage, 5), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 3), Ok(4)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 3), Ok(4)); + assert_eq!(deque_store.get_at(&storage, 4), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 3), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 1), Ok(2)); + assert_eq!(deque_store.get_at(&storage, 3), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 2), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 1), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 1), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 0), Ok(1)); + + assert!(deque_store.remove(&mut storage, 0).is_err()); + Ok(()) + } + + #[test] + fn test_paging() -> StdResult<()> { + let mut storage = MockStorage::new(); + let append_store: AppendStore = AppendStore::new(b"test"); + + let page_size: u32 = 5; + let total_items: u32 = 50; + + for i in 0..total_items { + append_store.push(&mut storage, &i)?; + } + + for i in 0..((total_items / page_size) - 1) { + let start_page = i; + + let values = append_store.paging(&storage, start_page, page_size)?; + + for (index, value) in values.iter().enumerate() { + assert_eq!(value, &(page_size * start_page + index as u32)) + } + } + + Ok(()) + } } diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index d107fc1..f9c7a08 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -4,7 +4,10 @@ //! This is achieved by storing each item in a separate storage entry. //! A special key is reserved for storing the length of the collection so far. //! Another special key is reserved for storing the offset of the collection. -use std::{convert::TryInto, marker::PhantomData}; +use std::any::type_name; +use std::convert::TryInto; +use std::marker::PhantomData; +use std::sync::Mutex; use serde::{de::DeserializeOwned, Serialize}; @@ -14,198 +17,194 @@ use secret_toolkit_serialization::{Bincode2, Serde}; const LEN_KEY: &[u8] = b"len"; const OFFSET_KEY: &[u8] = b"off"; -// Mutable deque_store -/// A type allowing both reads from and writes to the deque store at a given storage location. -pub struct DequeStoreMut<'a, T, Ser = Bincode2> +pub struct DequeStore<'a, T, Ser = Bincode2> where T: Serialize + DeserializeOwned, Ser: Serde, { - storage: &'a mut dyn Storage, - item_type: PhantomData<*const T>, - serialization_type: PhantomData<*const Ser>, - len: u32, - off: u32, + /// prefix of the newly constructed Storage + namespace: &'a [u8], + /// needed if any suffixes were added to the original namespace. + /// therefore it is not necessarily same as the namespace. + prefix: Option>, + length: Mutex>, + offset: Mutex>, + item_type: PhantomData, + serialization_type: PhantomData, } -impl<'a, T> DequeStoreMut<'a, T, Bincode2> -where - T: Serialize + DeserializeOwned, -{ - /// Try to use the provided storage as an DequeStore. If it doesn't seem to be one, then - /// initialize it as one. - /// - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create(storage: &'a mut dyn Storage) -> StdResult { - DequeStoreMut::attach_or_create_with_serialization(storage, Bincode2) +impl<'a, 'b, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { + /// constructor + pub const fn new(prefix: &'a [u8]) -> Self { + Self { + namespace: prefix, + prefix: None, + length: Mutex::new(None), + offset: Mutex::new(None), + item_type: PhantomData, + serialization_type: PhantomData, + } } - - /// Try to use the provided storage as an DequeStore. - /// - /// Returns None if the provided storage doesn't seem like an DequeStore. - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a mut dyn Storage) -> Option> { - DequeStoreMut::attach_with_serialization(storage, Bincode2) + /// This is used to produce a new DequeStorage. This can be used when you want to associate an AppendListStorage to each user + /// and you still get to define the DequeStorage as a static constant + pub fn add_suffix(&self, suffix: &[u8]) -> Self { + let prefix = if let Some(prefix) = &self.prefix { + [prefix.clone(), suffix.to_vec()].concat() + } else { + [self.namespace.to_vec(), suffix.to_vec()].concat() + }; + Self { + namespace: self.namespace, + prefix: Some(prefix), + length: Mutex::new(None), + offset: Mutex::new(None), + item_type: self.item_type, + serialization_type: self.serialization_type, + } } } -impl<'a, T, Ser> DequeStoreMut<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - /// Try to use the provided storage as an DequeStore. If it doesn't seem to be one, then - /// initialize it as one. This method allows choosing the serialization format you want to use. - /// - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_or_create_with_serialization( - storage: &'a mut dyn Storage, - _ser: Ser, - ) -> StdResult { - if let (Some(len_vec), Some(off_vec)) = (storage.get(LEN_KEY), (storage.get(OFFSET_KEY))) { - Self::new(storage, &len_vec, &off_vec) - } else { - let len_vec = 0_u32.to_be_bytes(); - storage.set(LEN_KEY, &len_vec); - let off_vec = 0_u32.to_be_bytes(); - storage.set(OFFSET_KEY, &off_vec); - Self::new(storage, &len_vec, &off_vec) +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { + /// gets the length from storage, and otherwise sets it to 0 + pub fn get_len(&self, storage: &S) -> StdResult { + let mut may_len = self.length.lock().unwrap(); + match *may_len { + Some(len) => Ok(len), + None => match self._get_u32(storage, LEN_KEY) { + Ok(len) => { + *may_len = Some(len); + Ok(len) + } + Err(e) => Err(e), + }, } } - - /// Try to use the provided storage as an DequeStore. - /// This method allows choosing the serialization format you want to use. - /// - /// Returns None if the provided storage doesn't seem like an DequeStore. - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization( - storage: &'a mut dyn Storage, - _ser: Ser, - ) -> Option> { - let len_vec = storage.get(LEN_KEY)?; - let off_vec = storage.get(OFFSET_KEY)?; - Some(Self::new(storage, &len_vec, &off_vec)) - } - - fn new(storage: &'a mut dyn Storage, len_vec: &[u8], off_vec: &[u8]) -> StdResult { - let len_array = len_vec - .try_into() - .map_err(|err| StdError::parse_err("u32", err))?; - let len = u32::from_be_bytes(len_array); - let off_array = off_vec - .try_into() - .map_err(|err| StdError::parse_err("u32", err))?; - let off = u32::from_be_bytes(off_array); - - Ok(Self { - storage, - item_type: PhantomData, - serialization_type: PhantomData, - len, - off, - }) + /// gets the offset from storage, and otherwise sets it to 0 + pub fn get_off(&self, storage: &S) -> StdResult { + let mut may_off = self.offset.lock().unwrap(); + match *may_off { + Some(len) => Ok(len), + None => match self._get_u32(storage, OFFSET_KEY) { + Ok(len) => { + *may_off = Some(len); + Ok(len) + } + Err(e) => Err(e), + }, + } } - - pub fn len(&self) -> u32 { - self.len + /// gets offset or length + fn _get_u32(&self, storage: &S, key: &[u8]) -> StdResult { + let num_key = [self.as_slice(), key].concat(); + if let Some(num_vec) = storage.get(&num_key) { + let num_bytes = num_vec + .as_slice() + .try_into() + .map_err(|err| StdError::parse_err("u32", err))?; + let num = u32::from_be_bytes(num_bytes); + Ok(num) + } else { + Ok(0) + } } - - pub fn is_empty(&self) -> bool { - self.len == 0 + /// checks if the collection has any elements + pub fn is_empty(&self, storage: &S) -> StdResult { + Ok(self.get_len(storage)? == 0) } - - pub fn storage(&mut self) -> &mut dyn Storage { - self.storage + /// gets the element at pos if within bounds + pub fn get_at(&self, storage: &S, pos: u32) -> StdResult { + let len = self.get_len(storage)?; + if pos >= len { + return Err(StdError::generic_err("DequeStore access out of bounds")); + } + self.get_at_unchecked(storage, pos) } - - pub fn readonly_storage(&self) -> &dyn Storage { - self.storage + /// tries to get the element at pos + fn get_at_unchecked(&self, storage: &S, pos: u32) -> StdResult { + self.load_impl(storage, &self._get_offset_pos(storage, pos)?.to_be_bytes()) } - - /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter { - self.as_readonly().iter() + /// add the offset to the pos + fn _get_offset_pos(&self, storage: &S, pos: u32) -> StdResult { + let off = self.get_off(storage)?; + Ok(pos.overflowing_add(off).0) } - - /// Get the value stored at a given position. - /// - /// # Errors - /// Will return an error if pos is out of bounds or if an item is not found. - pub fn get_at(&self, pos: u32) -> StdResult { - self.as_readonly().get_at(pos) + /// Set the length of the collection + fn set_len(&self, storage: &mut S, len: u32) { + let mut may_len = self.length.lock().unwrap(); + *may_len = Some(len); + self._set_u32(storage, LEN_KEY, len) } - - fn get_at_unchecked(&self, pos: u32) -> StdResult { - self.as_readonly().get_at_unchecked(pos) + /// Set the offset of the collection + fn set_off(&self, storage: &mut S, off: u32) { + let mut may_off = self.offset.lock().unwrap(); + *may_off = Some(off); + self._set_u32(storage, OFFSET_KEY, off) } - - /// Set the value of the item stored at a given position. - /// - /// # Errors - /// Will return an error if the position is out of bounds - pub fn set_at(&mut self, pos: u32, item: &T) -> StdResult<()> { - if pos >= self.len { - return Err(StdError::generic_err("DequeStorage access out of bounds")); - } - self.set_at_unchecked(pos, item) + /// Set the length or offset of the collection + fn _set_u32(&self, storage: &mut S, key: &[u8], num: u32) { + let num_key = [self.as_slice(), key].concat(); + storage.set(&num_key, &num.to_be_bytes()); } - - fn set_at_unchecked(&mut self, pos: u32, item: &T) -> StdResult<()> { - let serialized = Ser::serialize(item)?; - self.storage.set( - &(pos.overflowing_add(self.off).0).to_be_bytes(), - &serialized, - ); - Ok(()) + /// Clear the collection + pub fn clear(&self, storage: &mut S) { + self.set_len(storage, 0); + self.set_off(storage, 0); + } + /// Replaces data at a position within bounds + pub fn set_at(&self, storage: &mut S, pos: u32, item: &T) -> StdResult<()> { + let len = self.get_len(storage)?; + if pos >= len { + return Err(StdError::generic_err("DequeStore access out of bounds")); + } + self.set_at_unchecked(storage, pos, item) } - - /// Append an item to the end of the collection. - /// - /// This operation has a constant cost. - pub fn push_back(&mut self, item: &T) -> StdResult<()> { - self.set_at_unchecked(self.len, item)?; - self.set_length(self.len + 1); + /// Sets data at a given index + fn set_at_unchecked(&self, storage: &mut S, pos: u32, item: &T) -> StdResult<()> { + self.save_impl( + storage, + &self._get_offset_pos(storage, pos)?.to_be_bytes(), + item, + ) + } + /// Pushes an item to the back + pub fn push_back(&self, storage: &mut S, item: &T) -> StdResult<()> { + let len = self.get_len(storage)?; + self.set_at_unchecked(storage, len, item)?; + self.set_len(storage, len + 1); Ok(()) } - - /// Add an item to the begining of the collection. - /// - /// This operation has a constant cost. - pub fn push_front(&mut self, item: &T) -> StdResult<()> { - self.set_offset(self.off.overflowing_sub(1).0); - self.set_at_unchecked(0, item)?; - self.set_length(self.len + 1); + /// Pushes an item to the front + pub fn push_front(&self, storage: &mut S, item: &T) -> StdResult<()> { + let off = self.get_off(storage)?; + let len = self.get_len(storage)?; + self.set_off(storage, off.overflowing_sub(1).0); + self.set_at_unchecked(storage, 0, item)?; + self.set_len(storage, len + 1); Ok(()) } - - /// Pop the last item off the collection - /// - /// This operation has a constant cost. - pub fn pop_back(&mut self) -> StdResult { - if let Some(len) = self.len.checked_sub(1) { - let item = self.get_at_unchecked(len); - self.set_length(len); + /// Pops an item from the back + pub fn pop_back(&self, storage: &mut S) -> StdResult { + if let Some(len) = self.get_len(storage)?.checked_sub(1) { + let item = self.get_at_unchecked(storage, len); + self.set_len(storage, len); item } else { Err(StdError::generic_err("Can not pop from empty DequeStore")) } } - - /// Pop the first item off the collection - /// - /// This operation has a constant cost. - pub fn pop_front(&mut self) -> StdResult { - if let Some(len) = self.len.checked_sub(1) { - let item = self.get_at_unchecked(0); - self.set_length(len); - self.set_offset(self.off.overflowing_add(1).0); + /// Pops an item from the front + pub fn pop_front(&self, storage: &mut S) -> StdResult { + if let Some(len) = self.get_len(storage)?.checked_sub(1) { + let off = self.get_off(storage)?; + let item = self.get_at_unchecked(storage, 0); + self.set_len(storage, len); + self.set_off(storage, off.overflowing_add(1).0); item } else { Err(StdError::generic_err("Can not pop from empty DequeStore")) } } - /// Remove an element from the collection at the specified position. /// /// Removing an element from the head (first) or tail (last) has a constant cost. @@ -215,225 +214,137 @@ where /// /// Removing an element from the middle of the collection /// has the worst runtime and gas cost. - pub fn remove(&mut self, pos: u32) -> StdResult { - if pos >= self.len { + pub fn remove(&self, storage: &mut S, pos: u32) -> StdResult { + let off = self.get_off(storage)?; + let len = self.get_len(storage)?; + if pos >= len { return Err(StdError::generic_err("DequeStorage access out of bounds")); } - let item = self.get_at_unchecked(pos); - let to_tail = self.len - pos; + let item = self.get_at_unchecked(storage, pos); + let to_tail = len - pos; if to_tail < pos { // closer to the tail - for i in pos..self.len - 1 { - let element_to_shift = self.get_at_unchecked(i + 1)?; - self.set_at_unchecked(i, &element_to_shift)?; + for i in pos..(len - 1) { + let element_to_shift = self.get_at_unchecked(storage, i + 1)?; + self.set_at_unchecked(storage, i, &element_to_shift)?; } } else { // closer to the head for i in (0..pos).rev() { - let element_to_shift = self.get_at_unchecked(i)?; - self.set_at_unchecked(i + 1, &element_to_shift)?; + let element_to_shift = self.get_at_unchecked(storage, i)?; + self.set_at_unchecked(storage, i + 1, &element_to_shift)?; } - self.set_offset(self.off.overflowing_add(1).0); + self.set_off(storage, off.overflowing_add(1).0); } - self.set_length(self.len - 1); + self.set_len(storage, len - 1); item } - - /// Clear the collection - pub fn clear(&mut self) { - self.set_length(0); - self.set_offset(0); - } - - /// Set the length of the collection - fn set_length(&mut self, len: u32) { - self.storage.set(LEN_KEY, &len.to_be_bytes()); - self.len = len; + /// Returns a readonly iterator + pub fn iter(&self, storage: &'a S) -> StdResult> { + let len = self.get_len(storage)?; + let iter = DequeStoreIter::new(self, storage, 0, len); + Ok(iter) } - - /// Set the offset of the collection - fn set_offset(&mut self, off: u32) { - self.storage.set(OFFSET_KEY, &off.to_be_bytes()); - self.off = off; + /// does paging with the given parameters + pub fn paging(&self, storage: &S, start_page: u32, size: u32) -> StdResult> { + self.iter(storage)? + .skip((start_page as usize) * (size as usize)) + .take(size as usize) + .collect() } +} - /// Gain access to the implementation of the immutable methods - fn as_readonly(&self) -> DequeStore { - DequeStore { - storage: self.storage, - item_type: self.item_type, - serialization_type: self.serialization_type, - len: self.len, - off: self.off, +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { + fn as_slice(&self) -> &[u8] { + if let Some(prefix) = &self.prefix { + prefix + } else { + self.namespace } } -} -// Readonly deque-store - -/// A type allowing only reads from an deque store. useful in the context_, u8 of queries. -pub struct DequeStore<'a, T, Ser = Bincode2> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - storage: &'a dyn Storage, - item_type: PhantomData<*const T>, - serialization_type: PhantomData<*const Ser>, - len: u32, - off: u32, -} - -impl<'a, T> DequeStore<'a, T, Bincode2> -where - T: Serialize + DeserializeOwned, -{ - /// Try to use the provided storage as an DequeStore. + /// Returns StdResult from retrieving the item with the specified key. Returns a + /// StdError::NotFound if there is no item with that key /// - /// Returns None if the provided storage doesn't seem like an DequeStore. - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach(storage: &'a dyn Storage) -> Option> { - DequeStore::attach_with_serialization(storage, Bincode2) - } -} - -impl<'a, T, Ser> DequeStore<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - /// Try to use the provided storage as an DequeStore. - /// This method allows choosing the serialization format you want to use. + /// # Arguments /// - /// Returns None if the provided storage doesn't seem like an DequeStore. - /// Returns Err if the contents of the storage can not be parsed. - pub fn attach_with_serialization( - storage: &'a dyn Storage, - _ser: Ser, - ) -> Option> { - let len_vec = storage.get(LEN_KEY)?; - let off_vec = storage.get(OFFSET_KEY)?; - Some(DequeStore::new(storage, len_vec, off_vec)) - } - - fn new(storage: &'a dyn Storage, len_vec: Vec, off_vec: Vec) -> StdResult { - let len_array = len_vec - .as_slice() - .try_into() - .map_err(|err| StdError::parse_err("u32", err))?; - let len = u32::from_be_bytes(len_array); - let off_array = off_vec - .as_slice() - .try_into() - .map_err(|err| StdError::parse_err("u32", err))?; - let off = u32::from_be_bytes(off_array); - - Ok(Self { - storage, - item_type: PhantomData, - serialization_type: PhantomData, - len, - off, - }) - } - - pub fn len(&self) -> u32 { - self.len - } - - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - pub fn readonly_storage(&self) -> &dyn Storage { - self.storage - } - - /// Return an iterator over the items in the collection - pub fn iter(&self) -> Iter<'a, T, Ser> { - Iter { - storage: DequeStore::clone(self), - start: 0_u32, - end: self.len, - } - } - - /// Get the value stored at a given position. + /// * `storage` - a reference to the storage this item is in + /// * `key` - a byte slice representing the key to access the stored item + fn load_impl(&self, storage: &S, key: &[u8]) -> StdResult { + let prefixed_key = [self.as_slice(), key].concat(); + Ser::deserialize( + &storage + .get(&prefixed_key) + .ok_or(StdError::not_found(type_name::()))?, + ) + } + + /// Returns StdResult<()> resulting from saving an item to storage /// - /// # Errors - /// Will return an error if pos is out of bounds or if an item is not found. - pub fn get_at(&self, pos: u32) -> StdResult { - if pos >= self.len { - return Err(StdError::generic_err("DequeStorage access out of bounds")); - } - self.get_at_unchecked(pos) + /// # Arguments + /// + /// * `storage` - a mutable reference to the storage this item should go to + /// * `key` - a byte slice representing the key to access the stored item + /// * `value` - a reference to the item to store + fn save_impl(&self, storage: &mut S, key: &[u8], value: &T) -> StdResult<()> { + let prefixed_key = [self.as_slice(), key].concat(); + storage.set(&prefixed_key, &Ser::serialize(value)?); + Ok(()) } +} - fn get_at_unchecked(&self, pos: u32) -> StdResult { - let serialized = self - .storage - .get(&(pos.overflowing_add(self.off).0).to_be_bytes()) - .ok_or_else(|| { - StdError::generic_err(format!( - "No item in DequeStorage at position {}", - pos.overflowing_add(self.off).0 - )) - })?; - Ser::deserialize(&serialized) +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for DequeStore<'a, T, Ser> { + fn clone(&self) -> Self { + Self { + namespace: self.namespace.clone(), + prefix: self.prefix.clone(), + length: Mutex::new(None), + offset: Mutex::new(None), + item_type: self.item_type.clone(), + serialization_type: self.serialization_type.clone(), + } } } -impl<'a, T, Ser> IntoIterator for DequeStore<'a, T, Ser> +/// An iterator over the contents of the deque store. +pub struct DequeStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { - type Item = StdResult; - type IntoIter = Iter<'a, T, Ser>; - - fn into_iter(self) -> Iter<'a, T, Ser> { - let end = self.len; - Iter { - storage: self, - start: 0_u32, - end, - } - } + deque_store: &'a DequeStore<'a, T, Ser>, + storage: &'a S, + start: u32, + end: u32, } -// Manual `Clone` implementation because the default one tries to clone the Storage?? -impl<'a, T, Ser> Clone for DequeStore<'a, T, Ser> +impl<'a, T, S, Ser> DequeStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { - fn clone(&self) -> Self { + /// constructor + pub fn new( + deque_store: &'a DequeStore<'a, T, Ser>, + storage: &'a S, + start: u32, + end: u32, + ) -> Self { Self { - storage: self.storage, - item_type: self.item_type, - serialization_type: self.serialization_type, - len: self.len, - off: self.off, + deque_store, + storage, + start, + end, } } } -// Owning iterator - -/// An iterator over the contents of the deque store. -pub struct Iter<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - storage: DequeStore<'a, T, Ser>, - start: u32, - end: u32, -} - -impl<'a, T, Ser> Iterator for Iter<'a, T, Ser> +impl<'a, T, S, Ser> Iterator for DequeStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { type Item = StdResult; @@ -442,7 +353,7 @@ where if self.start >= self.end { return None; } - let item = self.storage.get_at(self.start); + let item = self.deque_store.get_at(self.storage, self.start); self.start += 1; Some(item) } @@ -465,9 +376,10 @@ where } } -impl<'a, T, Ser> DoubleEndedIterator for Iter<'a, T, Ser> +impl<'a, T, S, Ser> DoubleEndedIterator for DequeStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -475,7 +387,7 @@ where return None; } self.end -= 1; - let item = self.storage.get_at(self.end); + let item = self.deque_store.get_at(self.storage, self.end); Some(item) } @@ -492,9 +404,10 @@ where } // This enables writing `deque_store.iter().skip(n).rev()` -impl<'a, T, Ser> ExactSizeIterator for Iter<'a, T, Ser> +impl<'a, T, S, Ser> ExactSizeIterator for DequeStoreIter<'a, T, S, Ser> where T: Serialize + DeserializeOwned, + S: Storage, Ser: Serde, { } @@ -510,114 +423,114 @@ mod tests { #[test] fn test_pushs_pops() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut deque_store = DequeStoreMut::attach_or_create(&mut storage)?; - deque_store.push_front(&4)?; - deque_store.push_back(&5)?; - deque_store.push_front(&3)?; - deque_store.push_back(&6)?; - deque_store.push_front(&2)?; - deque_store.push_back(&7)?; - deque_store.push_front(&1)?; - deque_store.push_back(&8)?; - - assert_eq!(deque_store.pop_front(), Ok(1)); - assert_eq!(deque_store.pop_back(), Ok(8)); - assert_eq!(deque_store.pop_front(), Ok(2)); - assert_eq!(deque_store.pop_back(), Ok(7)); - assert_eq!(deque_store.pop_front(), Ok(3)); - assert_eq!(deque_store.pop_back(), Ok(6)); - assert_eq!(deque_store.pop_front(), Ok(4)); - assert_eq!(deque_store.pop_back(), Ok(5)); - assert!(deque_store.pop_back().is_err()); + let deque_store: DequeStore = DequeStore::new(b"test"); + deque_store.push_front(&mut storage, &4)?; + deque_store.push_back(&mut storage, &5)?; + deque_store.push_front(&mut storage, &3)?; + deque_store.push_back(&mut storage, &6)?; + deque_store.push_front(&mut storage, &2)?; + deque_store.push_back(&mut storage, &7)?; + deque_store.push_front(&mut storage, &1)?; + deque_store.push_back(&mut storage, &8)?; + + assert_eq!(deque_store.pop_front(&mut storage), Ok(1)); + assert_eq!(deque_store.pop_back(&mut storage), Ok(8)); + assert_eq!(deque_store.pop_front(&mut storage), Ok(2)); + assert_eq!(deque_store.pop_back(&mut storage), Ok(7)); + assert_eq!(deque_store.pop_front(&mut storage), Ok(3)); + assert_eq!(deque_store.pop_back(&mut storage), Ok(6)); + assert_eq!(deque_store.pop_front(&mut storage), Ok(4)); + assert_eq!(deque_store.pop_back(&mut storage), Ok(5)); + assert!(deque_store.pop_back(&mut storage).is_err()); Ok(()) } #[test] fn test_removes() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut deque_store = DequeStoreMut::attach_or_create(&mut storage)?; - deque_store.push_front(&2)?; - deque_store.push_back(&3)?; - deque_store.push_back(&4)?; - deque_store.push_back(&5)?; - deque_store.push_back(&6)?; - deque_store.push_front(&1)?; - deque_store.push_back(&7)?; - deque_store.push_back(&8)?; - - assert!(deque_store.remove(8).is_err()); - assert!(deque_store.remove(9).is_err()); - - assert_eq!(deque_store.remove(7), Ok(8)); - assert_eq!(deque_store.get_at(6), Ok(7)); - assert_eq!(deque_store.get_at(5), Ok(6)); - assert_eq!(deque_store.get_at(4), Ok(5)); - assert_eq!(deque_store.get_at(3), Ok(4)); - assert_eq!(deque_store.get_at(2), Ok(3)); - assert_eq!(deque_store.get_at(1), Ok(2)); - assert_eq!(deque_store.get_at(0), Ok(1)); - - assert_eq!(deque_store.remove(6), Ok(7)); - assert_eq!(deque_store.get_at(5), Ok(6)); - assert_eq!(deque_store.get_at(4), Ok(5)); - assert_eq!(deque_store.get_at(3), Ok(4)); - assert_eq!(deque_store.get_at(2), Ok(3)); - assert_eq!(deque_store.get_at(1), Ok(2)); - assert_eq!(deque_store.get_at(0), Ok(1)); - - assert_eq!(deque_store.remove(3), Ok(4)); - assert_eq!(deque_store.get_at(4), Ok(6)); - assert_eq!(deque_store.get_at(3), Ok(5)); - assert_eq!(deque_store.get_at(2), Ok(3)); - assert_eq!(deque_store.get_at(1), Ok(2)); - assert_eq!(deque_store.get_at(0), Ok(1)); - - assert_eq!(deque_store.remove(1), Ok(2)); - assert_eq!(deque_store.get_at(3), Ok(6)); - assert_eq!(deque_store.get_at(2), Ok(5)); - assert_eq!(deque_store.get_at(1), Ok(3)); - assert_eq!(deque_store.get_at(0), Ok(1)); - - assert_eq!(deque_store.remove(2), Ok(5)); - assert_eq!(deque_store.get_at(2), Ok(6)); - assert_eq!(deque_store.get_at(1), Ok(3)); - assert_eq!(deque_store.get_at(0), Ok(1)); - - assert_eq!(deque_store.remove(1), Ok(3)); - assert_eq!(deque_store.get_at(1), Ok(6)); - assert_eq!(deque_store.get_at(0), Ok(1)); - - assert_eq!(deque_store.remove(1), Ok(6)); - assert_eq!(deque_store.get_at(0), Ok(1)); - - assert_eq!(deque_store.remove(0), Ok(1)); - - assert!(deque_store.remove(0).is_err()); + let deque_store: DequeStore = DequeStore::new(b"test"); + deque_store.push_front(&mut storage, &2)?; + deque_store.push_back(&mut storage, &3)?; + deque_store.push_back(&mut storage, &4)?; + deque_store.push_back(&mut storage, &5)?; + deque_store.push_back(&mut storage, &6)?; + deque_store.push_front(&mut storage, &1)?; + deque_store.push_back(&mut storage, &7)?; + deque_store.push_back(&mut storage, &8)?; + + assert!(deque_store.remove(&mut storage, 8).is_err()); + assert!(deque_store.remove(&mut storage, 9).is_err()); + + assert_eq!(deque_store.remove(&mut storage, 7), Ok(8)); + assert_eq!(deque_store.get_at(&storage, 6), Ok(7)); + assert_eq!(deque_store.get_at(&storage, 5), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 3), Ok(4)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 6), Ok(7)); + assert_eq!(deque_store.get_at(&storage, 5), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 3), Ok(4)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 3), Ok(4)); + assert_eq!(deque_store.get_at(&storage, 4), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 3), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 1), Ok(2)); + assert_eq!(deque_store.get_at(&storage, 3), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 2), Ok(5)); + assert_eq!(deque_store.get_at(&storage, 2), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 1), Ok(3)); + assert_eq!(deque_store.get_at(&storage, 1), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 1), Ok(6)); + assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + + assert_eq!(deque_store.remove(&mut storage, 0), Ok(1)); + + assert!(deque_store.remove(&mut storage, 0).is_err()); Ok(()) } #[test] fn test_iterator() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut deque_store = DequeStoreMut::attach_or_create(&mut storage)?; + let deque_store: DequeStore = DequeStore::new(b"test"); - deque_store.push_front(&2143)?; - deque_store.push_back(&3333)?; - deque_store.push_back(&3412)?; - deque_store.push_front(&1234)?; - deque_store.push_back(&4321)?; + deque_store.push_front(&mut storage, &2143)?; + deque_store.push_back(&mut storage, &3333)?; + deque_store.push_back(&mut storage, &3412)?; + deque_store.push_front(&mut storage, &1234)?; + deque_store.push_back(&mut storage, &4321)?; - deque_store.remove(2)?; + deque_store.remove(&mut storage, 2)?; // iterate twice to make sure nothing changed - let mut iter = deque_store.iter(); + let mut iter = deque_store.iter(&storage)?; assert_eq!(iter.next(), Some(Ok(1234))); assert_eq!(iter.next(), Some(Ok(2143))); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), None); - let mut iter = deque_store.iter(); + let mut iter = deque_store.iter(&storage)?; assert_eq!(iter.next(), Some(Ok(1234))); assert_eq!(iter.next(), Some(Ok(2143))); assert_eq!(iter.next(), Some(Ok(3412))); @@ -625,7 +538,7 @@ mod tests { assert_eq!(iter.next(), None); // make sure our implementation of `nth` doesn't break anything - let mut iter = deque_store.iter().skip(2); + let mut iter = deque_store.iter(&storage)?.skip(2); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), None); @@ -636,16 +549,16 @@ mod tests { #[test] fn test_reverse_iterator() -> StdResult<()> { let mut storage = MockStorage::new(); - let mut deque_store = DequeStoreMut::attach_or_create(&mut storage)?; - deque_store.push_front(&2143)?; - deque_store.push_back(&3412)?; - deque_store.push_back(&3333)?; - deque_store.push_front(&1234)?; - deque_store.push_back(&4321)?; + let deque_store: DequeStore = DequeStore::new(b"test"); + deque_store.push_front(&mut storage, &2143)?; + deque_store.push_back(&mut storage, &3412)?; + deque_store.push_back(&mut storage, &3333)?; + deque_store.push_front(&mut storage, &1234)?; + deque_store.push_back(&mut storage, &4321)?; - deque_store.remove(3)?; + deque_store.remove(&mut storage, 3)?; - let mut iter = deque_store.iter().rev(); + let mut iter = deque_store.iter(&storage)?.rev(); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), Some(Ok(2143))); @@ -653,7 +566,7 @@ mod tests { assert_eq!(iter.next(), None); // iterate twice to make sure nothing changed - let mut iter = deque_store.iter().rev(); + let mut iter = deque_store.iter(&storage)?.rev(); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), Some(Ok(2143))); @@ -661,13 +574,13 @@ mod tests { assert_eq!(iter.next(), None); // make sure our implementation of `nth_back` doesn't break anything - let mut iter = deque_store.iter().rev().skip(2); + let mut iter = deque_store.iter(&storage)?.rev().skip(2); assert_eq!(iter.next(), Some(Ok(2143))); assert_eq!(iter.next(), Some(Ok(1234))); assert_eq!(iter.next(), None); // make sure our implementation of `ExactSizeIterator` works well - let mut iter = deque_store.iter().skip(2).rev(); + let mut iter = deque_store.iter(&storage)?.skip(2).rev(); assert_eq!(iter.next(), Some(Ok(4321))); assert_eq!(iter.next(), Some(Ok(3412))); assert_eq!(iter.next(), None); @@ -675,32 +588,53 @@ mod tests { Ok(()) } - #[test] - fn test_attach_to_wrong_location() { - let mut storage = MockStorage::new(); - assert!(DequeStore::::attach(&storage).is_none()); - assert!(DequeStoreMut::::attach(&mut storage).is_none()); - } - #[test] fn test_serializations() -> StdResult<()> { // Check the default behavior is Bincode2 let mut storage = MockStorage::new(); - let mut deque_store = DequeStoreMut::attach_or_create(&mut storage)?; - deque_store.push_back(&1234)?; + let deque_store: DequeStore = DequeStore::new(b"test"); + deque_store.push_back(&mut storage, &1234)?; - let bytes = deque_store.readonly_storage().get(&0_u32.to_be_bytes()); + let key = [deque_store.as_slice(), &0_u32.to_be_bytes()].concat(); + let bytes = storage.get(&key); assert_eq!(bytes, Some(vec![210, 4, 0, 0])); // Check that overriding the serializer with Json works let mut storage = MockStorage::new(); - let mut deque_store = - DequeStoreMut::attach_or_create_with_serialization(&mut storage, Json)?; - deque_store.push_back(&1234)?; - let bytes = deque_store.readonly_storage().get(&0_u32.to_be_bytes()); + let json_deque_store: DequeStore = DequeStore::new(b"test2"); + json_deque_store.push_back(&mut storage, &1234)?; + + let key = [json_deque_store.as_slice(), &0_u32.to_be_bytes()].concat(); + let bytes = storage.get(&key); assert_eq!(bytes, Some(b"1234".to_vec())); Ok(()) } + + #[test] + fn test_paging() -> StdResult<()> { + let mut storage = MockStorage::new(); + let append_store: DequeStore = DequeStore::new(b"test"); + + let page_size: u32 = 5; + let total_items: u32 = 50; + + for j in 0..total_items { + let i = total_items - j; + append_store.push_front(&mut storage, &i)?; + } + + for i in 0..((total_items / page_size) - 1) { + let start_page = i; + + let values = append_store.paging(&storage, start_page, page_size)?; + + for (index, value) in values.iter().enumerate() { + assert_eq!(value, &(page_size * start_page + index as u32 + 1)) + } + } + + Ok(()) + } } diff --git a/packages/storage/src/item.rs b/packages/storage/src/item.rs new file mode 100644 index 0000000..8c909b1 --- /dev/null +++ b/packages/storage/src/item.rs @@ -0,0 +1,183 @@ +use std::any::type_name; + +use std::marker::PhantomData; + +use cosmwasm_std::{StdError, StdResult, Storage}; +use secret_toolkit_serialization::{Bincode2, Serde}; +use serde::{de::DeserializeOwned, Serialize}; + +/// This storage struct is based on Item from cosmwasm-storage-plus +pub struct Item<'a, T, Ser = Bincode2> +where + T: Serialize + DeserializeOwned, + Ser: Serde, +{ + storage_key: &'a [u8], + item_type: PhantomData, + serialization_type: PhantomData, +} + +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Item<'a, T, Ser> { + pub const fn new(key: &'a [u8]) -> Self { + Self { + storage_key: key, + item_type: PhantomData, + serialization_type: PhantomData, + } + } +} + +impl<'a, T, Ser> Item<'a, T, Ser> +where + T: Serialize + DeserializeOwned, + Ser: Serde, +{ + /// save will serialize the model and store, returns an error on serialization issues + pub fn save(&self, storage: &mut S, data: &T) -> StdResult<()> { + self.save_impl(storage, data) + } + + /// userfacing remove function + pub fn remove(&self, storage: &mut S) { + self.remove_impl(storage); + } + + /// load will return an error if no data is set at the given key, or on parse error + pub fn load(&self, storage: &S) -> StdResult { + self.load_impl(storage) + } + + /// 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, storage: &S) -> StdResult> { + self.may_load_impl(storage) + } + + /// efficient way to see if any object is currently saved. + pub fn is_empty(&self, storage: &S) -> bool { + match storage.get(self.as_slice()) { + Some(_) => false, + None => true, + } + } + + /// 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. + /// + /// It assumes, that data was initialized before, and if it doesn't exist, `Err(StdError::NotFound)` + /// is returned. + pub fn update(&self, storage: &mut S, action: A) -> StdResult + where + S: Storage, + A: FnOnce(T) -> StdResult, + { + let input = self.load_impl(storage)?; + let output = action(input)?; + self.save_impl(storage, &output)?; + Ok(output) + } + + /// Returns StdResult from retrieving the item with the specified key. Returns a + /// StdError::NotFound if there is no item with that key + /// + /// # Arguments + /// + /// * `storage` - a reference to the storage this item is in + fn load_impl(&self, storage: &S) -> StdResult { + Ser::deserialize( + &storage + .get(self.as_slice()) + .ok_or(StdError::not_found(type_name::()))?, + ) + } + + /// Returns StdResult> from retrieving the item with the specified key. Returns a + /// None if there is no item with that key + /// + /// # Arguments + /// + /// * `storage` - a reference to the storage this item is in + fn may_load_impl(&self, storage: &S) -> StdResult> { + match storage.get(self.as_slice()) { + Some(value) => Ser::deserialize(&value).map(Some), + None => Ok(None), + } + } + + /// Returns StdResult<()> resulting from saving an item to storage + /// + /// # Arguments + /// + /// * `storage` - a mutable reference to the storage this item should go to + /// * `value` - a reference to the item to store + fn save_impl(&self, storage: &mut S, value: &T) -> StdResult<()> { + storage.set(self.as_slice(), &Ser::serialize(value)?); + Ok(()) + } + + /// Removes an item from storage + /// + /// # Arguments + /// + /// * `storage` - a mutable reference to the storage this item is in + fn remove_impl(&self, storage: &mut S) { + storage.remove(self.as_slice()); + } + + fn as_slice(&self) -> &[u8] { + self.storage_key + } +} + +#[cfg(test)] +mod tests { + use cosmwasm_std::testing::MockStorage; + + use secret_toolkit_serialization::Json; + + use super::*; + + #[test] + fn test_item() -> StdResult<()> { + let mut storage = MockStorage::new(); + let item: Item = Item::new(b"test"); + + assert!(item.is_empty(&storage)); + assert_eq!(item.may_load(&storage)?, None); + assert!(item.load(&storage).is_err()); + item.save(&mut storage, &6)?; + assert!(!item.is_empty(&storage)); + assert_eq!(item.load(&storage)?, 6); + assert_eq!(item.may_load(&storage)?, Some(6)); + item.remove(&mut storage); + assert!(item.is_empty(&storage)); + assert_eq!(item.may_load(&storage)?, None); + assert!(item.load(&storage).is_err()); + + Ok(()) + } + + #[test] + fn test_serializations() -> StdResult<()> { + // Check the default behavior is Bincode2 + let mut storage = MockStorage::new(); + + let item: Item = Item::new(b"test"); + item.save(&mut storage, &1234)?; + + let key = b"test"; + let bytes = storage.get(key); + assert_eq!(bytes, Some(vec![210, 4, 0, 0])); + + // Check that overriding the serializer with Json works + let mut storage = MockStorage::new(); + let json_item: Item = Item::new(b"test2"); + json_item.save(&mut storage, &1234)?; + + let key = b"test2"; + let bytes = storage.get(key); + assert_eq!(bytes, Some(b"1234".to_vec())); + + Ok(()) + } +} diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs new file mode 100644 index 0000000..baeaa9e --- /dev/null +++ b/packages/storage/src/keymap.rs @@ -0,0 +1,1432 @@ +use std::any::type_name; +use std::convert::TryInto; +use std::marker::PhantomData; +use std::sync::Mutex; + +use serde::Deserialize; +use serde::{de::DeserializeOwned, Serialize}; + +use cosmwasm_std::{StdError, StdResult, Storage}; + +use secret_toolkit_serialization::{Bincode2, Serde}; + +const INDEXES: &[u8] = b"indexes"; +const MAP_LENGTH: &[u8] = b"length"; + +const PAGE_SIZE: u32 = 5; + +fn _page_from_position(position: u32) -> u32 { + position / PAGE_SIZE +} + +#[derive(Serialize, Deserialize)] +struct InternalItem +where + T: Serialize + DeserializeOwned, + Ser: Serde, +{ + item: Vec, + index_pos: u32, + item_type: PhantomData, + serialization_type: PhantomData, +} + +impl InternalItem { + fn new(index_pos: u32, item: &T) -> StdResult { + Ok(Self { + item: Ser::serialize(item)?, + index_pos, + item_type: PhantomData, + serialization_type: PhantomData, + }) + } + fn get_item(&self) -> StdResult { + Ser::deserialize(&self.item) + } +} + +pub struct Keymap<'a, K, T, Ser = Bincode2> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + Ser: Serde, +{ + /// prefix of the newly constructed Storage + namespace: &'a [u8], + /// needed if any suffixes were added to the original namespace. + /// therefore it is not necessarily same as the namespace. + prefix: Option>, + length: Mutex>, + key_type: PhantomData, + item_type: PhantomData, + serialization_type: PhantomData, +} + +impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> + Keymap<'a, K, T, Ser> +{ + /// constructor + pub const fn new(prefix: &'a [u8]) -> Self { + Self { + namespace: prefix, + prefix: None, + length: Mutex::new(None), + key_type: PhantomData, + item_type: PhantomData, + serialization_type: PhantomData, + } + } + /// This is used to produce a new Keymap. This can be used when you want to associate an Keymap to each user + /// and you still get to define the Keymap as a static constant + pub fn add_suffix(&self, suffix: &[u8]) -> Self { + let prefix = if let Some(prefix) = &self.prefix { + [prefix.clone(), suffix.to_vec()].concat() + } else { + [self.namespace.to_vec(), suffix.to_vec()].concat() + }; + Self { + namespace: self.namespace, + prefix: Some(prefix), + length: Mutex::new(None), + key_type: self.key_type, + item_type: self.item_type, + serialization_type: self.serialization_type, + } + } +} + +impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> + Keymap<'a, K, T, Ser> +{ + /// Serialize key + fn serialize_key(&self, key: &K) -> StdResult> { + Ser::serialize(key) + } + /// Deserialize key + fn deserialize_key(&self, key_data: &[u8]) -> StdResult { + Ser::deserialize(key_data) + } + /// get total number of objects saved + pub fn get_len(&self, storage: &S) -> StdResult { + let mut may_len = self.length.lock().unwrap(); + match *may_len { + Some(length) => Ok(length), + None => { + let len_key = [self.as_slice(), MAP_LENGTH].concat(); + if let Some(len_vec) = storage.get(&len_key) { + let len_bytes = len_vec + .as_slice() + .try_into() + .map_err(|err| StdError::parse_err("u32", err))?; + let len = u32::from_be_bytes(len_bytes); + *may_len = Some(len); + Ok(len) + } else { + *may_len = Some(0); + Ok(0) + } + } + } + } + /// checks if the collection has any elements + pub fn is_empty(&self, storage: &S) -> StdResult { + Ok(self.get_len(storage)? == 0) + } + /// set length of the map + fn set_len(&self, storage: &mut S, len: u32) -> StdResult<()> { + let len_key = [self.as_slice(), MAP_LENGTH].concat(); + storage.set(&len_key, &len.to_be_bytes()); + + let mut may_len = self.length.lock().unwrap(); + *may_len = Some(len); + + Ok(()) + } + /// Used to get the indexes stored in the given page number + fn _get_indexes(&self, storage: &S, page: u32) -> StdResult>> { + let indexes_key = [self.as_slice(), INDEXES, page.to_be_bytes().as_slice()].concat(); + let maybe_serialized = storage.get(&indexes_key); + match maybe_serialized { + Some(serialized) => Bincode2::deserialize(&serialized), + None => Ok(vec![]), + } + } + /// Set an indexes page + fn _set_indexes_page( + &self, + storage: &mut S, + page: u32, + indexes: &Vec>, + ) -> StdResult<()> { + let indexes_key = [self.as_slice(), INDEXES, page.to_be_bytes().as_slice()].concat(); + storage.set(&indexes_key, &Bincode2::serialize(indexes)?); + Ok(()) + } + /// user facing get function + pub fn get(&self, storage: &S, key: &K) -> Option { + if let Ok(internal_item) = self._get_from_key(storage, key) { + internal_item.get_item().ok() + } else { + None + } + } + /// internal item get function + fn _get_from_key(&self, storage: &S, key: &K) -> StdResult> { + let key_vec = self.serialize_key(key)?; + self.load_impl(storage, &key_vec) + } + /// user facing remove function + pub fn remove(&self, storage: &mut S, key: &K) -> StdResult<()> { + let key_vec = self.serialize_key(key)?; + let removed_pos = self._get_from_key(storage, key)?.index_pos; + + self.remove_impl(storage, &key_vec); + let page = _page_from_position(removed_pos); + + let mut len = self.get_len(storage)?; + len -= 1; + self.set_len(storage, len)?; + + let mut indexes = self._get_indexes(storage, page)?; + + let pos_in_indexes = (removed_pos % PAGE_SIZE) as usize; + + if indexes[pos_in_indexes] != key_vec { + return Err(StdError::generic_err( + "Tried to remove, but hash not found - should never happen", + )); + } + + // if our object is the last item, then just remove it + if len == 0 || len == removed_pos { + indexes.pop(); + self._set_indexes_page(storage, page, &indexes)?; + return Ok(()); + } + + // max page should use previous_len - 1 which is exactly the current len + let max_page = _page_from_position(len); + if max_page == page { + // last page indexes is the same as indexes + let last_key = indexes.pop().ok_or(StdError::generic_err( + "Last item's key not found - should never happen", + ))?; + // modify last item + let mut last_internal_item = self.load_impl(storage, &last_key)?; + last_internal_item.index_pos = removed_pos; + self.save_impl(storage, &last_key, &last_internal_item)?; + // save to indexes + indexes[pos_in_indexes] = last_key; + self._set_indexes_page(storage, page, &indexes)?; + } else { + let mut last_page_indexes = self._get_indexes(storage, max_page)?; + let last_key = last_page_indexes.pop().ok_or(StdError::generic_err( + "Last item's key not found - should never happen", + ))?; + // modify last item + let mut last_internal_item = self.load_impl(storage, &last_key)?; + last_internal_item.index_pos = removed_pos; + self.save_impl(storage, &last_key, &last_internal_item)?; + // save indexes + indexes[pos_in_indexes] = last_key; + self._set_indexes_page(storage, page, &indexes)?; + self._set_indexes_page(storage, max_page, &last_page_indexes)?; + } + + Ok(()) + } + /// user facing insert function + pub fn insert(&self, storage: &mut S, key: &K, item: &T) -> StdResult<()> { + let key_vec = self.serialize_key(key)?; + match self.may_load_impl(storage, &key_vec)? { + Some(existing_internal_item) => { + // if item already exists + let new_internal_item = InternalItem::new(existing_internal_item.index_pos, item)?; + self.save_impl(storage, &key_vec, &new_internal_item) + } + None => { + // not already saved + let pos = self.get_len(storage)?; + self.set_len(storage, pos + 1)?; + let page = _page_from_position(pos); + // save the item + let internal_item = InternalItem::new(pos, item)?; + self.save_impl(storage, &key_vec, &internal_item)?; + // add index + let mut indexes = self._get_indexes(storage, page)?; + indexes.push(key_vec); + self._set_indexes_page(storage, page, &indexes) + } + } + } + /// user facing method that checks if any item is stored with this key. + pub fn contains(&self, storage: &S, key: &K) -> bool { + match self.serialize_key(key) { + Ok(key_vec) => self.contains_impl(storage, &key_vec), + Err(_) => false, + } + } + /// paginates (key, item) pairs. + pub fn paging( + &self, + storage: &S, + start_page: u32, + size: u32, + ) -> StdResult> { + let start_pos = start_page * size; + let mut end_pos = start_pos + size - 1; + + let max_size = self.get_len(storage)?; + + if max_size == 0 { + return Ok(vec![]); + } + + if start_pos > max_size { + return Err(StdError::NotFound { + kind: "Out of bounds".to_string(), + }); + } else if end_pos > max_size { + end_pos = max_size - 1; + } + self.get_pairs_at_positions(storage, start_pos, end_pos) + } + /// paginates only the keys. More efficient than paginating both items and keys + pub fn paging_keys( + &self, + storage: &S, + start_page: u32, + size: u32, + ) -> StdResult> { + let start_pos = start_page * size; + let mut end_pos = start_pos + size - 1; + + let max_size = self.get_len(storage)?; + + if max_size == 0 { + return Ok(vec![]); + } + + if start_pos > max_size { + return Err(StdError::NotFound { + kind: "Out of bounds".to_string(), + }); + } else if end_pos > max_size { + end_pos = max_size - 1; + } + self.get_keys_at_positions(storage, start_pos, end_pos) + } + /// tries to list keys without checking start/end bounds + fn get_keys_at_positions( + &self, + storage: &S, + start: u32, + end: u32, + ) -> StdResult> { + let start_page = _page_from_position(start); + let end_page = _page_from_position(end); + + let mut res = vec![]; + + for page in start_page..=end_page { + let indexes = self._get_indexes(storage, page)?; + let start_page_pos = if page == start_page { + start % PAGE_SIZE + } else { + 0 + }; + let end_page_pos = if page == end_page { + end % PAGE_SIZE + } else { + PAGE_SIZE - 1 + }; + for i in start_page_pos..=end_page_pos { + let key_vec = &indexes[i as usize]; + let key = self.deserialize_key(key_vec)?; + res.push(key); + } + } + Ok(res) + } + /// tries to list (key, item) pairs without checking start/end bounds + fn get_pairs_at_positions( + &self, + storage: &S, + start: u32, + end: u32, + ) -> StdResult> { + let start_page = _page_from_position(start); + let end_page = _page_from_position(end); + + let mut res = vec![]; + + for page in start_page..=end_page { + let indexes = self._get_indexes(storage, page)?; + let start_page_pos = if page == start_page { + start % PAGE_SIZE + } else { + 0 + }; + let end_page_pos = if page == end_page { + end % PAGE_SIZE + } else { + PAGE_SIZE - 1 + }; + for i in start_page_pos..=end_page_pos { + let key_vec = &indexes[i as usize]; + let key = self.deserialize_key(key_vec)?; + let item = self.load_impl(storage, key_vec)?.get_item()?; + res.push((key, item)); + } + } + Ok(res) + } + /// gets a key from a specific position in indexes + fn get_key_from_pos(&self, storage: &S, pos: u32) -> StdResult { + let page = _page_from_position(pos); + let indexes = self._get_indexes(storage, page)?; + let index = pos % PAGE_SIZE; + let key_vec = &indexes[index as usize]; + self.deserialize_key(key_vec) + } + /// gets a key from a specific position in indexes + fn get_pair_from_pos(&self, storage: &S, pos: u32) -> StdResult<(K, T)> { + let page = _page_from_position(pos); + let indexes = self._get_indexes(storage, page)?; + let index = pos % PAGE_SIZE; + let key_vec = &indexes[index as usize]; + let key = self.deserialize_key(key_vec)?; + let item = self.load_impl(storage, key_vec)?.get_item()?; + Ok((key, item)) + } + /// Returns a readonly iterator only for keys. More efficient than iter(). + pub fn iter_keys(&self, storage: &'a S) -> StdResult> { + let len = self.get_len(storage)?; + let iter = KeyIter::new(self, storage, 0, len); + Ok(iter) + } + /// Returns a readonly iterator for (key-item) pairs + pub fn iter(&self, storage: &'a S) -> StdResult> { + let len = self.get_len(storage)?; + let iter = KeyItemIter::new(self, storage, 0, len); + Ok(iter) + } +} + +impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> + PrefixedTypedStorage, Ser> for Keymap<'a, K, T, Ser> +{ + fn as_slice(&self) -> &[u8] { + if let Some(prefix) = &self.prefix { + prefix + } else { + self.namespace + } + } +} + +impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> Clone + for Keymap<'a, K, T, Ser> +{ + fn clone(&self) -> Self { + Self { + namespace: self.namespace.clone(), + prefix: self.prefix.clone(), + length: Mutex::new(None), + key_type: self.key_type.clone(), + item_type: self.item_type.clone(), + serialization_type: self.serialization_type.clone(), + } + } +} + +/// An iterator over the keys of the Keymap. +pub struct KeyIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ + keymap: &'a Keymap<'a, K, T, Ser>, + storage: &'a S, + start: u32, + end: u32, + saved_indexes: Option>>, + saved_index_page: Option, + saved_back_indexes: Option>>, + saved_back_index_page: Option, +} + +impl<'a, K, T, S, Ser> KeyIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ + /// constructor + pub fn new(keymap: &'a Keymap<'a, K, T, Ser>, storage: &'a S, start: u32, end: u32) -> Self { + Self { + keymap, + storage, + start, + end, + saved_indexes: None, + saved_index_page: None, + saved_back_indexes: None, + saved_back_index_page: None, + } + } +} + +impl<'a, K, T, S, Ser> Iterator for KeyIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ + type Item = StdResult; + + fn next(&mut self) -> Option { + if self.start >= self.end { + return None; + } + let res: Option; + if let (Some(page), Some(indexes)) = (&self.saved_index_page, &self.saved_indexes) { + let current_page = _page_from_position(self.start); + if *page == current_page { + let current_idx = (self.start % PAGE_SIZE) as usize; + if current_idx + 1 > indexes.len() { + res = None; + } else { + let key_vec = &indexes[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + } else { + match self.keymap._get_indexes(self.storage, current_page) { + Ok(new_indexes) => { + let current_idx = (self.start % PAGE_SIZE) as usize; + if current_idx + 1 > new_indexes.len() { + res = None; + } else { + let key_vec = &new_indexes[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + self.saved_index_page = Some(current_page); + self.saved_indexes = Some(new_indexes); + } + Err(_) => match self.keymap.get_key_from_pos(self.storage, self.start) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(_) => { + res = None; + } + }, + } + } + } else { + let next_page = _page_from_position(self.start + 1); + let current_page = _page_from_position(self.start); + match self.keymap._get_indexes(self.storage, next_page) { + Ok(next_index) => { + if current_page == next_page { + let current_idx = (self.start % PAGE_SIZE) as usize; + if current_idx + 1 > next_index.len() { + res = None; + } else { + let key_vec = &next_index[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + } else { + match self.keymap.get_key_from_pos(self.storage, self.start) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(_) => { + res = None; + } + } + } + self.saved_index_page = Some(next_page); + self.saved_indexes = Some(next_index); + } + Err(_) => match self.keymap.get_key_from_pos(self.storage, self.start) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(_) => { + res = None; + } + }, + } + } + self.start += 1; + res + } + + // This needs to be implemented correctly for `ExactSizeIterator` to work. + fn size_hint(&self) -> (usize, Option) { + let len = (self.end - self.start) as usize; + (len, Some(len)) + } + + // I implement `nth` manually because it is used in the standard library whenever + // it wants to skip over elements, but the default implementation repeatedly calls next. + // because that is very expensive in this case, and the items are just discarded, we wan + // do better here. + // In practice, this enables cheap paging over the storage by calling: + // `append_store.iter().skip(start).take(length).collect()` + fn nth(&mut self, n: usize) -> Option { + self.start = self.start.saturating_add(n as u32); + self.next() + } +} + +impl<'a, K, T, S, Ser> DoubleEndedIterator for KeyIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ + fn next_back(&mut self) -> Option { + if self.start >= self.end { + return None; + } + self.end -= 1; + let res; + if let (Some(page), Some(indexes)) = (&self.saved_back_index_page, &self.saved_back_indexes) + { + let current_page = _page_from_position(self.end); + if *page == current_page { + let current_idx = (self.end % PAGE_SIZE) as usize; + if current_idx + 1 > indexes.len() { + res = None; + } else { + let key_vec = &indexes[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + } else { + match self.keymap._get_indexes(self.storage, current_page) { + Ok(new_indexes) => { + let current_idx = (self.end % PAGE_SIZE) as usize; + if current_idx + 1 > new_indexes.len() { + res = None; + } else { + let key_vec = &new_indexes[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + self.saved_back_index_page = Some(current_page); + self.saved_back_indexes = Some(new_indexes); + } + Err(_) => match self.keymap.get_key_from_pos(self.storage, self.end) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(_) => { + res = None; + } + }, + } + } + } else { + let next_page = _page_from_position(self.end - 1); + let current_page = _page_from_position(self.end); + match self.keymap._get_indexes(self.storage, next_page) { + Ok(next_index) => { + if current_page == next_page { + let current_idx = (self.end % PAGE_SIZE) as usize; + if current_idx + 1 > next_index.len() { + res = None; + } else { + let key_vec = &next_index[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + } else { + match self.keymap.get_key_from_pos(self.storage, self.end) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(_) => { + res = None; + } + } + } + self.saved_back_index_page = Some(next_page); + self.saved_back_indexes = Some(next_index); + } + Err(_) => match self.keymap.get_key_from_pos(self.storage, self.end) { + Ok(key) => { + res = Some(Ok(key)); + } + Err(_) => { + res = None; + } + }, + } + } + res + } + + // I implement `nth_back` manually because it is used in the standard library whenever + // it wants to skip over elements, but the default implementation repeatedly calls next_back. + // because that is very expensive in this case, and the items are just discarded, we wan + // do better here. + // In practice, this enables cheap paging over the storage by calling: + // `append_store.iter().skip(start).take(length).collect()` + fn nth_back(&mut self, n: usize) -> Option { + self.end = self.end.saturating_sub(n as u32); + self.next_back() + } +} + +// This enables writing `append_store.iter().skip(n).rev()` +impl<'a, K, T, S, Ser> ExactSizeIterator for KeyIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ +} + +// =============================================================================================== + +/// An iterator over the (key, item) pairs of the Keymap. Less efficient than just iterating over keys. +pub struct KeyItemIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ + keymap: &'a Keymap<'a, K, T, Ser>, + storage: &'a S, + start: u32, + end: u32, + saved_indexes: Option>>, + saved_index_page: Option, + saved_back_indexes: Option>>, + saved_back_index_page: Option, +} + +impl<'a, K, T, S, Ser> KeyItemIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ + /// constructor + pub fn new(keymap: &'a Keymap<'a, K, T, Ser>, storage: &'a S, start: u32, end: u32) -> Self { + Self { + keymap, + storage, + start, + end, + saved_indexes: None, + saved_index_page: None, + saved_back_indexes: None, + saved_back_index_page: None, + } + } +} + +impl<'a, K, T, S, Ser> Iterator for KeyItemIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ + type Item = StdResult<(K, T)>; + + fn next(&mut self) -> Option { + if self.start >= self.end { + return None; + } + let res: Option; + if let (Some(page), Some(indexes)) = (&self.saved_index_page, &self.saved_indexes) { + let current_page = _page_from_position(self.start); + if *page == current_page { + let current_idx = (self.start % PAGE_SIZE) as usize; + if current_idx + 1 > indexes.len() { + res = None; + } else { + let key_vec = &indexes[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + let item = self.keymap.get(self.storage, &key)?; + res = Some(Ok((key, item))); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + } else { + match self.keymap._get_indexes(self.storage, current_page) { + Ok(new_indexes) => { + let current_idx = (self.start % PAGE_SIZE) as usize; + if current_idx + 1 > new_indexes.len() { + res = None; + } else { + let key_vec = &new_indexes[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + let item = self.keymap.get(self.storage, &key)?; + res = Some(Ok((key, item))); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + self.saved_index_page = Some(current_page); + self.saved_indexes = Some(new_indexes); + } + Err(_) => match self.keymap.get_pair_from_pos(self.storage, self.start) { + Ok(pair) => { + res = Some(Ok(pair)); + } + Err(_) => { + res = None; + } + }, + } + } + } else { + let next_page = _page_from_position(self.start + 1); + let current_page = _page_from_position(self.start); + match self.keymap._get_indexes(self.storage, next_page) { + Ok(next_index) => { + if current_page == next_page { + let current_idx = (self.start % PAGE_SIZE) as usize; + if current_idx + 1 > next_index.len() { + res = None; + } else { + let key_vec = &next_index[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + let item = self.keymap.get(self.storage, &key)?; + res = Some(Ok((key, item))); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + } else { + match self.keymap.get_pair_from_pos(self.storage, self.start) { + Ok(pair) => { + res = Some(Ok(pair)); + } + Err(_) => { + res = None; + } + } + } + self.saved_index_page = Some(next_page); + self.saved_indexes = Some(next_index); + } + Err(_) => match self.keymap.get_pair_from_pos(self.storage, self.start) { + Ok(pair) => { + res = Some(Ok(pair)); + } + Err(_) => { + res = None; + } + }, + } + } + self.start += 1; + res + } + + // This needs to be implemented correctly for `ExactSizeIterator` to work. + fn size_hint(&self) -> (usize, Option) { + let len = (self.end - self.start) as usize; + (len, Some(len)) + } + + // I implement `nth` manually because it is used in the standard library whenever + // it wants to skip over elements, but the default implementation repeatedly calls next. + // because that is very expensive in this case, and the items are just discarded, we wan + // do better here. + // In practice, this enables cheap paging over the storage by calling: + // `append_store.iter().skip(start).take(length).collect()` + fn nth(&mut self, n: usize) -> Option { + self.start = self.start.saturating_add(n as u32); + self.next() + } +} + +impl<'a, K, T, S, Ser> DoubleEndedIterator for KeyItemIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ + fn next_back(&mut self) -> Option { + if self.start >= self.end { + return None; + } + self.end -= 1; + let res; + if let (Some(page), Some(indexes)) = (&self.saved_back_index_page, &self.saved_back_indexes) + { + let current_page = _page_from_position(self.end); + if *page == current_page { + let current_idx = (self.end % PAGE_SIZE) as usize; + if current_idx + 1 > indexes.len() { + res = None; + } else { + let key_vec = &indexes[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + let item = self.keymap.get(self.storage, &key)?; + res = Some(Ok((key, item))); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + } else { + match self.keymap._get_indexes(self.storage, current_page) { + Ok(new_indexes) => { + let current_idx = (self.end % PAGE_SIZE) as usize; + if current_idx + 1 > new_indexes.len() { + res = None; + } else { + let key_vec = &new_indexes[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + let item = self.keymap.get(self.storage, &key)?; + res = Some(Ok((key, item))); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + self.saved_back_index_page = Some(current_page); + self.saved_back_indexes = Some(new_indexes); + } + Err(_) => match self.keymap.get_pair_from_pos(self.storage, self.end) { + Ok(pair) => { + res = Some(Ok(pair)); + } + Err(_) => { + res = None; + } + }, + } + } + } else { + let next_page = _page_from_position(self.end - 1); + let current_page = _page_from_position(self.end); + match self.keymap._get_indexes(self.storage, next_page) { + Ok(next_index) => { + if current_page == next_page { + let current_idx = (self.end % PAGE_SIZE) as usize; + if current_idx + 1 > next_index.len() { + res = None; + } else { + let key_vec = &next_index[current_idx]; + match self.keymap.deserialize_key(key_vec) { + Ok(key) => { + let item = self.keymap.get(self.storage, &key)?; + res = Some(Ok((key, item))); + } + Err(e) => { + res = Some(Err(e)); + } + } + } + } else { + match self.keymap.get_pair_from_pos(self.storage, self.end) { + Ok(pair) => { + res = Some(Ok(pair)); + } + Err(_) => { + res = None; + } + } + } + self.saved_back_index_page = Some(next_page); + self.saved_back_indexes = Some(next_index); + } + Err(_) => match self.keymap.get_pair_from_pos(self.storage, self.end) { + Ok(pair) => { + res = Some(Ok(pair)); + } + Err(_) => { + res = None; + } + }, + } + } + res + } + + // I implement `nth_back` manually because it is used in the standard library whenever + // it wants to skip over elements, but the default implementation repeatedly calls next_back. + // because that is very expensive in this case, and the items are just discarded, we wan + // do better here. + // In practice, this enables cheap paging over the storage by calling: + // `append_store.iter().skip(start).take(length).collect()` + fn nth_back(&mut self, n: usize) -> Option { + self.end = self.end.saturating_sub(n as u32); + self.next_back() + } +} + +// This enables writing `append_store.iter().skip(n).rev()` +impl<'a, K, T, S, Ser> ExactSizeIterator for KeyItemIter<'a, K, T, S, Ser> +where + K: Serialize + DeserializeOwned, + T: Serialize + DeserializeOwned, + S: Storage, + Ser: Serde, +{ +} + +trait PrefixedTypedStorage { + fn as_slice(&self) -> &[u8]; + + /// Returns bool from retrieving the item with the specified key. + /// + /// # Arguments + /// + /// * `storage` - a reference to the storage this item is in + /// * `key` - a byte slice representing the key to access the stored item + fn contains_impl(&self, storage: &S, key: &[u8]) -> bool { + let prefixed_key = [self.as_slice(), key].concat(); + storage.get(&prefixed_key).is_some() + } + + /// Returns StdResult from retrieving the item with the specified key. Returns a + /// StdError::NotFound if there is no item with that key + /// + /// # Arguments + /// + /// * `storage` - a reference to the storage this item is in + /// * `key` - a byte slice representing the key to access the stored item + fn load_impl(&self, storage: &S, key: &[u8]) -> StdResult { + let prefixed_key = [self.as_slice(), key].concat(); + Ser::deserialize( + &storage + .get(&prefixed_key) + .ok_or(StdError::not_found(type_name::()))?, + ) + } + + /// Returns StdResult> from retrieving the item with the specified key. Returns a + /// None if there is no item with that key + /// + /// # Arguments + /// + /// * `storage` - a reference to the storage this item is in + /// * `key` - a byte slice representing the key to access the stored item + fn may_load_impl(&self, storage: &S, key: &[u8]) -> StdResult> { + let prefixed_key = [self.as_slice(), key].concat(); + match storage.get(&prefixed_key) { + Some(value) => Ser::deserialize(&value).map(Some), + None => Ok(None), + } + } + + /// Returns StdResult<()> resulting from saving an item to storage + /// + /// # Arguments + /// + /// * `storage` - a mutable reference to the storage this item should go to + /// * `key` - a byte slice representing the key to access the stored item + /// * `value` - a reference to the item to store + fn save_impl(&self, storage: &mut S, key: &[u8], value: &T) -> StdResult<()> { + let prefixed_key = [self.as_slice(), key].concat(); + storage.set(&prefixed_key, &Ser::serialize(value)?); + Ok(()) + } + + /// Removes an item from storage + /// + /// # Arguments + /// + /// * `storage` - a mutable reference to the storage this item is in + /// * `key` - a byte slice representing the key to access the stored item + fn remove_impl(&self, storage: &mut S, key: &[u8]) { + let prefixed_key = [self.as_slice(), key].concat(); + storage.remove(&prefixed_key); + } +} + +#[cfg(test)] +mod tests { + use serde::{Deserialize, Serialize}; + + use cosmwasm_std::testing::MockStorage; + + use super::*; + + #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] + struct Foo { + string: String, + number: i32, + } + #[test] + fn test_keymap_perf_insert() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let total_items = 1000; + + let keymap: Keymap, i32> = Keymap::new(b"test"); + + for i in 0..total_items { + let key: Vec = (i as i32).to_be_bytes().to_vec(); + keymap.insert(&mut storage, &key, &i)?; + } + + assert_eq!(keymap.get_len(&storage)?, 1000); + + Ok(()) + } + + #[test] + fn test_keymap_perf_insert_remove() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let total_items = 100; + + let keymap: Keymap = Keymap::new(b"test"); + + for i in 0..total_items { + keymap.insert(&mut storage, &i, &i)?; + } + + for i in 0..total_items { + keymap.remove(&mut storage, &i)?; + } + + assert_eq!(keymap.get_len(&storage)?, 0); + + Ok(()) + } + + #[test] + fn test_keymap_paging() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let page_size: u32 = 5; + let total_items: u32 = 50; + let keymap: Keymap, u32> = Keymap::new(b"test"); + + for i in 0..total_items { + let key: Vec = (i as i32).to_be_bytes().to_vec(); + keymap.insert(&mut storage, &key, &i)?; + } + + for i in 0..((total_items / page_size) - 1) { + let start_page = i; + + let values = keymap.paging(&storage, start_page, page_size)?; + + for (index, (key_value, value)) in values.iter().enumerate() { + let i = page_size * start_page + index as u32; + let key: Vec = (i as i32).to_be_bytes().to_vec(); + assert_eq!(key_value, &key); + assert_eq!(value, &i); + } + } + + Ok(()) + } + + #[test] + fn test_keymap_paging_overflow() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let page_size = 50; + let total_items = 10; + let keymap: Keymap = Keymap::new(b"test"); + + for i in 0..total_items { + keymap.insert(&mut storage, &(i as i32), &i)?; + } + + let values = keymap.paging_keys(&storage, 0, page_size)?; + + assert_eq!(values.len(), total_items as usize); + + for (index, value) in values.iter().enumerate() { + assert_eq!(value, &(index as i32)) + } + + Ok(()) + } + + #[test] + fn test_keymap_insert_multiple() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let keymap: Keymap, Foo> = Keymap::new(b"test"); + let foo1 = Foo { + string: "string one".to_string(), + number: 1111, + }; + let foo2 = Foo { + string: "string two".to_string(), + number: 1111, + }; + + keymap.insert(&mut storage, &b"key1".to_vec(), &foo1)?; + keymap.insert(&mut storage, &b"key2".to_vec(), &foo2)?; + + let read_foo1 = keymap.get(&storage, &b"key1".to_vec()).unwrap(); + let read_foo2 = keymap.get(&storage, &b"key2".to_vec()).unwrap(); + + assert_eq!(foo1, read_foo1); + assert_eq!(foo2, read_foo2); + Ok(()) + } + + #[test] + fn test_keymap_contains() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let keymap: Keymap, Foo> = Keymap::new(b"test"); + let foo1 = Foo { + string: "string one".to_string(), + number: 1111, + }; + + keymap.insert(&mut storage, &b"key1".to_vec(), &foo1)?; + let contains_k1 = keymap.contains(&storage, &b"key1".to_vec()); + + assert_eq!(contains_k1, true); + + Ok(()) + } + + #[test] + fn test_keymap_iter() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let keymap: Keymap, Foo> = Keymap::new(b"test"); + let foo1 = Foo { + string: "string one".to_string(), + number: 1111, + }; + let foo2 = Foo { + string: "string two".to_string(), + number: 1111, + }; + + keymap.insert(&mut storage, &b"key1".to_vec(), &foo1)?; + keymap.insert(&mut storage, &b"key2".to_vec(), &foo2)?; + + let mut x = keymap.iter(&storage)?; + let (len, _) = x.size_hint(); + assert_eq!(len, 2); + + assert_eq!(x.next().unwrap()?, (b"key1".to_vec(), foo1)); + + assert_eq!(x.next().unwrap()?, (b"key2".to_vec(), foo2)); + + Ok(()) + } + + #[test] + fn test_keymap_iter_keys() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let keymap: Keymap = Keymap::new(b"test"); + let foo1 = Foo { + string: "string one".to_string(), + number: 1111, + }; + let foo2 = Foo { + string: "string two".to_string(), + number: 1111, + }; + + let key1 = "key1".to_string(); + let key2 = "key2".to_string(); + + keymap.insert(&mut storage, &key1, &foo1)?; + keymap.insert(&mut storage, &key2, &foo2)?; + + let mut x = keymap.iter_keys(&storage)?; + let (len, _) = x.size_hint(); + assert_eq!(len, 2); + + assert_eq!(x.next().unwrap()?, key1); + + assert_eq!(x.next().unwrap()?, key2); + + Ok(()) + } + + #[test] + fn test_keymap_overwrite() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let keymap: Keymap, Foo> = Keymap::new(b"test"); + let foo1 = Foo { + string: "string one".to_string(), + number: 1111, + }; + let foo2 = Foo { + string: "string two".to_string(), + number: 2222, + }; + + keymap.insert(&mut storage, &b"key1".to_vec(), &foo1)?; + keymap.insert(&mut storage, &b"key1".to_vec(), &foo2)?; + + let foo3 = keymap.get(&storage, &b"key1".to_vec()).unwrap(); + + assert_eq!(foo3, foo2); + + Ok(()) + } + + #[test] + fn test_keymap_suffixed_basics() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let original_keymap: Keymap = Keymap::new(b"test"); + let keymap = original_keymap.add_suffix(b"test_suffix"); + let foo1 = Foo { + string: "string one".to_string(), + number: 1111, + }; + let foo2 = Foo { + string: "string one".to_string(), + number: 1111, + }; + keymap.insert(&mut storage, &"key1".to_string(), &foo1)?; + keymap.insert(&mut storage, &"key2".to_string(), &foo2)?; + + let read_foo1 = keymap.get(&storage, &"key1".to_string()).unwrap(); + let read_foo2 = keymap.get(&storage, &"key2".to_string()).unwrap(); + + assert_eq!(original_keymap.get_len(&storage)?, 0); + assert_eq!(foo1, read_foo1); + assert_eq!(foo2, read_foo2); + + let alternative_keymap: Keymap = Keymap::new(b"alternative"); + let alt_same_suffix = alternative_keymap.add_suffix(b"test_suffix"); + + assert!(alt_same_suffix.is_empty(&storage)?); + + // show that it loads foo1 before removal + let before_remove_foo1 = keymap.get(&storage, &"key1".to_string()); + assert!(before_remove_foo1.is_some()); + assert_eq!(foo1, before_remove_foo1.unwrap()); + // and returns None after removal + keymap.remove(&mut storage, &"key1".to_string())?; + let removed_foo1 = keymap.get(&storage, &"key1".to_string()); + assert!(removed_foo1.is_none()); + + // show what happens when reading from keys that have not been set yet. + assert!(keymap.get(&storage, &"key3".to_string()).is_none()); + + Ok(()) + } + + #[test] + fn test_keymap_length() -> StdResult<()> { + let mut storage = MockStorage::new(); + + let keymap: Keymap = Keymap::new(b"test"); + let foo1 = Foo { + string: "string one".to_string(), + number: 1111, + }; + let foo2 = Foo { + string: "string one".to_string(), + number: 1111, + }; + + assert!(keymap.length.lock().unwrap().eq(&None)); + assert_eq!(keymap.get_len(&storage)?, 0); + assert!(keymap.length.lock().unwrap().eq(&Some(0))); + + let key1 = "k1".to_string(); + let key2 = "k2".to_string(); + + keymap.insert(&mut storage, &key1, &foo1)?; + assert_eq!(keymap.get_len(&storage)?, 1); + assert!(keymap.length.lock().unwrap().eq(&Some(1))); + + // add another item + keymap.insert(&mut storage, &key2, &foo2)?; + assert_eq!(keymap.get_len(&storage)?, 2); + assert!(keymap.length.lock().unwrap().eq(&Some(2))); + + // remove item and check length + keymap.remove(&mut storage, &key1)?; + assert_eq!(keymap.get_len(&storage)?, 1); + assert!(keymap.length.lock().unwrap().eq(&Some(1))); + + // override item (should not change length) + keymap.insert(&mut storage, &key2, &foo1)?; + assert_eq!(keymap.get_len(&storage)?, 1); + assert!(keymap.length.lock().unwrap().eq(&Some(1))); + + // remove item and check length + keymap.remove(&mut storage, &key2)?; + assert_eq!(keymap.get_len(&storage)?, 0); + assert!(keymap.length.lock().unwrap().eq(&Some(0))); + + Ok(()) + } +} diff --git a/packages/storage/src/lib.rs b/packages/storage/src/lib.rs index 0bacff8..65eed61 100644 --- a/packages/storage/src/lib.rs +++ b/packages/storage/src/lib.rs @@ -1,7 +1,10 @@ +#[doc = include_str!("../Readme.md")] pub mod append_store; pub mod deque_store; -pub mod typed_store; +pub mod item; +pub mod keymap; -pub use append_store::{AppendStore, AppendStoreMut}; -pub use deque_store::{DequeStore, DequeStoreMut}; -pub use typed_store::{TypedStore, TypedStoreMut}; +pub use append_store::AppendStore; +pub use deque_store::DequeStore; +pub use item::Item; +pub use keymap::Keymap; diff --git a/packages/storage/src/typed_store.rs b/packages/storage/src/typed_store.rs deleted file mode 100644 index 95ec8df..0000000 --- a/packages/storage/src/typed_store.rs +++ /dev/null @@ -1,176 +0,0 @@ -use std::any::type_name; -use std::marker::PhantomData; - -use serde::{de::DeserializeOwned, Serialize}; - -use cosmwasm_std::{StdError, StdResult, Storage}; - -use secret_toolkit_serialization::{Bincode2, Serde}; - -pub struct TypedStoreMut<'a, T, Ser = Bincode2> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - storage: &'a mut dyn Storage, - item_type: PhantomData<*const T>, - serialization_type: PhantomData<*const Ser>, -} - -impl<'a, T> TypedStoreMut<'a, T, Bincode2> -where - T: Serialize + DeserializeOwned, -{ - pub fn attach(storage: &'a mut dyn Storage) -> Self { - Self::attach_with_serialization(storage, Bincode2) - } -} - -impl<'a, T, Ser> TypedStoreMut<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - pub fn attach_with_serialization(storage: &'a mut dyn Storage, _serialization: Ser) -> Self { - Self { - storage, - serialization_type: PhantomData, - item_type: PhantomData, - } - } - - pub fn store(&mut self, key: &[u8], item: &T) -> StdResult<()> { - self.storage.set(key, &Ser::serialize(item)?); - Ok(()) - } - - pub fn remove(&mut self, key: &[u8]) { - self.storage.remove(key); - } - - fn as_readonly(&self) -> TypedStore { - TypedStore { - storage: self.storage, - item_type: self.item_type, - serialization_type: self.serialization_type, - } - } - - pub fn load(&self, key: &[u8]) -> StdResult { - self.as_readonly().load(key) - } - - pub fn may_load(&self, key: &[u8]) -> StdResult> { - self.as_readonly().may_load(key) - } -} - -pub struct TypedStore<'a, T, Ser = Bincode2> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - storage: &'a dyn Storage, - item_type: PhantomData<*const T>, - serialization_type: PhantomData<*const Ser>, -} - -impl<'a, T> TypedStore<'a, T, Bincode2> -where - T: Serialize + DeserializeOwned, -{ - pub fn attach(storage: &'a dyn Storage) -> Self { - Self::attach_with_serialization(storage, Bincode2) - } -} - -impl<'a, T, Ser> TypedStore<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - pub fn attach_with_serialization(storage: &'a dyn Storage, _serialization: Ser) -> Self { - Self { - storage, - serialization_type: PhantomData, - item_type: PhantomData, - } - } - - pub fn load(&self, key: &[u8]) -> StdResult { - let maybe_serialized = self.storage.get(key); - let serialized = maybe_serialized.ok_or_else(|| StdError::not_found(type_name::()))?; - Ser::deserialize(&serialized) - } - - pub fn may_load(&self, key: &[u8]) -> StdResult> { - match self.storage.get(key) { - Some(serialized) => Ser::deserialize(&serialized).map(Some), - None => Ok(None), - } - } -} - -#[cfg(test)] -mod tests { - use serde::{Deserialize, Serialize}; - - use cosmwasm_std::testing::MockStorage; - - use secret_toolkit_serialization::Json; - - use super::*; - - #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] - struct Foo { - string: String, - number: i32, - } - - #[test] - fn test_typed_store() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let mut typed_store_mut = TypedStoreMut::attach(&mut storage); - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - let foo2 = Foo { - string: "string one".to_string(), - number: 1111, - }; - typed_store_mut.store(b"key1", &foo1)?; - typed_store_mut.store(b"key2", &foo2)?; - - let read_foo1 = typed_store_mut.load(b"key1")?; - let read_foo2 = typed_store_mut.load(b"key2")?; - - assert_eq!(foo1, read_foo1); - assert_eq!(foo2, read_foo2); - - // show that it loads foo1 before removal - let before_remove_foo1 = typed_store_mut.may_load(b"key1")?; - assert!(before_remove_foo1.is_some()); - assert_eq!(foo1, before_remove_foo1.unwrap()); - // and returns None after removal - typed_store_mut.remove(b"key1"); - let removed_foo1 = typed_store_mut.may_load(b"key1")?; - assert!(removed_foo1.is_none()); - - // show what happens when reading from keys that have not been set yet. - assert!(typed_store_mut.load(b"key3").is_err()); - assert!(typed_store_mut.may_load(b"key3")?.is_none()); - - // Try to load it with the wrong format - let typed_store = TypedStore::::attach_with_serialization(&storage, Json); - match typed_store.load(b"key2") { - Err(StdError::ParseErr { - target_type, msg, .. - }) if target_type == "i32" && msg == "Invalid type" => {} - other => panic!("unexpected value: {:?}", other), - } - - Ok(()) - } -} From 4f4e154df8c0a845ed4c2da8b477778ffd869e52 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sun, 21 Aug 2022 23:06:36 +0300 Subject: [PATCH 18/37] removed some clippy errors --- packages/storage/src/append_store.rs | 6 +++--- packages/storage/src/deque_store.rs | 8 ++++---- packages/storage/src/item.rs | 5 +---- packages/storage/src/keymap.rs | 8 ++++---- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/storage/src/append_store.rs b/packages/storage/src/append_store.rs index 0e5f793..79bbff3 100644 --- a/packages/storage/src/append_store.rs +++ b/packages/storage/src/append_store.rs @@ -183,11 +183,11 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for AppendStore<'a, T, Ser> { fn clone(&self) -> Self { Self { - namespace: self.namespace.clone(), + namespace: self.namespace, prefix: self.prefix.clone(), length: Mutex::new(None), - item_type: self.item_type.clone(), - serialization_type: self.serialization_type.clone(), + item_type: self.item_type, + serialization_type: self.serialization_type, } } } diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index f9c7a08..34de104 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -34,7 +34,7 @@ where serialization_type: PhantomData, } -impl<'a, 'b, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// constructor pub const fn new(prefix: &'a [u8]) -> Self { Self { @@ -296,12 +296,12 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for DequeStore<'a, T, Ser> { fn clone(&self) -> Self { Self { - namespace: self.namespace.clone(), + namespace: self.namespace, prefix: self.prefix.clone(), length: Mutex::new(None), offset: Mutex::new(None), - item_type: self.item_type.clone(), - serialization_type: self.serialization_type.clone(), + item_type: self.item_type, + serialization_type: self.serialization_type, } } } diff --git a/packages/storage/src/item.rs b/packages/storage/src/item.rs index 8c909b1..94a93fc 100644 --- a/packages/storage/src/item.rs +++ b/packages/storage/src/item.rs @@ -55,10 +55,7 @@ where /// efficient way to see if any object is currently saved. pub fn is_empty(&self, storage: &S) -> bool { - match storage.get(self.as_slice()) { - Some(_) => false, - None => true, - } + storage.get(self.as_slice()).is_none() } /// Loads the data, perform the specified action, and store the result diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs index baeaa9e..adcafe7 100644 --- a/packages/storage/src/keymap.rs +++ b/packages/storage/src/keymap.rs @@ -430,12 +430,12 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: { fn clone(&self) -> Self { Self { - namespace: self.namespace.clone(), + namespace: self.namespace, prefix: self.prefix.clone(), length: Mutex::new(None), - key_type: self.key_type.clone(), - item_type: self.item_type.clone(), - serialization_type: self.serialization_type.clone(), + key_type: self.key_type, + item_type: self.item_type, + serialization_type: self.serialization_type, } } } From 0d87e11211bc050368f21ca28be28627aa51000d Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 22 Aug 2022 00:00:45 +0300 Subject: [PATCH 19/37] updated the clone methods --- packages/storage/src/append_store.rs | 4 ++-- packages/storage/src/deque_store.rs | 4 ++-- packages/storage/src/keymap.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/storage/src/append_store.rs b/packages/storage/src/append_store.rs index 79bbff3..a4a7ef0 100644 --- a/packages/storage/src/append_store.rs +++ b/packages/storage/src/append_store.rs @@ -186,8 +186,8 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for AppendStore<'a, namespace: self.namespace, prefix: self.prefix.clone(), length: Mutex::new(None), - item_type: self.item_type, - serialization_type: self.serialization_type, + item_type: PhantomData, + serialization_type: PhantomData, } } } diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 34de104..cb7ea48 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -300,8 +300,8 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for DequeStore<'a, T prefix: self.prefix.clone(), length: Mutex::new(None), offset: Mutex::new(None), - item_type: self.item_type, - serialization_type: self.serialization_type, + item_type: PhantomData, + serialization_type: PhantomData, } } } diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs index adcafe7..86d92c7 100644 --- a/packages/storage/src/keymap.rs +++ b/packages/storage/src/keymap.rs @@ -433,9 +433,9 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: namespace: self.namespace, prefix: self.prefix.clone(), length: Mutex::new(None), - key_type: self.key_type, - item_type: self.item_type, - serialization_type: self.serialization_type, + key_type: PhantomData, + item_type: PhantomData, + serialization_type: PhantomData, } } } From e9afc5968a86a39e2877746f61eca523311dcefa Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 22 Aug 2022 03:21:30 +0300 Subject: [PATCH 20/37] fixed a new serde bug in keymap, should be more efficient now too --- packages/storage/src/keymap.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs index 86d92c7..5a2a3bc 100644 --- a/packages/storage/src/keymap.rs +++ b/packages/storage/src/keymap.rs @@ -20,7 +20,7 @@ fn _page_from_position(position: u32) -> u32 { } #[derive(Serialize, Deserialize)] -struct InternalItem +struct InternalItem where T: Serialize + DeserializeOwned, Ser: Serde, @@ -171,7 +171,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } /// internal item get function - fn _get_from_key(&self, storage: &S, key: &K) -> StdResult> { + fn _get_from_key(&self, storage: &S, key: &K) -> StdResult> { let key_vec = self.serialize_key(key)?; self.load_impl(storage, &key_vec) } @@ -414,7 +414,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> - PrefixedTypedStorage, Ser> for Keymap<'a, K, T, Ser> + PrefixedTypedStorage, Bincode2> for Keymap<'a, K, T, Ser> { fn as_slice(&self) -> &[u8] { if let Some(prefix) = &self.prefix { From 90deb2d26ba63481bd5a18303449cedd7d963e43 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 22 Aug 2022 03:43:29 +0300 Subject: [PATCH 21/37] put the correct version of storage in cargo.toml, releases updated, versioning is more in sync with the master branch now. Cashmap removed from the incubator much like the master branch --- Releases.md | 44 +- packages/incubator/Cargo.toml | 4 +- packages/incubator/src/cashmap.rs | 1195 ----------------------------- packages/incubator/src/lib.rs | 5 - packages/storage/Cargo.toml | 2 +- packages/storage/src/keymap.rs | 6 +- packages/toolkit/Cargo.toml | 6 +- 7 files changed, 45 insertions(+), 1217 deletions(-) delete mode 100644 packages/incubator/src/cashmap.rs diff --git a/Releases.md b/Releases.md index 35b39a7..a03ca2a 100644 --- a/Releases.md +++ b/Releases.md @@ -1,22 +1,48 @@ # Release notes for the Secret Toolkit -## Next Release +## secret-toolkit-storage v0.4.1 + +* BUGFIX: `Item::is_empty` was returning the opposite value from what you'd expect. + +## v0.4.0 + +This release mostly includes the work of @srdtrk in #53. Thanks Srdtrk! + +It revamps the `secret-toolkit-storage` package to make it more similar to `cw-storage-plus` and much easier +to use. It also removes the `Cashmap` type from the incubator in favor of `KeyMap` in `secret-toolkit-storage`. + +This is a summary of the changes and additions in this release: + +* Minimum Rust version is bumped to the latest v1.63. This is because we want to use `Mutex::new` in a `const fn`. +* No more distinction between `Readonly*` and `*Mut` types. Instead, methods take references or mutable references to the storage every time. +* Usage of `PrefixedStore` is made mostly unnecessary. +* Storage type's constructors are const functions, which means they can be initialized as global static variables. +* Added `secret-toolkit::storage::Item` which is similar to `Item` from `cw-storage-plus` or `TypedStore` from `cosmwasm_storage` v0.10. +* Added `secret-toolkit::storage::KeyMap` which is similar to `Cashmap`. +* `Cashmap` is completely removed. + +A full guide to using the new `storage` types can be found +[in the package's readme file](https://github.com/srdtrk/secret-toolkit/blob/3725530aebe149d14f7f3f1662844340eb27e015/packages/storage/Readme.md). ## secret-toolkit-incubator v0.3.1 + * Fixed compilation issue with Rust v1.61 (#46, #48) * Removed Siphasher dependency (#46, #48) ## secret-toolkit-utils v0.3.1 ### Security + * BUGFIX: `secret-toolkit::utils::FeatureToggle::handle_pause` had an inverse authorization check: only non-pausers could pause features. ## secret-toolkit-permit v0.3.1 + * Removed the `ecc-secp256k1` feature from `secret-toolkit-crypto` dependency of `secret-toolkit-permit`. - * This tiny change significantly reduces the size of binaries that only use the permit feature. + * This tiny change significantly reduces the size of binaries that only use the permit feature. ## v0.3.0 + * Added `clear` method to `AppendStore` and `DequeStore` to quickly reset the collections (#34) * docs.rs documentation now includes all sub-crates. * BUGFIX: `secret-toolkit::snip721::Metadata` was severely out of date with the SNIP-721 specification, and not useful. @@ -29,8 +55,9 @@ * Added `secret-toolkit::utils::feature_toggle` which allow managing feature flags in your contract. ### Breaking -* `secret-toolkit::permit::validate()` Now supports validating any type of Cosmos address. -Interface changes: Now takes a reference to the current token address instead + +* `secret-toolkit::permit::validate()` Now supports validating any type of Cosmos address. +Interface changes: Now takes a reference to the current token address instead of taking it by value and an optional hrp string. In addition, it returns a String and not HumanAddr. * Renamed `secret-toolkit::permit::Permission` to `secret-toolkit::permit::TokenPermission`. @@ -44,6 +71,7 @@ In addition, it returns a String and not HumanAddr. * `secret-toolkit-incubator` now has features `["cashmap", "generational-store"]` which are all off by default. ## v0.2.0 + This release includes a ton of new features, and a few breaking changes in various interfaces. This version is also the first released to [crates.io](https://crates.io)! @@ -53,7 +81,7 @@ This version is also the first released to [crates.io](https://crates.io)! * Added support for SNIP-22 messages (batch operations) * Added support for SNIP-23 messages (improved Send operations) which broke some interfaces * Added support for SNIP-24 permits -* Added `Base64Of`, `Base64JsonOf`, and `Base64Bincode2Of`, +* Added `Base64Of`, `Base64JsonOf`, and `Base64Bincode2Of`, which are wrappers that automatically deserializes base64 strings to `T`. It can be used in message types' fields instead of `Binary` when the contents of the string should have more specific contents. @@ -65,9 +93,11 @@ This version is also the first released to [crates.io](https://crates.io)! while `["crypto", "permit", "incubator"]` are left disabled by default. ## v0.1.1 + * Removed unused dev-dependency that was slowing down test compilation times. ## v0.1.0 + This is the first release of `secret-toolkit`. It supports: * `secret-toolkit::snip20` - Helper types and functions for interaction with @@ -82,6 +112,6 @@ This is the first release of `secret-toolkit`. It supports: * `secret-toolkit::serialization` - marker types for overriding the storage format used by types in `secret-toolkit::storage`. `Json` and `Bincode2`. * `secret-toolkit::utils` - General utilities for writing contract code. - * `padding` - tools for padding queries and responses. - * `calls` - Tools for marking types as messages in queries and callbacks + * `padding` - tools for padding queries and responses. + * `calls` - Tools for marking types as messages in queries and callbacks to other contracts. diff --git a/packages/incubator/Cargo.toml b/packages/incubator/Cargo.toml index ab1a44f..2338c42 100644 --- a/packages/incubator/Cargo.toml +++ b/packages/incubator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-incubator" -version = "0.3.1" +version = "0.4.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -20,7 +20,5 @@ cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "sec secret-toolkit-serialization = { version = "0.3", path = "../serialization", optional = true } [features] -default = ["cashmap", "generational-store", "maxheap"] -cashmap = ["cosmwasm-storage", "serde", "secret-toolkit-serialization", "cosmwasm-std"] generational-store = ["secret-toolkit-serialization", "serde", "cosmwasm-std"] maxheap = ["secret-toolkit-serialization", "serde", "cosmwasm-std"] diff --git a/packages/incubator/src/cashmap.rs b/packages/incubator/src/cashmap.rs deleted file mode 100644 index 4ea1cc2..0000000 --- a/packages/incubator/src/cashmap.rs +++ /dev/null @@ -1,1195 +0,0 @@ -#![allow(dead_code)] -use std::any::type_name; -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; -use std::marker::PhantomData; - -use serde::{de::DeserializeOwned, Deserialize, Serialize}; - -use cosmwasm_std::{StdError, StdResult, Storage}; - -use cosmwasm_storage::{PrefixedStorage, ReadonlyPrefixedStorage}; -use secret_toolkit_serialization::{Bincode2, Serde}; -use std::cmp::min; - -const INDEXES: &[u8] = b"indexes"; -const MAP_LENGTH: &[u8] = b"length"; - -const PAGE_SIZE: u32 = 5; - -#[derive(PartialEq)] -enum KeyInMap { - No, - Yes, - Collision, -} - -fn _page_from_position(position: u32) -> u32 { - position / PAGE_SIZE -} - -#[derive(Serialize, Deserialize, Clone)] -struct MetaData { - position: u32, - // displacement is set if we encountered a collision and we needed to move this item - displacement: u64, - key: Vec, - deleted: bool, -} - -#[derive(Serialize, Deserialize)] -pub struct InternalItem -// where -// T: Serialize + DeserializeOwned, -{ - item: T, - meta_data: MetaData, -} - -pub struct CashMap<'a, T, Ser = Bincode2> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - storage: &'a mut dyn Storage, - item_type: PhantomData<*const InternalItem>, - serialization_type: PhantomData<*const Ser>, - prefix: Option>, -} - -impl<'a, T> CashMap<'a, T, Bincode2> -where - T: Serialize + DeserializeOwned, -{ - pub fn init(name: &[u8], storage: &'a mut dyn Storage) -> Self { - Self::attach_with_serialization(storage, Bincode2, Some(name.to_vec())) - } - - pub fn attach(storage: &'a mut dyn Storage) -> Self { - Self::attach_with_serialization(storage, Bincode2, None) - } -} - -impl<'a, T, Ser> CashMap<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - pub fn is_empty(&self) -> bool { - self.as_readonly().is_empty() - } - pub fn len(&self) -> u32 { - self.as_readonly().len() - } - - /// This method allows customization of the serialization, in case we want to force - /// something other than Bincode2, which has it's drawbacks (such as Enums fucking up) - pub fn attach_with_serialization( - storage: &'a mut dyn Storage, - _serialization: Ser, - prefix: Option>, - ) -> Self { - Self { - storage, - serialization_type: PhantomData, - item_type: PhantomData, - prefix, - } - } - - pub fn remove(&mut self, key: &[u8]) -> StdResult<()> { - let mut len = self.as_readonly().len(); - - let item = self.as_readonly()._direct_get(key); - - if item.is_none() || len == 0 { - return Err(StdError::not_found("Item not found in map")); - } - - let mut unwrapped_item = item.unwrap(); - unwrapped_item.meta_data.deleted = true; - - let removed_pos = unwrapped_item.meta_data.position; - //debug_print(format!("removing item from position {}", &removed_pos)); - - let page = _page_from_position(removed_pos); - - let mut indexes = self.as_readonly().get_indexes(page); - let hash = self - .as_readonly() - .key_to_hash(key) - .overflowing_add(unwrapped_item.meta_data.displacement) - .0; - - len -= 1; - self.set_length(len)?; - - return if !indexes.contains(&hash) { - Err(StdError::generic_err( - "Tried to remove, but hash not found - should never happen", - )) - } else { - if len == 0 || len == removed_pos { - indexes.pop(); - self.store_indexes(page, &indexes)?; - return self.store(&hash.to_be_bytes(), &unwrapped_item); - //return self.remove_from_store(&hash.to_be_bytes()); - } - - // find the index of our item - // todo: replace this since we know the absolute position from the internalitem - let pos_in_indexes = indexes.iter().position(|index| index == &hash).unwrap(); - - // replace the last item with our new item - let max_page = _page_from_position(len); - let mut last_item_indexes = self.as_readonly().get_indexes(max_page); - - if let Some(last_item_hash) = last_item_indexes.pop() { - if max_page != page { - self.store_indexes(max_page, &last_item_indexes)?; - } else { - // if we're already on the max page indexes has not removed the last item, - // so we do it here - indexes.pop(); - } - - if let Some(mut last_item) = self.as_readonly().get_no_hash(&last_item_hash) { - last_item.meta_data.position = removed_pos; - - // debug_print(format!( - // "replacing {} with {}", - // &indexes[pos_in_indexes], &last_item_hash - // )); - let _ = std::mem::replace(&mut indexes[pos_in_indexes], last_item_hash); - - // store the modified last item (with new position) - self.store(&last_item_hash.to_be_bytes(), &last_item)?; - - // debug_print(format!( - // "replacing {} with {}", - // &indexes[pos_in_indexes], &last_item_hash - // )); - self.store_indexes(page, &indexes)?; - //self.remove_from_store(&hash.to_be_bytes()) - - // store the item with the deleted = true flag - self.store(&hash.to_be_bytes(), &unwrapped_item) - } else { - return Err(StdError::not_found("Failed to remove item from map")); - } - } else { - Err(StdError::not_found("Failed to remove item from map")) - } - }; - } - - pub fn insert(&mut self, key: &[u8], item: T) -> StdResult<()> { - let hash = self.as_readonly().key_to_hash(key); - //debug_print(format!("***insert - inserting {:?}: {}", key, &hash)); - let pos = self.len(); - match self.as_readonly()._is_slot_taken(key)? { - // key is in map, but can also be in some other location other than the direct hash - (KeyInMap::Yes, prev_hash, Some(prev_item)) => { - let position = &prev_item.meta_data.position; - let to_store = InternalItem { - item, - meta_data: MetaData { - position: *position, - displacement: prev_item.meta_data.displacement, - key: key.to_vec(), - deleted: false, - }, - }; - - self.store(&prev_hash.to_be_bytes(), &to_store)?; - } - (KeyInMap::No, _, None) => { - // Key not in map, hash position not taken - let page = _page_from_position(pos); - let mut indexes = self.as_readonly().get_indexes(page); - //debug_print(format!("*** Got indexes: {:?}", &indexes)); - if !indexes.contains(&hash) { - //debug_print(format!("*** Pushing: {}", &hash)); - indexes.push(hash); - self.store_indexes(page, &indexes)?; - //debug_print(format!("*** stored indexes: {:?}", &indexes)); - } - - let to_store = InternalItem { - item, - meta_data: MetaData { - position: pos, - displacement: 0, - key: key.to_vec(), - deleted: false, - }, - }; - self.store(&hash.to_be_bytes(), &to_store)?; - self.set_length(pos + 1)?; - } - (KeyInMap::Collision, _, None) => { - // Key not in map, hash position is taken - if pos == u32::MAX { - return Err(StdError::generic_err( - "Map is full. How the hell did you get here?", - )); - } - let (displaced_hash, displacement) = - self.as_readonly()._get_next_empty_slot(hash)?; - - let page = _page_from_position(pos); - let mut indexes = self.as_readonly().get_indexes(page); - - indexes.push(displaced_hash); - self.store_indexes(page, &indexes)?; - - let to_store = InternalItem { - item, - meta_data: MetaData { - position: pos, - displacement, - key: key.to_vec(), - deleted: false, - }, - }; - self.store(&displaced_hash.to_be_bytes(), &to_store)?; - self.set_length(pos + 1)?; - } - _ => { - return Err(StdError::generic_err( - "Error checking if slot is taken. This can never happen", - )); - } - } - - Ok(()) - } - - /// user facing method to get T - pub fn get(&self, key: &[u8]) -> Option { - self.as_readonly().get(key) - } - - pub fn paging(&self, start_page: u32, size: u32) -> StdResult> { - self.as_readonly().paging(start_page, size) - } - - pub fn contains(&self, key: &[u8]) -> bool { - self.as_readonly().contains_key(key).is_some() - } - - fn get_position(&self, key: &[u8]) -> Option { - return if let Some(res) = self.as_readonly()._direct_get(key) { - Some(res.meta_data.position) - } else { - None - }; - } - - #[allow(clippy::ptr_arg)] - fn store_indexes(&mut self, index: u32, indexes: &Vec) -> StdResult<()> { - if let Some(prefix) = &self.prefix { - let mut store = PrefixedStorage::new(self.storage, prefix); - store.set( - &[INDEXES, index.to_be_bytes().to_vec().as_slice()].concat(), - &Ser::serialize(indexes)?, - ); - } else { - self.storage.set( - &[INDEXES, index.to_be_bytes().to_vec().as_slice()].concat(), - &Ser::serialize(indexes)?, - ); - } - Ok(()) - } - - // unused - we just set deleted = true - fn remove_from_store(&mut self, key: &[u8]) -> StdResult<()> { - if let Some(prefix) = &self.prefix { - let mut store = PrefixedStorage::new(self.storage, prefix); - store.remove(key) - } else { - self.storage.remove(key) - }; - Ok(()) - } - - fn store(&mut self, key: &[u8], item: &InternalItem) -> StdResult<()> { - if let Some(prefix) = &self.prefix { - let mut store = PrefixedStorage::new(self.storage, prefix); - store.set(key, &Ser::serialize(item)?) - } else { - self.storage.set(key, &Ser::serialize(item)?) - } - - Ok(()) - } - - fn as_readonly(&self) -> ReadOnlyCashMap { - ReadOnlyCashMap { - storage: self.storage, - item_type: self.item_type, - serialization_type: self.serialization_type, - prefix: self.prefix.clone(), - } - } - - fn set_length(&mut self, length: u32) -> StdResult<()> { - if let Some(prefix) = &self.prefix { - let mut store = PrefixedStorage::new(self.storage, prefix); - store.set(MAP_LENGTH, &Ser::serialize(&length.to_be_bytes())?) - } else { - self.storage - .set(MAP_LENGTH, &Ser::serialize(&length.to_be_bytes())?) - } - - Ok(()) - } - - // fn get(&self, key: &[u8]) -> StdResult { - // self.as_readonly().get(key) - // } -} - -/// basically this is used in queries -pub struct ReadOnlyCashMap<'a, T, Ser = Bincode2> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - storage: &'a dyn Storage, - item_type: PhantomData<*const InternalItem>, - serialization_type: PhantomData<*const Ser>, - prefix: Option>, -} - -impl<'a, T> ReadOnlyCashMap<'a, T, Bincode2> -where - T: Serialize + DeserializeOwned, -{ - pub fn init(name: &[u8], storage: &'a dyn Storage) -> Self { - Self::attach_with_serialization(storage, Bincode2, Some(name.to_vec())) - } - - pub fn attach(storage: &'a dyn Storage) -> Self { - Self::attach_with_serialization(storage, Bincode2, None) - } -} - -impl<'a, T, Ser> ReadOnlyCashMap<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - pub fn attach_with_serialization( - storage: &'a dyn Storage, - _serialization: Ser, - prefix: Option>, - ) -> Self { - Self { - storage, - serialization_type: PhantomData, - item_type: PhantomData, - prefix, - } - } - - fn _is_slot_taken(&self, key: &[u8]) -> StdResult<(KeyInMap, u64, Option>)> { - let (in_map, hash) = self._get_slot_and_status(key)?; - - if in_map == KeyInMap::Yes { - if let Ok(item) = self._load_internal(&hash) { - return Ok((in_map, hash, Some(item))); - } - } - - Ok((in_map, hash, None)) - - // (item) = self._get_slot_and_status(key) { - // return if item.meta_data.key == key.to_vec() { - // (KeyInMap::Yes, Some(item)) - // } else { - // (KeyInMap::Collision, Some(item)) - // }; - // } - // (KeyInMap::No, None) - } - - // returns the slot and the displacement - fn _get_next_empty_slot(&self, hash: u64) -> StdResult<(u64, u64)> { - for i in 0..u32::MAX { - let testing_value = hash.overflowing_add(i as u64).0; - let item = self.get_no_hash(&testing_value); - if item.is_none() || item.unwrap().meta_data.deleted { - return Ok((testing_value, i as u64)); - } - } - - Err(StdError::generic_err( - "Failed to get available slot. How did you get here?", - )) - } - - pub fn contains_key(&self, key: &[u8]) -> Option { - let hash = self.key_to_hash(key); - let vec_key = key.to_vec(); - for i in 0..u32::MAX { - let testing_value = hash.overflowing_add(i as u64).0; - let item = self.get_no_hash(&testing_value); - if let Some(val) = item { - if val.meta_data.key == vec_key && !val.meta_data.deleted { - return Some(testing_value); - } - } else { - // empty slot found - so we didn't find the correct item - return None; - } - } - - None - } - - /// user facing method to get T - pub fn get(&self, key: &[u8]) -> Option { - if self.is_empty() { - return None; - } - - if let Some(place) = self.contains_key(key) { - if let Ok(result) = self._direct_load(&place) { - Some(result) - } else { - None - } - } else { - None - } - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - pub fn len(&self) -> u32 { - let maybe_serialized = if let Some(prefix) = &self.prefix { - let store = ReadonlyPrefixedStorage::new(self.storage, prefix); - store.get(MAP_LENGTH) - } else { - self.storage.get(MAP_LENGTH) - }; - // let maybe_serialized = self.storage.get(&MAP_LENGTH); - let serialized = maybe_serialized.unwrap_or_default(); - u32::from_be(Ser::deserialize(&serialized).unwrap_or_default()) - } - - /// starts from page 0 - /// - /// Will return error if you access out of bounds - pub fn paging(&self, start_page: u32, size: u32) -> StdResult> { - let start_pos = start_page * size; - let mut end_pos = start_pos + size - 1; - - let max_size = self.len(); - - if max_size == 0 { - return Ok(vec![]); - } - - if start_pos > max_size { - return Err(StdError::NotFound { - kind: "Out of bounds".to_string(), - }); - } else if end_pos >= max_size { - end_pos = max_size - 1; - } - - // debug_print(format!( - // "***paging - reading from {} to {}", - // start_pos, end_pos - // )); - - self.get_positions(start_pos, end_pos) - } - - fn get_positions(&self, start: u32, end: u32) -> StdResult> { - let start_page = _page_from_position(start); - let end_page = _page_from_position(end); - - let mut results = vec![]; - - for page in start_page..=end_page { - let start_pos = if page == start_page { - start % PAGE_SIZE - } else { - 0 - }; - - let max_page_pos = min(end, ((page + 1) * PAGE_SIZE) - 1) % PAGE_SIZE; - - let indexes = self.get_indexes(page); - - if max_page_pos as usize > indexes.len() { - return Err(StdError::generic_err("Out of bounds")); - } - - let hashes: Vec = indexes[start_pos as usize..=max_page_pos as usize].to_vec(); - // debug_print(format!( - // "***paging - got hashes of length {}: {:?}", - // &hashes.len(), - // &hashes - // )); - - let res: Vec = hashes - .iter() - .map(|h| self._direct_load(h).unwrap()) - .collect(); - - results.extend(res); - } - - Ok(results) - } - - pub fn get_indexes(&self, index: u32) -> Vec { - let maybe_serialized = if let Some(prefix) = &self.prefix { - let store = ReadonlyPrefixedStorage::new(self.storage, prefix); - store.get(&[INDEXES, index.to_be_bytes().to_vec().as_slice()].concat()) - } else { - self.storage - .get(&[INDEXES, index.to_be_bytes().to_vec().as_slice()].concat()) - }; - let serialized = maybe_serialized.unwrap_or_default(); - Ser::deserialize(&serialized).unwrap_or_default() - } - - fn _direct_load(&self, hash: &u64) -> StdResult { - let int_item = self._load_internal(hash)?; - Ok(int_item.item) - } - - fn _get_slot_and_status(&self, key: &[u8]) -> StdResult<(KeyInMap, u64)> { - let hash = self.key_to_hash(key); - if let Some(place) = self.contains_key(key) { - Ok((KeyInMap::Yes, place)) - } else { - let (next_slot, _) = self._get_next_empty_slot(hash)?; - - if next_slot == hash { - return Ok((KeyInMap::No, next_slot)); - } - - Ok((KeyInMap::Collision, next_slot)) - } - } - - /// get InternalItem and not just T - fn _direct_get(&self, key: &[u8]) -> Option> { - if let Some(place) = self.contains_key(key) { - if let Ok(result) = self._load_internal(&place) { - Some(result) - } else { - None - } - } else { - None - } - } - - fn _load_internal(&self, hash: &u64) -> StdResult> { - let int_item = self._prefix_load(hash)?; - Ok(int_item) - } - - pub fn load(&self, key: &[u8]) -> StdResult { - let hash = self.key_to_hash(key); - - let int_item = self._prefix_load(&hash)?; - Ok(int_item.item) - } - - fn _prefix_load(&self, hash: &u64) -> StdResult> { - let serialized = if let Some(prefix) = &self.prefix { - let store = ReadonlyPrefixedStorage::new(self.storage, prefix); - store.get(&hash.to_be_bytes()) - } else { - self.storage.get(&hash.to_be_bytes()) - } - .ok_or_else(|| StdError::not_found(type_name::()))?; - - let int_item: InternalItem = Ser::deserialize(&serialized)?; - Ok(int_item) - } - - fn get_no_hash(&self, hash: &u64) -> Option> { - if let Ok(result) = self._load_internal(hash) { - Some(result) - } else { - None - } - } - - fn key_to_hash(&self, key: &[u8]) -> u64 { - let mut hasher = DefaultHasher::default(); - key.hash(&mut hasher); - hasher.finish() - } - - pub fn iter(&self) -> Iter<'a, T, Ser> { - Iter { - storage: Self::clone(self), - start: 0, - end: self.len(), - } - } -} - -/// An iterator over the contents of the append store. -pub struct Iter<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - storage: ReadOnlyCashMap<'a, T, Ser>, - start: u32, - end: u32, -} - -impl<'a, T, Ser> Iterator for Iter<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - type Item = T; - - fn next(&mut self) -> Option { - if self.start >= self.end { - return None; - } - let item = self.storage.get_positions(self.start, self.start); - self.start += 1; - if let Ok(mut inner) = item { - Some(inner.pop().unwrap()) - } else { - None - } - } - - // This needs to be implemented correctly for `ExactSizeIterator` to work. - fn size_hint(&self) -> (usize, Option) { - let len = (self.end - self.start) as usize; - (len, Some(len)) - } - - // I implement `nth` manually because it is used in the standard library whenever - // it wants to skip over elements, but the default implementation repeatedly calls next. - // because that is very expensive in this case, and the items are just discarded, we wan - // do better here. - // In practice, this enables cheap paging over the storage by calling: - // `append_store.iter().skip(start).take(length).collect()` - fn nth(&mut self, n: usize) -> Option { - self.start = self.start.saturating_add(n as u32); - self.next() - } -} - -impl<'a, T, Ser> IntoIterator for ReadOnlyCashMap<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - type Item = T; - type IntoIter = Iter<'a, T, Ser>; - - fn into_iter(self) -> Iter<'a, T, Ser> { - let end = self.len(); - Iter { - storage: self, - start: 0, - end, - } - } -} - -// Manual `Clone` implementation because the default one tries to clone the Storage?? -impl<'a, T, Ser> Clone for ReadOnlyCashMap<'a, T, Ser> -where - T: Serialize + DeserializeOwned, - Ser: Serde, -{ - fn clone(&self) -> Self { - Self { - storage: self.storage, - item_type: self.item_type, - serialization_type: self.serialization_type, - prefix: self.prefix.clone(), - } - } -} - -#[cfg(test)] -mod tests { - use serde::{Deserialize, Serialize}; - - use cosmwasm_std::testing::MockStorage; - - use secret_toolkit_serialization::Json; - - use super::*; - - #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] - struct Foo { - string: String, - number: i32, - } - #[test] - fn test_hashmap_perf_insert() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let total_items = 1000; - - let mut cashmap = CashMap::attach(&mut storage); - - for i in 0..total_items { - cashmap.insert(&(i as i32).to_be_bytes(), i)?; - } - - assert_eq!(cashmap.len(), 1000); - - Ok(()) - } - - #[test] - fn test_hashmap_perf_insert_remove() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let total_items = 100; - - let mut cashmap = CashMap::attach(&mut storage); - - for i in 0..total_items { - cashmap.insert(&(i as i32).to_be_bytes(), i)?; - } - - for i in 0..total_items { - cashmap.remove(&(i as i32).to_be_bytes())?; - } - - assert_eq!(cashmap.len(), 0); - - Ok(()) - } - - #[test] - fn test_hashmap_paging() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let page_size = 50; - let total_items = 50; - let mut cashmap = CashMap::attach(&mut storage); - - for i in 0..total_items { - cashmap.insert(&(i as i32).to_be_bytes(), i)?; - } - - for i in 0..((total_items / page_size) - 1) { - let start_page = i; - - let values = cashmap.paging(start_page, page_size)?; - - for (index, value) in values.iter().enumerate() { - assert_eq!(value, &(page_size * start_page + index as u32)) - } - } - - Ok(()) - } - - #[test] - fn test_hashmap_paging_prefixed() -> StdResult<()> { - let mut storage = MockStorage::new(); - let mut prefixed = PrefixedStorage::new(&mut storage, b"test"); - let mut cashmap = CashMap::init(b"yo", &mut prefixed); - - let page_size = 50; - let total_items = 50; - //let mut cashmap = CashMap::attach(&mut storage); - - for i in 0..total_items { - cashmap.insert(&(i as i32).to_be_bytes(), i)?; - } - - for i in 0..((total_items / page_size) - 1) { - let start_page = i; - - let values = cashmap.paging(start_page, page_size)?; - - for (index, value) in values.iter().enumerate() { - assert_eq!(value, &(page_size * start_page + index as u32)) - } - } - - Ok(()) - } - - #[test] - fn test_hashmap_paging_overflow() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let page_size = 50; - let total_items = 10; - let mut cashmap = CashMap::attach(&mut storage); - - for i in 0..total_items { - cashmap.insert(&(i as i32).to_be_bytes(), i)?; - } - - let values = cashmap.paging(0, page_size)?; - - assert_eq!(values.len(), total_items as usize); - - for (index, value) in values.iter().enumerate() { - assert_eq!(value, &(index as u32)) - } - - Ok(()) - } - - #[test] - fn test_hashmap_insert_multiple() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let mut typed_store_mut = CashMap::attach(&mut storage); - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - let foo2 = Foo { - string: "string two".to_string(), - number: 1111, - }; - - typed_store_mut.insert(b"key1", foo1.clone())?; - typed_store_mut.insert(b"key2", foo2.clone())?; - - let read_foo1 = typed_store_mut.get(b"key1").unwrap(); - let read_foo2 = typed_store_mut.get(b"key2").unwrap(); - - assert_eq!(foo1, read_foo1); - assert_eq!(foo2, read_foo2); - Ok(()) - } - - #[test] - fn test_hashmap_insert_get() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let mut typed_store_mut = CashMap::attach(&mut storage); - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - - typed_store_mut.insert(b"key1", foo1.clone())?; - let read_foo1 = typed_store_mut.get(b"key1").unwrap(); - assert_eq!(foo1, read_foo1); - - Ok(()) - } - - #[test] - fn test_hashmap_insert_contains() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let mut typed_store_mut = CashMap::attach(&mut storage); - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - - typed_store_mut.insert(b"key1", foo1.clone())?; - let contains_k1 = typed_store_mut.contains(b"key1"); - - assert_eq!(contains_k1, true); - - Ok(()) - } - - #[test] - fn test_hashmap_insert_remove() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let mut typed_store_mut = CashMap::attach(&mut storage); - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - - typed_store_mut.insert(b"key1", foo1.clone())?; - let before_remove_foo1 = typed_store_mut.get(b"key1"); - - assert!(before_remove_foo1.is_some()); - assert_eq!(foo1, before_remove_foo1.unwrap()); - - typed_store_mut.remove(b"key1")?; - - let result = typed_store_mut.get(b"key1"); - assert!(result.is_none()); - - Ok(()) - } - - #[test] - fn test_hashmap_iter() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let mut hashmap = CashMap::attach(&mut storage); - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - let foo2 = Foo { - string: "string two".to_string(), - number: 1111, - }; - - hashmap.insert(b"key1", foo1.clone())?; - hashmap.insert(b"key2", foo2.clone())?; - - let mut x = hashmap.as_readonly().iter(); - let (len, _) = x.size_hint(); - assert_eq!(len, 2); - - assert_eq!(x.next().unwrap(), foo1); - - assert_eq!(x.next().unwrap(), foo2); - - Ok(()) - } - - #[test] - fn test_hashmap_overwrite() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let mut hashmap = CashMap::attach(&mut storage); - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - let foo2 = Foo { - string: "string two".to_string(), - number: 2222, - }; - - hashmap.insert(b"key1", foo1.clone())?; - hashmap.insert(b"key1", foo2.clone())?; - - let foo3 = hashmap.get(b"key1").unwrap(); - - assert_eq!(foo3, foo2); - - Ok(()) - } - - #[test] - fn test_hashmap_overwrite_prefixed() -> StdResult<()> { - let mut storage = MockStorage::new(); - let mut prefixed = PrefixedStorage::new(&mut storage, b"test"); - let mut hashmap = CashMap::init(b"yo", &mut prefixed); - - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - let foo2 = Foo { - string: "string two".to_string(), - number: 2222, - }; - - hashmap.insert(b"key1", foo1.clone())?; - hashmap.insert(b"key1", foo2.clone())?; - - let foo3 = hashmap.get(b"key1").unwrap(); - - assert_eq!(hashmap.len(), 1); - assert_eq!(foo3, foo2); - - Ok(()) - } - - #[test] - fn test_cashmap_basics() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let mut typed_store_mut = CashMap::attach(&mut storage); - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - let foo2 = Foo { - string: "string one".to_string(), - number: 1111, - }; - typed_store_mut.insert(b"key1", foo1.clone())?; - typed_store_mut.insert(b"key2", foo2.clone())?; - - let read_foo1 = typed_store_mut.get(b"key1").unwrap(); - let read_foo2 = typed_store_mut.get(b"key2").unwrap(); - - assert_eq!(foo1, read_foo1); - assert_eq!(foo2, read_foo2); - - // show that it loads foo1 before removal - let before_remove_foo1 = typed_store_mut.get(b"key1"); - assert!(before_remove_foo1.is_some()); - assert_eq!(foo1, before_remove_foo1.unwrap()); - // and returns None after removal - typed_store_mut.remove(b"key1")?; - let removed_foo1 = typed_store_mut.get(b"key1"); - assert!(removed_foo1.is_none()); - - // show what happens when reading from keys that have not been set yet. - assert!(typed_store_mut.get(b"key3").is_none()); - - // Try to load it with the wrong format - let typed_store = - ReadOnlyCashMap::::attach_with_serialization(&storage, Json, None); - match typed_store.load(b"key2") { - Err(StdError::ParseErr { - target_type, msg, .. - }) if target_type == "secret_toolkit_incubator::cashmap::InternalItem" - && msg == "Invalid type" => {} - other => panic!("unexpected value: {:?}", other), - } - - Ok(()) - } - - #[test] - fn test_cashmap_basics_prefixed() -> StdResult<()> { - let mut storage = MockStorage::new(); - //let mut prefixed = PrefixedStorage::new(b"test", &mut storage); - let mut cmap = CashMap::init(b"yo", &mut storage); - - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - let foo2 = Foo { - string: "string one".to_string(), - number: 1111, - }; - cmap.insert(b"key1", foo1.clone())?; - cmap.insert(b"key2", foo2.clone())?; - - let read_foo1 = cmap.get(b"key1").unwrap(); - let read_foo2 = cmap.get(b"key2").unwrap(); - - assert_eq!(foo1, read_foo1); - assert_eq!(foo2, read_foo2); - - // show that it loads foo1 before removal - let before_remove_foo1 = cmap.get(b"key1"); - assert!(before_remove_foo1.is_some()); - assert_eq!(foo1, before_remove_foo1.unwrap()); - // and returns None after removal - cmap.remove(b"key1")?; - let removed_foo1 = cmap.get(b"key1"); - assert!(removed_foo1.is_none()); - - // show what happens when reading from keys that have not been set yet. - assert!(cmap.get(b"key3").is_none()); - - // Try to load it with the wrong format - let typed_store = ReadOnlyCashMap::::attach_with_serialization( - &storage, - Json, - Some(b"yo".to_vec()), - ); - match typed_store.load(b"key2") { - Err(StdError::ParseErr { - target_type, msg, .. - }) if target_type == "secret_toolkit_incubator::cashmap::InternalItem" - && msg == "Invalid type" => {} - other => panic!("unexpected value: {:?}", other), - } - - Ok(()) - } - - #[test] - fn test_cashmap_length() -> StdResult<()> { - let mut storage = MockStorage::new(); - - let mut cmap = CashMap::attach(&mut storage); - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - let foo2 = Foo { - string: "string one".to_string(), - number: 1111, - }; - - assert_eq!(cmap.len(), 0); - - cmap.insert(b"k1", foo1.clone())?; - assert_eq!(cmap.len(), 1); - - // add another item - cmap.insert(b"k2", foo2.clone())?; - assert_eq!(cmap.len(), 2); - - // remove item and check length - cmap.remove(b"k1")?; - assert_eq!(cmap.len(), 1); - - // override item (should not change length) - cmap.insert(b"k2", foo1)?; - assert_eq!(cmap.len(), 1); - - // remove item and check length - cmap.remove(b"k2")?; - assert_eq!(cmap.len(), 0); - - Ok(()) - } - - #[test] - fn test_cashmap_length_prefixed() -> StdResult<()> { - let mut storage = MockStorage::new(); - let mut prefixed = PrefixedStorage::new(&mut storage, b"test"); - let mut cmap = CashMap::init(b"yo", &mut prefixed); - - let foo1 = Foo { - string: "string one".to_string(), - number: 1111, - }; - let foo2 = Foo { - string: "string one".to_string(), - number: 1111, - }; - - assert_eq!(cmap.len(), 0); - - cmap.insert(b"k1", foo1.clone())?; - assert_eq!(cmap.len(), 1); - - // add another item - cmap.insert(b"k2", foo2.clone())?; - assert_eq!(cmap.len(), 2); - - // remove item and check length - cmap.remove(b"k1")?; - assert_eq!(cmap.len(), 1); - - // override item (should not change length) - cmap.insert(b"k2", foo1)?; - assert_eq!(cmap.len(), 1); - - // remove item and check length - cmap.remove(b"k2")?; - assert_eq!(cmap.len(), 0); - - Ok(()) - } -} diff --git a/packages/incubator/src/lib.rs b/packages/incubator/src/lib.rs index 806637d..a5ad360 100644 --- a/packages/incubator/src/lib.rs +++ b/packages/incubator/src/lib.rs @@ -1,8 +1,3 @@ -#[cfg(feature = "cashmap")] -pub mod cashmap; -#[cfg(feature = "cashmap")] -pub use cashmap::{CashMap, ReadOnlyCashMap}; - #[cfg(feature = "generational-store")] pub mod generational_store; #[cfg(feature = "generational-store")] diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index 0461873..50c64d4 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-storage" -version = "0.3.0" +version = "0.4.1" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs index 5a2a3bc..ce33387 100644 --- a/packages/storage/src/keymap.rs +++ b/packages/storage/src/keymap.rs @@ -25,7 +25,7 @@ where T: Serialize + DeserializeOwned, Ser: Serde, { - item: Vec, + item_vec: Vec, index_pos: u32, item_type: PhantomData, serialization_type: PhantomData, @@ -34,14 +34,14 @@ where impl InternalItem { fn new(index_pos: u32, item: &T) -> StdResult { Ok(Self { - item: Ser::serialize(item)?, + item_vec: Ser::serialize(item)?, index_pos, item_type: PhantomData, serialization_type: PhantomData, }) } fn get_item(&self) -> StdResult { - Ser::deserialize(&self.item) + Ser::deserialize(&self.item_vec) } } diff --git a/packages/toolkit/Cargo.toml b/packages/toolkit/Cargo.toml index 54f00ad..837cefe 100644 --- a/packages/toolkit/Cargo.toml +++ b/packages/toolkit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit" -version = "0.3.0" +version = "0.4.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -28,11 +28,11 @@ viewing-key = ["secret-toolkit-viewing-key"] [dependencies] secret-toolkit-crypto = { version = "0.3.0", path = "../crypto", optional = true } -secret-toolkit-incubator = { version = "0.3.0", path = "../incubator", optional = true } +secret-toolkit-incubator = { version = "0.4.0", path = "../incubator", optional = true } secret-toolkit-permit = { version = "0.3.0", path = "../permit", optional = true } secret-toolkit-serialization = { version = "0.3", path = "../serialization", optional = true } secret-toolkit-snip20 = { version = "0.3", path = "../snip20", optional = true } secret-toolkit-snip721 = { version = "0.3", path = "../snip721", optional = true } -secret-toolkit-storage = { version = "0.3", path = "../storage", optional = true } +secret-toolkit-storage = { version = "0.4.1", path = "../storage", optional = true } secret-toolkit-utils = { version = "0.3", path = "../utils", optional = true } secret-toolkit-viewing-key = { version = "0.3", path = "../viewing_key", optional = true } From 7325f5b381c9751fc88a961b4d4a0c6666cffa2c Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 22 Aug 2022 12:23:48 +0300 Subject: [PATCH 22/37] changing the storage version in the toolkit package since the default behaviour is to import the highest compatible version --- packages/toolkit/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/toolkit/Cargo.toml b/packages/toolkit/Cargo.toml index 837cefe..ae51848 100644 --- a/packages/toolkit/Cargo.toml +++ b/packages/toolkit/Cargo.toml @@ -33,6 +33,6 @@ secret-toolkit-permit = { version = "0.3.0", path = "../permit", optional = true secret-toolkit-serialization = { version = "0.3", path = "../serialization", optional = true } secret-toolkit-snip20 = { version = "0.3", path = "../snip20", optional = true } secret-toolkit-snip721 = { version = "0.3", path = "../snip721", optional = true } -secret-toolkit-storage = { version = "0.4.1", path = "../storage", optional = true } +secret-toolkit-storage = { version = "0.4", path = "../storage", optional = true } secret-toolkit-utils = { version = "0.3", path = "../utils", optional = true } secret-toolkit-viewing-key = { version = "0.3", path = "../viewing_key", optional = true } From c86c906cfad2123c9a1b4a785f419c6741c1548a Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 25 Aug 2022 12:53:31 +0300 Subject: [PATCH 23/37] minor fix to readme --- packages/storage/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/storage/Readme.md b/packages/storage/Readme.md index 3d784cd..aea5af9 100644 --- a/packages/storage/Readme.md +++ b/packages/storage/Readme.md @@ -178,7 +178,7 @@ use secret_toolkit::storage::{Keymap} ```ignore pub static ADDR_VOTE: Keymap = Keymap::new(b"vote"); -pub static BET_STORE: Keymap = Keymap::new(b"vote"); +pub static BET_STORE: Keymap = Keymap::new(b"bet"); ``` > ❗ Initializing the object as const instead of static will also work but be less efficient since the variable won't be able to cache length data. From 54151e48f9475e0aea1df2c234328b9664d063d1 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Sat, 27 Aug 2022 20:36:04 +0300 Subject: [PATCH 24/37] fixed an error that would prevent the storage from working in a contract --- packages/storage/src/append_store.rs | 49 ++++++------- packages/storage/src/deque_store.rs | 70 ++++++++---------- packages/storage/src/item.rs | 20 +++--- packages/storage/src/keymap.rs | 104 +++++++++++++-------------- 4 files changed, 115 insertions(+), 128 deletions(-) diff --git a/packages/storage/src/append_store.rs b/packages/storage/src/append_store.rs index a4a7ef0..45f138f 100644 --- a/packages/storage/src/append_store.rs +++ b/packages/storage/src/append_store.rs @@ -62,7 +62,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { /// gets the length from storage, and otherwise sets it to 0 - pub fn get_len(&self, storage: &S) -> StdResult { + pub fn get_len(&self, storage: &dyn Storage) -> StdResult { let mut may_len = self.length.lock().unwrap(); match *may_len { Some(len) => Ok(len), @@ -84,11 +84,11 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { } } /// checks if the collection has any elements - pub fn is_empty(&self, storage: &S) -> StdResult { + pub fn is_empty(&self, storage: &dyn Storage) -> StdResult { Ok(self.get_len(storage)? == 0) } /// gets the element at pos if within bounds - pub fn get_at(&self, storage: &S, pos: u32) -> StdResult { + pub fn get_at(&self, storage: &dyn Storage, pos: u32) -> StdResult { let len = self.get_len(storage)?; if pos > len { return Err(StdError::generic_err("AppendStore access out of bounds")); @@ -96,13 +96,13 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { self.get_at_unchecked(storage, pos) } /// tries to get the element at pos - fn get_at_unchecked(&self, storage: &S, pos: u32) -> StdResult { + fn get_at_unchecked(&self, storage: &dyn Storage, pos: u32) -> StdResult { let key = pos.to_be_bytes(); self.load_impl(storage, &key) } /// Set the length of the collection - fn set_len(&self, storage: &mut S, len: u32) { + fn set_len(&self, storage: &mut dyn Storage, len: u32) { let len_key = [self.as_slice(), LEN_KEY].concat(); storage.set(&len_key, &len.to_be_bytes()); @@ -110,11 +110,11 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { *may_len = Some(len); } /// Clear the collection - pub fn clear(&self, storage: &mut S) { + pub fn clear(&self, storage: &mut dyn Storage) { self.set_len(storage, 0); } /// Replaces data at a position within bounds - pub fn set_at(&self, storage: &mut S, pos: u32, item: &T) -> StdResult<()> { + pub fn set_at(&self, storage: &mut dyn Storage, pos: u32, item: &T) -> StdResult<()> { let len = self.get_len(storage)?; if pos >= len { return Err(StdError::generic_err("AppendStore access out of bounds")); @@ -122,18 +122,18 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { self.set_at_unchecked(storage, pos, item) } /// Sets data at a given index - fn set_at_unchecked(&self, storage: &mut S, pos: u32, item: &T) -> StdResult<()> { + fn set_at_unchecked(&self, storage: &mut dyn Storage, pos: u32, item: &T) -> StdResult<()> { self.save_impl(storage, &pos.to_be_bytes(), item) } /// Pushes an item to AppendStorage - pub fn push(&self, storage: &mut S, item: &T) -> StdResult<()> { + pub fn push(&self, storage: &mut dyn Storage, item: &T) -> StdResult<()> { let len = self.get_len(storage)?; self.set_at_unchecked(storage, len, item)?; self.set_len(storage, len + 1); Ok(()) } /// Pops an item from AppendStore - pub fn pop(&self, storage: &mut S) -> StdResult { + pub fn pop(&self, storage: &mut dyn Storage) -> StdResult { if let Some(len) = self.get_len(storage)?.checked_sub(1) { let item = self.get_at_unchecked(storage, len); self.set_len(storage, len); @@ -150,7 +150,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { /// /// Removing an element from the start (head) of the collection /// has the worst runtime and gas cost. - pub fn remove(&self, storage: &mut S, pos: u32) -> StdResult { + pub fn remove(&self, storage: &mut dyn Storage, pos: u32) -> StdResult { let len = self.get_len(storage)?; if pos >= len { @@ -166,13 +166,13 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { item } /// Returns a readonly iterator - pub fn iter(&self, storage: &'a S) -> StdResult> { + pub fn iter(&self, storage: &'a dyn Storage) -> StdResult> { let len = self.get_len(storage)?; let iter = AppendStoreIter::new(self, storage, 0, len); Ok(iter) } /// does paging with the given parameters - pub fn paging(&self, storage: &S, start_page: u32, size: u32) -> StdResult> { + pub fn paging(&self, storage: &dyn Storage, start_page: u32, size: u32) -> StdResult> { self.iter(storage)? .skip((start_page as usize) * (size as usize)) .take(size as usize) @@ -208,7 +208,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { /// /// * `storage` - a reference to the storage this item is in /// * `key` - a byte slice representing the key to access the stored item - fn load_impl(&self, storage: &S, key: &[u8]) -> StdResult { + fn load_impl(&self, storage: &dyn Storage, key: &[u8]) -> StdResult { let prefixed_key = [self.as_slice(), key].concat(); Ser::deserialize( &storage @@ -224,7 +224,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { /// * `storage` - a mutable reference to the storage this item should go to /// * `key` - a byte slice representing the key to access the stored item /// * `value` - a reference to the item to store - fn save_impl(&self, storage: &mut S, key: &[u8], value: &T) -> StdResult<()> { + fn save_impl(&self, storage: &mut dyn Storage, key: &[u8], value: &T) -> StdResult<()> { let prefixed_key = [self.as_slice(), key].concat(); storage.set(&prefixed_key, &Ser::serialize(value)?); Ok(()) @@ -232,28 +232,26 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { } /// An iterator over the contents of the append store. -pub struct AppendStoreIter<'a, T, S, Ser> +pub struct AppendStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { append_store: &'a AppendStore<'a, T, Ser>, - storage: &'a S, + storage: &'a dyn Storage, start: u32, end: u32, } -impl<'a, T, S, Ser> AppendStoreIter<'a, T, S, Ser> +impl<'a, T, Ser> AppendStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { /// constructor pub fn new( append_store: &'a AppendStore<'a, T, Ser>, - storage: &'a S, + storage: &'a dyn Storage, start: u32, end: u32, ) -> Self { @@ -266,10 +264,9 @@ where } } -impl<'a, T, S, Ser> Iterator for AppendStoreIter<'a, T, S, Ser> +impl<'a, T, Ser> Iterator for AppendStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { type Item = StdResult; @@ -301,10 +298,9 @@ where } } -impl<'a, T, S, Ser> DoubleEndedIterator for AppendStoreIter<'a, T, S, Ser> +impl<'a, T, Ser> DoubleEndedIterator for AppendStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -329,10 +325,9 @@ where } // This enables writing `append_store.iter().skip(n).rev()` -impl<'a, T, S, Ser> ExactSizeIterator for AppendStoreIter<'a, T, S, Ser> +impl<'a, T, Ser> ExactSizeIterator for AppendStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { } diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index cb7ea48..812b433 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -67,7 +67,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// gets the length from storage, and otherwise sets it to 0 - pub fn get_len(&self, storage: &S) -> StdResult { + pub fn get_len(&self, storage: &dyn Storage) -> StdResult { let mut may_len = self.length.lock().unwrap(); match *may_len { Some(len) => Ok(len), @@ -81,7 +81,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } } /// gets the offset from storage, and otherwise sets it to 0 - pub fn get_off(&self, storage: &S) -> StdResult { + pub fn get_off(&self, storage: &dyn Storage) -> StdResult { let mut may_off = self.offset.lock().unwrap(); match *may_off { Some(len) => Ok(len), @@ -95,7 +95,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } } /// gets offset or length - fn _get_u32(&self, storage: &S, key: &[u8]) -> StdResult { + fn _get_u32(&self, storage: &dyn Storage, key: &[u8]) -> StdResult { let num_key = [self.as_slice(), key].concat(); if let Some(num_vec) = storage.get(&num_key) { let num_bytes = num_vec @@ -109,11 +109,11 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } } /// checks if the collection has any elements - pub fn is_empty(&self, storage: &S) -> StdResult { + pub fn is_empty(&self, storage: &dyn Storage) -> StdResult { Ok(self.get_len(storage)? == 0) } /// gets the element at pos if within bounds - pub fn get_at(&self, storage: &S, pos: u32) -> StdResult { + pub fn get_at(&self, storage: &dyn Storage, pos: u32) -> StdResult { let len = self.get_len(storage)?; if pos >= len { return Err(StdError::generic_err("DequeStore access out of bounds")); @@ -121,38 +121,38 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { self.get_at_unchecked(storage, pos) } /// tries to get the element at pos - fn get_at_unchecked(&self, storage: &S, pos: u32) -> StdResult { + fn get_at_unchecked(&self, storage: &dyn Storage, pos: u32) -> StdResult { self.load_impl(storage, &self._get_offset_pos(storage, pos)?.to_be_bytes()) } /// add the offset to the pos - fn _get_offset_pos(&self, storage: &S, pos: u32) -> StdResult { + fn _get_offset_pos(&self, storage: &dyn Storage, pos: u32) -> StdResult { let off = self.get_off(storage)?; Ok(pos.overflowing_add(off).0) } /// Set the length of the collection - fn set_len(&self, storage: &mut S, len: u32) { + fn set_len(&self, storage: &mut dyn Storage, len: u32) { let mut may_len = self.length.lock().unwrap(); *may_len = Some(len); self._set_u32(storage, LEN_KEY, len) } /// Set the offset of the collection - fn set_off(&self, storage: &mut S, off: u32) { + fn set_off(&self, storage: &mut dyn Storage, off: u32) { let mut may_off = self.offset.lock().unwrap(); *may_off = Some(off); self._set_u32(storage, OFFSET_KEY, off) } /// Set the length or offset of the collection - fn _set_u32(&self, storage: &mut S, key: &[u8], num: u32) { + fn _set_u32(&self, storage: &mut dyn Storage, key: &[u8], num: u32) { let num_key = [self.as_slice(), key].concat(); storage.set(&num_key, &num.to_be_bytes()); } /// Clear the collection - pub fn clear(&self, storage: &mut S) { + pub fn clear(&self, storage: &mut dyn Storage) { self.set_len(storage, 0); self.set_off(storage, 0); } /// Replaces data at a position within bounds - pub fn set_at(&self, storage: &mut S, pos: u32, item: &T) -> StdResult<()> { + pub fn set_at(&self, storage: &mut dyn Storage, pos: u32, item: &T) -> StdResult<()> { let len = self.get_len(storage)?; if pos >= len { return Err(StdError::generic_err("DequeStore access out of bounds")); @@ -160,22 +160,19 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { self.set_at_unchecked(storage, pos, item) } /// Sets data at a given index - fn set_at_unchecked(&self, storage: &mut S, pos: u32, item: &T) -> StdResult<()> { - self.save_impl( - storage, - &self._get_offset_pos(storage, pos)?.to_be_bytes(), - item, - ) + fn set_at_unchecked(&self, storage: &mut dyn Storage, pos: u32, item: &T) -> StdResult<()> { + let get_offset_pos = self._get_offset_pos(storage, pos)?; + self.save_impl(storage, &get_offset_pos.to_be_bytes(), item) } /// Pushes an item to the back - pub fn push_back(&self, storage: &mut S, item: &T) -> StdResult<()> { + pub fn push_back(&self, storage: &mut dyn Storage, item: &T) -> StdResult<()> { let len = self.get_len(storage)?; self.set_at_unchecked(storage, len, item)?; self.set_len(storage, len + 1); Ok(()) } /// Pushes an item to the front - pub fn push_front(&self, storage: &mut S, item: &T) -> StdResult<()> { + pub fn push_front(&self, storage: &mut dyn Storage, item: &T) -> StdResult<()> { let off = self.get_off(storage)?; let len = self.get_len(storage)?; self.set_off(storage, off.overflowing_sub(1).0); @@ -184,7 +181,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { Ok(()) } /// Pops an item from the back - pub fn pop_back(&self, storage: &mut S) -> StdResult { + pub fn pop_back(&self, storage: &mut dyn Storage) -> StdResult { if let Some(len) = self.get_len(storage)?.checked_sub(1) { let item = self.get_at_unchecked(storage, len); self.set_len(storage, len); @@ -194,7 +191,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } } /// Pops an item from the front - pub fn pop_front(&self, storage: &mut S) -> StdResult { + pub fn pop_front(&self, storage: &mut dyn Storage) -> StdResult { if let Some(len) = self.get_len(storage)?.checked_sub(1) { let off = self.get_off(storage)?; let item = self.get_at_unchecked(storage, 0); @@ -214,7 +211,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// /// Removing an element from the middle of the collection /// has the worst runtime and gas cost. - pub fn remove(&self, storage: &mut S, pos: u32) -> StdResult { + pub fn remove(&self, storage: &mut dyn Storage, pos: u32) -> StdResult { let off = self.get_off(storage)?; let len = self.get_len(storage)?; if pos >= len { @@ -240,13 +237,13 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { item } /// Returns a readonly iterator - pub fn iter(&self, storage: &'a S) -> StdResult> { + pub fn iter(&self, storage: &'a dyn Storage) -> StdResult> { let len = self.get_len(storage)?; let iter = DequeStoreIter::new(self, storage, 0, len); Ok(iter) } /// does paging with the given parameters - pub fn paging(&self, storage: &S, start_page: u32, size: u32) -> StdResult> { + pub fn paging(&self, storage: &dyn Storage, start_page: u32, size: u32) -> StdResult> { self.iter(storage)? .skip((start_page as usize) * (size as usize)) .take(size as usize) @@ -270,7 +267,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// /// * `storage` - a reference to the storage this item is in /// * `key` - a byte slice representing the key to access the stored item - fn load_impl(&self, storage: &S, key: &[u8]) -> StdResult { + fn load_impl(&self, storage: &dyn Storage, key: &[u8]) -> StdResult { let prefixed_key = [self.as_slice(), key].concat(); Ser::deserialize( &storage @@ -286,7 +283,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// * `storage` - a mutable reference to the storage this item should go to /// * `key` - a byte slice representing the key to access the stored item /// * `value` - a reference to the item to store - fn save_impl(&self, storage: &mut S, key: &[u8], value: &T) -> StdResult<()> { + fn save_impl(&self, storage: &mut dyn Storage, key: &[u8], value: &T) -> StdResult<()> { let prefixed_key = [self.as_slice(), key].concat(); storage.set(&prefixed_key, &Ser::serialize(value)?); Ok(()) @@ -307,28 +304,26 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for DequeStore<'a, T } /// An iterator over the contents of the deque store. -pub struct DequeStoreIter<'a, T, S, Ser> +pub struct DequeStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { deque_store: &'a DequeStore<'a, T, Ser>, - storage: &'a S, + storage: &'a dyn Storage, start: u32, end: u32, } -impl<'a, T, S, Ser> DequeStoreIter<'a, T, S, Ser> +impl<'a, T, Ser> DequeStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { /// constructor pub fn new( deque_store: &'a DequeStore<'a, T, Ser>, - storage: &'a S, + storage: &'a dyn Storage, start: u32, end: u32, ) -> Self { @@ -341,10 +336,9 @@ where } } -impl<'a, T, S, Ser> Iterator for DequeStoreIter<'a, T, S, Ser> +impl<'a, T, Ser> Iterator for DequeStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { type Item = StdResult; @@ -376,10 +370,9 @@ where } } -impl<'a, T, S, Ser> DoubleEndedIterator for DequeStoreIter<'a, T, S, Ser> +impl<'a, T, Ser> DoubleEndedIterator for DequeStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -404,10 +397,9 @@ where } // This enables writing `deque_store.iter().skip(n).rev()` -impl<'a, T, S, Ser> ExactSizeIterator for DequeStoreIter<'a, T, S, Ser> +impl<'a, T, Ser> ExactSizeIterator for DequeStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { } diff --git a/packages/storage/src/item.rs b/packages/storage/src/item.rs index 94a93fc..3a3e03d 100644 --- a/packages/storage/src/item.rs +++ b/packages/storage/src/item.rs @@ -33,28 +33,28 @@ where Ser: Serde, { /// save will serialize the model and store, returns an error on serialization issues - pub fn save(&self, storage: &mut S, data: &T) -> StdResult<()> { + pub fn save(&self, storage: &mut dyn Storage, data: &T) -> StdResult<()> { self.save_impl(storage, data) } /// userfacing remove function - pub fn remove(&self, storage: &mut S) { + pub fn remove(&self, storage: &mut dyn Storage) { self.remove_impl(storage); } /// load will return an error if no data is set at the given key, or on parse error - pub fn load(&self, storage: &S) -> StdResult { + pub fn load(&self, storage: &dyn Storage) -> StdResult { self.load_impl(storage) } /// 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, storage: &S) -> StdResult> { + pub fn may_load(&self, storage: &dyn Storage) -> StdResult> { self.may_load_impl(storage) } /// efficient way to see if any object is currently saved. - pub fn is_empty(&self, storage: &S) -> bool { + pub fn is_empty(&self, storage: &dyn Storage) -> bool { storage.get(self.as_slice()).is_none() } @@ -63,7 +63,7 @@ where /// /// It assumes, that data was initialized before, and if it doesn't exist, `Err(StdError::NotFound)` /// is returned. - pub fn update(&self, storage: &mut S, action: A) -> StdResult + pub fn update(&self, storage: &mut dyn Storage, action: A) -> StdResult where S: Storage, A: FnOnce(T) -> StdResult, @@ -80,7 +80,7 @@ where /// # Arguments /// /// * `storage` - a reference to the storage this item is in - fn load_impl(&self, storage: &S) -> StdResult { + fn load_impl(&self, storage: &dyn Storage) -> StdResult { Ser::deserialize( &storage .get(self.as_slice()) @@ -94,7 +94,7 @@ where /// # Arguments /// /// * `storage` - a reference to the storage this item is in - fn may_load_impl(&self, storage: &S) -> StdResult> { + fn may_load_impl(&self, storage: &dyn Storage) -> StdResult> { match storage.get(self.as_slice()) { Some(value) => Ser::deserialize(&value).map(Some), None => Ok(None), @@ -107,7 +107,7 @@ where /// /// * `storage` - a mutable reference to the storage this item should go to /// * `value` - a reference to the item to store - fn save_impl(&self, storage: &mut S, value: &T) -> StdResult<()> { + fn save_impl(&self, storage: &mut dyn Storage, value: &T) -> StdResult<()> { storage.set(self.as_slice(), &Ser::serialize(value)?); Ok(()) } @@ -117,7 +117,7 @@ where /// # Arguments /// /// * `storage` - a mutable reference to the storage this item is in - fn remove_impl(&self, storage: &mut S) { + fn remove_impl(&self, storage: &mut dyn Storage) { storage.remove(self.as_slice()); } diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs index ce33387..9fb1f6e 100644 --- a/packages/storage/src/keymap.rs +++ b/packages/storage/src/keymap.rs @@ -107,7 +107,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Ser::deserialize(key_data) } /// get total number of objects saved - pub fn get_len(&self, storage: &S) -> StdResult { + pub fn get_len(&self, storage: &dyn Storage) -> StdResult { let mut may_len = self.length.lock().unwrap(); match *may_len { Some(length) => Ok(length), @@ -129,11 +129,11 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } /// checks if the collection has any elements - pub fn is_empty(&self, storage: &S) -> StdResult { + pub fn is_empty(&self, storage: &dyn Storage) -> StdResult { Ok(self.get_len(storage)? == 0) } /// set length of the map - fn set_len(&self, storage: &mut S, len: u32) -> StdResult<()> { + fn set_len(&self, storage: &mut dyn Storage, len: u32) -> StdResult<()> { let len_key = [self.as_slice(), MAP_LENGTH].concat(); storage.set(&len_key, &len.to_be_bytes()); @@ -143,7 +143,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Ok(()) } /// Used to get the indexes stored in the given page number - fn _get_indexes(&self, storage: &S, page: u32) -> StdResult>> { + fn _get_indexes(&self, storage: &dyn Storage, page: u32) -> StdResult>> { let indexes_key = [self.as_slice(), INDEXES, page.to_be_bytes().as_slice()].concat(); let maybe_serialized = storage.get(&indexes_key); match maybe_serialized { @@ -152,9 +152,9 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } /// Set an indexes page - fn _set_indexes_page( + fn _set_indexes_page( &self, - storage: &mut S, + storage: &mut dyn Storage, page: u32, indexes: &Vec>, ) -> StdResult<()> { @@ -163,7 +163,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Ok(()) } /// user facing get function - pub fn get(&self, storage: &S, key: &K) -> Option { + pub fn get(&self, storage: &dyn Storage, key: &K) -> Option { if let Ok(internal_item) = self._get_from_key(storage, key) { internal_item.get_item().ok() } else { @@ -171,12 +171,12 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } /// internal item get function - fn _get_from_key(&self, storage: &S, key: &K) -> StdResult> { + fn _get_from_key(&self, storage: &dyn Storage, key: &K) -> StdResult> { let key_vec = self.serialize_key(key)?; self.load_impl(storage, &key_vec) } /// user facing remove function - pub fn remove(&self, storage: &mut S, key: &K) -> StdResult<()> { + pub fn remove(&self, storage: &mut dyn Storage, key: &K) -> StdResult<()> { let key_vec = self.serialize_key(key)?; let removed_pos = self._get_from_key(storage, key)?.index_pos; @@ -236,7 +236,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Ok(()) } /// user facing insert function - pub fn insert(&self, storage: &mut S, key: &K, item: &T) -> StdResult<()> { + pub fn insert(&self, storage: &mut dyn Storage, key: &K, item: &T) -> StdResult<()> { let key_vec = self.serialize_key(key)?; match self.may_load_impl(storage, &key_vec)? { Some(existing_internal_item) => { @@ -260,16 +260,16 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } /// user facing method that checks if any item is stored with this key. - pub fn contains(&self, storage: &S, key: &K) -> bool { + pub fn contains(&self, storage: &dyn Storage, key: &K) -> bool { match self.serialize_key(key) { Ok(key_vec) => self.contains_impl(storage, &key_vec), Err(_) => false, } } /// paginates (key, item) pairs. - pub fn paging( + pub fn paging( &self, - storage: &S, + storage: &dyn Storage, start_page: u32, size: u32, ) -> StdResult> { @@ -292,9 +292,9 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: self.get_pairs_at_positions(storage, start_pos, end_pos) } /// paginates only the keys. More efficient than paginating both items and keys - pub fn paging_keys( + pub fn paging_keys( &self, - storage: &S, + storage: &dyn Storage, start_page: u32, size: u32, ) -> StdResult> { @@ -317,9 +317,9 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: self.get_keys_at_positions(storage, start_pos, end_pos) } /// tries to list keys without checking start/end bounds - fn get_keys_at_positions( + fn get_keys_at_positions( &self, - storage: &S, + storage: &dyn Storage, start: u32, end: u32, ) -> StdResult> { @@ -349,9 +349,9 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Ok(res) } /// tries to list (key, item) pairs without checking start/end bounds - fn get_pairs_at_positions( + fn get_pairs_at_positions( &self, - storage: &S, + storage: &dyn Storage, start: u32, end: u32, ) -> StdResult> { @@ -382,7 +382,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Ok(res) } /// gets a key from a specific position in indexes - fn get_key_from_pos(&self, storage: &S, pos: u32) -> StdResult { + fn get_key_from_pos(&self, storage: &dyn Storage, pos: u32) -> StdResult { let page = _page_from_position(pos); let indexes = self._get_indexes(storage, page)?; let index = pos % PAGE_SIZE; @@ -390,7 +390,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: self.deserialize_key(key_vec) } /// gets a key from a specific position in indexes - fn get_pair_from_pos(&self, storage: &S, pos: u32) -> StdResult<(K, T)> { + fn get_pair_from_pos(&self, storage: &dyn Storage, pos: u32) -> StdResult<(K, T)> { let page = _page_from_position(pos); let indexes = self._get_indexes(storage, page)?; let index = pos % PAGE_SIZE; @@ -400,13 +400,13 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Ok((key, item)) } /// Returns a readonly iterator only for keys. More efficient than iter(). - pub fn iter_keys(&self, storage: &'a S) -> StdResult> { + pub fn iter_keys(&self, storage: &'a dyn Storage) -> StdResult> { let len = self.get_len(storage)?; let iter = KeyIter::new(self, storage, 0, len); Ok(iter) } /// Returns a readonly iterator for (key-item) pairs - pub fn iter(&self, storage: &'a S) -> StdResult> { + pub fn iter(&self, storage: &'a dyn Storage) -> StdResult> { let len = self.get_len(storage)?; let iter = KeyItemIter::new(self, storage, 0, len); Ok(iter) @@ -441,15 +441,14 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } /// An iterator over the keys of the Keymap. -pub struct KeyIter<'a, K, T, S, Ser> +pub struct KeyIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { keymap: &'a Keymap<'a, K, T, Ser>, - storage: &'a S, + storage: &'a dyn Storage, start: u32, end: u32, saved_indexes: Option>>, @@ -458,15 +457,19 @@ where saved_back_index_page: Option, } -impl<'a, K, T, S, Ser> KeyIter<'a, K, T, S, Ser> +impl<'a, K, T, Ser> KeyIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { /// constructor - pub fn new(keymap: &'a Keymap<'a, K, T, Ser>, storage: &'a S, start: u32, end: u32) -> Self { + pub fn new( + keymap: &'a Keymap<'a, K, T, Ser>, + storage: &'a dyn Storage, + start: u32, + end: u32, + ) -> Self { Self { keymap, storage, @@ -480,11 +483,10 @@ where } } -impl<'a, K, T, S, Ser> Iterator for KeyIter<'a, K, T, S, Ser> +impl<'a, K, T, Ser> Iterator for KeyIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { type Item = StdResult; @@ -606,11 +608,10 @@ where } } -impl<'a, K, T, S, Ser> DoubleEndedIterator for KeyIter<'a, K, T, S, Ser> +impl<'a, K, T, Ser> DoubleEndedIterator for KeyIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -726,11 +727,10 @@ where } // This enables writing `append_store.iter().skip(n).rev()` -impl<'a, K, T, S, Ser> ExactSizeIterator for KeyIter<'a, K, T, S, Ser> +impl<'a, K, T, Ser> ExactSizeIterator for KeyIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { } @@ -738,15 +738,14 @@ where // =============================================================================================== /// An iterator over the (key, item) pairs of the Keymap. Less efficient than just iterating over keys. -pub struct KeyItemIter<'a, K, T, S, Ser> +pub struct KeyItemIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { keymap: &'a Keymap<'a, K, T, Ser>, - storage: &'a S, + storage: &'a dyn Storage, start: u32, end: u32, saved_indexes: Option>>, @@ -755,15 +754,19 @@ where saved_back_index_page: Option, } -impl<'a, K, T, S, Ser> KeyItemIter<'a, K, T, S, Ser> +impl<'a, K, T, Ser> KeyItemIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { /// constructor - pub fn new(keymap: &'a Keymap<'a, K, T, Ser>, storage: &'a S, start: u32, end: u32) -> Self { + pub fn new( + keymap: &'a Keymap<'a, K, T, Ser>, + storage: &'a dyn Storage, + start: u32, + end: u32, + ) -> Self { Self { keymap, storage, @@ -777,11 +780,10 @@ where } } -impl<'a, K, T, S, Ser> Iterator for KeyItemIter<'a, K, T, S, Ser> +impl<'a, K, T, Ser> Iterator for KeyItemIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { type Item = StdResult<(K, T)>; @@ -906,11 +908,10 @@ where } } -impl<'a, K, T, S, Ser> DoubleEndedIterator for KeyItemIter<'a, K, T, S, Ser> +impl<'a, K, T, Ser> DoubleEndedIterator for KeyItemIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { fn next_back(&mut self) -> Option { @@ -1029,11 +1030,10 @@ where } // This enables writing `append_store.iter().skip(n).rev()` -impl<'a, K, T, S, Ser> ExactSizeIterator for KeyItemIter<'a, K, T, S, Ser> +impl<'a, K, T, Ser> ExactSizeIterator for KeyItemIter<'a, K, T, Ser> where K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, - S: Storage, Ser: Serde, { } @@ -1047,7 +1047,7 @@ trait PrefixedTypedStorage { /// /// * `storage` - a reference to the storage this item is in /// * `key` - a byte slice representing the key to access the stored item - fn contains_impl(&self, storage: &S, key: &[u8]) -> bool { + fn contains_impl(&self, storage: &dyn Storage, key: &[u8]) -> bool { let prefixed_key = [self.as_slice(), key].concat(); storage.get(&prefixed_key).is_some() } @@ -1059,7 +1059,7 @@ trait PrefixedTypedStorage { /// /// * `storage` - a reference to the storage this item is in /// * `key` - a byte slice representing the key to access the stored item - fn load_impl(&self, storage: &S, key: &[u8]) -> StdResult { + fn load_impl(&self, storage: &dyn Storage, key: &[u8]) -> StdResult { let prefixed_key = [self.as_slice(), key].concat(); Ser::deserialize( &storage @@ -1075,7 +1075,7 @@ trait PrefixedTypedStorage { /// /// * `storage` - a reference to the storage this item is in /// * `key` - a byte slice representing the key to access the stored item - fn may_load_impl(&self, storage: &S, key: &[u8]) -> StdResult> { + fn may_load_impl(&self, storage: &dyn Storage, key: &[u8]) -> StdResult> { let prefixed_key = [self.as_slice(), key].concat(); match storage.get(&prefixed_key) { Some(value) => Ser::deserialize(&value).map(Some), @@ -1090,7 +1090,7 @@ trait PrefixedTypedStorage { /// * `storage` - a mutable reference to the storage this item should go to /// * `key` - a byte slice representing the key to access the stored item /// * `value` - a reference to the item to store - fn save_impl(&self, storage: &mut S, key: &[u8], value: &T) -> StdResult<()> { + fn save_impl(&self, storage: &mut dyn Storage, key: &[u8], value: &T) -> StdResult<()> { let prefixed_key = [self.as_slice(), key].concat(); storage.set(&prefixed_key, &Ser::serialize(value)?); Ok(()) @@ -1102,7 +1102,7 @@ trait PrefixedTypedStorage { /// /// * `storage` - a mutable reference to the storage this item is in /// * `key` - a byte slice representing the key to access the stored item - fn remove_impl(&self, storage: &mut S, key: &[u8]) { + fn remove_impl(&self, storage: &mut dyn Storage, key: &[u8]) { let prefixed_key = [self.as_slice(), key].concat(); storage.remove(&prefixed_key); } From d677ea34d725e6044ded214c5ad4a7464e2a1b67 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 29 Aug 2022 15:38:08 +0300 Subject: [PATCH 25/37] added support for generic errors in padding. This is needed because cw 1.0 allows generic errors in entry points unlike cw 0.1 --- packages/utils/src/padding.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/utils/src/padding.rs b/packages/utils/src/padding.rs index 2b37dbf..a778083 100644 --- a/packages/utils/src/padding.rs +++ b/packages/utils/src/padding.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Binary, Response, StdResult}; +use cosmwasm_std::{Binary, Response}; /// Take a Vec and pad it up to a multiple of `block_size`, using spaces at the end. pub fn space_pad(message: &mut Vec, block_size: usize) -> &mut Vec { @@ -14,13 +14,13 @@ pub fn space_pad(message: &mut Vec, block_size: usize) -> &mut Vec { message } -/// Pad the data and logs in a `StdResult` to the block size, with spaces. +/// Pad the data and logs in a `Result` to the block size, with spaces. // Users don't need to care about it as the type `T` has a default, and will // always be known in the context of the caller. -pub fn pad_handle_result( - response: StdResult>, +pub fn pad_handle_result( + response: Result, E>, block_size: usize, -) -> StdResult> +) -> Result, E> where T: Clone + std::fmt::Debug + PartialEq + schemars::JsonSchema, { @@ -40,7 +40,7 @@ where } /// Pad a `QueryResult` with spaces -pub fn pad_query_result(response: StdResult, block_size: usize) -> StdResult { +pub fn pad_query_result(response: Result, block_size: usize) -> Result { response.map(|mut response| { space_pad(&mut response.0, block_size); response From 281297f4e5cb7892a2ec6786d51c0ea9687d7119 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Mon, 29 Aug 2022 15:49:26 +0300 Subject: [PATCH 26/37] fixed reference to cw0.1 type Storage pattern in viewing_key::set function --- packages/viewing_key/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/viewing_key/src/lib.rs b/packages/viewing_key/src/lib.rs index d4bd962..ffe5baa 100644 --- a/packages/viewing_key/src/lib.rs +++ b/packages/viewing_key/src/lib.rs @@ -63,7 +63,7 @@ pub trait ViewingKeyStore { } /// Set a new viewing key based on a predetermined value. - fn set(storage: &mut S, account: &str, viewing_key: &str) { + fn set(storage: &mut dyn Storage, account: &str, viewing_key: &str) { let mut balance_store = PrefixedStorage::new(storage, Self::STORAGE_KEY); balance_store.set(account.as_bytes(), &sha_256(viewing_key.as_bytes())); } From 1d3b58ce3c59cf810a95c78173b06e89fd8ae0dc Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 30 Aug 2022 18:03:36 +0300 Subject: [PATCH 27/37] fixed a bug in item::update, also added the add_suffix feature to item. Expanded the tests for Item --- packages/storage/src/append_store.rs | 3 +- packages/storage/src/deque_store.rs | 3 +- packages/storage/src/item.rs | 66 ++++++++++++++++++++++++++-- packages/storage/src/keymap.rs | 15 +++---- 4 files changed, 71 insertions(+), 16 deletions(-) diff --git a/packages/storage/src/append_store.rs b/packages/storage/src/append_store.rs index 45f138f..0087465 100644 --- a/packages/storage/src/append_store.rs +++ b/packages/storage/src/append_store.rs @@ -24,7 +24,6 @@ where /// prefix of the newly constructed Storage namespace: &'a [u8], /// needed if any suffixes were added to the original namespace. - /// therefore it is not necessarily same as the namespace. prefix: Option>, length: Mutex>, item_type: PhantomData, @@ -213,7 +212,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { Ser::deserialize( &storage .get(&prefixed_key) - .ok_or(StdError::not_found(type_name::()))?, + .ok_or_else(|| StdError::not_found(type_name::()))?, ) } diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 812b433..86c0a02 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -26,7 +26,6 @@ where /// prefix of the newly constructed Storage namespace: &'a [u8], /// needed if any suffixes were added to the original namespace. - /// therefore it is not necessarily same as the namespace. prefix: Option>, length: Mutex>, offset: Mutex>, @@ -272,7 +271,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { Ser::deserialize( &storage .get(&prefixed_key) - .ok_or(StdError::not_found(type_name::()))?, + .ok_or_else(|| StdError::not_found(type_name::()))?, ) } diff --git a/packages/storage/src/item.rs b/packages/storage/src/item.rs index 3a3e03d..6e82fe3 100644 --- a/packages/storage/src/item.rs +++ b/packages/storage/src/item.rs @@ -13,6 +13,8 @@ where Ser: Serde, { storage_key: &'a [u8], + /// needed if any suffixes were added to the original storage key. + prefix: Option>, item_type: PhantomData, serialization_type: PhantomData, } @@ -21,10 +23,26 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Item<'a, T, Ser> { pub const fn new(key: &'a [u8]) -> Self { Self { storage_key: key, + prefix: None, item_type: PhantomData, serialization_type: PhantomData, } } + /// This is used to produce a new Item. This can be used when you want to associate an Item to each user + /// and you still get to define the Item as a static constant + pub fn add_suffix(&self, suffix: &[u8]) -> Self { + let prefix = if let Some(prefix) = &self.prefix { + [prefix.clone(), suffix.to_vec()].concat() + } else { + [self.storage_key.to_vec(), suffix.to_vec()].concat() + }; + Self { + storage_key: self.storage_key, + prefix: Some(prefix), + item_type: self.item_type, + serialization_type: self.serialization_type, + } + } } impl<'a, T, Ser> Item<'a, T, Ser> @@ -63,9 +81,8 @@ where /// /// It assumes, that data was initialized before, and if it doesn't exist, `Err(StdError::NotFound)` /// is returned. - pub fn update(&self, storage: &mut dyn Storage, action: A) -> StdResult + pub fn update(&self, storage: &mut dyn Storage, action: A) -> StdResult where - S: Storage, A: FnOnce(T) -> StdResult, { let input = self.load_impl(storage)?; @@ -84,7 +101,7 @@ where Ser::deserialize( &storage .get(self.as_slice()) - .ok_or(StdError::not_found(type_name::()))?, + .ok_or_else(|| StdError::not_found(type_name::()))?, ) } @@ -122,7 +139,11 @@ where } fn as_slice(&self) -> &[u8] { - self.storage_key + if let Some(prefix) = &self.prefix { + prefix + } else { + self.storage_key + } } } @@ -154,6 +175,43 @@ mod tests { Ok(()) } + #[test] + fn test_suffix() -> StdResult<()> { + let mut storage = MockStorage::new(); + let item: Item = Item::new(b"test"); + let item1 = item.add_suffix(b"suffix1"); + let item2 = item.add_suffix(b"suffix2"); + + item.save(&mut storage, &0)?; + assert!(item1.is_empty(&storage)); + assert!(item2.is_empty(&storage)); + + item1.save(&mut storage, &1)?; + assert!(!item1.is_empty(&storage)); + assert!(item2.is_empty(&storage)); + assert_eq!(item.may_load(&storage)?, Some(0)); + assert_eq!(item1.may_load(&storage)?, Some(1)); + item2.save(&mut storage, &2)?; + assert_eq!(item.may_load(&storage)?, Some(0)); + assert_eq!(item1.may_load(&storage)?, Some(1)); + assert_eq!(item2.may_load(&storage)?, Some(2)); + + Ok(()) + } + + #[test] + fn test_update() -> StdResult<()> { + let mut storage = MockStorage::new(); + let item: Item = Item::new(b"test"); + + assert!(item.update(&mut storage, |x| Ok(x + 1)).is_err()); + item.save(&mut storage, &7)?; + assert!(item.update(&mut storage, |x| Ok(x + 1)).is_ok()); + assert_eq!(item.load(&storage), Ok(8)); + + Ok(()) + } + #[test] fn test_serializations() -> StdResult<()> { // Check the default behavior is Bincode2 diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs index 9fb1f6e..d47bd1a 100644 --- a/packages/storage/src/keymap.rs +++ b/packages/storage/src/keymap.rs @@ -54,7 +54,6 @@ where /// prefix of the newly constructed Storage namespace: &'a [u8], /// needed if any suffixes were added to the original namespace. - /// therefore it is not necessarily same as the namespace. prefix: Option>, length: Mutex>, key_type: PhantomData, @@ -208,9 +207,9 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: let max_page = _page_from_position(len); if max_page == page { // last page indexes is the same as indexes - let last_key = indexes.pop().ok_or(StdError::generic_err( - "Last item's key not found - should never happen", - ))?; + let last_key = indexes.pop().ok_or_else(|| { + StdError::generic_err("Last item's key not found - should never happen") + })?; // modify last item let mut last_internal_item = self.load_impl(storage, &last_key)?; last_internal_item.index_pos = removed_pos; @@ -220,9 +219,9 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: self._set_indexes_page(storage, page, &indexes)?; } else { let mut last_page_indexes = self._get_indexes(storage, max_page)?; - let last_key = last_page_indexes.pop().ok_or(StdError::generic_err( - "Last item's key not found - should never happen", - ))?; + let last_key = last_page_indexes.pop().ok_or_else(|| { + StdError::generic_err("Last item's key not found - should never happen") + })?; // modify last item let mut last_internal_item = self.load_impl(storage, &last_key)?; last_internal_item.index_pos = removed_pos; @@ -1064,7 +1063,7 @@ trait PrefixedTypedStorage { Ser::deserialize( &storage .get(&prefixed_key) - .ok_or(StdError::not_found(type_name::()))?, + .ok_or_else(|| StdError::not_found(type_name::()))?, ) } From 898c52dcadce6e678818295918d875f8b81f6284 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 30 Aug 2022 18:11:27 +0300 Subject: [PATCH 28/37] implemented Clone for Item --- packages/storage/src/item.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/storage/src/item.rs b/packages/storage/src/item.rs index 6e82fe3..fc45116 100644 --- a/packages/storage/src/item.rs +++ b/packages/storage/src/item.rs @@ -147,6 +147,17 @@ where } } +impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for Item<'a, T, Ser> { + fn clone(&self) -> Self { + Self { + storage_key: self.storage_key, + prefix: self.prefix.clone(), + item_type: PhantomData, + serialization_type: PhantomData, + } + } +} + #[cfg(test)] mod tests { use cosmwasm_std::testing::MockStorage; From 6dbd789ce0f449996a0c917a969f966863211aa9 Mon Sep 17 00:00:00 2001 From: eladr7 Date: Mon, 5 Sep 2022 11:28:57 +0300 Subject: [PATCH 29/37] Added Eq feature where required by clippy --- packages/snip20/src/batch.rs | 12 ++++----- packages/snip20/src/handle.rs | 2 +- packages/snip20/src/query.rs | 18 ++++++------- packages/snip721/src/expiration.rs | 2 +- packages/snip721/src/handle.rs | 12 ++++----- packages/snip721/src/metadata.rs | 10 ++++---- packages/snip721/src/query.rs | 38 ++++++++++++++-------------- packages/utils/src/feature_toggle.rs | 6 ++--- packages/utils/src/types.rs | 2 +- 9 files changed, 51 insertions(+), 51 deletions(-) diff --git a/packages/snip20/src/batch.rs b/packages/snip20/src/batch.rs index af9581c..4be8566 100644 --- a/packages/snip20/src/batch.rs +++ b/packages/snip20/src/batch.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use cosmwasm_std::{Binary, Uint128}; -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub struct TransferAction { pub recipient: String, @@ -21,7 +21,7 @@ impl TransferAction { } } -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub struct SendAction { pub recipient: String, @@ -64,7 +64,7 @@ impl SendAction { } } -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub struct TransferFromAction { pub owner: String, @@ -84,7 +84,7 @@ impl TransferFromAction { } } -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub struct SendFromAction { pub owner: String, @@ -132,7 +132,7 @@ impl SendFromAction { } } -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub struct MintAction { pub recipient: String, @@ -150,7 +150,7 @@ impl MintAction { } } -#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub struct BurnFromAction { pub owner: String, diff --git a/packages/snip20/src/handle.rs b/packages/snip20/src/handle.rs index 0ce79e3..7d8cc09 100644 --- a/packages/snip20/src/handle.rs +++ b/packages/snip20/src/handle.rs @@ -8,7 +8,7 @@ use crate::batch::{ use secret_toolkit_utils::space_pad; /// SNIP20 token handle messages -#[derive(Serialize, Clone, Debug, PartialEq)] +#[derive(Serialize, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub enum HandleMsg { // Native coin interactions diff --git a/packages/snip20/src/query.rs b/packages/snip20/src/query.rs index 171e561..8ac86ce 100644 --- a/packages/snip20/src/query.rs +++ b/packages/snip20/src/query.rs @@ -10,7 +10,7 @@ use cosmwasm_std::{ use secret_toolkit_utils::space_pad; /// TokenInfo response -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct TokenInfo { pub name: String, pub symbol: String, @@ -20,7 +20,7 @@ pub struct TokenInfo { } /// TokenConfig response -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct TokenConfig { pub public_total_supply: bool, pub deposit_enabled: bool, @@ -30,7 +30,7 @@ pub struct TokenConfig { } /// Contract status -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] pub enum ContractStatusLevel { NormalRun, StopAllButRedeems, @@ -38,20 +38,20 @@ pub enum ContractStatusLevel { } /// ContractStatus Response -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct ContractStatus { pub status: ContractStatusLevel, } /// ExchangeRate response -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct ExchangeRate { pub rate: Uint128, pub denom: String, } /// Allowance response -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct Allowance { pub spender: String, pub owner: String, @@ -61,7 +61,7 @@ pub struct Allowance { } /// Balance response -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct Balance { pub amount: Uint128, } @@ -90,7 +90,7 @@ pub struct TransferHistory { } /// Types of transactions for RichTx -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum TxAction { Transfer { @@ -130,7 +130,7 @@ pub struct TransactionHistory { } /// Minters response -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct Minters { pub minters: Vec, } diff --git a/packages/snip721/src/expiration.rs b/packages/snip721/src/expiration.rs index a376af3..ac7855e 100644 --- a/packages/snip721/src/expiration.rs +++ b/packages/snip721/src/expiration.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use cosmwasm_std::BlockInfo; use std::fmt; -#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, JsonSchema, Debug)] +#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] /// at the given point in time and after, Expiration will be considered expired pub enum Expiration { diff --git a/packages/snip721/src/handle.rs b/packages/snip721/src/handle.rs index 66fc8fc..48ca781 100644 --- a/packages/snip721/src/handle.rs +++ b/packages/snip721/src/handle.rs @@ -13,7 +13,7 @@ use secret_toolkit_utils::space_pad; // /// permission access level -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug)] #[serde(rename_all = "snake_case")] pub enum AccessLevel { /// approve permission only for the specified token @@ -32,7 +32,7 @@ pub enum AccessLevel { // /// token mint info used when doing a [`BatchMintNft`](HandleMsg::BatchMintNft) -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug)] pub struct Mint { /// optional token id. if omitted, use current token index pub token_id: Option, @@ -47,7 +47,7 @@ pub struct Mint { } /// token burn info used when doing a [`BatchBurnNft`](HandleMsg::BatchBurnNft) -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug)] pub struct Burn { /// tokens being burnt pub token_ids: Vec, @@ -56,7 +56,7 @@ pub struct Burn { } /// token transfer info used when doing a [`BatchTransferNft`](HandleMsg::BatchTransferNft) -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug)] pub struct Transfer { /// recipient of the transferred tokens pub recipient: String, @@ -67,7 +67,7 @@ pub struct Transfer { } /// send token info used when doing a [`BatchSendNft`](HandleMsg::BatchSendNft) -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug)] pub struct Send { /// recipient of the sent tokens pub contract: String, @@ -80,7 +80,7 @@ pub struct Send { } /// SNIP-721 contract handle messages -#[derive(Serialize, Clone, Debug, PartialEq)] +#[derive(Serialize, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub enum HandleMsg { // diff --git a/packages/snip721/src/metadata.rs b/packages/snip721/src/metadata.rs index 3dc2ce9..59a53bd 100644 --- a/packages/snip721/src/metadata.rs +++ b/packages/snip721/src/metadata.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; // /// token metadata -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug, Default)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug, Default)] pub struct Metadata { /// optional uri for off-chain metadata. This should be prefixed with `http://`, `https://`, `ipfs://`, or /// `ar://`. Only use this if you are not using `extension` @@ -19,7 +19,7 @@ pub struct Metadata { /// https://docs.opensea.io/docs/metadata-standards and are the metadata fields that /// Stashh uses for robust NFT display. Urls should be prefixed with `http://`, `https://`, `ipfs://`, or /// `ar://` -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug, Default)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug, Default)] pub struct Extension { /// url to the image pub image: Option, @@ -49,7 +49,7 @@ pub struct Extension { } /// attribute trait -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug, Default)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug, Default)] pub struct Trait { /// indicates how a trait should be displayed pub display_type: Option, @@ -62,7 +62,7 @@ pub struct Trait { } /// media file -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug, Default)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug, Default)] pub struct MediaFile { /// file type /// Stashh currently uses: "image", "video", "audio", "text", "font", "application" @@ -76,7 +76,7 @@ pub struct MediaFile { } /// media file authentication -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug, Default)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug, Default)] pub struct Authentication { /// either a decryption key for encrypted files or a password for basic authentication pub key: Option, diff --git a/packages/snip721/src/query.rs b/packages/snip721/src/query.rs index fea5c1f..96d69ea 100644 --- a/packages/snip721/src/query.rs +++ b/packages/snip721/src/query.rs @@ -15,7 +15,7 @@ use secret_toolkit_utils::space_pad; // /// the address and viewing key making an authenticated query request -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct ViewerInfo { /// querying address pub address: String, @@ -30,7 +30,7 @@ pub struct ViewerInfo { /// [`ContractInfo`](QueryMsg::ContractInfo) response /// /// display the contract's name and symbol -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct ContractInfo { pub name: String, pub symbol: String, @@ -40,7 +40,7 @@ pub struct ContractInfo { /// /// display the number of tokens controlled by the contract. The token supply must /// either be public, or the querier must be authorized to view -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct NumTokens { pub count: u32, } @@ -53,14 +53,14 @@ pub struct NumTokens { /// * Tokens: /// displays a list of all the tokens belonging to the input owner in which the viewer /// has view_owner permission -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct TokenList { /// list of token IDs pub tokens: Vec, } /// CW-721 Approval -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct Cw721Approval { /// address that can transfer the token pub spender: String, @@ -74,7 +74,7 @@ pub struct Cw721Approval { /// is also the token's owner, the response will also include a list of any addresses /// that can transfer this token. The transfer approval list is for CW721 compliance, /// but the [`NftDossier`](QueryMsg::NftDossier) query will be more complete by showing viewing approvals as well -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct OwnerOf { /// Owner of the token if permitted to view it pub owner: Option, @@ -85,7 +85,7 @@ pub struct OwnerOf { /// response of [`AllNftInfo`](QueryMsg::AllNftInfo) /// /// displays all the information contained in the [`OwnerOf`](QueryMsg::OwnerOf) and [`NftInfo`](QueryMsg::NftInfo) queries -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct AllNftInfo { /// OwnerOf response pub access: OwnerOf, @@ -94,7 +94,7 @@ pub struct AllNftInfo { } /// SNIP721 Approval -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct Snip721Approval { /// whitelisted address pub address: String, @@ -111,7 +111,7 @@ pub struct Snip721Approval { /// displays all the information about a token that the viewer has permission to /// see. This may include the owner, the public metadata, the private metadata, and /// the token and inventory approvals -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct NftDossier { /// owner of the token if permitted to view it pub owner: Option, @@ -140,7 +140,7 @@ pub struct NftDossier { /// /// list all the [`Approvals`](Snip721Approval) in place for a specified token if given the owner's viewing /// key -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct TokenApprovals { /// true if the owner is publicly viewable pub owner_is_public: bool, @@ -160,7 +160,7 @@ pub struct TokenApprovals { /// approval to transfer all of the owner's tokens). This query is provided to maintain /// CW-721 compliance, however, approvals are private on secret network, so only the /// owner's viewing key will authorize the ability to see the list of operators -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct ApprovedForAll { pub operators: Vec, } @@ -169,7 +169,7 @@ pub struct ApprovedForAll { /// /// list all the inventory-wide [`Approvals`](Snip721Approval) in place for the specified address if given the /// the correct viewing key for the address -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct InventoryApprovals { /// true if the owner is publicly viewable pub owner_is_public: bool, @@ -184,7 +184,7 @@ pub struct InventoryApprovals { } /// tx type and specifics -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug)] #[serde(rename_all = "snake_case")] pub enum TxAction { /// transferred token ownership @@ -213,7 +213,7 @@ pub enum TxAction { } /// tx for display -#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq, Debug)] #[serde(rename_all = "snake_case")] pub struct Tx { /// tx id @@ -234,7 +234,7 @@ pub struct Tx { /// /// display the transaction history for the specified address in reverse /// chronological order -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct TransactionHistory { /// total transaction count pub total: u64, @@ -249,7 +249,7 @@ pub struct TransactionHistory { /// response of [`Minters`](QueryMsg::Minters) /// /// display the list of authorized minters -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct Minters { pub minters: Vec, } @@ -257,7 +257,7 @@ pub struct Minters { /// response of [`IsUnwrapped`](QueryMsg::IsUnwrapped) /// /// display if a token is unwrapped -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IsUnwrapped { pub token_is_unwrapped: bool, } @@ -265,7 +265,7 @@ pub struct IsUnwrapped { /// response of [`VerifyTransferApproval`](QueryMsg::VerifyTransferApproval) /// /// verify that the specified address has approval to transfer every listed token -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct VerifyTransferApproval { /// true if `address` has transfer approval for all tokens in the list pub approved_for_all: bool, @@ -274,7 +274,7 @@ pub struct VerifyTransferApproval { } /// SNIP-721 queries -#[derive(Serialize, Clone, Debug, PartialEq)] +#[derive(Serialize, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { // diff --git a/packages/utils/src/feature_toggle.rs b/packages/utils/src/feature_toggle.rs index 5ee85cc..82bab57 100644 --- a/packages/utils/src/feature_toggle.rs +++ b/packages/utils/src/feature_toggle.rs @@ -187,7 +187,7 @@ pub trait FeatureToggleTrait { } } -#[derive(Serialize, Debug, Deserialize, Clone, JsonSchema, PartialEq)] +#[derive(Serialize, Debug, Deserialize, Clone, JsonSchema, PartialEq, Eq)] pub enum Status { NotPaused, Paused, @@ -199,7 +199,7 @@ impl Default for Status { } } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum FeatureToggleHandleMsg { #[serde(bound = "")] @@ -234,7 +234,7 @@ enum HandleAnswer { RemovePauser { status: ResponseStatus }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum FeatureToggleQueryMsg { #[serde(bound = "")] diff --git a/packages/utils/src/types.rs b/packages/utils/src/types.rs index 2a0286e..2870025 100644 --- a/packages/utils/src/types.rs +++ b/packages/utils/src/types.rs @@ -13,7 +13,7 @@ pub struct WasmCode { pub hash: String, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum Token { Snip20(Contract), From f79badb6e428612064b2dc5cd9759a57709baf2c Mon Sep 17 00:00:00 2001 From: elad Date: Mon, 5 Sep 2022 19:04:16 +0300 Subject: [PATCH 30/37] CI: Make cargo clippy fail on warnings | Added more Eq --- .github/workflows/Static.yml | 2 +- packages/incubator/src/generational_store.rs | 2 +- packages/permit/src/structs.rs | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/Static.yml b/.github/workflows/Static.yml index 00aad69..c191f82 100644 --- a/.github/workflows/Static.yml +++ b/.github/workflows/Static.yml @@ -13,7 +13,7 @@ jobs: rust: [stable] make: - name: Clippy - task: "cargo clippy --all --all-features" + task: "cargo clippy --all --all-features -- -D warnings" - name: Unit tests task: "cargo test --all --all-features" include: diff --git a/packages/incubator/src/generational_store.rs b/packages/incubator/src/generational_store.rs index cc8bc95..6d1ae84 100644 --- a/packages/incubator/src/generational_store.rs +++ b/packages/incubator/src/generational_store.rs @@ -62,7 +62,7 @@ impl Index { } } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub enum Entry { Free { next_free: u32 }, Occupied { generation: u64, value: T }, diff --git a/packages/permit/src/structs.rs b/packages/permit/src/structs.rs index 2cfbb2a..9c03c41 100644 --- a/packages/permit/src/structs.rs +++ b/packages/permit/src/structs.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use crate::pubkey_to_account; use cosmwasm_std::{Binary, CanonicalAddr, Uint128}; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct Permit { #[serde(bound = "")] @@ -24,7 +24,7 @@ impl Permit { } } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct PermitParams { pub allowed_tokens: Vec, @@ -34,14 +34,14 @@ pub struct PermitParams { pub permissions: Vec, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct PermitSignature { pub pub_key: PubKey, pub signature: Binary, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct PubKey { /// ignored, but must be "tendermint/PubKeySecp256k1" otherwise the verification will fail @@ -58,7 +58,7 @@ impl PubKey { // Note: The order of fields in this struct is important for the permit signature verification! #[remain::sorted] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct SignedPermit { /// ignored @@ -91,7 +91,7 @@ impl SignedPermit { // Note: The order of fields in this struct is important for the permit signature verification! #[remain::sorted] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct Fee { pub amount: Vec, @@ -115,7 +115,7 @@ impl Default for Fee { // Note: The order of fields in this struct is important for the permit signature verification! #[remain::sorted] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct Coin { pub amount: Uint128, @@ -139,7 +139,7 @@ impl Default for Coin { // Note: The order of fields in this struct is important for the permit signature verification! #[remain::sorted] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct PermitMsg { pub r#type: String, @@ -158,7 +158,7 @@ impl PermitMsg { // Note: The order of fields in this struct is important for the permit signature verification! #[remain::sorted] -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub struct PermitContent { pub allowed_tokens: Vec, @@ -190,7 +190,7 @@ impl Permissions for T where { } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum TokenPermissions { /// Allowance for SNIP-20 - Permission to query allowance of the owner & spender From 1101272ee353a18ba93a3827dc72d3e57b60e1f8 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Tue, 6 Sep 2022 01:19:41 +0300 Subject: [PATCH 31/37] dev 0.5 update for cosmwasm v1.0 branch --- Releases.md | 121 +++++++++++++++------------ packages/snip20/src/query.rs | 1 + packages/storage/Cargo.toml | 2 +- packages/storage/Readme.md | 8 +- packages/storage/src/append_store.rs | 33 ++++---- packages/storage/src/deque_store.rs | 42 ++++++---- packages/storage/src/item.rs | 23 ++--- packages/storage/src/keymap.rs | 45 +++++----- packages/toolkit/Cargo.toml | 4 +- 9 files changed, 148 insertions(+), 131 deletions(-) diff --git a/Releases.md b/Releases.md index a03ca2a..70829f7 100644 --- a/Releases.md +++ b/Releases.md @@ -1,8 +1,23 @@ # Release notes for the Secret Toolkit +## v0.5.0 + +This release includes some minor fixed to the storage package which required some breaking changes. +We are releasing these breaking changes because we reached the conclusion that the current interfaces +are prone to bugs, or inefficient. Unless you are using these specific interfaces, you should be able to upgrade from 0.4 without issues. + +### Breaking + +- Removed the implementations of Clone for storage types which are not useful and may cause data corruption if used incorrectly. +- Changed `Keymap::insert` to take the item by reference rather than by value. This should reduce the cost of calling that function by avoiding cloning. + +### Features + +- Changed the implementation of the `add_prefix` methods in the storage package to use length prefixing, which should help avoid namespace collisions. + ## secret-toolkit-storage v0.4.1 -* BUGFIX: `Item::is_empty` was returning the opposite value from what you'd expect. +- BUGFIX: `Item::is_empty` was returning the opposite value from what you'd expect. ## v0.4.0 @@ -13,105 +28,105 @@ to use. It also removes the `Cashmap` type from the incubator in favor of `KeyMa This is a summary of the changes and additions in this release: -* Minimum Rust version is bumped to the latest v1.63. This is because we want to use `Mutex::new` in a `const fn`. -* No more distinction between `Readonly*` and `*Mut` types. Instead, methods take references or mutable references to the storage every time. -* Usage of `PrefixedStore` is made mostly unnecessary. -* Storage type's constructors are const functions, which means they can be initialized as global static variables. -* Added `secret-toolkit::storage::Item` which is similar to `Item` from `cw-storage-plus` or `TypedStore` from `cosmwasm_storage` v0.10. -* Added `secret-toolkit::storage::KeyMap` which is similar to `Cashmap`. -* `Cashmap` is completely removed. +- Minimum Rust version is bumped to the latest v1.63. This is because we want to use `Mutex::new` in a `const fn`. +- No more distinction between `Readonly*` and `*Mut` types. Instead, methods take references or mutable references to the storage every time. +- Usage of `PrefixedStore` is made mostly unnecessary. +- Storage type's constructors are const functions, which means they can be initialized as global static variables. +- Added `secret-toolkit::storage::Item` which is similar to `Item` from `cw-storage-plus` or `TypedStore` from `cosmwasm_storage` v0.10. +- Added `secret-toolkit::storage::KeyMap` which is similar to `Cashmap`. +- `Cashmap` is completely removed. A full guide to using the new `storage` types can be found [in the package's readme file](https://github.com/srdtrk/secret-toolkit/blob/3725530aebe149d14f7f3f1662844340eb27e015/packages/storage/Readme.md). ## secret-toolkit-incubator v0.3.1 -* Fixed compilation issue with Rust v1.61 (#46, #48) -* Removed Siphasher dependency (#46, #48) +- Fixed compilation issue with Rust v1.61 (#46, #48) +- Removed Siphasher dependency (#46, #48) ## secret-toolkit-utils v0.3.1 ### Security -* BUGFIX: `secret-toolkit::utils::FeatureToggle::handle_pause` had an inverse authorization check: only non-pausers +- BUGFIX: `secret-toolkit::utils::FeatureToggle::handle_pause` had an inverse authorization check: only non-pausers could pause features. ## secret-toolkit-permit v0.3.1 -* Removed the `ecc-secp256k1` feature from `secret-toolkit-crypto` dependency of `secret-toolkit-permit`. - * This tiny change significantly reduces the size of binaries that only use the permit feature. +- Removed the `ecc-secp256k1` feature from `secret-toolkit-crypto` dependency of `secret-toolkit-permit`. + - This tiny change significantly reduces the size of binaries that only use the permit feature. ## v0.3.0 -* Added `clear` method to `AppendStore` and `DequeStore` to quickly reset the collections (#34) -* docs.rs documentation now includes all sub-crates. -* BUGFIX: `secret-toolkit::snip721::Metadata` was severely out of date with the SNIP-721 specification, and not useful. +- Added `clear` method to `AppendStore` and `DequeStore` to quickly reset the collections (#34) +- docs.rs documentation now includes all sub-crates. +- BUGFIX: `secret-toolkit::snip721::Metadata` was severely out of date with the SNIP-721 specification, and not useful. It is now compatible with deployed SNIP-721 contracts. -* Added `types` module under the `util` package, to standardize often used types. -* Added `secret-toolkit::viewing_key`, which can be imported by enabling the `viewing-key` feature. -* Added `secret-toolkit::permit::PubKey::canonical_address()`. -* Types in `secret-toolkit::permit::Permit` are now generic over the type of permissions they accept. -* Added the `maxheap` type to the incubator. -* Added `secret-toolkit::utils::feature_toggle` which allow managing feature flags in your contract. +- Added `types` module under the `util` package, to standardize often used types. +- Added `secret-toolkit::viewing_key`, which can be imported by enabling the `viewing-key` feature. +- Added `secret-toolkit::permit::PubKey::canonical_address()`. +- Types in `secret-toolkit::permit::Permit` are now generic over the type of permissions they accept. +- Added the `maxheap` type to the incubator. +- Added `secret-toolkit::utils::feature_toggle` which allow managing feature flags in your contract. ### Breaking -* `secret-toolkit::permit::validate()` Now supports validating any type of Cosmos address. +- `secret-toolkit::permit::validate()` Now supports validating any type of Cosmos address. Interface changes: Now takes a reference to the current token address instead of taking it by value and an optional hrp string. In addition, it returns a String and not HumanAddr. -* Renamed `secret-toolkit::permit::Permission` to `secret-toolkit::permit::TokenPermission`. -* `secret-toolkit-crypto` now has features `["hash", "rng" and "ecc-secp256k1"]` which are all off by default - enable those you need. -* `secret-toolkit-crypto::secp256k1::PublicKey::parse` now returns `StdResult`. -* Changes to `secret-toolkit::crypto::secp256k1::PrivateKey::sign`: - * The `data` argument is now any slice of bytes, and not the hash of a slice of data. - * the `Api` from `deps.api` is now required as the second argument as we now use the precompiled implementation. -* Changes to `secret-toolkit::crypto::secp256k1::PublicKey::verify`: - * the `Api` from `deps.api` is now required as the third argument as we now use the precompiled implementation. -* `secret-toolkit-incubator` now has features `["cashmap", "generational-store"]` which are all off by default. +- Renamed `secret-toolkit::permit::Permission` to `secret-toolkit::permit::TokenPermission`. +- `secret-toolkit-crypto` now has features `["hash", "rng" and "ecc-secp256k1"]` which are all off by default - enable those you need. +- `secret-toolkit-crypto::secp256k1::PublicKey::parse` now returns `StdResult`. +- Changes to `secret-toolkit::crypto::secp256k1::PrivateKey::sign`: + - The `data` argument is now any slice of bytes, and not the hash of a slice of data. + - the `Api` from `deps.api` is now required as the second argument as we now use the precompiled implementation. +- Changes to `secret-toolkit::crypto::secp256k1::PublicKey::verify`: + - the `Api` from `deps.api` is now required as the third argument as we now use the precompiled implementation. +- `secret-toolkit-incubator` now has features `["cashmap", "generational-store"]` which are all off by default. ## v0.2.0 This release includes a ton of new features, and a few breaking changes in various interfaces. This version is also the first released to [crates.io](https://crates.io)! -* Change: when a query fails because of a bad viewing key, this now correctly fails with `StdError::Unauthorized` -* Added support for some missing SNIP-20 functionality, such as `CreateViewingKey` -* Added support for SNIP-21 queries (memos and improved history) which broke some interfaces -* Added support for SNIP-22 messages (batch operations) -* Added support for SNIP-23 messages (improved Send operations) which broke some interfaces -* Added support for SNIP-24 permits -* Added `Base64Of`, `Base64JsonOf`, and `Base64Bincode2Of`, +- Change: when a query fails because of a bad viewing key, this now correctly fails with `StdError::Unauthorized` +- Added support for some missing SNIP-20 functionality, such as `CreateViewingKey` +- Added support for SNIP-21 queries (memos and improved history) which broke some interfaces +- Added support for SNIP-22 messages (batch operations) +- Added support for SNIP-23 messages (improved Send operations) which broke some interfaces +- Added support for SNIP-24 permits +- Added `Base64Of`, `Base64JsonOf`, and `Base64Bincode2Of`, which are wrappers that automatically deserializes base64 strings to `T`. It can be used in message types' fields instead of `Binary` when the contents of the string should have more specific contents. -* Added `storage::DequeStore` - Similar to `AppendStore` but allows pushing and popping on both ends -* Added the `secret-toolkit::incubator` package intended for experimental features. It contains: - * `CashMap` - A hashmap like storage abstraction - * `GenerationalIndex` - A generational index storage abstraction -* The various subpackages can now be selected using feature flags. The default flags are `["serialization", "snip20", "snip721", "storage", "utils"]` +- Added `storage::DequeStore` - Similar to `AppendStore` but allows pushing and popping on both ends +- Added the `secret-toolkit::incubator` package intended for experimental features. It contains: + - `CashMap` - A hashmap like storage abstraction + - `GenerationalIndex` - A generational index storage abstraction +- The various subpackages can now be selected using feature flags. The default flags are `["serialization", "snip20", "snip721", "storage", "utils"]` while `["crypto", "permit", "incubator"]` are left disabled by default. ## v0.1.1 -* Removed unused dev-dependency that was slowing down test compilation times. +- Removed unused dev-dependency that was slowing down test compilation times. ## v0.1.0 This is the first release of `secret-toolkit`. It supports: -* `secret-toolkit::snip20` - Helper types and functions for interaction with +- `secret-toolkit::snip20` - Helper types and functions for interaction with SNIP-20 contracts. -* `secret-toolkit::snip721` - Helper types and functions for interaction with +- `secret-toolkit::snip721` - Helper types and functions for interaction with SNIP-721 contracts. -* `secret-toolkit::crypto` - Wrappers for known-to-work crypto primitives from +- `secret-toolkit::crypto` - Wrappers for known-to-work crypto primitives from ecosystem libraries. We include implementations for Sha256, Secp256k1 keys, and ChaChaRng. -* `secret-toolkit::storage` - Types implementing useful storage managements +- `secret-toolkit::storage` - Types implementing useful storage managements techniques: `AppendStore` and `TypedStore`, using `bincode2` by default. -* `secret-toolkit::serialization` - marker types for overriding the storage +- `secret-toolkit::serialization` - marker types for overriding the storage format used by types in `secret-toolkit::storage`. `Json` and `Bincode2`. -* `secret-toolkit::utils` - General utilities for writing contract code. - * `padding` - tools for padding queries and responses. - * `calls` - Tools for marking types as messages in queries and callbacks +- `secret-toolkit::utils` - General utilities for writing contract code. + - `padding` - tools for padding queries and responses. + - `calls` - Tools for marking types as messages in queries and callbacks to other contracts. diff --git a/packages/snip20/src/query.rs b/packages/snip20/src/query.rs index 8ac86ce..1e26099 100644 --- a/packages/snip20/src/query.rs +++ b/packages/snip20/src/query.rs @@ -242,6 +242,7 @@ pub enum AuthenticatedQueryResponse { msg: String, }, } + /// wrapper to deserialize TokenInfo response #[derive(Deserialize)] pub struct TokenInfoResponse { diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index 50c64d4..a9eda29 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-storage" -version = "0.4.1" +version = "0.5.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" diff --git a/packages/storage/Readme.md b/packages/storage/Readme.md index aea5af9..e27c9ec 100644 --- a/packages/storage/Readme.md +++ b/packages/storage/Readme.md @@ -1,6 +1,6 @@ # Secret Contract Development Toolkit - Storage Tools -⚠️ This package is a cw v1.0 fork of the `secret-toolkit` package. Please see its crate page for more context. You need Rust 1.63+ to compile this package. +⚠️ This is a sub-package of the `secret-toolkit` package. Please see its crate page for more context. You need Rust 1.63+ to compile this package. This package contains many tools related to storage access patterns. This readme file assumes basic familiarity with basic cosmwasm storage, [click here to learn about this](https://docs.scrt.network/secret-network-documentation/development/secret-contracts/storage). @@ -9,13 +9,13 @@ This package contains many tools related to storage access patterns. This readme To import this package, add one of the following lines to your `Cargo.toml` file ```toml -secret-toolkit = { version = "0.4", default-features = false, features = ["utils", "storage", "serialization"] } +secret-toolkit = { version = "0.5", default-features = false, features = ["utils", "storage", "serialization"] } ``` for the release versions (when it is updated to cosmwasm 1.0), or ```toml -secret-toolkit = { git = "https://github.com/scrtlabs/secret-toolkit", branch = "cosmwasm-v1.0", default-features = false, features = ["utils", "storage", "serialization"]} +secret-toolkit = { git = "https://github.com/scrtlabs/secret-toolkit", branch = "master", default-features = false, features = ["utils", "storage", "serialization"]} ``` for the github version. We also import the `serialization` feature in case we want to switch to using Json instead of Bincode2 to serialize/deserialize data. @@ -40,7 +40,7 @@ And initialize it using the following lines: pub static OWNER: Item = Item::new(b"owner"); ``` -This uses Bincode2 to serde HumanAddr by default. To specify the Serde algorithm as Json, first import it from `secret-toolkit-serialization` +This uses Bincode2 to serde HumanAddr by default. To specify the Serde algorithm as Json, first import it from `secret-toolkit::serialization` ```ignore use secret_toolkit::serialization::{Bincode2, Json}; diff --git a/packages/storage/src/append_store.rs b/packages/storage/src/append_store.rs index 0087465..89bd287 100644 --- a/packages/storage/src/append_store.rs +++ b/packages/storage/src/append_store.rs @@ -11,6 +11,7 @@ use std::sync::Mutex; use serde::{de::DeserializeOwned, Serialize}; use cosmwasm_std::{StdError, StdResult, Storage}; +use cosmwasm_storage::to_length_prefixed; use secret_toolkit_serialization::{Bincode2, Serde}; @@ -41,14 +42,13 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { serialization_type: PhantomData, } } + /// This is used to produce a new AppendListStorage. This can be used when you want to associate an AppendListStorage to each user /// and you still get to define the AppendListStorage as a static constant pub fn add_suffix(&self, suffix: &[u8]) -> Self { - let prefix = if let Some(prefix) = &self.prefix { - [prefix.clone(), suffix.to_vec()].concat() - } else { - [self.namespace.to_vec(), suffix.to_vec()].concat() - }; + let suffix = to_length_prefixed(suffix); + let prefix = self.prefix.as_deref().unwrap_or(self.namespace); + let prefix = [prefix, suffix.as_slice()].concat(); Self { namespace: self.namespace, prefix: Some(prefix), @@ -82,10 +82,12 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { } } } + /// checks if the collection has any elements pub fn is_empty(&self, storage: &dyn Storage) -> StdResult { Ok(self.get_len(storage)? == 0) } + /// gets the element at pos if within bounds pub fn get_at(&self, storage: &dyn Storage, pos: u32) -> StdResult { let len = self.get_len(storage)?; @@ -94,6 +96,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { } self.get_at_unchecked(storage, pos) } + /// tries to get the element at pos fn get_at_unchecked(&self, storage: &dyn Storage, pos: u32) -> StdResult { let key = pos.to_be_bytes(); @@ -108,10 +111,12 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { let mut may_len = self.length.lock().unwrap(); *may_len = Some(len); } + /// Clear the collection pub fn clear(&self, storage: &mut dyn Storage) { self.set_len(storage, 0); } + /// Replaces data at a position within bounds pub fn set_at(&self, storage: &mut dyn Storage, pos: u32, item: &T) -> StdResult<()> { let len = self.get_len(storage)?; @@ -120,10 +125,12 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { } self.set_at_unchecked(storage, pos, item) } + /// Sets data at a given index fn set_at_unchecked(&self, storage: &mut dyn Storage, pos: u32, item: &T) -> StdResult<()> { self.save_impl(storage, &pos.to_be_bytes(), item) } + /// Pushes an item to AppendStorage pub fn push(&self, storage: &mut dyn Storage, item: &T) -> StdResult<()> { let len = self.get_len(storage)?; @@ -131,6 +138,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { self.set_len(storage, len + 1); Ok(()) } + /// Pops an item from AppendStore pub fn pop(&self, storage: &mut dyn Storage) -> StdResult { if let Some(len) = self.get_len(storage)?.checked_sub(1) { @@ -141,6 +149,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { Err(StdError::generic_err("Can not pop from empty AppendStore")) } } + /// Remove an element from the collection at the specified position. /// /// Removing the last element has a constant cost. @@ -164,12 +173,14 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { self.set_len(storage, len - 1); item } + /// Returns a readonly iterator pub fn iter(&self, storage: &'a dyn Storage) -> StdResult> { let len = self.get_len(storage)?; let iter = AppendStoreIter::new(self, storage, 0, len); Ok(iter) } + /// does paging with the given parameters pub fn paging(&self, storage: &dyn Storage, start_page: u32, size: u32) -> StdResult> { self.iter(storage)? @@ -179,18 +190,6 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { } } -impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for AppendStore<'a, T, Ser> { - fn clone(&self) -> Self { - Self { - namespace: self.namespace, - prefix: self.prefix.clone(), - length: Mutex::new(None), - item_type: PhantomData, - serialization_type: PhantomData, - } - } -} - impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> { fn as_slice(&self) -> &[u8] { if let Some(prefix) = &self.prefix { diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 86c0a02..5e917ad 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -12,6 +12,7 @@ use std::sync::Mutex; use serde::{de::DeserializeOwned, Serialize}; use cosmwasm_std::{StdError, StdResult, Storage}; +use cosmwasm_storage::to_length_prefixed; use secret_toolkit_serialization::{Bincode2, Serde}; @@ -45,14 +46,13 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { serialization_type: PhantomData, } } + /// This is used to produce a new DequeStorage. This can be used when you want to associate an AppendListStorage to each user /// and you still get to define the DequeStorage as a static constant pub fn add_suffix(&self, suffix: &[u8]) -> Self { - let prefix = if let Some(prefix) = &self.prefix { - [prefix.clone(), suffix.to_vec()].concat() - } else { - [self.namespace.to_vec(), suffix.to_vec()].concat() - }; + let suffix = to_length_prefixed(suffix); + let prefix = self.prefix.as_deref().unwrap_or(self.namespace); + let prefix = [prefix, suffix.as_slice()].concat(); Self { namespace: self.namespace, prefix: Some(prefix), @@ -79,6 +79,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { }, } } + /// gets the offset from storage, and otherwise sets it to 0 pub fn get_off(&self, storage: &dyn Storage) -> StdResult { let mut may_off = self.offset.lock().unwrap(); @@ -93,6 +94,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { }, } } + /// gets offset or length fn _get_u32(&self, storage: &dyn Storage, key: &[u8]) -> StdResult { let num_key = [self.as_slice(), key].concat(); @@ -107,10 +109,12 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { Ok(0) } } + /// checks if the collection has any elements pub fn is_empty(&self, storage: &dyn Storage) -> StdResult { Ok(self.get_len(storage)? == 0) } + /// gets the element at pos if within bounds pub fn get_at(&self, storage: &dyn Storage, pos: u32) -> StdResult { let len = self.get_len(storage)?; @@ -119,37 +123,44 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } self.get_at_unchecked(storage, pos) } + /// tries to get the element at pos fn get_at_unchecked(&self, storage: &dyn Storage, pos: u32) -> StdResult { self.load_impl(storage, &self._get_offset_pos(storage, pos)?.to_be_bytes()) } + /// add the offset to the pos fn _get_offset_pos(&self, storage: &dyn Storage, pos: u32) -> StdResult { let off = self.get_off(storage)?; Ok(pos.overflowing_add(off).0) } + /// Set the length of the collection fn set_len(&self, storage: &mut dyn Storage, len: u32) { let mut may_len = self.length.lock().unwrap(); *may_len = Some(len); self._set_u32(storage, LEN_KEY, len) } + /// Set the offset of the collection fn set_off(&self, storage: &mut dyn Storage, off: u32) { let mut may_off = self.offset.lock().unwrap(); *may_off = Some(off); self._set_u32(storage, OFFSET_KEY, off) } + /// Set the length or offset of the collection fn _set_u32(&self, storage: &mut dyn Storage, key: &[u8], num: u32) { let num_key = [self.as_slice(), key].concat(); storage.set(&num_key, &num.to_be_bytes()); } + /// Clear the collection pub fn clear(&self, storage: &mut dyn Storage) { self.set_len(storage, 0); self.set_off(storage, 0); } + /// Replaces data at a position within bounds pub fn set_at(&self, storage: &mut dyn Storage, pos: u32, item: &T) -> StdResult<()> { let len = self.get_len(storage)?; @@ -158,11 +169,13 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } self.set_at_unchecked(storage, pos, item) } + /// Sets data at a given index fn set_at_unchecked(&self, storage: &mut dyn Storage, pos: u32, item: &T) -> StdResult<()> { let get_offset_pos = self._get_offset_pos(storage, pos)?; self.save_impl(storage, &get_offset_pos.to_be_bytes(), item) } + /// Pushes an item to the back pub fn push_back(&self, storage: &mut dyn Storage, item: &T) -> StdResult<()> { let len = self.get_len(storage)?; @@ -170,6 +183,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { self.set_len(storage, len + 1); Ok(()) } + /// Pushes an item to the front pub fn push_front(&self, storage: &mut dyn Storage, item: &T) -> StdResult<()> { let off = self.get_off(storage)?; @@ -179,6 +193,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { self.set_len(storage, len + 1); Ok(()) } + /// Pops an item from the back pub fn pop_back(&self, storage: &mut dyn Storage) -> StdResult { if let Some(len) = self.get_len(storage)?.checked_sub(1) { @@ -189,6 +204,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { Err(StdError::generic_err("Can not pop from empty DequeStore")) } } + /// Pops an item from the front pub fn pop_front(&self, storage: &mut dyn Storage) -> StdResult { if let Some(len) = self.get_len(storage)?.checked_sub(1) { @@ -201,6 +217,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { Err(StdError::generic_err("Can not pop from empty DequeStore")) } } + /// Remove an element from the collection at the specified position. /// /// Removing an element from the head (first) or tail (last) has a constant cost. @@ -235,12 +252,14 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { self.set_len(storage, len - 1); item } + /// Returns a readonly iterator pub fn iter(&self, storage: &'a dyn Storage) -> StdResult> { let len = self.get_len(storage)?; let iter = DequeStoreIter::new(self, storage, 0, len); Ok(iter) } + /// does paging with the given parameters pub fn paging(&self, storage: &dyn Storage, start_page: u32, size: u32) -> StdResult> { self.iter(storage)? @@ -289,19 +308,6 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } } -impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for DequeStore<'a, T, Ser> { - fn clone(&self) -> Self { - Self { - namespace: self.namespace, - prefix: self.prefix.clone(), - length: Mutex::new(None), - offset: Mutex::new(None), - item_type: PhantomData, - serialization_type: PhantomData, - } - } -} - /// An iterator over the contents of the deque store. pub struct DequeStoreIter<'a, T, Ser> where diff --git a/packages/storage/src/item.rs b/packages/storage/src/item.rs index fc45116..155debe 100644 --- a/packages/storage/src/item.rs +++ b/packages/storage/src/item.rs @@ -3,6 +3,8 @@ use std::any::type_name; use std::marker::PhantomData; use cosmwasm_std::{StdError, StdResult, Storage}; +use cosmwasm_storage::to_length_prefixed; + use secret_toolkit_serialization::{Bincode2, Serde}; use serde::{de::DeserializeOwned, Serialize}; @@ -20,6 +22,7 @@ where } impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Item<'a, T, Ser> { + /// constructor pub const fn new(key: &'a [u8]) -> Self { Self { storage_key: key, @@ -28,14 +31,13 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Item<'a, T, Ser> { serialization_type: PhantomData, } } + /// This is used to produce a new Item. This can be used when you want to associate an Item to each user /// and you still get to define the Item as a static constant pub fn add_suffix(&self, suffix: &[u8]) -> Self { - let prefix = if let Some(prefix) = &self.prefix { - [prefix.clone(), suffix.to_vec()].concat() - } else { - [self.storage_key.to_vec(), suffix.to_vec()].concat() - }; + let suffix = to_length_prefixed(suffix); + let prefix = self.prefix.as_deref().unwrap_or(self.storage_key); + let prefix = [prefix, suffix.as_slice()].concat(); Self { storage_key: self.storage_key, prefix: Some(prefix), @@ -147,17 +149,6 @@ where } } -impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for Item<'a, T, Ser> { - fn clone(&self) -> Self { - Self { - storage_key: self.storage_key, - prefix: self.prefix.clone(), - item_type: PhantomData, - serialization_type: PhantomData, - } - } -} - #[cfg(test)] mod tests { use cosmwasm_std::testing::MockStorage; diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs index d47bd1a..ebc809d 100644 --- a/packages/storage/src/keymap.rs +++ b/packages/storage/src/keymap.rs @@ -7,6 +7,7 @@ use serde::Deserialize; use serde::{de::DeserializeOwned, Serialize}; use cosmwasm_std::{StdError, StdResult, Storage}; +use cosmwasm_storage::to_length_prefixed; use secret_toolkit_serialization::{Bincode2, Serde}; @@ -40,6 +41,7 @@ impl InternalItem { serialization_type: PhantomData, }) } + fn get_item(&self) -> StdResult { Ser::deserialize(&self.item_vec) } @@ -75,14 +77,13 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: serialization_type: PhantomData, } } + /// This is used to produce a new Keymap. This can be used when you want to associate an Keymap to each user /// and you still get to define the Keymap as a static constant pub fn add_suffix(&self, suffix: &[u8]) -> Self { - let prefix = if let Some(prefix) = &self.prefix { - [prefix.clone(), suffix.to_vec()].concat() - } else { - [self.namespace.to_vec(), suffix.to_vec()].concat() - }; + let suffix = to_length_prefixed(suffix); + let prefix = self.prefix.as_deref().unwrap_or(self.namespace); + let prefix = [prefix, suffix.as_slice()].concat(); Self { namespace: self.namespace, prefix: Some(prefix), @@ -101,10 +102,12 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: fn serialize_key(&self, key: &K) -> StdResult> { Ser::serialize(key) } + /// Deserialize key fn deserialize_key(&self, key_data: &[u8]) -> StdResult { Ser::deserialize(key_data) } + /// get total number of objects saved pub fn get_len(&self, storage: &dyn Storage) -> StdResult { let mut may_len = self.length.lock().unwrap(); @@ -127,10 +130,12 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } } + /// checks if the collection has any elements pub fn is_empty(&self, storage: &dyn Storage) -> StdResult { Ok(self.get_len(storage)? == 0) } + /// set length of the map fn set_len(&self, storage: &mut dyn Storage, len: u32) -> StdResult<()> { let len_key = [self.as_slice(), MAP_LENGTH].concat(); @@ -141,6 +146,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Ok(()) } + /// Used to get the indexes stored in the given page number fn _get_indexes(&self, storage: &dyn Storage, page: u32) -> StdResult>> { let indexes_key = [self.as_slice(), INDEXES, page.to_be_bytes().as_slice()].concat(); @@ -150,6 +156,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: None => Ok(vec![]), } } + /// Set an indexes page fn _set_indexes_page( &self, @@ -161,6 +168,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: storage.set(&indexes_key, &Bincode2::serialize(indexes)?); Ok(()) } + /// user facing get function pub fn get(&self, storage: &dyn Storage, key: &K) -> Option { if let Ok(internal_item) = self._get_from_key(storage, key) { @@ -169,11 +177,13 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: None } } + /// internal item get function fn _get_from_key(&self, storage: &dyn Storage, key: &K) -> StdResult> { let key_vec = self.serialize_key(key)?; self.load_impl(storage, &key_vec) } + /// user facing remove function pub fn remove(&self, storage: &mut dyn Storage, key: &K) -> StdResult<()> { let key_vec = self.serialize_key(key)?; @@ -234,6 +244,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Ok(()) } + /// user facing insert function pub fn insert(&self, storage: &mut dyn Storage, key: &K, item: &T) -> StdResult<()> { let key_vec = self.serialize_key(key)?; @@ -258,6 +269,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } } + /// user facing method that checks if any item is stored with this key. pub fn contains(&self, storage: &dyn Storage, key: &K) -> bool { match self.serialize_key(key) { @@ -265,6 +277,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Err(_) => false, } } + /// paginates (key, item) pairs. pub fn paging( &self, @@ -290,6 +303,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } self.get_pairs_at_positions(storage, start_pos, end_pos) } + /// paginates only the keys. More efficient than paginating both items and keys pub fn paging_keys( &self, @@ -315,6 +329,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } self.get_keys_at_positions(storage, start_pos, end_pos) } + /// tries to list keys without checking start/end bounds fn get_keys_at_positions( &self, @@ -347,6 +362,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } Ok(res) } + /// tries to list (key, item) pairs without checking start/end bounds fn get_pairs_at_positions( &self, @@ -380,6 +396,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } Ok(res) } + /// gets a key from a specific position in indexes fn get_key_from_pos(&self, storage: &dyn Storage, pos: u32) -> StdResult { let page = _page_from_position(pos); @@ -388,6 +405,7 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: let key_vec = &indexes[index as usize]; self.deserialize_key(key_vec) } + /// gets a key from a specific position in indexes fn get_pair_from_pos(&self, storage: &dyn Storage, pos: u32) -> StdResult<(K, T)> { let page = _page_from_position(pos); @@ -398,12 +416,14 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: let item = self.load_impl(storage, key_vec)?.get_item()?; Ok((key, item)) } + /// Returns a readonly iterator only for keys. More efficient than iter(). pub fn iter_keys(&self, storage: &'a dyn Storage) -> StdResult> { let len = self.get_len(storage)?; let iter = KeyIter::new(self, storage, 0, len); Ok(iter) } + /// Returns a readonly iterator for (key-item) pairs pub fn iter(&self, storage: &'a dyn Storage) -> StdResult> { let len = self.get_len(storage)?; @@ -424,21 +444,6 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } } -impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> Clone - for Keymap<'a, K, T, Ser> -{ - fn clone(&self) -> Self { - Self { - namespace: self.namespace, - prefix: self.prefix.clone(), - length: Mutex::new(None), - key_type: PhantomData, - item_type: PhantomData, - serialization_type: PhantomData, - } - } -} - /// An iterator over the keys of the Keymap. pub struct KeyIter<'a, K, T, Ser> where diff --git a/packages/toolkit/Cargo.toml b/packages/toolkit/Cargo.toml index ae51848..db876bb 100644 --- a/packages/toolkit/Cargo.toml +++ b/packages/toolkit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit" -version = "0.4.0" +version = "0.5.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -33,6 +33,6 @@ secret-toolkit-permit = { version = "0.3.0", path = "../permit", optional = true secret-toolkit-serialization = { version = "0.3", path = "../serialization", optional = true } secret-toolkit-snip20 = { version = "0.3", path = "../snip20", optional = true } secret-toolkit-snip721 = { version = "0.3", path = "../snip721", optional = true } -secret-toolkit-storage = { version = "0.4", path = "../storage", optional = true } +secret-toolkit-storage = { version = "0.5", path = "../storage", optional = true } secret-toolkit-utils = { version = "0.3", path = "../utils", optional = true } secret-toolkit-viewing-key = { version = "0.3", path = "../viewing_key", optional = true } From 99c2ee6e2599a837fbdd90436224d01cc48ea8d4 Mon Sep 17 00:00:00 2001 From: eladr7 Date: Tue, 13 Sep 2022 12:02:16 +0300 Subject: [PATCH 32/37] Fixed bug of revoke_permit() created by setting an empty value for the revoked permit key --- packages/permit/src/state.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/permit/src/state.rs b/packages/permit/src/state.rs index cd35daf..02ff3e3 100644 --- a/packages/permit/src/state.rs +++ b/packages/permit/src/state.rs @@ -22,6 +22,8 @@ impl RevokedPermits { ) { let storage_key = storage_prefix.to_string() + account + permit_name; - storage.set(storage_key.as_bytes(), &[]) + // Since cosmwasm V1.0 it's not possible to set an empty value, hence set some unimportant + // character '_' + storage.set(storage_key.as_bytes(), "_".as_bytes()) } } From 8380c00d4abb4585e02ba2d2bab8194aff52743e Mon Sep 17 00:00:00 2001 From: eladr7 Date: Tue, 13 Sep 2022 12:41:36 +0300 Subject: [PATCH 33/37] Added a reference to the commit where the panicing line was added --- packages/permit/src/state.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/permit/src/state.rs b/packages/permit/src/state.rs index 02ff3e3..9a47e93 100644 --- a/packages/permit/src/state.rs +++ b/packages/permit/src/state.rs @@ -24,6 +24,9 @@ impl RevokedPermits { // Since cosmwasm V1.0 it's not possible to set an empty value, hence set some unimportant // character '_' + // + // Here is the line of the new panic that was added when trying to insert an empty value: + // https://github.com/scrtlabs/cosmwasm/blob/f7e2b1dbf11e113e258d796288752503a5012367/packages/std/src/storage.rs#L30 storage.set(storage_key.as_bytes(), "_".as_bytes()) } } From 39823b3f358111e89d0c640e1c66657ffdcbcd39 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Tue, 25 Oct 2022 16:21:49 +0300 Subject: [PATCH 34/37] Update cosmwasm versions to the crates.io ones --- packages/crypto/Cargo.toml | 4 ++-- packages/incubator/Cargo.toml | 4 ++-- packages/permit/Cargo.toml | 7 ++++--- packages/serialization/Cargo.toml | 2 +- packages/snip20/Cargo.toml | 2 +- packages/snip721/Cargo.toml | 2 +- packages/storage/Cargo.toml | 4 ++-- packages/utils/Cargo.toml | 4 ++-- packages/viewing_key/Cargo.toml | 9 ++++++--- 9 files changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index f56fec8..f72f16f 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -23,10 +23,10 @@ rand_chacha = { version = "0.2.2", default-features = false, optional = true } rand_core = { version = "0.5.1", default-features = false, optional = true } sha2 = { version = "0.9.1", default-features = false, optional = true } secp256k1 = { version = "0.21.3", optional = true } -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } [dev-dependencies] secp256k1-test = { package = "secp256k1", version = "0.17", features = [ "rand-std", - "recovery" + "recovery", ] } diff --git a/packages/incubator/Cargo.toml b/packages/incubator/Cargo.toml index 2338c42..01091f8 100644 --- a/packages/incubator/Cargo.toml +++ b/packages/incubator/Cargo.toml @@ -15,8 +15,8 @@ all-features = true [dependencies] serde = { version = "1.0", optional = true } -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret", optional = true } -cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret", optional = true } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0", optional = true } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "1.0.0", optional = true } secret-toolkit-serialization = { version = "0.3", path = "../serialization", optional = true } [features] diff --git a/packages/permit/Cargo.toml b/packages/permit/Cargo.toml index 01e077a..579d4f2 100644 --- a/packages/permit/Cargo.toml +++ b/packages/permit/Cargo.toml @@ -14,11 +14,12 @@ keywords = ["secret-network", "secret-contracts", "secret-toolkit"] all-features = true [dependencies] -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } - +cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } serde = "1.0" ripemd160 = { version = "0.9.1", default-features = false } schemars = "0.8.1" bech32 = "0.8.1" remain = "0.2.2" -secret-toolkit-crypto = { version = "0.3.0", path = "../crypto", features=["hash"] } +secret-toolkit-crypto = { version = "0.3.0", path = "../crypto", features = [ + "hash", +] } diff --git a/packages/serialization/Cargo.toml b/packages/serialization/Cargo.toml index 80e00ff..cfc6fdc 100644 --- a/packages/serialization/Cargo.toml +++ b/packages/serialization/Cargo.toml @@ -22,7 +22,7 @@ base64 = ["schemars"] serde = "1.0" bincode2 = { version = "2.0", optional = true } schemars = { version = "0.8.1", optional = true } -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } [dev-dependencies] serde_json = "1" diff --git a/packages/snip20/Cargo.toml b/packages/snip20/Cargo.toml index 551914f..a6046cd 100644 --- a/packages/snip20/Cargo.toml +++ b/packages/snip20/Cargo.toml @@ -16,5 +16,5 @@ all-features = true [dependencies] serde = "1.0" schemars = "0.8.1" -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } secret-toolkit-utils = { version = "0.3", path = "../utils" } diff --git a/packages/snip721/Cargo.toml b/packages/snip721/Cargo.toml index a5bc93f..1e12763 100644 --- a/packages/snip721/Cargo.toml +++ b/packages/snip721/Cargo.toml @@ -16,5 +16,5 @@ all-features = true [dependencies] serde = "1.0" schemars = "0.8.1" -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } secret-toolkit-utils = { version = "0.3", path = "../utils" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index a9eda29..0fd3acf 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -15,6 +15,6 @@ all-features = true [dependencies] serde = "1.0" -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } -cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "1.0.0" } secret-toolkit-serialization = { version = "0.3", path = "../serialization" } diff --git a/packages/utils/Cargo.toml b/packages/utils/Cargo.toml index 7187271..87faed8 100644 --- a/packages/utils/Cargo.toml +++ b/packages/utils/Cargo.toml @@ -16,5 +16,5 @@ all-features = true [dependencies] serde = "1.0" schemars = "0.8.1" -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } -cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "1.0.0" } diff --git a/packages/viewing_key/Cargo.toml b/packages/viewing_key/Cargo.toml index 5ea822c..8afb31c 100644 --- a/packages/viewing_key/Cargo.toml +++ b/packages/viewing_key/Cargo.toml @@ -18,7 +18,10 @@ serde = "1.0" schemars = "0.7" base64 = "0.11.0" # Same as used by cosmwas-std subtle = { version = "2.2.3", default-features = false } -cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } -cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } -secret-toolkit-crypto = { version = "0.3", path = "../crypto", default-features = false, features = ["hash", "rand"] } +cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "1.0.0" } +secret-toolkit-crypto = { version = "0.3", path = "../crypto", default-features = false, features = [ + "hash", + "rand", +] } secret-toolkit-utils = { version = "0.3", path = "../utils" } From 6877bee4cba1810d26fdd49d24fea6f98c119dd9 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Tue, 25 Oct 2022 16:42:55 +0300 Subject: [PATCH 35/37] Update versions for a new release --- packages/crypto/Cargo.toml | 2 +- packages/incubator/Cargo.toml | 4 ++-- packages/permit/Cargo.toml | 4 ++-- packages/serialization/Cargo.toml | 2 +- packages/snip20/Cargo.toml | 4 ++-- packages/snip721/Cargo.toml | 4 ++-- packages/storage/Cargo.toml | 4 ++-- packages/toolkit/Cargo.toml | 35 +++++++++++++++++++------------ packages/utils/Cargo.toml | 2 +- packages/viewing_key/Cargo.toml | 6 +++--- 10 files changed, 38 insertions(+), 29 deletions(-) diff --git a/packages/crypto/Cargo.toml b/packages/crypto/Cargo.toml index f72f16f..bb351f6 100644 --- a/packages/crypto/Cargo.toml +++ b/packages/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-crypto" -version = "0.3.0" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" diff --git a/packages/incubator/Cargo.toml b/packages/incubator/Cargo.toml index 01091f8..ca6f50e 100644 --- a/packages/incubator/Cargo.toml +++ b/packages/incubator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-incubator" -version = "0.4.0" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -17,7 +17,7 @@ all-features = true serde = { version = "1.0", optional = true } cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0", optional = true } cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "1.0.0", optional = true } -secret-toolkit-serialization = { version = "0.3", path = "../serialization", optional = true } +secret-toolkit-serialization = { version = "0.6", path = "../serialization", optional = true } [features] generational-store = ["secret-toolkit-serialization", "serde", "cosmwasm-std"] diff --git a/packages/permit/Cargo.toml b/packages/permit/Cargo.toml index 579d4f2..31195ff 100644 --- a/packages/permit/Cargo.toml +++ b/packages/permit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-permit" -version = "0.3.1" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -20,6 +20,6 @@ ripemd160 = { version = "0.9.1", default-features = false } schemars = "0.8.1" bech32 = "0.8.1" remain = "0.2.2" -secret-toolkit-crypto = { version = "0.3.0", path = "../crypto", features = [ +secret-toolkit-crypto = { version = "0.6.0", path = "../crypto", features = [ "hash", ] } diff --git a/packages/serialization/Cargo.toml b/packages/serialization/Cargo.toml index cfc6fdc..2f2a53e 100644 --- a/packages/serialization/Cargo.toml +++ b/packages/serialization/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-serialization" -version = "0.3.0" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" diff --git a/packages/snip20/Cargo.toml b/packages/snip20/Cargo.toml index a6046cd..034289b 100644 --- a/packages/snip20/Cargo.toml +++ b/packages/snip20/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-snip20" -version = "0.3.0" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -17,4 +17,4 @@ all-features = true serde = "1.0" schemars = "0.8.1" cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } -secret-toolkit-utils = { version = "0.3", path = "../utils" } +secret-toolkit-utils = { version = "0.6", path = "../utils" } diff --git a/packages/snip721/Cargo.toml b/packages/snip721/Cargo.toml index 1e12763..9491535 100644 --- a/packages/snip721/Cargo.toml +++ b/packages/snip721/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-snip721" -version = "0.3.0" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -17,4 +17,4 @@ all-features = true serde = "1.0" schemars = "0.8.1" cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } -secret-toolkit-utils = { version = "0.3", path = "../utils" } +secret-toolkit-utils = { version = "0.6", path = "../utils" } diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index 0fd3acf..5f55634 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-storage" -version = "0.5.0" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -17,4 +17,4 @@ all-features = true serde = "1.0" cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "1.0.0" } -secret-toolkit-serialization = { version = "0.3", path = "../serialization" } +secret-toolkit-serialization = { version = "0.6", path = "../serialization" } diff --git a/packages/toolkit/Cargo.toml b/packages/toolkit/Cargo.toml index db876bb..148b486 100644 --- a/packages/toolkit/Cargo.toml +++ b/packages/toolkit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit" -version = "0.5.0" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -16,9 +16,18 @@ all-features = true [features] default = ["serialization", "snip20", "snip721", "storage", "utils"] -crypto = ["secret-toolkit-crypto"] # Not in default features because this is slow to compile -incubator = ["secret-toolkit-incubator", "serialization"] # Should never be in default features! -permit = ["secret-toolkit-permit", "crypto", "utils"] # Not in default features because it requires "crypto" +crypto = [ + "secret-toolkit-crypto", +] # Not in default features because this is slow to compile +incubator = [ + "secret-toolkit-incubator", + "serialization", +] # Should never be in default features! +permit = [ + "secret-toolkit-permit", + "crypto", + "utils", +] # Not in default features because it requires "crypto" serialization = ["secret-toolkit-serialization"] snip20 = ["secret-toolkit-snip20", "utils"] snip721 = ["secret-toolkit-snip721", "utils"] @@ -27,12 +36,12 @@ utils = ["secret-toolkit-utils"] viewing-key = ["secret-toolkit-viewing-key"] [dependencies] -secret-toolkit-crypto = { version = "0.3.0", path = "../crypto", optional = true } -secret-toolkit-incubator = { version = "0.4.0", path = "../incubator", optional = true } -secret-toolkit-permit = { version = "0.3.0", path = "../permit", optional = true } -secret-toolkit-serialization = { version = "0.3", path = "../serialization", optional = true } -secret-toolkit-snip20 = { version = "0.3", path = "../snip20", optional = true } -secret-toolkit-snip721 = { version = "0.3", path = "../snip721", optional = true } -secret-toolkit-storage = { version = "0.5", path = "../storage", optional = true } -secret-toolkit-utils = { version = "0.3", path = "../utils", optional = true } -secret-toolkit-viewing-key = { version = "0.3", path = "../viewing_key", optional = true } +secret-toolkit-crypto = { version = "0.6.0", path = "../crypto", optional = true } +secret-toolkit-incubator = { version = "0.6.0", path = "../incubator", optional = true } +secret-toolkit-permit = { version = "0.6.0", path = "../permit", optional = true } +secret-toolkit-serialization = { version = "0.6", path = "../serialization", optional = true } +secret-toolkit-snip20 = { version = "0.6", path = "../snip20", optional = true } +secret-toolkit-snip721 = { version = "0.6", path = "../snip721", optional = true } +secret-toolkit-storage = { version = "0.6", path = "../storage", optional = true } +secret-toolkit-utils = { version = "0.6", path = "../utils", optional = true } +secret-toolkit-viewing-key = { version = "0.6", path = "../viewing_key", optional = true } diff --git a/packages/utils/Cargo.toml b/packages/utils/Cargo.toml index 87faed8..02267c4 100644 --- a/packages/utils/Cargo.toml +++ b/packages/utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-utils" -version = "0.3.1" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" diff --git a/packages/viewing_key/Cargo.toml b/packages/viewing_key/Cargo.toml index 8afb31c..46632fc 100644 --- a/packages/viewing_key/Cargo.toml +++ b/packages/viewing_key/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-toolkit-viewing-key" -version = "0.3.0" +version = "0.6.0" edition = "2018" authors = ["SCRT Labs "] license-file = "../../LICENSE" @@ -20,8 +20,8 @@ base64 = "0.11.0" # Same as used by cosmwas-std subtle = { version = "2.2.3", default-features = false } cosmwasm-std = { package = "secret-cosmwasm-std", version = "1.0.0" } cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "1.0.0" } -secret-toolkit-crypto = { version = "0.3", path = "../crypto", default-features = false, features = [ +secret-toolkit-crypto = { version = "0.6", path = "../crypto", default-features = false, features = [ "hash", "rand", ] } -secret-toolkit-utils = { version = "0.3", path = "../utils" } +secret-toolkit-utils = { version = "0.6", path = "../utils" } From 4c3dc31cbe60b29d8a946228cdf42002b4ac3af3 Mon Sep 17 00:00:00 2001 From: TomL94 Date: Tue, 25 Oct 2022 16:58:43 +0300 Subject: [PATCH 36/37] Update Releases file --- Releases.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Releases.md b/Releases.md index 70829f7..3ac9564 100644 --- a/Releases.md +++ b/Releases.md @@ -1,5 +1,14 @@ # Release notes for the Secret Toolkit +## v0.6.0 + +This release upgrades all `secret-toolkit` packages to be compatible with Cosmwasm v1.0 (Secret Network v1.4). +The APIs remains the same, but it is necessary to upgrade the contract's `cosmwasm` dependencies to `v1.0.0`. + +### Breaking + +- This version will not work with `cosmwasm v0.10`. It is necessary to upgrade to `cosmwasm v1` in order to use this release. + ## v0.5.0 This release includes some minor fixed to the storage package which required some breaking changes. From 284a56b2c992dd30e18c89ea9e319f137f24ebda Mon Sep 17 00:00:00 2001 From: TomL94 Date: Tue, 25 Oct 2022 17:25:25 +0300 Subject: [PATCH 37/37] fix a conflict fuckup --- packages/storage/src/keymap.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/storage/src/keymap.rs b/packages/storage/src/keymap.rs index 3ee8fd1..ebc809d 100644 --- a/packages/storage/src/keymap.rs +++ b/packages/storage/src/keymap.rs @@ -179,7 +179,6 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: } /// internal item get function - cosmwasm-v1.0 fn _get_from_key(&self, storage: &dyn Storage, key: &K) -> StdResult> { let key_vec = self.serialize_key(key)?; self.load_impl(storage, &key_vec)