diff --git a/Cargo.lock b/Cargo.lock index 1dd2fec9228..1c1e4e02a14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3075,6 +3075,7 @@ dependencies = [ "prost-types", "rand 0.8.5", "rand_core 0.6.4", + "regex", "rust_decimal", "rust_decimal_macros", "serde 1.0.145", diff --git a/core/Cargo.toml b/core/Cargo.toml index 6e1b325e2a6..553c5a81b40 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -90,6 +90,7 @@ tendermint-proto-abcipp = {package = "tendermint-proto", git = "https://github.c thiserror = "1.0.30" tracing = "0.1.30" zeroize = {version = "1.5.5", features = ["zeroize_derive"]} +regex = "1" [dev-dependencies] assert_matches = "1.5.0" diff --git a/core/src/types/storage.rs b/core/src/types/storage.rs index 1e7ad26d939..9e813490492 100644 --- a/core/src/types/storage.rs +++ b/core/src/types/storage.rs @@ -12,6 +12,7 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use data_encoding::BASE32HEX_NOPAD; use serde::{Deserialize, Serialize}; use thiserror::Error; +use regex::Regex; use crate::bytes::ByteBuf; use crate::types::address::{self, Address}; @@ -771,6 +772,31 @@ impl_int_key_seg!(u32, i32, 4); impl_int_key_seg!(u64, i64, 8); impl_int_key_seg!(u128, i128, 16); +impl KeySeg for (Epoch, Epoch) { + fn parse(string: String) -> Result + where + Self: Sized, + { + let re = Regex::new(r"\((\d{1}),(\d{1})\)").unwrap(); + let caps = re.captures(string.as_str()).unwrap(); + let first = caps.get(1).map(|m| m.as_str().to_owned()).unwrap(); + let second = caps.get(2).map(|m| m.as_str().to_owned()).unwrap(); + + let first = u64::parse(first)?; + let second = u64::parse(second)?; + + Ok((Epoch(first), Epoch(second))) + } + + fn raw(&self) -> String { + format!("({},{})",self.0,self.1) + } + + fn to_db_key(&self) -> DbKeySeg { + DbKeySeg::StringSeg(self.raw()) + } +} + impl KeySeg for Epoch { fn parse(string: String) -> Result where diff --git a/proof_of_stake/src/epoched_new.rs b/proof_of_stake/src/epoched_new.rs index 08880a96a50..872fa376ccd 100644 --- a/proof_of_stake/src/epoched_new.rs +++ b/proof_of_stake/src/epoched_new.rs @@ -185,7 +185,7 @@ where } } let key = self.get_last_update_storage_key(); - storage.write(&key, expected_epoch)?; + storage.write(&key, current_epoch)?; } Ok(()) } @@ -425,7 +425,7 @@ where } } let key = self.get_last_update_storage_key(); - storage.write(&key, expected_oldest_epoch)?; + storage.write(&key, current_epoch)?; } Ok(()) } diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index a9c6127175b..bffef8a26ed 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -29,6 +29,7 @@ use epoched::{ DynEpochOffset, EpochOffset, Epoched, EpochedDelta, OffsetPipelineLen, }; use namada_core::ledger::storage_api::{self, StorageRead, StorageWrite}; +use namada_core::ledger::storage_api::collections::{LazyCollection, LazyMap}; use namada_core::types::address::{self, Address, InternalAddress}; use namada_core::types::{key::common, token, storage::Epoch}; use parameters::PosParams; @@ -39,7 +40,8 @@ use types::{ Slash, SlashType, Slashes, TotalDeltas, Unbond, Unbonds, ValidatorConsensusKeys, ValidatorConsensusKeys_NEW, ValidatorSet, ValidatorSetUpdate, ValidatorSets, ValidatorState, ValidatorStates, - ValidatorDeltas + ValidatorDeltas, ValidatorStates_NEW, + ValidatorDeltas_NEW, ValidatorSets_NEW, BondId_NEW }; use crate::btree_set::BTreeSetShims; @@ -1640,6 +1642,10 @@ fn withdraw_unbonds( }) } +// ------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------ impl From for storage_api::Error { fn from(err: BecomeValidatorError) -> Self { Self::new(err) @@ -1670,6 +1676,12 @@ impl From for storage_api::Error { } } +/// Get the storage handle to the Validator sets +pub fn validator_sets_handle() -> ValidatorSets_NEW { + let key = storage::validator_set_key(); + crate::epoched_new::Epoched::open(key) +} + /// Get the storage handle to a PoS validator's consensus key (used for /// signing block votes). pub fn validator_consensus_key_handle( @@ -1679,6 +1691,33 @@ pub fn validator_consensus_key_handle( crate::epoched_new::Epoched::open(key) } +/// Get the storage handle to a PoS validator's state +pub fn validator_state_handle( + validator: &Address +) -> ValidatorStates_NEW { + let key = storage::validator_state_key(&validator); + crate::epoched_new::Epoched::open(key) +} + +/// Get the storage handle to a PoS validator's deltas +pub fn validator_deltas_handle( + validator: &Address +) -> ValidatorDeltas_NEW { + let key = storage::validator_total_deltas_key(&validator); + crate::epoched_new::EpochedDelta::open(key) +} + +/// Get the storage handle to a bonds +pub fn bond_handle( + source: &Address, + validator: &Address +) -> LazyMap { + let bond_id = BondId_NEW {source: source.clone(), validator: validator.clone()}; + let key = storage::bond_key(&bond_id); + LazyMap::open(key) +} + +/// new init genesis pub fn init_genesis_NEW( storage: &mut S, params: &PosParams, @@ -1688,6 +1727,7 @@ pub fn init_genesis_NEW( where S: for<'iter> StorageRead<'iter> + StorageWrite, { + // validator_sets_handle().init_at_genesis(storage, value, current_epoch) for GenesisValidator { address, tokens, @@ -1699,6 +1739,17 @@ where consensus_key, current_epoch, )?; + validator_state_handle(&address).init_at_genesis( + storage, + ValidatorState::Candidate, + current_epoch + )?; + let delta = token::Change::from(tokens); + validator_deltas_handle(&address).init_at_genesis( + storage, + delta, + current_epoch + )?; } Ok(()) @@ -1733,3 +1784,112 @@ where let offset = OffsetPipelineLen::value(params); handle.set(storage, consensus_key, current_epoch, offset) } + +/// Read PoS validator's delta value. +pub fn read_validator_delta( + storage: &S, + params: &PosParams, + validator: &Address, + epoch: namada_core::types::storage::Epoch, +) -> storage_api::Result> +where + S: for<'iter> StorageRead<'iter>, +{ + let handle = validator_deltas_handle(&validator); + handle.get_delta_val(storage, epoch, params) +} + +/// Read PoS validator's stake (sum of deltas). +pub fn read_validator_stake( + storage: &S, + params: &PosParams, + validator: &Address, + epoch: namada_core::types::storage::Epoch, +) -> storage_api::Result> +where + S: for<'iter> StorageRead<'iter>, +{ + let handle = validator_deltas_handle(&validator); + handle.get_sum(storage, epoch, params) +} + +/// Write PoS validator's consensus key (used for signing block votes). +/// Note: for EpochedDelta, write the value to change storage by +pub fn write_validator_deltas( + storage: &mut S, + params: &PosParams, + validator: &Address, + delta: token::Change, + current_epoch: namada_core::types::storage::Epoch, +) -> storage_api::Result<()> +where + S: for<'iter> StorageRead<'iter> + StorageWrite, +{ + let handle = validator_deltas_handle(&validator); + let offset = OffsetPipelineLen::value(params); + + // TODO: either use read_validator_deltas here to update the value properly + // or use a new or updated method to update the Data val for EpochedDelta (set currently just sets the val like discrete Epoched) + handle.set(storage, delta, current_epoch, offset) +} +/// Read PoS validator's state. +pub fn read_validator_state( + storage: &S, + params: &PosParams, + validator: &Address, + epoch: namada_core::types::storage::Epoch, +) -> storage_api::Result> +where + S: for<'iter> StorageRead<'iter>, +{ + let handle = validator_state_handle(&validator); + handle.get(storage, epoch, params) +} + +/// Write PoS validator's consensus key (used for signing block votes). +pub fn write_validator_state( + storage: &mut S, + params: &PosParams, + validator: &Address, + state: ValidatorState, + current_epoch: namada_core::types::storage::Epoch, +) -> storage_api::Result<()> +where + S: for<'iter> StorageRead<'iter> + StorageWrite, +{ + let handle = validator_state_handle(&validator); + let offset = OffsetPipelineLen::value(params); + handle.set(storage, state, current_epoch, offset) +} + +/// Read PoS validator's bonds +pub fn read_bonds( + storage: &S, + params: &PosParams, + source: &Address, + validator: &Address, + epoch: namada_core::types::storage::Epoch, +) -> storage_api::Result>> +where + S: for<'iter> StorageRead<'iter>, +{ + // What exactly should we have this read? Should we look up by source, validator? + // Should it be the sum of all bonds? + todo!() +} + +/// Write PoS validator's consensus key (used for signing block votes). +pub fn write_bond( + storage: &mut S, + params: &PosParams, + validator: &Address, + state: ValidatorState, + current_epoch: namada_core::types::storage::Epoch, +) -> storage_api::Result<()> +where + S: for<'iter> StorageRead<'iter> + StorageWrite, +{ + let handle = validator_state_handle(&validator); + let offset = OffsetPipelineLen::value(params); + handle.set(storage, state, current_epoch, offset) +} diff --git a/proof_of_stake/src/types.rs b/proof_of_stake/src/types.rs index 248f93888af..81ebde868d1 100644 --- a/proof_of_stake/src/types.rs +++ b/proof_of_stake/src/types.rs @@ -9,6 +9,8 @@ use std::ops::{Add}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use namada_core::types::address::Address; +use namada_core::ledger::storage_api::collections::lazy_map::LazyMap; +use namada_core::ledger::storage_api::collections::LazyCollection; use namada_core::types::key::common; use namada_core::types::storage::Epoch; use namada_core::types::token; @@ -25,6 +27,37 @@ pub type ValidatorConsensusKeys_NEW = crate::epoched_new::Epoched< crate::epoched_new::OffsetPipelineLen, 0, >; + +/// Epoched validator's state. +pub type ValidatorStates_NEW = crate::epoched_new::Epoched< + ValidatorState, + crate::epoched_new::OffsetPipelineLen, + 0 +>; + +/// Epoched validator sets. +pub type ValidatorSets_NEW = crate::epoched_new::Epoched< + ValidatorSet_NEW, + crate::epoched_new::OffsetPipelineLen, + 0 +>; + +/// Epoched validator's deltas. +pub type ValidatorDeltas_NEW = crate::epoched_new::EpochedDelta< + token::Change, + // TODO: check the offsets + crate::epoched_new::OffsetUnbondingLen, + 21, +>; + +/// Epoched validator's bonds +pub type Bonds_NEW = crate::epoched_new::Epoched< + Bond_NEW, + // TODO: check the offsets + crate::epoched_new::OffsetUnbondingLen, + 21, +>; + /// Epoched validator's consensus key. pub type ValidatorConsensusKeys = Epoched; /// Epoched validator's state. @@ -180,6 +213,8 @@ pub struct ValidatorSet { pub inactive: BTreeSet, } +pub type ValidatorSet_NEW = ValidatorSet
; + /// Validator's state. #[derive( Debug, @@ -222,6 +257,8 @@ pub struct Bond { pub neg_deltas: token::Amount, } +type Bond_NEW = LazyMap>>; + /// An unbond contains unbonded tokens from a validator's self-bond or a /// delegation from a regular account to a validator. #[derive(