Compare commits

...

3 Commits

Author SHA1 Message Date
Jędrzej Stuczyński bde44164e7 Usingn IndexedMap for mixnodes 2021-11-25 16:56:53 +00:00
Jędrzej Stuczyński 18add0a0f1 The same for main mixnode storage 2021-11-25 14:51:07 +00:00
Jędrzej Stuczyński 1846ed3476 Experimentally replaced storage for config and layers with cw plus Item 2021-11-25 14:26:51 +00:00
15 changed files with 347 additions and 296 deletions
+11
View File
@@ -190,6 +190,16 @@ dependencies = [
"zeroize",
]
[[package]]
name = "cw-storage-plus"
version = "0.6.2"
source = "git+https://github.com/jstuczyn/cw-plus?branch=feature/0.6.2-cosmwasm-fork#5d3e59c8327d1ab4a748c0be5ad3a376b710bfe5"
dependencies = [
"cosmwasm-std",
"schemars",
"serde",
]
[[package]]
name = "der"
version = "0.4.4"
@@ -493,6 +503,7 @@ dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
"cosmwasm-storage",
"cw-storage-plus",
"fixed",
"mixnet-contract",
"schemars",
+1
View File
@@ -40,6 +40,7 @@ config = { path = "../../common/config"}
cosmwasm-std = { git = "https://github.com/jstuczyn/cosmwasm", branch="0.14.1-updatedk256", features = ["iterator"] }
cosmwasm-storage = { git = "https://github.com/jstuczyn/cosmwasm", branch="0.14.1-updatedk256", features = ["iterator"] }
cw-storage-plus = { git = "https://github.com/jstuczyn/cw-plus", branch = "feature/0.6.2-cosmwasm-fork", features = ["iterator"] }
#cosmwasm-std = { version = "0.14.1", features = ["iterator"] }
#cosmwasm-storage = { version = "0.14.1", features = ["iterator"] }
+5 -5
View File
@@ -70,8 +70,8 @@ pub fn instantiate(
) -> Result<Response, ContractError> {
let state = default_initial_state(info.sender, env);
mixnet_params_storage::contract_settings(deps.storage).save(&state)?;
mixnet_params_storage::layer_distribution(deps.storage).save(&Default::default())?;
mixnet_params_storage::CONTRACT_SETTINGS.save(deps.storage, &state)?;
mixnet_params_storage::LAYERS.save(deps.storage, &Default::default())?;
Ok(Response::default())
}
@@ -168,9 +168,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
to_binary(&mixnode_queries::query_owns_mixnode(deps, address)?)
}
QueryMsg::OwnsGateway { address } => to_binary(&query_owns_gateway(deps, address)?),
QueryMsg::StateParams {} => to_binary(&query_contract_settings_params(deps)),
QueryMsg::CurrentRewardingInterval {} => to_binary(&query_rewarding_interval(deps)),
QueryMsg::LayerDistribution {} => to_binary(&query_layer_distribution(deps)),
QueryMsg::StateParams {} => to_binary(&query_contract_settings_params(deps)?),
QueryMsg::CurrentRewardingInterval {} => to_binary(&query_rewarding_interval(deps)?),
QueryMsg::LayerDistribution {} => to_binary(&query_layer_distribution(deps)?),
QueryMsg::GetMixDelegations {
mix_identity,
start_after,
@@ -15,8 +15,10 @@ pub(crate) fn try_add_gateway(
let sender_bytes = info.sender.as_bytes();
// if the client has an active bonded mixnode, don't allow gateway bonding
if mixnodes_storage::mixnodes_owners_read(deps.storage)
.may_load(sender_bytes)?
if mixnodes_storage::mixnodes()
.idx
.owner
.item(deps.storage, info.sender.to_string())?
.is_some()
{
return Err(ContractError::AlreadyOwnsMixnode);
@@ -41,8 +43,10 @@ pub(crate) fn try_add_gateway(
}
}
let minimum_bond =
mixnet_params_storage::read_contract_settings_params(deps.storage).minimum_gateway_bond;
let minimum_bond = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.storage)?
.params
.minimum_gateway_bond;
validate_gateway_bond(&info.funds, minimum_bond)?;
let bond = GatewayBond::new(
@@ -1,20 +1,21 @@
use super::storage;
use cosmwasm_std::Deps;
use cosmwasm_std::{Deps, StdResult};
use mixnet_contract::{ContractSettingsParams, RewardingIntervalResponse};
pub(crate) fn query_contract_settings_params(deps: Deps) -> ContractSettingsParams {
storage::read_contract_settings_params(deps.storage)
pub(crate) fn query_contract_settings_params(deps: Deps) -> StdResult<ContractSettingsParams> {
storage::CONTRACT_SETTINGS
.load(deps.storage)
.map(|settings| settings.params)
}
pub(crate) fn query_rewarding_interval(deps: Deps) -> RewardingIntervalResponse {
let state = storage::contract_settings_read(deps.storage)
.load()
.unwrap();
RewardingIntervalResponse {
pub(crate) fn query_rewarding_interval(deps: Deps) -> StdResult<RewardingIntervalResponse> {
let state = storage::CONTRACT_SETTINGS.load(deps.storage)?;
Ok(RewardingIntervalResponse {
current_rewarding_interval_starting_block: state.rewarding_interval_starting_block,
current_rewarding_interval_nonce: state.latest_rewarding_interval_nonce,
rewarding_in_progress: state.rewarding_in_progress,
}
})
}
#[cfg(test)]
@@ -43,13 +44,13 @@ pub(crate) mod tests {
rewarding_in_progress: false,
};
storage::contract_settings(deps.as_mut().storage)
.save(&dummy_state)
storage::CONTRACT_SETTINGS
.save(deps.as_mut().storage, &dummy_state)
.unwrap();
assert_eq!(
dummy_state.params,
query_contract_settings_params(deps.as_ref())
query_contract_settings_params(deps.as_ref()).unwrap()
)
}
}
@@ -4,87 +4,57 @@
use crate::mixnet_contract_settings::models::ContractSettings;
use cosmwasm_std::StdResult;
use cosmwasm_std::Storage;
use cosmwasm_storage::singleton;
use cosmwasm_storage::singleton_read;
use cosmwasm_storage::ReadonlySingleton;
use cosmwasm_storage::Singleton;
use mixnet_contract::ContractSettingsParams;
use cw_storage_plus::Item;
use mixnet_contract::Layer;
use mixnet_contract::LayerDistribution;
// storage prefixes
const CONFIG_KEY: &[u8] = b"config";
const LAYER_DISTRIBUTION_KEY: &[u8] = b"layers";
pub fn contract_settings(storage: &mut dyn Storage) -> Singleton<ContractSettings> {
singleton(storage, CONFIG_KEY)
}
pub fn contract_settings_read(storage: &dyn Storage) -> ReadonlySingleton<ContractSettings> {
singleton_read(storage, CONFIG_KEY)
}
pub(crate) fn read_contract_settings_params(storage: &dyn Storage) -> ContractSettingsParams {
// note: In any other case, I wouldn't have attempted to unwrap this result, but in here
// if we fail to load the stored state we would already be in the undefined behaviour land,
// so we better just blow up immediately.
contract_settings_read(storage).load().unwrap().params
}
pub fn layer_distribution(storage: &mut dyn Storage) -> Singleton<LayerDistribution> {
singleton(storage, LAYER_DISTRIBUTION_KEY)
}
pub(crate) fn read_layer_distribution(storage: &dyn Storage) -> LayerDistribution {
// note: In any other case, I wouldn't have attempted to unwrap this result, but in here
// if we fail to load the stored state we would already be in the undefined behaviour land,
// so we better just blow up immediately.
layer_distribution_read(storage).load().unwrap()
}
pub fn layer_distribution_read(storage: &dyn Storage) -> ReadonlySingleton<LayerDistribution> {
singleton_read(storage, LAYER_DISTRIBUTION_KEY)
}
pub(crate) const CONTRACT_SETTINGS: Item<ContractSettings> = Item::new("config");
pub(crate) const LAYERS: Item<LayerDistribution> = Item::new("layers");
pub fn increment_layer_count(storage: &mut dyn Storage, layer: Layer) -> StdResult<()> {
let mut distribution = layer_distribution(storage).load()?;
match layer {
Layer::Gateway => distribution.gateways += 1,
Layer::One => distribution.layer1 += 1,
Layer::Two => distribution.layer2 += 1,
Layer::Three => distribution.layer3 += 1,
}
layer_distribution(storage).save(&distribution)
LAYERS
.update(storage, |mut distribution| {
match layer {
Layer::Gateway => distribution.gateways += 1,
Layer::One => distribution.layer1 += 1,
Layer::Two => distribution.layer2 += 1,
Layer::Three => distribution.layer3 += 1,
}
Ok(distribution)
})
.map(|_| ())
}
pub fn decrement_layer_count(storage: &mut dyn Storage, layer: Layer) -> StdResult<()> {
let mut distribution = layer_distribution(storage).load()?;
// It can't possibly go below zero, if it does, it means there's a serious error in the contract logic
match layer {
Layer::Gateway => {
distribution.gateways = distribution
.gateways
.checked_sub(1)
.expect("tried to subtract from unsigned zero!")
}
Layer::One => {
distribution.layer1 = distribution
.layer1
.checked_sub(1)
.expect("tried to subtract from unsigned zero!")
}
Layer::Two => {
distribution.layer2 = distribution
.layer2
.checked_sub(1)
.expect("tried to subtract from unsigned zero!")
}
Layer::Three => {
distribution.layer3 = distribution
.layer3
.checked_sub(1)
.expect("tried to subtract from unsigned zero!")
}
};
layer_distribution(storage).save(&distribution)
LAYERS
.update(storage, |mut distribution| {
match layer {
Layer::Gateway => {
distribution.gateways = distribution
.gateways
.checked_sub(1)
.expect("tried to subtract from unsigned zero!")
}
Layer::One => {
distribution.layer1 = distribution
.layer1
.checked_sub(1)
.expect("tried to subtract from unsigned zero!")
}
Layer::Two => {
distribution.layer2 = distribution
.layer2
.checked_sub(1)
.expect("tried to subtract from unsigned zero!")
}
Layer::Three => {
distribution.layer3 = distribution
.layer3
.checked_sub(1)
.expect("tried to subtract from unsigned zero!")
}
}
Ok(distribution)
})
.map(|_| ())
}
@@ -13,7 +13,7 @@ pub(crate) fn try_update_contract_settings(
info: MessageInfo,
params: ContractSettingsParams,
) -> Result<Response, ContractError> {
let mut state = storage::contract_settings_read(deps.storage).load()?;
let mut state = storage::CONTRACT_SETTINGS.load(deps.storage)?;
// check if this is executed by the owner, if not reject the transaction
if info.sender != state.owner {
@@ -35,8 +35,33 @@ pub(crate) fn try_update_contract_settings(
}
state.params = params;
storage::CONTRACT_SETTINGS.save(deps.storage, &state)?;
storage::contract_settings(deps.storage).save(&state)?;
// alternative:
// storage::CONTRACT_SETTINGS.update(deps.storage, |mut state| {
// // check if this is executed by the owner, if not reject the transaction
// if info.sender != state.owner {
// return Err(ContractError::Unauthorized);
// }
//
// if params.mixnode_rewarded_set_size == 0 {
// return Err(ContractError::ZeroRewardedSet);
// }
//
// if params.mixnode_active_set_size == 0 {
// return Err(ContractError::ZeroActiveSet);
// }
//
// // note: rewarded_set = active_set + idle_set
// // hence rewarded set must always be bigger than (or equal to) the active set
// if params.mixnode_rewarded_set_size < params.mixnode_active_set_size {
// return Err(ContractError::InvalidActiveSetSize);
// }
//
// state.params = params;
// Ok(state)
// });
Ok(Response::default())
}
@@ -66,8 +91,8 @@ pub mod tests {
// sanity check to ensure new_params are different than the default ones
assert_ne!(
new_params,
storage::contract_settings_read(deps.as_ref().storage)
.load()
storage::CONTRACT_SETTINGS
.load(deps.as_ref().storage)
.unwrap()
.params
);
@@ -83,8 +108,8 @@ pub mod tests {
assert_eq!(res, Ok(Response::default()));
// and the state is actually updated
let current_state = storage::contract_settings_read(deps.as_ref().storage)
.load()
let current_state = storage::CONTRACT_SETTINGS
.load(deps.as_ref().storage)
.unwrap();
assert_eq!(current_state.params, new_params);
@@ -5,6 +5,7 @@ use super::storage;
use crate::query_support::calculate_start_value;
use config::defaults::DENOM;
use cosmwasm_std::{coin, Addr, Deps, Order, StdResult};
use cw_storage_plus::Bound;
use mixnet_contract::{
Delegation, IdentityKey, MixNodeBond, MixOwnershipResponse, PagedMixDelegationsResponse,
PagedMixnodeResponse,
@@ -18,10 +19,11 @@ pub fn query_mixnodes_paged(
let limit = limit
.unwrap_or(storage::BOND_PAGE_DEFAULT_LIMIT)
.min(storage::BOND_PAGE_MAX_LIMIT) as usize;
let start = calculate_start_value(start_after);
let nodes = storage::mixnodes_read(deps.storage)
.range(start.as_deref(), None, Order::Ascending)
let start = start_after.map(Bound::exclusive);
let nodes = storage::mixnodes()
.range(deps.storage, start, None, Order::Ascending)
.take(limit)
.map(|res| res.map(|item| item.1))
.map(|stored_bond| {
@@ -41,8 +43,10 @@ pub fn query_mixnodes_paged(
}
pub fn query_owns_mixnode(deps: Deps, address: Addr) -> StdResult<MixOwnershipResponse> {
let has_node = storage::mixnodes_owners_read(deps.storage)
.may_load(address.as_bytes())?
let has_node = storage::mixnodes()
.idx
.owner
.item(deps.storage, address.to_string())?
.is_some();
Ok(MixOwnershipResponse { address, has_node })
}
@@ -28,8 +28,10 @@ pub(crate) fn try_add_mixnode(
}
// if the client has an active bonded mixnode, regardless of its identity, don't allow bonding
if storage::mixnodes_owners_read(deps.storage)
.may_load(sender_bytes)?
if storage::mixnodes()
.idx
.owner
.item(deps.storage, info.sender.to_string())?
.is_some()
{
return Err(ContractError::AlreadyOwnsMixnode);
@@ -37,7 +39,7 @@ pub(crate) fn try_add_mixnode(
// check if somebody else has already bonded a mixnode with this identity
if let Some(existing_bond) =
storage::mixnodes_read(deps.storage).may_load(mix_node.identity_key.as_bytes())?
storage::mixnodes().may_load(deps.storage, mix_node.identity_key.as_bytes())?
{
if existing_bond.owner != info.sender {
return Err(ContractError::DuplicateMixnode {
@@ -46,11 +48,13 @@ pub(crate) fn try_add_mixnode(
}
}
let minimum_bond =
mixnet_params_storage::read_contract_settings_params(deps.storage).minimum_mixnode_bond;
let minimum_bond = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.storage)?
.params
.minimum_mixnode_bond;
validate_mixnode_bond(&info.funds, minimum_bond)?;
let layer_distribution = query_layer_distribution(deps.as_ref());
let layer_distribution = query_layer_distribution(deps.as_ref())?;
let layer = layer_distribution.choose_with_fewest();
let stored_bond = StoredMixnodeBond::new(
@@ -62,13 +66,11 @@ pub(crate) fn try_add_mixnode(
None,
);
let identity = stored_bond.identity();
// technically we don't have to set the total_delegation bucket, but it makes things easier
// in different places that we can guarantee that if node exists, so does the data behind the total delegation
storage::mixnodes(deps.storage).save(identity.as_bytes(), &stored_bond)?;
storage::mixnodes_owners(deps.storage).save(sender_bytes, identity)?;
storage::total_delegation(deps.storage).save(identity.as_bytes(), &Uint128::zero())?;
let identity = stored_bond.identity().as_bytes();
storage::mixnodes().save(deps.storage, identity, &stored_bond)?;
storage::total_delegation(deps.storage).save(identity, &Uint128::zero())?;
mixnet_params_storage::increment_layer_count(deps.storage, stored_bond.layer)?;
Ok(Response::new())
@@ -78,17 +80,16 @@ pub(crate) fn try_remove_mixnode(
deps: DepsMut,
info: MessageInfo,
) -> Result<Response, ContractError> {
let sender_bytes = info.sender.as_bytes();
// try to find the identity of the sender's node
let mix_identity = match storage::mixnodes_owners_read(deps.storage).may_load(sender_bytes)? {
Some(identity) => identity,
// try to find the node of the sender
let (entry_key, mixnode_bond) = match storage::mixnodes()
.idx
.owner
.item(deps.storage, info.sender.to_string())?
{
Some(node) => (node.0, node.1),
None => return Err(ContractError::NoAssociatedMixNodeBond { owner: info.sender }),
};
// get the bond, since we found associated identity, the node MUST exist
let mixnode_bond = storage::mixnodes_read(deps.storage).load(mix_identity.as_bytes())?;
// send bonded funds back to the bond owner
let messages = vec![BankMsg::Send {
to_address: info.sender.as_str().to_owned(),
@@ -96,10 +97,9 @@ pub(crate) fn try_remove_mixnode(
}
.into()];
// remove the bond from the list of bonded mixnodes
storage::mixnodes(deps.storage).remove(mix_identity.as_bytes());
// remove the node ownership
storage::mixnodes_owners(deps.storage).remove(sender_bytes);
// remove the bond
storage::mixnodes().remove(deps.storage, &entry_key)?;
// decrement layer count
mixnet_params_storage::decrement_layer_count(deps.storage, mixnode_bond.layer)?;
@@ -303,8 +303,10 @@ pub mod tests {
};
// before the execution the node had no associated owner
assert!(storage::mixnodes_owners_read(deps.as_ref().storage)
.may_load("myAwesomeMixnode".as_bytes())
assert!(storage::mixnodes()
.idx
.owner
.item(deps.as_ref().storage, "mix-owner".to_string())
.unwrap()
.is_none());
@@ -314,9 +316,14 @@ pub mod tests {
assert_eq!(
"myAwesomeMixnode",
storage::mixnodes_owners_read(deps.as_ref().storage)
.load("mix-owner".as_bytes())
storage::mixnodes()
.idx
.owner
.item(deps.as_ref().storage, "mix-owner".to_string())
.unwrap()
.unwrap()
.1
.identity()
);
}
@@ -386,9 +393,7 @@ pub mod tests {
assert_eq!(
LayerDistribution::default(),
mixnet_params_storage::layer_distribution_read(&deps.storage)
.load()
.unwrap(),
mixnet_params_storage::LAYERS.load(&deps.storage).unwrap(),
);
let info = mock_info("mix-owner", &test_helpers::good_mixnode_bond());
@@ -405,9 +410,7 @@ pub mod tests {
layer1: 1,
..Default::default()
},
mixnet_params_storage::layer_distribution_read(&deps.storage)
.load()
.unwrap()
mixnet_params_storage::LAYERS.load(&deps.storage).unwrap()
);
}
@@ -517,9 +520,14 @@ pub mod tests {
execute(deps.as_mut(), mock_env(), info, msg).unwrap();
assert_eq!(
"myAwesomeMixnode",
storage::mixnodes_owners_read(deps.as_ref().storage)
.load("mix-owner".as_bytes())
storage::mixnodes()
.idx
.owner
.item(deps.as_ref().storage, "mix-owner".to_string())
.unwrap()
.unwrap()
.1
.identity()
);
let info = mock_info("mix-owner", &[]);
@@ -527,8 +535,10 @@ pub mod tests {
assert!(execute(deps.as_mut(), mock_env(), info, msg).is_ok());
assert!(storage::mixnodes_owners_read(deps.as_ref().storage)
.may_load("mix-owner".as_bytes())
assert!(storage::mixnodes()
.idx
.owner
.item(deps.as_ref().storage, "mix-owner".to_string())
.unwrap()
.is_none());
@@ -544,9 +554,14 @@ pub mod tests {
assert!(execute(deps.as_mut(), mock_env(), info, msg).is_ok());
assert_eq!(
"myAwesomeMixnode",
storage::mixnodes_owners_read(deps.as_ref().storage)
.load("mix-owner".as_bytes())
storage::mixnodes()
.idx
.owner
.item(deps.as_ref().storage, "mix-owner".to_string())
.unwrap()
.unwrap()
.1
.identity()
);
}
@@ -41,8 +41,8 @@ pub(crate) fn try_delegate_to_mixnode(
validate_delegation_stake(&info.funds)?;
// check if the target node actually exists
if storage::mixnodes_read(deps.storage)
.load(mix_identity.as_bytes())
if storage::mixnodes()
.load(deps.storage, mix_identity.as_bytes())
.is_err()
{
return Err(ContractError::MixNodeBondNotFound {
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use cosmwasm_std::Deps;
use cosmwasm_std::{Deps, StdResult};
use mixnet_contract::LayerDistribution;
pub(crate) fn query_layer_distribution(deps: Deps) -> LayerDistribution {
mixnet_params_storage::read_layer_distribution(deps.storage)
pub(crate) fn query_layer_distribution(deps: Deps) -> StdResult<LayerDistribution> {
mixnet_params_storage::LAYERS.load(deps.storage)
}
+36 -27
View File
@@ -4,6 +4,7 @@
use config::defaults::DENOM;
use cosmwasm_std::{StdResult, Storage, Uint128};
use cosmwasm_storage::{bucket, bucket_read, Bucket, ReadonlyBucket};
use cw_storage_plus::{Index, IndexList, IndexedMap, UniqueIndex};
use mixnet_contract::{
Addr, Coin, IdentityKey, IdentityKeyRef, Layer, MixNode, MixNodeBond, RawDelegationData,
RewardingStatus,
@@ -13,8 +14,8 @@ use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
// storage prefixes
const PREFIX_MIXNODES: &[u8] = b"mn";
const PREFIX_MIXNODES_OWNERS: &[u8] = b"mo";
// const PREFIX_MIXNODES: &[u8] = b"mn";
// const PREFIX_MIXNODES_OWNERS: &[u8] = b"mo";
const PREFIX_MIX_DELEGATION: &[u8] = b"md";
const PREFIX_REVERSE_MIX_DELEGATION: &[u8] = b"dm";
pub const PREFIX_REWARDED_MIXNODES: &[u8] = b"rm";
@@ -28,7 +29,32 @@ pub(crate) const BOND_PAGE_DEFAULT_LIMIT: u32 = 50;
const PREFIX_TOTAL_DELEGATION: &[u8] = b"td";
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub(crate) struct MixnodeBondIndex<'a> {
pub(crate) identity: UniqueIndex<'a, IdentityKey, StoredMixnodeBond>,
// somehow PrimaryKey is not implemented for Addr but is for String?
// maybe it's an omission in this version and is fixed in the cosmwasm 1.0 compatible release?
pub(crate) owner: UniqueIndex<'a, String, StoredMixnodeBond>,
}
// IndexList is just boilerplate code for fetching a struct's indexes
impl<'a> IndexList<StoredMixnodeBond> for MixnodeBondIndex<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<StoredMixnodeBond>> + '_> {
let v: Vec<&dyn Index<StoredMixnodeBond>> = vec![&self.identity, &self.owner];
Box::new(v.into_iter())
}
}
// mixnodes() is the storage access function.
pub(crate) fn mixnodes<'a>() -> IndexedMap<'a, &'a [u8], StoredMixnodeBond, MixnodeBondIndex<'a>> {
let indexes = MixnodeBondIndex {
identity: UniqueIndex::new(|d| d.mix_node.identity_key.clone(), "mni"),
owner: UniqueIndex::new(|d| d.owner.to_string(), "mno"),
};
IndexedMap::new("mn", indexes)
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub(crate) struct StoredMixnodeBond {
pub bond_amount: Coin,
pub owner: Addr,
@@ -93,23 +119,6 @@ impl Display for StoredMixnodeBond {
// Mixnode-related stuff
pub(crate) fn mixnodes(storage: &mut dyn Storage) -> Bucket<StoredMixnodeBond> {
bucket(storage, PREFIX_MIXNODES)
}
pub(crate) fn mixnodes_read(storage: &dyn Storage) -> ReadonlyBucket<StoredMixnodeBond> {
bucket_read(storage, PREFIX_MIXNODES)
}
// owner address -> node identity
pub fn mixnodes_owners(storage: &mut dyn Storage) -> Bucket<IdentityKey> {
bucket(storage, PREFIX_MIXNODES_OWNERS)
}
pub fn mixnodes_owners_read(storage: &dyn Storage) -> ReadonlyBucket<IdentityKey> {
bucket_read(storage, PREFIX_MIXNODES_OWNERS)
}
pub fn total_delegation(storage: &mut dyn Storage) -> Bucket<Uint128> {
bucket(storage, PREFIX_TOTAL_DELEGATION)
}
@@ -151,7 +160,7 @@ pub(crate) fn read_mixnode_bond(
storage: &dyn Storage,
mix_identity: IdentityKeyRef,
) -> StdResult<Option<MixNodeBond>> {
let stored_bond = mixnodes_read(storage).may_load(mix_identity.as_bytes())?;
let stored_bond = mixnodes().may_load(storage, mix_identity.as_bytes())?;
match stored_bond {
None => Ok(None),
Some(stored_bond) => {
@@ -223,13 +232,13 @@ mod tests {
#[test]
fn mixnode_single_read_retrieval() {
let mut storage = MockStorage::new();
let bond1 = test_helpers::stored_mixnode_bond_fixture();
let bond2 = test_helpers::stored_mixnode_bond_fixture();
mixnodes(&mut storage).save(b"bond1", &bond1).unwrap();
mixnodes(&mut storage).save(b"bond2", &bond2).unwrap();
let bond1 = test_helpers::stored_mixnode_bond_fixture("owner1");
let bond2 = test_helpers::stored_mixnode_bond_fixture("owner2");
mixnodes().save(&mut storage, b"bond1", &bond1).unwrap();
mixnodes().save(&mut storage, b"bond2", &bond2).unwrap();
let res1 = storage::mixnodes_read(&storage).load(b"bond1").unwrap();
let res2 = storage::mixnodes_read(&storage).load(b"bond2").unwrap();
let res1 = mixnodes().load(&storage, b"bond1").unwrap();
let res2 = mixnodes().load(&storage, b"bond2").unwrap();
assert_eq!(bond1, res1);
assert_eq!(bond2, res2);
}
+9 -12
View File
@@ -52,10 +52,9 @@ pub(crate) mod tests {
fn returns_empty_status_for_unrewarded_nodes() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let node_identity =
@@ -93,10 +92,9 @@ pub(crate) mod tests {
// with single page
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let node_identity = "bobsnode".to_string();
@@ -216,10 +214,9 @@ pub(crate) mod tests {
fn returns_pending_next_delegator_page_status_when_there_are_more_delegators_to_reward() {
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let node_identity = "bobsnode".to_string();
+110 -98
View File
@@ -34,7 +34,7 @@ fn verify_rewarding_state(
info: MessageInfo,
rewarding_interval_nonce: u32,
) -> Result<(), ContractError> {
let state = mixnet_params_storage::contract_settings_read(storage).load()?;
let state = mixnet_params_storage::CONTRACT_SETTINGS.load(storage)?;
// check if this is executed by the permitted validator, if not reject the transaction
if info.sender != state.rewarding_validator_address {
@@ -70,7 +70,7 @@ pub(crate) fn try_begin_mixnode_rewarding(
info: MessageInfo,
rewarding_interval_nonce: u32,
) -> Result<Response, ContractError> {
let mut state = mixnet_params_storage::contract_settings_read(deps.storage).load()?;
let mut state = mixnet_params_storage::CONTRACT_SETTINGS.load(deps.storage)?;
// check if this is executed by the permitted validator, if not reject the transaction
if info.sender != state.rewarding_validator_address {
@@ -102,7 +102,7 @@ pub(crate) fn try_begin_mixnode_rewarding(
state.latest_rewarding_interval_nonce = rewarding_interval_nonce;
state.rewarding_in_progress = true;
mixnet_params_storage::contract_settings(deps.storage).save(&state)?;
mixnet_params_storage::CONTRACT_SETTINGS.save(deps.storage, &state)?;
let mut response = Response::new();
response.add_attribute(
@@ -341,7 +341,8 @@ pub(crate) fn try_reward_mixnode_v2(
Ok(current_total.unwrap() + delegation_rewarding_result.total_rewarded)
},
)?;
mixnodes_storage::mixnodes(deps.storage).update::<_, ContractError>(
mixnodes_storage::mixnodes().update::<_, ContractError>(
deps.storage,
mix_identity.as_bytes(),
|current_bond| {
// unwrap is fine because we just read the entry...
@@ -405,7 +406,7 @@ pub(crate) fn try_finish_mixnode_rewarding(
info: MessageInfo,
rewarding_interval_nonce: u32,
) -> Result<Response, ContractError> {
let mut state = mixnet_params_storage::contract_settings_read(deps.storage).load()?;
let mut state = mixnet_params_storage::CONTRACT_SETTINGS.load(deps.storage)?;
// check if this is executed by the permitted validator, if not reject the transaction
if info.sender != state.rewarding_validator_address {
@@ -425,7 +426,30 @@ pub(crate) fn try_finish_mixnode_rewarding(
}
state.rewarding_in_progress = false;
mixnet_params_storage::contract_settings(deps.storage).save(&state)?;
mixnet_params_storage::CONTRACT_SETTINGS.save(deps.storage, &state)?;
// // alternative:
// mixnet_params_storage::CONTRACT_SETTINGS.update(storage, |mut state| {
// // check if this is executed by the permitted validator, if not reject the transaction
// if info.sender != state.rewarding_validator_address {
// return Err(ContractError::Unauthorized);
// }
//
// if !state.rewarding_in_progress {
// return Err(ContractError::RewardingNotInProgress);
// }
//
// // make sure the validator is in sync with the contract state
// if rewarding_interval_nonce != state.latest_rewarding_interval_nonce {
// return Err(ContractError::InvalidRewardingIntervalNonce {
// received: rewarding_interval_nonce,
// expected: state.latest_rewarding_interval_nonce,
// });
// }
//
// state.rewarding_in_progress = false;
// Ok(state)
// })?;
Ok(Response::new())
}
@@ -465,10 +489,9 @@ pub mod tests {
fn can_only_be_called_by_specified_validator_address() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let res = try_begin_mixnode_rewarding(
@@ -492,10 +515,9 @@ pub mod tests {
fn cannot_be_called_if_rewarding_is_already_in_progress_with_little_day() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
try_begin_mixnode_rewarding(
@@ -519,10 +541,9 @@ pub mod tests {
fn can_be_called_if_rewarding_is_in_progress_if_sufficient_number_of_blocks_elapsed() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
try_begin_mixnode_rewarding(
@@ -550,13 +571,12 @@ pub mod tests {
fn provided_nonce_must_be_equal_the_current_plus_one() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let mut current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
current_state.latest_rewarding_interval_nonce = 42;
mixnet_params_storage::contract_settings(deps.as_mut().storage)
.save(&current_state)
mixnet_params_storage::CONTRACT_SETTINGS
.save(deps.as_mut().storage, &current_state)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
@@ -616,8 +636,8 @@ pub mod tests {
fn updates_contract_state() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let start_state = mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
let start_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = start_state.rewarding_validator_address;
@@ -629,8 +649,8 @@ pub mod tests {
)
.unwrap();
let new_state = mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
let new_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
assert!(new_state.rewarding_in_progress);
assert_eq!(
@@ -656,10 +676,9 @@ pub mod tests {
fn can_only_be_called_by_specified_validator_address() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
try_begin_mixnode_rewarding(
@@ -688,10 +707,9 @@ pub mod tests {
#[test]
fn cannot_be_called_if_rewarding_is_not_in_progress() {
let mut deps = test_helpers::init_contract();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let res = try_finish_mixnode_rewarding(
@@ -706,13 +724,12 @@ pub mod tests {
fn provided_nonce_must_be_equal_the_current_one() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let mut current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
current_state.latest_rewarding_interval_nonce = 42;
mixnet_params_storage::contract_settings(deps.as_mut().storage)
.save(&current_state)
mixnet_params_storage::CONTRACT_SETTINGS
.save(deps.as_mut().storage, &current_state)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
@@ -776,10 +793,9 @@ pub mod tests {
fn updates_contract_state() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
try_begin_mixnode_rewarding(
@@ -797,8 +813,8 @@ pub mod tests {
)
.unwrap();
let new_state = mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
let new_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
assert!(!new_state.rewarding_in_progress);
}
@@ -808,8 +824,8 @@ pub mod tests {
fn rewarding_mixnodes_outside_rewarding_period() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state = mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
@@ -856,8 +872,8 @@ pub mod tests {
fn rewarding_mixnodes_with_incorrect_rewarding_nonce() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state = mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
@@ -925,8 +941,8 @@ pub mod tests {
fn attempting_rewarding_mixnode_multiple_times_per_interval() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state = mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
@@ -994,8 +1010,8 @@ pub mod tests {
fn rewarding_mixnode_blockstamp_based() {
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state = mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
@@ -1016,8 +1032,12 @@ pub mod tests {
profit_margin_percent: Some(10),
};
mixnodes_storage::mixnodes(deps.as_mut().storage)
.save(node_identity.as_bytes(), &mixnode_bond)
mixnodes_storage::mixnodes()
.save(
deps.as_mut().storage,
node_identity.as_bytes(),
&mixnode_bond,
)
.unwrap();
mixnodes_storage::total_delegation(deps.as_mut().storage)
.save(node_identity.as_bytes(), &Uint128::new(initial_delegation))
@@ -1048,7 +1068,7 @@ pub mod tests {
assert_eq!(
initial_bond,
test_helpers::read_mixnode_bond_amount(deps.as_ref().storage, node_identity.as_bytes())
test_helpers::read_mixnode_bond_amount(deps.as_ref().storage, &node_identity)
.unwrap()
.u128()
);
@@ -1082,7 +1102,7 @@ pub mod tests {
try_finish_mixnode_rewarding(deps.as_mut(), info, 2).unwrap();
assert!(
test_helpers::read_mixnode_bond_amount(deps.as_ref().storage, node_identity.as_bytes())
test_helpers::read_mixnode_bond_amount(deps.as_ref().storage, &node_identity)
.unwrap()
.u128()
> initial_bond
@@ -1104,7 +1124,7 @@ pub mod tests {
env.block.height += storage::MINIMUM_BLOCK_AGE_FOR_REWARDING - 1;
let bond_before_rewarding =
test_helpers::read_mixnode_bond_amount(deps.as_ref().storage, node_identity.as_bytes())
test_helpers::read_mixnode_bond_amount(deps.as_ref().storage, &node_identity)
.unwrap()
.u128();
@@ -1122,7 +1142,7 @@ pub mod tests {
try_finish_mixnode_rewarding(deps.as_mut(), info, 3).unwrap();
assert!(
test_helpers::read_mixnode_bond_amount(deps.as_ref().storage, node_identity.as_bytes())
test_helpers::read_mixnode_bond_amount(deps.as_ref().storage, &node_identity)
.unwrap()
.u128()
> bond_before_rewarding
@@ -1149,8 +1169,8 @@ pub mod tests {
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state = mixnet_params_storage::contract_settings_read(deps.as_ref().storage)
.load()
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_ref().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let period_reward_pool = (INITIAL_REWARD_POOL / 100) * EPOCH_REWARD_PERCENT as u128;
@@ -1246,7 +1266,7 @@ pub mod tests {
assert_eq!(mix1_delegator1_reward, U128::from_num(22552615));
assert_eq!(mix1_delegator2_reward, U128::from_num(5638153));
let pre_reward_bond = test_helpers::read_mixnode_bond_amount(&deps.storage, b"alice")
let pre_reward_bond = test_helpers::read_mixnode_bond_amount(&deps.storage, "alice")
.unwrap()
.u128();
assert_eq!(pre_reward_bond, 10_000_000_000);
@@ -1260,7 +1280,7 @@ pub mod tests {
try_reward_mixnode_v2(deps.as_mut(), env, info, "alice".to_string(), params, 1).unwrap();
assert_eq!(
test_helpers::read_mixnode_bond_amount(&deps.storage, b"alice")
test_helpers::read_mixnode_bond_amount(&deps.storage, "alice")
.unwrap()
.u128(),
U128::from_num(pre_reward_bond) + U128::from_num(mix1_operator_profit)
@@ -1308,10 +1328,9 @@ pub mod tests {
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let mix_bond = Uint128(10000_000_000);
@@ -1390,10 +1409,9 @@ pub mod tests {
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let mix_bond = Uint128(10000_000_000);
@@ -1474,10 +1492,9 @@ pub mod tests {
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let mix_bond = Uint128(10000_000_000);
@@ -1736,10 +1753,9 @@ pub mod tests {
#[test]
fn cannot_be_called_if_rewarding_is_not_in_progress() {
let mut deps = test_helpers::init_contract();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let res = try_reward_next_mixnode_delegators_v2(
@@ -1756,10 +1772,9 @@ pub mod tests {
fn cannot_be_called_if_mixnodes_operator_wasnt_rewarded() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
try_begin_mixnode_rewarding(
@@ -1790,10 +1805,9 @@ pub mod tests {
// everything was done in a single reward call
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
try_add_mixnode(
@@ -1942,10 +1956,9 @@ pub mod tests {
// setup: bond > page limit delegators, reward operator + first batch
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let mix_bond = Uint128(10000_000_000);
@@ -2041,10 +2054,9 @@ pub mod tests {
// setup: bond > page limit delegators, reward operator + first batch
let mut deps = test_helpers::init_contract();
let mut env = mock_env();
let current_state =
mixnet_params_storage::contract_settings_read(deps.as_mut().storage)
.load()
.unwrap();
let current_state = mixnet_params_storage::CONTRACT_SETTINGS
.load(deps.as_mut().storage)
.unwrap();
let rewarding_validator_address = current_state.rewarding_validator_address;
let mix_bond = Uint128(10000_000_000);
+10 -8
View File
@@ -24,8 +24,8 @@ pub mod test_helpers {
use cosmwasm_std::{Empty, MemoryStorage};
use mixnet_contract::mixnode::NodeRewardParams;
use mixnet_contract::{
Gateway, GatewayBond, InstantiateMsg, Layer, MixNode, MixNodeBond, PagedGatewayResponse,
PagedMixnodeResponse, QueryMsg, RawDelegationData,
Gateway, GatewayBond, IdentityKeyRef, InstantiateMsg, Layer, MixNode, MixNodeBond,
PagedGatewayResponse, PagedMixnodeResponse, QueryMsg, RawDelegationData,
};
pub fn add_mixnode(sender: &str, stake: Vec<Coin>, deps: DepsMut) -> String {
@@ -139,13 +139,16 @@ pub mod test_helpers {
)
}
pub(crate) fn stored_mixnode_bond_fixture() -> mixnodes_storage::StoredMixnodeBond {
pub(crate) fn stored_mixnode_bond_fixture(owner: &str) -> mixnodes_storage::StoredMixnodeBond {
StoredMixnodeBond::new(
coin(50, DENOM),
Addr::unchecked("foo"),
Addr::unchecked(owner),
Layer::One,
12_345,
mix_node_fixture(),
MixNode {
identity_key: format!("id-{}", owner),
..mix_node_fixture()
},
None,
)
}
@@ -227,10 +230,9 @@ pub mod test_helpers {
// currently not used outside tests
pub(crate) fn read_mixnode_bond_amount(
storage: &dyn Storage,
identity: &[u8],
identity: IdentityKeyRef,
) -> StdResult<cosmwasm_std::Uint128> {
let bucket = mixnodes_storage::mixnodes_read(storage);
let node = bucket.load(identity)?;
let node = mixnodes_storage::mixnodes().load(storage, identity.as_bytes())?;
Ok(node.bond_amount.amount)
}
}