Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions contracts/cw3-fixed-multisig/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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())
}
Expand Down Expand Up @@ -92,9 +92,8 @@ pub fn execute_propose(
latest: Option<Expiration>,
) -> Result<Response<Empty>, 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)?;
Expand Down Expand Up @@ -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![],
Expand All @@ -156,9 +155,8 @@ pub fn execute_vote(
vote: Vote,
) -> Result<Response<Empty>, 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
Expand All @@ -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 {
Expand Down Expand Up @@ -395,12 +393,10 @@ fn map_proposal(
}

fn query_vote(deps: Deps, proposal_id: u64, voter: String) -> StdResult<VoteResponse> {
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,
});
Expand Down Expand Up @@ -434,7 +430,8 @@ fn list_votes(
}

fn query_voter(deps: Deps, voter: String) -> StdResult<VoterResponse> {
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 })
}

Expand Down
8 changes: 4 additions & 4 deletions contracts/cw3-fixed-multisig/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -57,9 +57,9 @@ pub const CONFIG: Item<Config> = Item::new("config");
pub const PROPOSAL_COUNT: Item<u64> = Item::new("proposal_count");

// multiple-item maps
pub const VOTERS: Map<AddrRef, u64> = Map::new("voters");
pub const VOTERS: Map<&Addr, u64> = Map::new("voters");
pub const PROPOSALS: Map<U64Key, Proposal> = 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<u64> {
let id: u64 = PROPOSAL_COUNT.may_load(store)?.unwrap_or_default() + 1;
Expand Down
6 changes: 0 additions & 6 deletions packages/storage-plus/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down
127 changes: 14 additions & 113 deletions packages/storage-plus/src/keys.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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] {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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> {
Expand All @@ -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
Expand All @@ -205,10 +176,6 @@ impl<'a, T: AsRef<PkOwned> + From<PkOwned> + 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!)
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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";
Expand Down