Skip to content

Commit c36eadf

Browse files
durchjstuczynneacsuDrazen Urch
committed
Total mix stake accounting (#794)
* Feature/persistent gateway storage (#784) * Sqlx struct stub * Initial schema * Initial error enum * Managed for persisted shared keys * Initial inbox manager * Comments * Using new database in clients handler * Extending gateway storage API * tokio::main + placeholder values * Removed old client store * Simplified logic of async packet processing * Renamed table + not null restriction * BandwidthManager * Removed sled dependency * Using centralised storage for bandwidth * Dead code removal * WIP connection_handler split and simplification Maybe it doesn't look like it right now, but once completed it will remove bunch of redundant checks for Nones etc * Further more explicit clients handler split * Minor cleanup * Temporary store for active client handles * Fixed error types * Error trait on iv and encrypted address * Authentication and registration moved to the handler * Removal of clients handler * Further logic simplification + returned explicit bandwidth values * Further cleanup and comments * Updated config with relevant changes * Basic bandwidth tracking in client * FreshHandle doc comments + fixed stagger issue * Removed side-effects from .map * More doc comments * Database migration on build * Increased default claimed bandwidth * Renaming * Fixed client determining available bandwidth * Removed dead sql table that might be used in the future * Windows workaround * Comment * Return error rather than cap credential * Feature/migrate hidden delegations (#786) * Remove migration code * Added function to iterate over delegation of variable type * Add unit tests * Refactored some naming and reused mix/gateway functionality * Borrow bucket instead of move * Linked with existing delegations function * Migration of left-over delegations * Remove unused imports * Put a gateway test as well, next to the mix one * Expose queries for all delegations * Change break point * Added client side calls to the new queries * Fix clippy * Added pagination and read check tests * Fix gateway test from the last commit * Test functions for (de)serialization of identity and owner (in)to storage keys * Add delegation function unit test * Feature guard import * Changed UnpackedDelegation from type to struct * Remove mutable parameter and put start_after in returned value * Made all delegations into iterator for OOM safety * Fix clippy * Add test for delegations iterator size in memory * Change map with if let for ease of read * Use DENOM instead of hardcoded value * Total mixnode stake accounting in the contract * GetTotalMixState query * Add total_mix_stake to validator api * cargo fmt * Handle errors properly * Gateway stake accounting * tests * Naming :) Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com> Co-authored-by: Bogdan-Ștefan Neacşu <bogdan@nymtech.net> Co-authored-by: Drazen Urch <durch@users.noreply.guthub.com>
1 parent 9b867b2 commit c36eadf

File tree

12 files changed

+321
-13
lines changed

12 files changed

+321
-13
lines changed

common/client-libs/validator-client/src/client.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,20 @@ impl<C> Client<C> {
182182
Ok(self.nymd.get_state_params().await?)
183183
}
184184

185+
pub async fn get_total_mix_stake(&self) -> Result<u128, ValidatorClientError>
186+
where
187+
C: CosmWasmClient + Sync,
188+
{
189+
Ok(self.nymd.get_total_mix_stake().await?.u128())
190+
}
191+
192+
pub async fn get_total_gateway_stake(&self) -> Result<u128, ValidatorClientError>
193+
where
194+
C: CosmWasmClient + Sync,
195+
{
196+
Ok(self.nymd.get_total_gateway_stake().await?.u128())
197+
}
198+
185199
// basically handles paging for us
186200
pub async fn get_all_nymd_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
187201
where

common/client-libs/validator-client/src/nymd/mod.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::nymd::wallet::DirectSecp256k1HdWallet;
1212
use cosmrs::rpc::endpoint::broadcast;
1313
use cosmrs::rpc::{Error as TendermintRpcError, HttpClientUrl};
1414
use cosmwasm_std::Coin;
15+
use cosmwasm_std::{Coin, Uint128};
1516
use mixnet_contract::{
1617
Addr, Delegation, ExecuteMsg, Gateway, GatewayOwnershipResponse, IdentityKey,
1718
LayerDistribution, MixNode, MixOwnershipResponse, PagedAllDelegationsResponse,
@@ -212,6 +213,26 @@ impl<C> NymdClient<C> {
212213
.await
213214
}
214215

216+
pub async fn get_total_mix_stake(&self) -> Result<Uint128, NymdError>
217+
where
218+
C: CosmWasmClient + Sync,
219+
{
220+
let request = QueryMsg::GetTotalMixStake {};
221+
self.client
222+
.query_contract_smart(self.contract_address()?, &request)
223+
.await
224+
}
225+
226+
pub async fn get_total_gateway_stake(&self) -> Result<Uint128, NymdError>
227+
where
228+
C: CosmWasmClient + Sync,
229+
{
230+
let request = QueryMsg::GetTotalGatewayStake {};
231+
self.client
232+
.query_contract_smart(self.contract_address()?, &request)
233+
.await
234+
}
235+
215236
/// Checks whether there is a bonded mixnode associated with the provided client's address
216237
pub async fn owns_mixnode(&self, address: &AccountId) -> Result<bool, NymdError>
217238
where

common/mixnet-contract/src/gateway.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ impl GatewayBond {
5959
pub fn gateway(&self) -> &Gateway {
6060
&self.gateway
6161
}
62+
63+
pub fn total_delegation(&self) -> Coin {
64+
self.total_delegation.clone()
65+
}
6266
}
6367

6468
impl PartialOrd for GatewayBond {

common/mixnet-contract/src/mixnode.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ impl MixNodeBond {
7979
pub fn mix_node(&self) -> &MixNode {
8080
&self.mix_node
8181
}
82+
83+
pub fn total_delegation(&self) -> Coin {
84+
self.total_delegation.clone()
85+
}
8286
}
8387

8488
impl PartialOrd for MixNodeBond {

common/mixnet-contract/src/msg.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ pub enum QueryMsg {
107107
address: Addr,
108108
},
109109
LayerDistribution {},
110+
GetTotalMixStake {},
111+
GetTotalGatewayStake {},
110112
}
111113

112114
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]

contracts/mixnet/src/contract.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,17 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
207207
gateway_identity,
208208
address,
209209
)?),
210+
QueryMsg::GetTotalMixStake {} => to_binary(&queries::query_total_mix_stake(deps)),
211+
QueryMsg::GetTotalGatewayStake {} => to_binary(&queries::query_total_gt_stake(deps)),
210212
};
211213

