Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add query helpers to Item and Map and use them in cw4 helpers #412

Merged
merged 4 commits into from
Sep 13, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/cw4/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ homepage = "https://cosmwasm.com"
documentation = "https://docs.cosmwasm.com"

[dependencies]
cw-storage-plus = { path = "../storage-plus", version = "0.8.1" }
cosmwasm-std = { version = "0.16.0" }
schemars = "0.8.1"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
Expand Down
42 changes: 5 additions & 37 deletions packages/cw4/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use cosmwasm_std::{
from_slice, to_binary, to_vec, Addr, Binary, ContractResult, CosmosMsg, Empty, QuerierWrapper,
QueryRequest, StdError, StdResult, SystemResult, WasmMsg, WasmQuery,
to_binary, Addr, CosmosMsg, Empty, QuerierWrapper, QueryRequest, StdResult, WasmMsg, WasmQuery,
};

use crate::msg::Cw4ExecuteMsg;
use crate::query::HooksResponse;
use crate::{
member_key, AdminResponse, Cw4QueryMsg, Member, MemberListResponse, MemberResponse, TOTAL_KEY,
AdminResponse, Cw4QueryMsg, Member, MemberListResponse, MemberResponse, MEMBERS_KEY, TOTAL_KEY,
};
use cw_storage_plus::{Item, Map};

/// Cw4Contract is a wrapper around Addr that provides a lot of helpers
/// for working with cw4 contracts
Expand Down Expand Up @@ -62,14 +62,6 @@ impl Cw4Contract {
.into())
}

fn encode_raw_query<T: Into<Binary>>(&self, key: T) -> QueryRequest<Empty> {
WasmQuery::Raw {
contract_addr: self.addr().into(),
key: key.into(),
}
.into()
}

/// Show the hooks
pub fn hooks(&self, querier: &QuerierWrapper) -> StdResult<Vec<String>> {
let query = self.encode_smart_query(Cw4QueryMsg::Hooks {})?;
Expand All @@ -79,36 +71,12 @@ impl Cw4Contract {

/// Read the total weight
pub fn total_weight(&self, querier: &QuerierWrapper) -> StdResult<u64> {
let query = self.encode_raw_query(TOTAL_KEY.as_bytes());
querier.query(&query)
Item::new(TOTAL_KEY).query(querier, self.addr())
}

/// Check if this address is a member, and if so, with which weight
pub fn is_member(&self, querier: &QuerierWrapper, addr: &Addr) -> StdResult<Option<u64>> {
let path = member_key(addr.as_ref());
let query = self.encode_raw_query(path);

// We have to copy the logic of Querier.query to handle the empty case, and not
// try to decode empty result into a u64.
// TODO: add similar API on Querier - this is not the first time I came across it
let raw = to_vec(&query)?;
match querier.raw_query(&raw) {
SystemResult::Err(system_err) => Err(StdError::generic_err(format!(
"Querier system error: {}",
system_err
))),
SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(
format!("Querier contract error: {}", contract_err),
)),
SystemResult::Ok(ContractResult::Ok(value)) => {
// This is the only place we customize
if value.is_empty() {
Ok(None)
} else {
from_slice(&value)
}
}
}
Map::new(MEMBERS_KEY).query(querier, self.addr(), addr)
}

/// Return the member's weight at the given snapshot - requires a smart query
Expand Down
14 changes: 13 additions & 1 deletion packages/storage-plus/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use serde::de::DeserializeOwned;
use serde::Serialize;
use std::marker::PhantomData;

use cosmwasm_std::{to_vec, StdError, StdResult, Storage};
use cosmwasm_std::{to_vec, Addr, QuerierWrapper, StdError, StdResult, Storage, WasmQuery};

use crate::helpers::{may_deserialize, must_deserialize};

Expand Down Expand Up @@ -72,6 +72,18 @@ where
self.save(store, &output)?;
Ok(output)
}

/// If you import the proper Item from the remote contract, this will let you read the data
/// from a remote contract in a type-safe way using WasmQuery::RawQuery.
///
/// Note that we expect an Item to be set, and error if there is no data there
pub fn query(&self, querier: &QuerierWrapper, remote_contract: Addr) -> StdResult<T> {
let request = WasmQuery::Raw {
contract_addr: remote_contract.into(),
key: self.storage_key.into(),
};
querier.query(&request.into())
}
}

#[cfg(test)]
Expand Down
50 changes: 49 additions & 1 deletion packages/storage-plus/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use crate::keys::{EmptyPrefix, Prefixer};
use crate::path::Path;
#[cfg(feature = "iterator")]
use crate::prefix::{Bound, Prefix};
use cosmwasm_std::{StdError, StdResult, Storage};
use cosmwasm_std::{
from_slice, to_vec, Addr, Binary, ContractResult, Empty, QuerierWrapper, QueryRequest,
StdError, StdResult, Storage, SystemResult, WasmQuery,
};

#[derive(Debug, Clone)]
pub struct Map<'a, K, T> {
Expand Down Expand Up @@ -83,6 +86,51 @@ where
{
self.key(k).update(store, action)
}

/// If you import the proper Map from the remote contract, this will let you read the data
/// from a remote contract in a type-safe way using WasmQuery::RawQuery
pub fn query(
maurolacy marked this conversation as resolved.
Show resolved Hide resolved
&self,
querier: &QuerierWrapper,
remote_contract: Addr,
k: K,
) -> StdResult<Option<T>> {
let key = self.key(k).storage_key.into();
let result = query_raw(querier, remote_contract, key)?;
if result.is_empty() {
Ok(None)
} else {
from_slice(&result).map(Some)
}
}
}

// TODO: move this to a better helpers location
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have something specific in mind? Maybe create an issue along the way?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do this before merge.
Can't merge with a TODO (gotta make an issue for it first)

pub(crate) fn query_raw(
querier: &QuerierWrapper,
contract_addr: Addr,
key: Binary,
) -> StdResult<Binary> {
let request: QueryRequest<Empty> = WasmQuery::Raw {
contract_addr: contract_addr.into(),
key,
}
.into();

let raw = to_vec(&request).map_err(|serialize_err| {
StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err))
})?;
match querier.raw_query(&raw) {
SystemResult::Err(system_err) => Err(StdError::generic_err(format!(
"Querier system error: {}",
system_err
))),
SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(format!(
"Querier contract error: {}",
contract_err
))),
SystemResult::Ok(ContractResult::Ok(value)) => Ok(value),
}
}

// short-cut for simple keys, rather than .prefix(()).range(...)
Expand Down
2 changes: 1 addition & 1 deletion packages/storage-plus/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ where
T: Serialize + DeserializeOwned,
{
/// all namespaces prefixes and concatenated with the key
storage_key: Vec<u8>,
pub(crate) storage_key: Vec<u8>,
// see https://doc.rust-lang.org/std/marker/struct.PhantomData.html#unused-type-parameters for why this is needed
data: PhantomData<T>,
}
Expand Down