diff --git a/Cargo.lock b/Cargo.lock index 47513eecd84..dbff60b4588 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2946,7 +2946,6 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "rust_decimal", - "rust_decimal_macros", "serde 1.0.145", "serde_json", "sha2 0.9.9", diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index 17f474190d5..c0e07fc7f74 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -17,11 +17,10 @@ use namada::ledger::governance::parameters::GovParams; use namada::ledger::governance::storage as gov_storage; use namada::ledger::governance::utils::Votes; use namada::ledger::parameters::{storage as param_storage, EpochDuration}; -use namada::ledger::pos::types::{ - Epoch as PosEpoch, WeightedValidator, -}; +use namada::ledger::pos::types::{Epoch as PosEpoch, WeightedValidator}; use namada::ledger::pos::{ - self, is_validator_slashes_key, BondId, Bonds, PosParams, Slash, Unbonds, into_tm_voting_power, + self, into_tm_voting_power, is_validator_slashes_key, BondId, Bonds, + PosParams, Slash, Unbonds, }; use namada::types::address::Address; use namada::types::governance::{ @@ -938,17 +937,18 @@ pub async fn query_voting_power(ctx: Context, args: args::QueryVotingPower) { Some(validator) => { let validator = ctx.get(&validator); // Find voting power for the given validator - let validator_deltas_key = - pos::validator_deltas_key(&validator); - let validator_deltas = query_storage_value::< - pos::ValidatorDeltas, - >(&client, &validator_deltas_key) + let validator_deltas_key = pos::validator_deltas_key(&validator); + let validator_deltas = query_storage_value::( + &client, + &validator_deltas_key, + ) .await; match validator_deltas.and_then(|data| data.get(epoch)) { Some(val_stake) => { let bonded_stake: u64 = val_stake.try_into().expect( - "The sum of the bonded stake deltas shouldn't be negative", - ); + "The sum of the bonded stake deltas shouldn't be \ + negative", + ); let weighted = WeightedValidator { address: validator.clone(), bonded_stake, @@ -1001,22 +1001,24 @@ pub async fn query_voting_power(ctx: Context, args: args::QueryVotingPower) { } } let total_deltas_key = pos::total_deltas_key(); - let total_deltas = query_storage_value::( - &client, - &total_deltas_key, - ) - .await - .expect("Total bonded stake should always be set"); + let total_deltas = + query_storage_value::(&client, &total_deltas_key) + .await + .expect("Total bonded stake should always be set"); let total_bonded_stake = total_deltas .get(epoch) .expect("Total bonded stake should be always set in the current epoch"); let pos_params_key = pos::params_key(); - let pos_params = query_storage_value::(&client, &pos_params_key) - .await - .expect("PoS parameters should always exist in storage"); - let total_bonded_stake: u64 = total_bonded_stake.try_into().expect("total_bonded_stake should be a positive value"); - let total_voting_power = into_tm_voting_power(pos_params.tm_votes_per_token, total_bonded_stake); - + let pos_params = + query_storage_value::(&client, &pos_params_key) + .await + .expect("PoS parameters should always exist in storage"); + let total_bonded_stake: u64 = total_bonded_stake + .try_into() + .expect("total_bonded_stake should be a positive value"); + let total_voting_power = + into_tm_voting_power(pos_params.votes_per_token, total_bonded_stake); + println!("Total voting power: {}", total_voting_power); } @@ -1963,8 +1965,7 @@ async fn get_validator_stake( .expect("Total deltas should be defined"); let validator_stake = validator_deltas.get(epoch); - VotePower::try_from(validator_stake.unwrap_or_default()) - .unwrap_or_default() + VotePower::try_from(validator_stake.unwrap_or_default()).unwrap_or_default() } pub async fn get_delegators_delegation( diff --git a/apps/src/lib/config/genesis.rs b/apps/src/lib/config/genesis.rs index 03a614abdea..980167a18da 100644 --- a/apps/src/lib/config/genesis.rs +++ b/apps/src/lib/config/genesis.rs @@ -37,6 +37,7 @@ pub mod genesis_config { use namada::types::time::Rfc3339String; use namada::types::{storage, token}; use rust_decimal::Decimal; + use rust_decimal_macros::dec; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -547,9 +548,8 @@ pub mod genesis_config { max_validator_slots: config.pos_params.max_validator_slots, pipeline_len: config.pos_params.pipeline_len, unbonding_len: config.pos_params.unbonding_len, - votes_per_token: BasisPoints::new( - config.pos_params.votes_per_token, - ), + votes_per_token: Decimal::from(config.pos_params.votes_per_token) + / dec!(10_000), block_proposer_reward: config.pos_params.block_proposer_reward, block_vote_reward: config.pos_params.block_vote_reward, duplicate_vote_slash_rate: BasisPoints::new( diff --git a/apps/src/lib/node/ledger/shell/init_chain.rs b/apps/src/lib/node/ledger/shell/init_chain.rs index aef22a774dc..1f4136ef45f 100644 --- a/apps/src/lib/node/ledger/shell/init_chain.rs +++ b/apps/src/lib/node/ledger/shell/init_chain.rs @@ -273,7 +273,10 @@ where sum: Some(key_to_tendermint(&consensus_key).unwrap()), }; abci_validator.pub_key = Some(pub_key); - abci_validator.power = into_tm_voting_power(genesis.pos_params.tm_votes_per_token, validator.pos_data.tokens); + abci_validator.power = into_tm_voting_power( + genesis.pos_params.votes_per_token, + validator.pos_data.tokens, + ); response.validators.push(abci_validator); } Ok(response) diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index 75d373ea4b4..5c965721aab 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -35,10 +35,9 @@ use rust_decimal::Decimal; use thiserror::Error; use types::{ ActiveValidator, Bonds, CommissionRates, Epoch, GenesisValidator, Slash, - SlashType, Slashes, TotalVotingPowers, Unbond, Unbonds, - ValidatorConsensusKeys, ValidatorSet, ValidatorSetUpdate, ValidatorSets, - ValidatorState, ValidatorStates, ValidatorDeltas, - TotalDeltas + SlashType, Slashes, TotalDeltas, Unbond, Unbonds, ValidatorConsensusKeys, + ValidatorDeltas, ValidatorSet, ValidatorSetUpdate, ValidatorSets, + ValidatorState, ValidatorStates, }; use crate::btree_set::BTreeSetShims; @@ -158,7 +157,9 @@ pub trait PosReadOnly { &self, ) -> Result, Self::Error>; /// Read PoS total deltas for all validators (active and inactive) - fn read_total_deltas(&self) -> Result, Self::Error>; + fn read_total_deltas( + &self, + ) -> Result, Self::Error>; } /// PoS system trait to be implemented in integration that can read and write @@ -244,7 +245,6 @@ pub trait PosActions: PosReadOnly { &mut self, value: TotalDeltas, ) -> Result<(), Self::Error>; - ) -> Result<(), Self::Error>; /// Delete an emptied PoS bond (validator self-bond or a delegation). fn delete_bond( &mut self, @@ -285,8 +285,7 @@ pub trait PosActions: PosReadOnly { let BecomeValidatorData { consensus_key, state, - total_deltas, - voting_power, + deltas, commission_rate, max_commission_rate_change, } = become_validator( @@ -350,8 +349,7 @@ pub trait PosActions: PosReadOnly { validator: validator.clone(), }; let bond = self.read_bond(&bond_id)?; - let validator_deltas = - self.read_validator_deltas(validator)?; + let validator_deltas = self.read_validator_deltas(validator)?; let mut total_deltas = self.read_total_deltas()?; let mut validator_set = self.read_validator_set()?; @@ -406,9 +404,8 @@ pub trait PosActions: PosReadOnly { None => Err(UnbondError::NoBondFound)?, }; let unbond = self.read_unbond(&bond_id)?; - let mut validator_deltas = self - .read_validator_deltas(validator)? - .ok_or_else(|| { + let mut validator_deltas = + self.read_validator_deltas(validator)?.ok_or_else(|| { UnbondError::ValidatorHasNoBonds(validator.clone()) })?; let slashes = self.read_validator_slashes(validator)?; @@ -1249,7 +1246,8 @@ where } in validators.clone() { total_bonded_balance += *tokens; - // is some extra error handling needed here for casting the delta as i64? (TokenChange) + // is some extra error handling needed here for casting the delta as + // i64? (TokenChange) let delta = TokenChange::from(*tokens); total_bonded_delta = total_bonded_delta + delta; active.insert(WeightedValidator { @@ -1491,7 +1489,7 @@ where BecomeValidatorData { consensus_key, state, - total_deltas, + deltas, commission_rate, max_commission_rate_change, } @@ -1656,7 +1654,6 @@ where total_deltas.add_at_offset(delta, current_epoch, update_offset, params); - Ok(BondData { bond, validator_deltas, diff --git a/proof_of_stake/src/parameters.rs b/proof_of_stake/src/parameters.rs index 1c265bf1a84..c0e58ecd3fd 100644 --- a/proof_of_stake/src/parameters.rs +++ b/proof_of_stake/src/parameters.rs @@ -1,6 +1,9 @@ //! Proof-of-Stake system parameters use borsh::{BorshDeserialize, BorshSerialize}; +use rust_decimal::prelude::ToPrimitive; +use rust_decimal::Decimal; +use rust_decimal_macros::dec; use thiserror::Error; use crate::types::BasisPoints; @@ -20,7 +23,7 @@ pub struct PosParams { pub unbonding_len: u64, /// Used in validators' voting power calculation. Given in basis points /// (voting power per ten thousand tokens). - pub votes_per_token: BasisPoints, + pub votes_per_token: Decimal, /// Amount of tokens rewarded to a validator for proposing a block pub block_proposer_reward: u64, /// Amount of tokens rewarded to each validator that voted on a block @@ -41,7 +44,7 @@ impl Default for PosParams { pipeline_len: 2, unbonding_len: 6, // 1 voting power per 1000 tokens - votes_per_token: BasisPoints::new(10), + votes_per_token: dec!(0.001), block_proposer_reward: 100, block_vote_reward: 1, // slash 5% @@ -61,7 +64,7 @@ pub enum ValidationError { )] TotalVotingPowerTooLarge(u64), #[error("Votes per token cannot be greater than 1, got {0}")] - VotesPerTokenGreaterThanOne(BasisPoints), + VotesPerTokenGreaterThanOne(Decimal), #[error("Pipeline length must be >= 2, got {0}")] PipelineLenTooShort(u64), #[error( @@ -101,23 +104,23 @@ impl PosParams { // Check maximum total voting power cannot get larger than what // Tendermint allows - let max_total_voting_power = self.max_validator_slots - * (self.votes_per_token * TOKEN_MAX_AMOUNT); + let max_total_voting_power = Decimal::from(self.max_validator_slots) + * (self.votes_per_token * Decimal::from(TOKEN_MAX_AMOUNT)); match i64::try_from(max_total_voting_power) { Ok(max_total_voting_power_i64) => { if max_total_voting_power_i64 > MAX_TOTAL_VOTING_POWER { errors.push(ValidationError::TotalVotingPowerTooLarge( - max_total_voting_power, + max_total_voting_power.to_u64().unwrap(), )) } } Err(_) => errors.push(ValidationError::TotalVotingPowerTooLarge( - max_total_voting_power, + max_total_voting_power.to_u64().unwrap(), )), } // Check that there is no more than 1 vote per token - if self.votes_per_token > BasisPoints::new(10_000) { + if self.votes_per_token > Decimal::ONE { errors.push(ValidationError::VotesPerTokenGreaterThanOne( self.votes_per_token, )) @@ -153,6 +156,8 @@ mod tests { #[cfg(any(test, feature = "testing"))] pub mod testing { use proptest::prelude::*; + use rust_decimal::Decimal; + use rust_decimal_macros::dec; use super::*; @@ -170,7 +175,7 @@ pub mod testing { max_validator_slots, pipeline_len, unbonding_len, - votes_per_token: BasisPoints::new(votes_per_token), + votes_per_token: Decimal::from(votes_per_token) / dec!(10_000), // The rest of the parameters that are not being used in the PoS // VP are constant for now ..Default::default() diff --git a/proof_of_stake/src/types.rs b/proof_of_stake/src/types.rs index d522190c6df..a6fc1062ca2 100644 --- a/proof_of_stake/src/types.rs +++ b/proof_of_stake/src/types.rs @@ -5,11 +5,10 @@ use std::collections::{BTreeSet, HashMap}; use std::convert::TryFrom; use std::fmt::Display; use std::hash::Hash; -use std::num::TryFromIntError; -use std::ops::{Add, AddAssign, Mul, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Mul, Sub}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use rust_decimal::Decimal; +use rust_decimal::prelude::{Decimal, ToPrimitive}; use crate::epoched::{ Epoched, EpochedDelta, OffsetPipelineLen, OffsetUnbondingLen, @@ -35,7 +34,8 @@ pub type Unbonds = pub type ValidatorSets
= Epoched, OffsetUnbondingLen>; /// Epoched total deltas. -pub type TotalDeltas = EpochedDelta; +pub type TotalDeltas = + EpochedDelta; /// Epoched validator commission rate pub type CommissionRates = Epoched; @@ -329,9 +329,6 @@ pub trait PublicKeyTmRawHash { fn tm_raw_hash(&self) -> String; } - - - impl Epoch { /// Iterate a range of consecutive epochs starting from `self` of a given /// length. Work-around for `Step` implementation pending on stabilization of . @@ -580,11 +577,30 @@ impl Mul for BasisPoints { } } -/// Calculate voting power in the tendermint context (which is stored as i64) from the number of tokens -pub fn into_tm_voting_power(votes_per_token: Decimal, tokens: impl Into) -> i64 { +/// Calculate voting power in the tendermint context (which is stored as i64) +/// from the number of tokens +pub fn into_tm_voting_power( + votes_per_token: Decimal, + tokens: impl Into, +) -> i64 { let prod = decimal_mult_u64(votes_per_token, tokens.into()); i64::try_from(prod).expect("Invalid voting power") } +/// Multiply a value of type Decimal with one of type u64 and then return the +/// truncated u64 +pub fn decimal_mult_u64(dec: Decimal, int: u64) -> u64 { + let prod = dec * Decimal::from(int); + // truncate the number to the floor + prod.to_u64().expect("Product is out of bounds") +} + +/// Multiply a value of type Decimal with one of type i128 and then return the +/// truncated i128 +pub fn decimal_mult_i128(dec: Decimal, int: i128) -> i128 { + let prod = dec * Decimal::from(int); + // truncate the number to the floor + prod.to_i128().expect("Product is out of bounds") +} #[cfg(test)] pub mod tests { diff --git a/proof_of_stake/src/validation.rs b/proof_of_stake/src/validation.rs index 3fdf9c24080..0761facab6d 100644 --- a/proof_of_stake/src/validation.rs +++ b/proof_of_stake/src/validation.rs @@ -16,10 +16,9 @@ use crate::btree_set::BTreeSetShims; use crate::epoched::DynEpochOffset; use crate::parameters::PosParams; use crate::types::{ - BondId, Bonds, Epoch, PublicKeyTmRawHash, Slash, Slashes, - Unbonds, ValidatorConsensusKeys, ValidatorSets, - ValidatorState, ValidatorStates, ValidatorDeltas, - WeightedValidator, TotalDeltas, + BondId, Bonds, Epoch, PublicKeyTmRawHash, Slash, Slashes, TotalDeltas, + Unbonds, ValidatorConsensusKeys, ValidatorDeltas, ValidatorSets, + ValidatorState, ValidatorStates, WeightedValidator, }; #[allow(missing_docs)] @@ -387,7 +386,7 @@ where total_stake_by_epoch, validator_set_pre, validator_set_post, - total_deltas_by_epoch, + total_deltas_by_epoch: _, bonded_stake_by_epoch, new_validators, } = Validate::::accumulate_changes( @@ -459,11 +458,12 @@ where for validator in &post.active { match total_stakes.get(&validator.address) { Some((_stake_pre, stake_post)) => { - // Any validator who's total deltas changed, // should // be up-to-date - if validator.bonded_stake != Into::::into(*stake_post) { + if validator.bonded_stake + != Into::::into(*stake_post) + { errors.push( Error::InvalidActiveValidator( validator.clone(), @@ -505,7 +505,9 @@ where { is_valid = validator .bonded_stake - == Into::::into(*last_total_stake); + == Into::::into( + *last_total_stake, + ); break; } else { search_epoch -= 1; @@ -528,7 +530,9 @@ where // be up-to-date match total_stakes.get(&validator.address) { Some((_stake_pre, stake_post)) => { - if validator.bonded_stake != Into::::into(*stake_post) { + if validator.bonded_stake + != Into::::into(*stake_post) + { errors.push( Error::InvalidInactiveValidator( validator.clone(), @@ -570,7 +574,9 @@ where { is_valid = validator .bonded_stake - == Into::::into(*last_total_stake); + == Into::::into( + *last_total_stake, + ); break; } else { search_epoch -= 1; @@ -650,10 +656,7 @@ where bonded_stake, } = &new_validator; // The new validator must have set all the required fields - if !(*has_state - && *has_total_deltas - && *has_bonded_stake) - { + if !(*has_state && *has_total_deltas && *has_bonded_stake) { errors.push(Error::InvalidNewValidator( address.clone(), new_validator.clone(), @@ -924,7 +927,7 @@ where { fn accumulate_changes( changes: Vec>, - params: &PosParams, + _params: &PosParams, constants: &Constants, errors: &mut Vec>, ) -> Accumulator { @@ -939,7 +942,7 @@ where total_deltas, total_stake_by_epoch, total_deltas_by_epoch, - bonded_stake_by_epoch, + bonded_stake_by_epoch: _, validator_set_pre, validator_set_post, new_validators, @@ -962,7 +965,7 @@ where address, data, ), - TotalDeltas(data) => Self::validator_total_deltas( + ValidatorDeltas(data) => Self::validator_total_deltas( constants, errors, total_deltas, @@ -971,7 +974,6 @@ where address, data, ), - }, Balance(data) => Self::balance(errors, balance_delta, data), Bond { id, data, slashes } => { @@ -1798,10 +1800,7 @@ where fn total_deltas( constants: &Constants, errors: &mut Vec>, - total_delta_by_epoch: &mut HashMap< - Epoch, - TokenChange, - >, + total_delta_by_epoch: &mut HashMap, data: Data>, ) { match (data.pre, data.post) { diff --git a/shared/src/ledger/governance/utils.rs b/shared/src/ledger/governance/utils.rs index 9bae8944f5a..5de8fb57d5c 100644 --- a/shared/src/ledger/governance/utils.rs +++ b/shared/src/ledger/governance/utils.rs @@ -8,7 +8,7 @@ use thiserror::Error; use crate::ledger::governance::storage as gov_storage; use crate::ledger::pos; -use crate::ledger::pos::{BondId, Bonds, ValidatorSets, ValidatorDeltas}; +use crate::ledger::pos::{BondId, Bonds, ValidatorDeltas, ValidatorSets}; use crate::ledger::storage::{DBIter, Storage, StorageHasher, DB}; use crate::types::address::Address; use crate::types::governance::{ProposalVote, TallyResult, VotePower}; diff --git a/shared/src/ledger/pos/mod.rs b/shared/src/ledger/pos/mod.rs index bb3892088d3..79c7b1edc6a 100644 --- a/shared/src/ledger/pos/mod.rs +++ b/shared/src/ledger/pos/mod.rs @@ -6,7 +6,7 @@ pub mod vp; pub use namada_proof_of_stake; pub use namada_proof_of_stake::parameters::PosParams; pub use namada_proof_of_stake::types::{ - self, Slash, Slashes, ValidatorStates, decimal_mult_u64 + self, decimal_mult_u64, Slash, Slashes, ValidatorStates, }; use namada_proof_of_stake::PosBase; use rust_decimal::Decimal; @@ -31,8 +31,12 @@ pub fn staking_token_address() -> Address { address::xan() } -/// Calculate voting power in the tendermint context (which is stored as i64) from the number of tokens -pub fn into_tm_voting_power(votes_per_token: Decimal, tokens: impl Into) -> i64 { +/// Calculate voting power in the tendermint context (which is stored as i64) +/// from the number of tokens +pub fn into_tm_voting_power( + votes_per_token: Decimal, + tokens: impl Into, +) -> i64 { let prod = decimal_mult_u64(votes_per_token, tokens.into()); i64::try_from(prod).expect("Invalid validator voting power (i64)") } @@ -261,7 +265,6 @@ mod macros { let value = $crate::ledger::storage_api::StorageRead::read_bytes(self, &total_deltas_key())?.unwrap(); Ok($crate::ledger::storage::types::decode(value).unwrap()) - Ok($crate::ledger::storage::types::decode(value).unwrap()) } } } diff --git a/shared/src/ledger/pos/storage.rs b/shared/src/ledger/pos/storage.rs index b161e1c753f..2aec4122cb0 100644 --- a/shared/src/ledger/pos/storage.rs +++ b/shared/src/ledger/pos/storage.rs @@ -1,14 +1,12 @@ //! Proof-of-Stake storage keys and storage integration via [`PosBase`] trait. use namada_proof_of_stake::parameters::PosParams; -use namada_proof_of_stake::types::{ -ValidatorStates, -}; +use namada_proof_of_stake::types::ValidatorStates; use namada_proof_of_stake::{types, PosBase}; use super::{ - BondId, Bonds, CommissionRates, ValidatorConsensusKeys, ValidatorSets, ValidatorDeltas, TotalDeltas, - ADDRESS, + BondId, Bonds, CommissionRates, TotalDeltas, ValidatorConsensusKeys, + ValidatorDeltas, ValidatorSets, ADDRESS, }; use crate::ledger::storage::types::{decode, encode}; use crate::ledger::storage::{self, Storage, StorageHasher}; @@ -421,8 +419,7 @@ where &self, key: &Self::Address, ) -> Option> { - let (value, _gas) = - self.read(&validator_deltas_key(key)).unwrap(); + let (value, _gas) = self.read(&validator_deltas_key(key)).unwrap(); value.map(|value| decode(value).unwrap()) } @@ -458,7 +455,7 @@ where } fn read_total_deltas(&self) -> TotalDeltas { - let (value, _gas) = self.read(&total_staked_tokens_key()).unwrap(); + let (value, _gas) = self.read(&total_deltas_key()).unwrap(); decode(value.unwrap()).unwrap() } diff --git a/shared/src/ledger/pos/vp.rs b/shared/src/ledger/pos/vp.rs index e8a4439be69..89ed161d4f5 100644 --- a/shared/src/ledger/pos/vp.rs +++ b/shared/src/ledger/pos/vp.rs @@ -7,23 +7,21 @@ use borsh::BorshDeserialize; use itertools::Itertools; pub use namada_proof_of_stake; pub use namada_proof_of_stake::parameters::PosParams; -pub use namada_proof_of_stake::types::{ - self, Slash, Slashes, ValidatorStates -}; +pub use namada_proof_of_stake::types::{self, Slash, Slashes, ValidatorStates}; use namada_proof_of_stake::validation::validate; use namada_proof_of_stake::{validation, PosReadOnly}; use rust_decimal::Decimal; use thiserror::Error; use super::{ - bond_key, is_bond_key, is_params_key, is_total_deltas_key, - is_unbond_key, is_validator_set_key, is_validator_deltas_key, - params_key, staking_token_address, unbond_key, validator_commission_rate_key, - validator_consensus_key_key, validator_max_commission_rate_change_key, - validator_set_key, validator_slashes_key, validator_state_key, total_deltas_key, - validator_deltas_key, BondId, Bonds, - CommissionRates, Unbonds, ValidatorConsensusKeys, ValidatorSets, - ValidatorDeltas, + bond_key, is_bond_key, is_params_key, is_total_deltas_key, is_unbond_key, + is_validator_deltas_key, is_validator_set_key, params_key, + staking_token_address, total_deltas_key, unbond_key, + validator_commission_rate_key, validator_consensus_key_key, + validator_deltas_key, validator_max_commission_rate_change_key, + validator_set_key, validator_slashes_key, validator_state_key, BondId, + Bonds, CommissionRates, Unbonds, ValidatorConsensusKeys, ValidatorDeltas, + ValidatorSets, }; use crate::impl_pos_read_only; use crate::ledger::governance::vp::is_proposal_accepted; diff --git a/tests/src/native_vp/pos.rs b/tests/src/native_vp/pos.rs index 4b1abca5eda..0df5a2485b8 100644 --- a/tests/src/native_vp/pos.rs +++ b/tests/src/native_vp/pos.rs @@ -579,8 +579,7 @@ pub mod testing { DynEpochOffset, Epoched, EpochedDelta, }; use namada_tx_prelude::proof_of_stake::types::{ - Bond, Unbond, ValidatorState, - WeightedValidator, + Bond, Unbond, ValidatorState, WeightedValidator, }; use namada_tx_prelude::proof_of_stake::{ staking_token_address, BondId, Bonds, PosParams, Unbonds, @@ -590,10 +589,6 @@ pub mod testing { use crate::tx::{self, tx_host_env}; - const TOKENS_PER_NAM: i128 = - namada::ledger::pos::namada_proof_of_stake::parameters::TOKENS_PER_NAM - as i128; - #[derive(Clone, Debug, Default)] pub struct TestValidator { pub address: Option
, @@ -678,7 +673,7 @@ pub mod testing { #[derivative(Debug = "ignore")] pk: PublicKey, }, - ValidatorTotalDeltas { + ValidatorDeltas { validator: Address, delta: i128, offset: DynEpochOffset, @@ -959,13 +954,12 @@ pub mod testing { let offset = DynEpochOffset::UnbondingLen; let token_delta = -amount.change(); - let mut changes = Vec::with_capacity(6); - // IMPORTANT: we have to update `ValidatorSet` and - // `TotalVotingPower` before we update - // `ValidatorTotalDeltas`, because they needs to - // read the total deltas before they change. + // IMPORTANT: we have to update `ValidatorSet` before we + // update `ValidatorDeltas`, because + // they needs to read the total deltas + // before they change. changes.extend([ PosStorageChange::ValidatorSet { validator: validator.clone(), @@ -979,11 +973,11 @@ pub mod testing { PosStorageChange::ValidatorDeltas { validator: validator.clone(), delta: token_delta, - offset: offset, + offset, }, ]); - // do I need ValidatorDeltas in here again?? + // do I need ValidatorDeltas in here again?? changes.extend([ // IMPORTANT: we have to update `Unbond` before we // update `Bond`, because it needs to read the bonds to @@ -1195,8 +1189,7 @@ pub mod testing { tx::ctx().write_unbond(&bond_id, unbonds).unwrap(); } PosStorageChange::TotalDeltas { delta, offset } => { - let mut total_deltas = - tx::ctx().read_total_deltas().unwrap(); + let mut total_deltas = tx::ctx().read_total_deltas().unwrap(); match offset { Either::Left(offset) => { total_deltas.add_at_offset( @@ -1215,9 +1208,7 @@ pub mod testing { ); } } - tx::ctx() - .write_total_deltas(total_deltas) - .unwrap() + tx::ctx().write_total_deltas(total_deltas).unwrap() } PosStorageChange::ValidatorAddressRawHash { address, @@ -1255,7 +1246,7 @@ pub mod testing { .write_validator_consensus_key(&validator, consensus_key) .unwrap(); } - PosStorageChange::ValidatorTotalDeltas { + PosStorageChange::ValidatorDeltas { validator, delta, offset, @@ -1347,7 +1338,8 @@ pub mod testing { .and_then(|deltas| deltas.get(epoch)); match validator_stake { Some(validator_stake) => { - let tokens_pre: u64 = validator_stake.try_into().unwrap(); + let tokens_pre: u64 = + validator_stake.try_into().unwrap(); let tokens_post: u64 = (validator_stake + token_delta).try_into().unwrap(); let weighed_validator_pre = WeightedValidator { diff --git a/tx_prelude/src/proof_of_stake.rs b/tx_prelude/src/proof_of_stake.rs index e65a097eec7..d71ee832b69 100644 --- a/tx_prelude/src/proof_of_stake.rs +++ b/tx_prelude/src/proof_of_stake.rs @@ -2,11 +2,11 @@ pub use namada::ledger::pos::*; use namada::ledger::pos::{ - bond_key, namada_proof_of_stake, params_key, - unbond_key, validator_address_raw_hash_key, validator_commission_rate_key, - validator_consensus_key_key, validator_max_commission_rate_change_key, - validator_set_key, validator_slashes_key, validator_state_key, - validator_deltas_key + bond_key, namada_proof_of_stake, params_key, unbond_key, + validator_address_raw_hash_key, validator_commission_rate_key, + validator_consensus_key_key, validator_deltas_key, + validator_max_commission_rate_change_key, validator_set_key, + validator_slashes_key, validator_state_key, }; use namada::types::address::Address; use namada::types::transaction::InitValidator; @@ -174,7 +174,7 @@ impl namada_proof_of_stake::PosActions for Ctx { key: &Self::Address, value: ValidatorDeltas, ) -> Result<(), Self::Error> { - self.write(&validator_total_deltas_key(key), &value) + self.write(&validator_deltas_key(key), &value) } fn write_bond( diff --git a/wasm/checksums.json b/wasm/checksums.json index 22dc699c303..22e03da1151 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,18 +1,19 @@ { - "tx_bond.wasm": "tx_bond.059b1256240d15a64cf419f3a2d24af1496211c386d85acc3733095bc2e5da9b.wasm", - "tx_ibc.wasm": "tx_ibc.4eeb30bc1e6a32b8efe8958eab568082a238db01eb98340f28a9fa41371a3753.wasm", - "tx_init_account.wasm": "tx_init_account.85d017ac76e51f359fa07e753c0e6fcbd3341e7661492cbf2801cf3c41480dd4.wasm", - "tx_init_nft.wasm": "tx_init_nft.fbeb1687a364b2c249c9fd69588ff0985bd9c1f8f4c93e5328de1e9ba527d991.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.43b52414649bb0fec86dfb35d001656c1825bc5906e450e8b0c3a60aaa5f3d45.wasm", - "tx_init_validator.wasm": "tx_init_validator.6ccb7fcf246cb7a2f97a5dfdcefe16ee1add72a832081c2572adc2d7a355cf56.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.f2ed21521c676f04be4c6278cc60bec83265c3750437c87d9ea681b830767d71.wasm", - "tx_transfer.wasm": "tx_transfer.b6fc342f4a76918874e6d037a3864e4369dbba7cd7d558622e7a723e3d854da3.wasm", - "tx_unbond.wasm": "tx_unbond.6e7316d08bf8ab9a6fb1889f64a5a2265ee0399661dbb48e33555170545d1c7c.wasm", - "tx_update_vp.wasm": "tx_update_vp.6d291dadb43545a809ba33fe26582b7984c67c65f05e363a93dbc62e06a33484.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.d0a87d58f64f46586ae3d83852deee269e22520f4780875c05aaf1731044c356.wasm", - "tx_withdraw.wasm": "tx_withdraw.e5dcc5ef2362018c1fa5ea02912528ee929aa7b6fefcf06f4ccf7509bfa52283.wasm", - "vp_nft.wasm": "vp_nft.9be5a821bc7b3075b917e8ead45893502d82cc7417e6af50dfd3f6baf36243e0.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.8e2e45ff165d40dc8249188aca108e5cba86ac5dd1cd989b0237cadd4b66bfdf.wasm", - "vp_token.wasm": "vp_token.4a0446f20e7436de1e889c640a11644d1a1295c4d29e45b24582df2b9ed3176e.wasm", - "vp_user.wasm": "vp_user.eb1d6f1f524c28571ad0f21f75371aa635257313cea2702b9a70e5022fe6c3ef.wasm" -} + "tx_bond.wasm": "tx_bond.bc30201ee0b2a4a6575d141186ba92e49ff50b5ca59ef8f0972fd474db567fde.wasm", + "tx_from_intent.wasm": "tx_from_intent.ca53fb741d257b0f322a6d7348e13a097d3007147a49b206fb85ee8544ffda49.wasm", + "tx_ibc.wasm": "tx_ibc.ad8f7cd5a01e6845ab682b41fa7dfe6d9d01c53e23c676f520f62ffa58017550.wasm", + "tx_init_account.wasm": "tx_init_account.b21236668699e1162ff976e2a579e29072b900dca6b0c3a512671bcf07443055.wasm", + "tx_init_nft.wasm": "tx_init_nft.eabf28683527f98fd122cf3a546d3bd1181b16480eb31073cb5146d7312801e6.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.1b36a48a57136227f4ff5d5dfe894ab95596ca4093bdb9063df1b982e44dd491.wasm", + "tx_init_validator.wasm": "tx_init_validator.40164d82e5971de2976cc9513ad0dd35be12dee79dadc0b812cb73e056f4072e.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.4896080a0649c052cae8a7dc17aef2c2aa813c2e68d5db0111174a919e6b4032.wasm", + "tx_transfer.wasm": "tx_transfer.687523568078f4eb77167d76420d413b356cebebf38c297252e8054dad83953b.wasm", + "tx_unbond.wasm": "tx_unbond.6eed1afb416e4d784d95ce3f14f3543e919b2ebdce6ea5b6a122fa04facd1198.wasm", + "tx_update_vp.wasm": "tx_update_vp.4d377057e6a8ed4404d8d5f7a7784244db67e16cc34aa15bf9b8ec6130bf6d95.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.310c89905a5bfea8b59f52bc8aae0d1fc14cf13f566ae36fd1b42e1ec9b76e9e.wasm", + "tx_withdraw.wasm": "tx_withdraw.65b5ddeee878bebd0b83044092f13c6ec0215ff6a8ed7d49549be29d429b3c81.wasm", + "vp_nft.wasm": "vp_nft.e51439c4332327dfdd9d63fc03ac0b1174357fb788d1d8f78d2e51a5fe01bfe3.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.20dda6deabe03766faaf3ee86ec305bb5b95b3eff9eba1039fa74618c36db5d2.wasm", + "vp_token.wasm": "vp_token.94bad47495fcd5d2259ba1a7ead06caedc1e610b4c9513100a75ee2eaa7462ea.wasm", + "vp_user.wasm": "vp_user.b779866a3e3e3016b9b51c8b50899f5d5d919b4bb5d3afef9d35890278b90512.wasm" +} \ No newline at end of file diff --git a/wasm/wasm_source/src/tx_bond.rs b/wasm/wasm_source/src/tx_bond.rs index 4a438ad60f4..047a748f23e 100644 --- a/wasm/wasm_source/src/tx_bond.rs +++ b/wasm/wasm_source/src/tx_bond.rs @@ -97,7 +97,8 @@ mod tests { let signed_tx = tx.sign(&key); let tx_data = signed_tx.data.unwrap(); - // Ensure that the initial stake of the sole validator is equal to the PoS account balance + // Ensure that the initial stake of the sole validator is equal to the + // PoS account balance let pos_balance_key = token::balance_key( &staking_token_address(), &Address::Internal(InternalAddress::PoS), @@ -109,13 +110,15 @@ mod tests { // Read some data before the tx is executed let total_deltas_pre = ctx().read_total_deltas()?; - let validator_deltas_pre = ctx().read_validator_deltas(&bond.validator)?.unwrap(); + let validator_deltas_pre = + ctx().read_validator_deltas(&bond.validator)?.unwrap(); let validator_sets_pre = ctx().read_validator_set()?; apply_tx(ctx(), tx_data)?; // Read the data after the tx is executed. - let validator_deltas_post = ctx().read_validator_deltas(&bond.validator)?.unwrap(); + let validator_deltas_post = + ctx().read_validator_deltas(&bond.validator)?.unwrap(); let total_deltas_post = ctx().read_total_deltas()?; let validator_sets_post = ctx().read_validator_set()?; @@ -125,9 +128,10 @@ mod tests { // - `#{PoS}/total_deltas` // - `#{PoS}/validator_set` - // Check that the validator set and deltas are unchanged before pipeline length and that they are - // updated between the pipeline and unbonding lengths - // TODO: should end be pipeline + unbonding now? + // Check that the validator set and deltas are unchanged before pipeline + // length and that they are updated between the pipeline and + // unbonding lengths TODO: should end be pipeline + unbonding + // now? if bond.amount == token::Amount::from(0) { // None of the optional storage fields should have been updated assert_eq!(validator_sets_pre, validator_sets_post); @@ -138,20 +142,20 @@ mod tests { assert_eq!( validator_deltas_post.get(epoch), Some(initial_stake.into()), - "The validator deltas before the pipeline offset must not change \ - - checking in epoch: {epoch}" + "The validator deltas before the pipeline offset must not \ + change - checking in epoch: {epoch}" ); assert_eq!( total_deltas_post.get(epoch), Some(initial_stake.into()), - "The total deltas before the pipeline offset must not change \ - - checking in epoch: {epoch}" + "The total deltas before the pipeline offset must not \ + change - checking in epoch: {epoch}" ); assert_eq!( validator_sets_pre.get(epoch), validator_sets_post.get(epoch), "Validator set before pipeline offset must not change - \ - checking epoch {epoch}" + checking epoch {epoch}" ); } for epoch in pos_params.pipeline_len..=pos_params.unbonding_len { @@ -160,19 +164,20 @@ mod tests { assert_eq!( validator_deltas_post.get(epoch), Some(expected_stake), - "The total deltas at and after the pipeline offset epoch must \ - be incremented by the bonded amount - checking in epoch: \ - {epoch}" + "The total deltas at and after the pipeline offset epoch \ + must be incremented by the bonded amount - checking in \ + epoch: {epoch}" ); assert_eq!( total_deltas_post.get(epoch), Some(expected_stake), - "The total deltas at and after the pipeline offset epoch must \ - be incremented by the bonded amount - checking in epoch: \ - {epoch}" + "The total deltas at and after the pipeline offset epoch \ + must be incremented by the bonded amount - checking in \ + epoch: {epoch}" ); assert_ne!( - validator_sets_pre.get(epoch), validator_sets_post.get(epoch), + validator_sets_pre.get(epoch), + validator_sets_post.get(epoch), "Validator set at and after pipeline offset must have \ changed - checking epoch {epoch}" ); @@ -224,7 +229,8 @@ mod tests { } } else { // This is a self-bond - // Check that a bond already exists from genesis with initial stake for the validator + // Check that a bond already exists from genesis with initial stake + // for the validator let genesis_epoch = namada_tx_prelude::proof_of_stake::types::Epoch::from(0); for epoch in 0..pos_params.pipeline_len { diff --git a/wasm/wasm_source/src/tx_unbond.rs b/wasm/wasm_source/src/tx_unbond.rs index 6c64fb3d021..4f1f7fcdc0e 100644 --- a/wasm/wasm_source/src/tx_unbond.rs +++ b/wasm/wasm_source/src/tx_unbond.rs @@ -102,8 +102,8 @@ mod tests { } }); - // Initialize the delegation if it is the case - unlike genesis validator's self-bond, - // this happens at pipeline offset + // Initialize the delegation if it is the case - unlike genesis + // validator's self-bond, this happens at pipeline offset if is_delegation { ctx().bond_tokens( unbond.source.as_ref(), @@ -139,9 +139,8 @@ mod tests { let total_deltas_pre = ctx().read_total_deltas()?; let validator_sets_pre = ctx().read_validator_set()?; - let validator_deltas_pre = ctx() - .read_validator_deltas(&unbond.validator)? - .unwrap(); + let validator_deltas_pre = + ctx().read_validator_deltas(&unbond.validator)?.unwrap(); let bonds_pre = ctx().read_bond(&unbond_id)?.unwrap(); dbg!(&bonds_pre); @@ -176,8 +175,8 @@ mod tests { assert_eq!( validator_deltas_post.as_ref().unwrap().get(epoch), Some(expected_amount_before_pipeline.into()), - "The validator deltas before the pipeline offset must not change \ - - checking in epoch: {epoch}" + "The validator deltas before the pipeline offset must not \ + change - checking in epoch: {epoch}" ); assert_eq!( total_deltas_post.get(epoch), @@ -186,7 +185,8 @@ mod tests { - checking in epoch: {epoch}" ); assert_eq!( - validator_sets_pre.get(epoch), validator_sets_post.get(epoch), + validator_sets_pre.get(epoch), + validator_sets_post.get(epoch), "Validator set before pipeline offset must not change - \ checking epoch {epoch}" ); @@ -198,24 +198,27 @@ mod tests { assert_eq!( validator_deltas_post.as_ref().unwrap().get(epoch), Some(initial_stake.into()), - "The validator deltas at and after the unbonding offset must have changed \ - - checking in epoch: {epoch}" + "The validator deltas at and after the unbonding offset must \ + have changed - checking in epoch: {epoch}" ); assert_eq!( total_deltas_post.get(epoch), Some(initial_stake.into()), - "The total deltas at and after the unbonding offset must have changed \ - - checking in epoch: {epoch}" + "The total deltas at and after the unbonding offset must have \ + changed - checking in epoch: {epoch}" ); - assert_ne!( - validator_sets_post.get(epoch), validator_sets_post.get(epoch), - "Validator set at and after pipeline offset must have \ - changed - checking epoch {epoch}" + assert_eq!( + validator_sets_pre.get(epoch), + validator_sets_post.get(epoch), + "Validator set at and after pipeline offset should be the \ + same since we are before the unbonding offset - checking \ + epoch {epoch}" ); } { - // TODO: should this loop over epochs after this one as well? Are there any? + // TODO: should this loop over epochs after this one as well? Are + // there any? let epoch = pos_params.unbonding_len + 1; let expected_stake = i128::from(initial_stake) - i128::from(unbond.amount);