diff --git a/contracts/cw3-fixed-multisig/src/contract.rs b/contracts/cw3-fixed-multisig/src/contract.rs index f15102592..4b336e3f3 100644 --- a/contracts/cw3-fixed-multisig/src/contract.rs +++ b/contracts/cw3-fixed-multisig/src/contract.rs @@ -13,7 +13,7 @@ use cw3::{ ProposalListResponse, ProposalResponse, Status, ThresholdResponse, Vote, VoteInfo, VoteListResponse, VoteResponse, VoterDetail, VoterListResponse, VoterResponse, }; -use cw_storage_plus::{AddrRef, Bound}; +use cw_storage_plus::Bound; use crate::error::ContractError; use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; @@ -56,7 +56,7 @@ pub fn instantiate( // add all voters for voter in msg.voters.iter() { let key = deps.api.addr_validate(&voter.addr)?; - VOTERS.save(deps.storage, AddrRef::new(&key), &voter.weight)?; + VOTERS.save(deps.storage, &key, &voter.weight)?; } Ok(Response::default()) } @@ -92,9 +92,8 @@ pub fn execute_propose( latest: Option, ) -> Result, ContractError> { // only members of the multisig can create a proposal - let sender = AddrRef::new(&info.sender); let vote_power = VOTERS - .may_load(deps.storage, sender)? + .may_load(deps.storage, &info.sender)? .ok_or(ContractError::Unauthorized {})?; let cfg = CONFIG.load(deps.storage)?; @@ -133,7 +132,7 @@ pub fn execute_propose( weight: vote_power, vote: Vote::Yes, }; - BALLOTS.save(deps.storage, (id.into(), sender), &ballot)?; + BALLOTS.save(deps.storage, (id.into(), &info.sender), &ballot)?; Ok(Response { submessages: vec![], @@ -156,9 +155,8 @@ pub fn execute_vote( vote: Vote, ) -> Result, ContractError> { // only members of the multisig can vote - let sender = AddrRef::new(&info.sender); let vote_power = VOTERS - .may_load(deps.storage, sender)? + .may_load(deps.storage, &info.sender)? .ok_or(ContractError::Unauthorized {})?; // ensure proposal exists and can be voted on @@ -173,7 +171,7 @@ pub fn execute_vote( // cast vote if no vote previously cast BALLOTS.update( deps.storage, - (proposal_id.into(), sender), + (proposal_id.into(), &info.sender), |bal| match bal { Some(_) => Err(ContractError::AlreadyVoted {}), None => Ok(Ballot { @@ -395,12 +393,10 @@ fn map_proposal( } fn query_vote(deps: Deps, proposal_id: u64, voter: String) -> StdResult { - let ballot = BALLOTS.may_load( - deps.storage, - (proposal_id.into(), AddrRef::unchecked(&voter)), - )?; + let voter = deps.api.addr_validate(&voter)?; + let ballot = BALLOTS.may_load(deps.storage, (proposal_id.into(), &voter))?; let vote = ballot.map(|b| VoteInfo { - voter, + voter: voter.into(), vote: b.vote, weight: b.weight, }); @@ -434,7 +430,8 @@ fn list_votes( } fn query_voter(deps: Deps, voter: String) -> StdResult { - let weight = VOTERS.may_load(deps.storage, AddrRef::unchecked(&voter))?; + let voter = deps.api.addr_validate(&voter)?; + let weight = VOTERS.may_load(deps.storage, &voter)?; Ok(VoterResponse { weight }) } diff --git a/contracts/cw3-fixed-multisig/src/state.rs b/contracts/cw3-fixed-multisig/src/state.rs index 3f6dd3c82..8ebc86934 100644 --- a/contracts/cw3-fixed-multisig/src/state.rs +++ b/contracts/cw3-fixed-multisig/src/state.rs @@ -2,11 +2,11 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::convert::TryInto; -use cosmwasm_std::{BlockInfo, CosmosMsg, Empty, StdError, StdResult, Storage}; +use cosmwasm_std::{Addr, BlockInfo, CosmosMsg, Empty, StdError, StdResult, Storage}; use cw0::{Duration, Expiration}; use cw3::{Status, Vote}; -use cw_storage_plus::{AddrRef, Item, Map, U64Key}; +use cw_storage_plus::{Item, Map, U64Key}; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct Config { @@ -57,9 +57,9 @@ pub const CONFIG: Item = Item::new("config"); pub const PROPOSAL_COUNT: Item = Item::new("proposal_count"); // multiple-item maps -pub const VOTERS: Map = Map::new("voters"); +pub const VOTERS: Map<&Addr, u64> = Map::new("voters"); pub const PROPOSALS: Map = Map::new("proposals"); -pub const BALLOTS: Map<(U64Key, AddrRef), Ballot> = Map::new("ballots"); +pub const BALLOTS: Map<(U64Key, &Addr), Ballot> = Map::new("ballots"); pub fn next_id(store: &mut dyn Storage) -> StdResult { let id: u64 = PROPOSAL_COUNT.may_load(store)?.unwrap_or_default() + 1; diff --git a/packages/storage-plus/src/helpers.rs b/packages/storage-plus/src/helpers.rs index 413ee083b..8841bfa7a 100644 --- a/packages/storage-plus/src/helpers.rs +++ b/packages/storage-plus/src/helpers.rs @@ -84,12 +84,6 @@ pub(crate) fn encode_length(namespace: &[u8]) -> [u8; 2] { [length_bytes[2], length_bytes[3]] } -// pub(crate) fn decode_length(prefix: [u8; 2]) -> usize { -pub(crate) fn decode_length(prefix: &[u8]) -> usize { - // TODO: enforce exactly 2 bytes somehow, but usable with slices - (prefix[0] as usize) * 256 + (prefix[1] as usize) -} - #[cfg(test)] mod test { use super::*; diff --git a/packages/storage-plus/src/keys.rs b/packages/storage-plus/src/keys.rs index 655be7509..4fb5c7298 100644 --- a/packages/storage-plus/src/keys.rs +++ b/packages/storage-plus/src/keys.rs @@ -1,8 +1,8 @@ +use cosmwasm_std::Addr; use std::marker::PhantomData; -use std::str::from_utf8; use crate::addr::AddrRef; -use crate::helpers::{decode_length, namespaces_with_key}; +use crate::helpers::namespaces_with_key; use crate::Endian; // pub trait PrimaryKey<'a>: Copy { @@ -18,10 +18,6 @@ pub trait PrimaryKey<'a>: Clone { let l = keys.len(); namespaces_with_key(&keys[0..l - 1], &keys[l - 1]) } - - /// extracts a single or composite key from a joined key, - /// only lives as long as the original bytes - fn parse_key(serialized: &'a [u8]) -> Self; } impl<'a> PrimaryKey<'a> for &'a [u8] { @@ -32,10 +28,6 @@ impl<'a> PrimaryKey<'a> for &'a [u8] { // this is simple, we don't add more prefixes vec![self] } - - fn parse_key(serialized: &'a [u8]) -> Self { - serialized - } } // Provide a string version of this to raw encode strings @@ -47,10 +39,6 @@ impl<'a> PrimaryKey<'a> for &'a str { // this is simple, we don't add more prefixes vec![self.as_bytes()] } - - fn parse_key(serialized: &'a [u8]) -> Self { - from_utf8(serialized).unwrap() - } } // use generics for combining there - so we can use &[u8], PkOwned, or IntKey @@ -63,13 +51,6 @@ impl<'a, T: PrimaryKey<'a> + Prefixer<'a>, U: PrimaryKey<'a>> PrimaryKey<'a> for keys.extend(&self.1.key()); keys } - - fn parse_key(serialized: &'a [u8]) -> Self { - let l = decode_length(&serialized[0..2]); - let first = &serialized[2..l + 2]; - let second = &serialized[l + 2..]; - (T::parse_key(first), U::parse_key(second)) - } } // use generics for combining there - so we can use &[u8], PkOwned, or IntKey @@ -85,19 +66,6 @@ impl<'a, T: PrimaryKey<'a> + Prefixer<'a>, U: PrimaryKey<'a> + Prefixer<'a>, V: keys.extend(&self.2.key()); keys } - - fn parse_key(serialized: &'a [u8]) -> Self { - let l1 = decode_length(&serialized[0..2]); - let first = &serialized[2..2 + l1]; - let l2 = decode_length(&serialized[2 + l1..2 + l1 + 2]); - let second = &serialized[2 + l1 + 2..2 + l1 + 2 + l2]; - let third = &serialized[2 + l1 + 2 + l2..]; - ( - T::parse_key(first), - U::parse_key(second), - V::parse_key(third), - ) - } } // pub trait Prefixer<'a>: Copy { @@ -162,10 +130,6 @@ impl<'a> PrimaryKey<'a> for PkOwned { fn key(&self) -> Vec<&[u8]> { vec![&self.0] } - - fn parse_key(serialized: &'a [u8]) -> Self { - PkOwned(serialized.to_vec()) - } } impl<'a> Prefixer<'a> for PkOwned { @@ -174,6 +138,17 @@ impl<'a> Prefixer<'a> for PkOwned { } } +/// type safe version to ensure address was validated before use. +impl<'a> PrimaryKey<'a> for &'a Addr { + type Prefix = (); + type SubPrefix = (); + + fn key(&self) -> Vec<&[u8]> { + // this is simple, we don't add more prefixes + vec![self.as_ref().as_bytes()] + } +} + /// type safe version to ensure address was validated before use. /// This is equivalent to &Addr but compatible with these lifetimes impl<'a> PrimaryKey<'a> for AddrRef<'a> { @@ -184,10 +159,6 @@ impl<'a> PrimaryKey<'a> for AddrRef<'a> { // this is simple, we don't add more prefixes vec![self.as_bytes()] } - - fn parse_key(serialized: &'a [u8]) -> Self { - AddrRef::unchecked(from_utf8(serialized).unwrap()) - } } /// A type-safe way to use verified addresses as keys @@ -205,10 +176,6 @@ impl<'a, T: AsRef + From + Clone> PrimaryKey<'a> for T { fn key(&self) -> Vec<&[u8]> { self.as_ref().key() } - - fn parse_key(serialized: &'a [u8]) -> Self { - PkOwned::parse_key(serialized).into() - } } // this auto-implements Prefixer for all the IntKey types (and more!) @@ -315,8 +282,7 @@ mod test { assert_eq!("hello".as_bytes(), path[0]); let joined = k.joined_key(); - let parsed = K::parse_key(&joined); - assert_eq!(parsed, "hello"); + assert_eq!(joined, b"hello") } #[test] @@ -367,71 +333,6 @@ mod test { assert_eq!(dir, vec![foo, b"bar"]); } - #[test] - fn parse_joined_keys_pk1() { - type K<'a> = &'a [u8]; - - let key: K = b"four"; - let joined = key.joined_key(); - assert_eq!(key, joined.as_slice()); - let parsed = K::parse_key(&joined); - assert_eq!(key, parsed); - } - - #[test] - fn parse_joined_keys_pk2() { - type K<'a> = (&'a [u8], &'a [u8]); - - let key: K = (b"four", b"square"); - let joined = key.joined_key(); - assert_eq!(4 + 6 + 2, joined.len()); - let parsed = K::parse_key(&joined); - assert_eq!(key, parsed); - } - - #[test] - fn parse_joined_keys_pk3() { - type K<'a> = (&'a str, U32Key, &'a [u8]); - - let key: K = ("four", 15.into(), b"cinco"); - let joined = key.joined_key(); - assert_eq!(4 + 4 + 5 + 2 * 2, joined.len()); - let parsed = K::parse_key(&joined); - assert_eq!(key, parsed); - } - - #[test] - fn parse_joined_keys_pk3_alt() { - type K<'a> = (&'a str, U64Key, &'a str); - - let key: K = ("one", 222.into(), "three"); - let joined = key.joined_key(); - assert_eq!(3 + 8 + 5 + 2 * 2, joined.len()); - let parsed = K::parse_key(&joined); - assert_eq!(key, parsed); - } - - #[test] - fn parse_joined_keys_int() { - let key: U64Key = 12345678.into(); - let joined = key.joined_key(); - assert_eq!(8, joined.len()); - let parsed = U64Key::parse_key(&joined); - assert_eq!(key, parsed); - } - - #[test] - fn parse_joined_keys_string_int() { - type K<'a> = (U32Key, &'a str); - - let key: K = (54321.into(), "random"); - let joined = key.joined_key(); - assert_eq!(2 + 4 + 6, joined.len()); - let parsed = K::parse_key(&joined); - assert_eq!(key, parsed); - assert_eq!("random", parsed.1); - } - #[test] fn proper_prefixes() { let simple: &str = "hello";