212214
Ok(query_res?)
213215
}
214-
215216
#[entry_point]
216217
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
218+
todo!("Calculate initial total mix and gateway stake after initial deployment");
219+
220+
#[allow(unreachable_code)]
217221
Ok(Default::default())
218222
}
219223

contracts/mixnet/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,7 @@ pub enum ContractError {
8989
identity: IdentityKey,
9090
address: Addr,
9191
},
92+
93+
#[error("Overflow error!")]
94+
Overflow(#[from] cosmwasm_std::OverflowError),
9295
}

contracts/mixnet/src/queries.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use crate::storage::{
77
all_gateway_delegations_read, all_mix_delegations_read, gateway_delegations_read,
88
gateways_owners_read, gateways_read, mix_delegations_read, mixnodes_owners_read, mixnodes_read,
99
read_layer_distribution, read_state_params, reverse_gateway_delegations_read,
10-
reverse_mix_delegations_read,
10+
reverse_mix_delegations_read, total_gateway_stake_value, total_mix_stake_value,
1111
};
1212
use config::defaults::DENOM;
13-
use cosmwasm_std::{coin, Addr, Deps, Order, StdResult};
13+
use cosmwasm_std::{coin, Addr, Deps, Order, StdResult, Uint128};
1414
use mixnet_contract::{
1515
Delegation, GatewayBond, GatewayOwnershipResponse, IdentityKey, LayerDistribution, MixNodeBond,
1616
MixOwnershipResponse, PagedAllDelegationsResponse, PagedGatewayDelegationsResponse,
@@ -93,6 +93,14 @@ pub(crate) fn query_layer_distribution(deps: Deps) -> LayerDistribution {
9393
read_layer_distribution(deps.storage)
9494
}
9595

96+
pub(crate) fn query_total_mix_stake(deps: Deps) -> Uint128 {
97+
total_mix_stake_value(deps.storage)
98+
}
99+
100+
pub(crate) fn query_total_gt_stake(deps: Deps) -> Uint128 {
101+
total_gateway_stake_value(deps.storage)
102+
}
103+
96104
/// Adds a 0 byte to terminate the `start_after` value given. This allows CosmWasm
97105
/// to get the succeeding key as the start of the next page.
98106
// S works for both `String` and `Addr` and that's what we wanted

contracts/mixnet/src/storage.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use crate::queries;
54
use crate::state::State;
65
use crate::transactions::MINIMUM_BLOCK_AGE_FOR_REWARDING;
6+
use crate::{error::ContractError, queries};
77
use cosmwasm_std::{Decimal, Order, StdResult, Storage, Uint128};
88
use cosmwasm_storage::{
99
bucket, bucket_read, singleton, singleton_read, Bucket, ReadonlyBucket, ReadonlySingleton,
@@ -24,6 +24,9 @@ use serde::Serialize;
2424
// singletons
2525
const CONFIG_KEY: &[u8] = b"config";
2626
const LAYER_DISTRIBUTION_KEY: &[u8] = b"layers";
27+
// Keeps total amount of stake towards mixnodes and gateways. Removing a bond removes all its delegations from the total, the reverse is true for adding a bond.
28+
const TOTAL_MIX_STAKE_KEY: &[u8] = b"total_mn";
29+
const TOTAL_GATEWAY_STAKE_KEY: &[u8] = b"total_gt";
2730

2831
// buckets
2932
const PREFIX_MIXNODES: &[u8] = b"mn";
@@ -48,6 +51,72 @@ pub fn config_read(storage: &dyn Storage) -> ReadonlySingleton<State> {
4851
singleton_read(storage, CONFIG_KEY)
4952
}
5053

54+
fn total_mix_stake(storage: &dyn Storage) -> ReadonlySingleton<Uint128> {
55+
singleton_read(storage, TOTAL_MIX_STAKE_KEY)
56+
}
57+
58+
pub fn mut_total_mix_stake(storage: &mut dyn Storage) -> Singleton<Uint128> {
59+
singleton(storage, TOTAL_MIX_STAKE_KEY)
60+
}
61+
62+
fn total_gateway_stake(storage: &dyn Storage) -> ReadonlySingleton<Uint128> {
63+
singleton_read(storage, TOTAL_GATEWAY_STAKE_KEY)
64+
}
65+
66+
pub fn mut_total_gateway_stake(storage: &mut dyn Storage) -> Singleton<Uint128> {
67+
singleton(storage, TOTAL_GATEWAY_STAKE_KEY)
68+
}
69+
70+
pub fn total_mix_stake_value(storage: &dyn Storage) -> Uint128 {
71+
match total_mix_stake(storage).load() {
72+
Ok(value) => value,
73+
Err(_e) => Uint128(0),
74+
}
75+
}
76+
77+
pub fn total_gateway_stake_value(storage: &dyn Storage) -> Uint128 {
78+
match total_gateway_stake(storage).load() {
79+
Ok(value) => value,
80+
Err(_e) => Uint128(0),
81+
}
82+
}
83+
84+
pub fn incr_total_mix_stake(
85+
amount: Uint128,
86+
storage: &mut dyn Storage,
87+
) -> Result<Uint128, ContractError> {
88+
let stake = total_mix_stake_value(storage).checked_add(amount)?;
89+
mut_total_mix_stake(storage).save(&stake)?;
90+
Ok(stake)
91+
}
92+
93+
pub fn decr_total_mix_stake(
94+
amount: Uint128,
95+
storage: &mut dyn Storage,
96+
) -> Result<Uint128, ContractError> {
97+
let stake = total_mix_stake_value(storage).checked_sub(amount)?;
98+
mut_total_mix_stake(storage).save(&stake)?;
99+
Ok(stake)
100+
}
101+
102+
pub fn incr_total_gateway_stake(
103+
amount: Uint128,
104+
storage: &mut dyn Storage,
105+
) -> Result<Uint128, ContractError> {
106+
let stake = total_gateway_stake_value(storage).checked_add(amount)?;
107+
mut_total_gateway_stake(storage).save(&stake)?;
108+
Ok(stake)
109+
}
110+
111+
pub fn decr_total_gateway_stake(
112+
amount: Uint128,
113+
storage: &mut dyn Storage,
114+
) -> Result<Uint128, ContractError> {
115+
let stake = total_gateway_stake_value(storage).checked_sub(amount)?;
116+
mut_total_gateway_stake(storage).save(&stake)?;
117+
Ok(stake)
118+
}
119+
51120
pub(crate) fn read_state_params(storage: &dyn Storage) -> StateParams {
52121
// note: In any other case, I wouldn't have attempted to unwrap this result, but in here
53122
// if we fail to load the stored state we would already be in the undefined behaviour land,

0 commit comments

Comments
 (0)