From 6e1852030cee4beff422ef242b1e1c57f156a9b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 7 Jul 2023 09:22:58 +0100 Subject: [PATCH 1/5] pos: add a function to get genesis validator consensus set for TM --- proof_of_stake/src/lib.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index 7f7265be91..289bc55dbe 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -2455,6 +2455,41 @@ where Ok((total, total_active)) } +/// Get the genesis consensus validators stake and consensus key for Tendermint, +/// converted from [`ValidatorSetUpdate`]s using the given function. +pub fn genesis_validator_set_tendermint( + storage: &S, + params: &PosParams, + current_epoch: Epoch, + mut f: impl FnMut(ValidatorSetUpdate) -> T, +) -> storage_api::Result> +where + S: StorageRead, +{ + let consensus_validator_handle = + consensus_validator_set_handle().at(¤t_epoch); + let iter = consensus_validator_handle.iter(storage)?; + + iter.map(|validator| { + let ( + NestedSubKey::Data { + key: new_stake, + nested_sub_key: _, + }, + address, + ) = validator?; + let consensus_key = validator_consensus_key_handle(&address) + .get(storage, current_epoch, params)? + .unwrap(); + let converted = f(ValidatorSetUpdate::Consensus(ConsensusValidator { + consensus_key, + bonded_stake: new_stake, + })); + Ok(converted) + }) + .collect() +} + /// Communicate imminent validator set updates to Tendermint. This function is /// called two blocks before the start of a new epoch because Tendermint /// validator updates become active two blocks after the updates are submitted. From feda19a8a8989fcbf326e97acde30965d91394d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 7 Jul 2023 09:23:50 +0100 Subject: [PATCH 2/5] app/ledger/init_chain: get genesis validator set using the new fn --- apps/src/lib/node/ledger/shell/init_chain.rs | 30 +++-------- apps/src/lib/node/ledger/shell/mod.rs | 54 ++++++++++++++++++++ 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/apps/src/lib/node/ledger/shell/init_chain.rs b/apps/src/lib/node/ledger/shell/init_chain.rs index 91f48e3e05..cb696f665f 100644 --- a/apps/src/lib/node/ledger/shell/init_chain.rs +++ b/apps/src/lib/node/ledger/shell/init_chain.rs @@ -6,9 +6,7 @@ use std::hash::Hash; use namada::core::ledger::testnet_pow; use namada::ledger::eth_bridge::EthBridgeStatus; use namada::ledger::parameters::{self, Parameters}; -use namada::ledger::pos::{ - into_tm_voting_power, staking_token_address, PosParams, -}; +use namada::ledger::pos::{staking_token_address, PosParams}; use namada::ledger::storage::traits::StorageHasher; use namada::ledger::storage::{DBIter, DB}; use namada::ledger::storage_api::token::{ @@ -23,8 +21,6 @@ use namada::types::time::{DateTimeUtc, TimeZone, Utc}; use namada::types::token; use super::*; -use crate::facade::tendermint_proto::abci; -use crate::facade::tendermint_proto::crypto::PublicKey as TendermintPublicKey; use crate::facade::tendermint_proto::google::protobuf; use crate::facade::tower_abci::{request, response}; use crate::wasm_loader; @@ -473,10 +469,7 @@ where pos::init_genesis_storage( &mut self.wl_storage, pos_params, - validators - .clone() - .into_iter() - .map(|validator| validator.pos_data), + validators.into_iter().map(|validator| validator.pos_data), current_epoch, ); @@ -507,20 +500,11 @@ where ibc::init_genesis_storage(&mut self.wl_storage); // Set the initial validator set - for validator in validators { - let mut abci_validator = abci::ValidatorUpdate::default(); - let consensus_key: common::PublicKey = - validator.pos_data.consensus_key.clone(); - let pub_key = TendermintPublicKey { - sum: Some(key_to_tendermint(&consensus_key).unwrap()), - }; - abci_validator.pub_key = Some(pub_key); - abci_validator.power = into_tm_voting_power( - pos_params.tm_votes_per_token, - validator.pos_data.tokens, - ); - response.validators.push(abci_validator); - } + response.validators = self + .get_abci_validator_updates(true) + .expect("Must be able to set genesis validator set"); + debug_assert!(!response.validators.is_empty()); + response } } diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index e1b7f08883..23bc6fe64b 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -28,6 +28,7 @@ use namada::ledger::eth_bridge::{EthBridgeQueries, EthereumBridgeConfig}; use namada::ledger::events::log::EventLog; use namada::ledger::events::Event; use namada::ledger::gas::BlockGasMeter; +use namada::ledger::pos::into_tm_voting_power; use namada::ledger::pos::namada_proof_of_stake::types::{ ConsensusValidator, ValidatorSetUpdate, }; @@ -1374,6 +1375,59 @@ where } false } + + fn get_abci_validator_updates( + &self, + is_genesis: bool, + ) -> storage_api::Result> + { + use namada::ledger::pos::namada_proof_of_stake; + + use crate::facade::tendermint_proto::crypto::PublicKey as TendermintPublicKey; + + let (current_epoch, _gas) = self.wl_storage.storage.get_current_epoch(); + let pos_params = + namada_proof_of_stake::read_pos_params(&self.wl_storage) + .expect("Could not find the PoS parameters"); + + let validator_set_update_fn = if is_genesis { + namada_proof_of_stake::genesis_validator_set_tendermint + } else { + namada_proof_of_stake::validator_set_update_tendermint + }; + + validator_set_update_fn( + &self.wl_storage, + &pos_params, + current_epoch, + |update| { + let (consensus_key, power) = match update { + ValidatorSetUpdate::Consensus(ConsensusValidator { + consensus_key, + bonded_stake, + }) => { + let power: i64 = into_tm_voting_power( + pos_params.tm_votes_per_token, + bonded_stake, + ); + (consensus_key, power) + } + ValidatorSetUpdate::Deactivated(consensus_key) => { + // Any validators that have been dropped from the + // consensus set must have voting power set to 0 to + // remove them from the conensus set + let power = 0_i64; + (consensus_key, power) + } + }; + let pub_key = TendermintPublicKey { + sum: Some(key_to_tendermint(&consensus_key).unwrap()), + }; + let pub_key = Some(pub_key); + ValidatorUpdate { pub_key, power } + }, + ) + } } impl<'a, D, H> From<&'a mut Shell> From 5fead6af65abca37ac88ff60681d57d854e5282c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 7 Jul 2023 09:24:46 +0100 Subject: [PATCH 3/5] app/ledger/finalize_block: refactor validator set update for re-use --- .../lib/node/ledger/shell/finalize_block.rs | 44 ++----------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs index 3af8ab9e3f..5c7e9d5b62 100644 --- a/apps/src/lib/node/ledger/shell/finalize_block.rs +++ b/apps/src/lib/node/ledger/shell/finalize_block.rs @@ -4,7 +4,6 @@ use std::collections::HashMap; use data_encoding::HEXUPPER; use namada::ledger::parameters::storage as params_storage; -use namada::ledger::pos::types::into_tm_voting_power; use namada::ledger::pos::{namada_proof_of_stake, staking_token_address}; use namada::ledger::storage::EPOCH_SWITCH_BLOCKS_DELAY; use namada::ledger::storage_api::token::credit_tokens; @@ -32,7 +31,6 @@ use super::*; use crate::facade::tendermint_proto::abci::{ Misbehavior as Evidence, VoteInfo, }; -use crate::facade::tendermint_proto::crypto::PublicKey as TendermintPublicKey; use crate::node::ledger::shell::stats::InternalStats; impl Shell @@ -634,45 +632,9 @@ where /// changes to the validator sets and consensus parameters fn update_epoch(&mut self, response: &mut shim::response::FinalizeBlock) { // Apply validator set update - let (current_epoch, _gas) = self.wl_storage.storage.get_current_epoch(); - let pos_params = - namada_proof_of_stake::read_pos_params(&self.wl_storage) - .expect("Could not find the PoS parameters"); - // TODO ABCI validator updates on block H affects the validator set - // on block H+2, do we need to update a block earlier? - response.validator_updates = - namada_proof_of_stake::validator_set_update_tendermint( - &self.wl_storage, - &pos_params, - current_epoch, - |update| { - let (consensus_key, power) = match update { - ValidatorSetUpdate::Consensus(ConsensusValidator { - consensus_key, - bonded_stake, - }) => { - let power: i64 = into_tm_voting_power( - pos_params.tm_votes_per_token, - bonded_stake, - ); - (consensus_key, power) - } - ValidatorSetUpdate::Deactivated(consensus_key) => { - // Any validators that have been dropped from the - // consensus set must have voting power set to 0 to - // remove them from the conensus set - let power = 0_i64; - (consensus_key, power) - } - }; - let pub_key = TendermintPublicKey { - sum: Some(key_to_tendermint(&consensus_key).unwrap()), - }; - let pub_key = Some(pub_key); - ValidatorUpdate { pub_key, power } - }, - ) - .expect("Must be able to update validator sets"); + response.validator_updates = self + .get_abci_validator_updates(false) + .expect("Must be able to update validator set"); } /// Calculate the new inflation rate, mint the new tokens to the PoS From eaebb7bdf91c1312e5989af9d57697c9ec475033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 7 Jul 2023 09:43:33 +0100 Subject: [PATCH 4/5] changelog: add #1686 --- .changelog/unreleased/bug-fixes/1686-delete-prefix.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/unreleased/bug-fixes/1686-delete-prefix.md diff --git a/.changelog/unreleased/bug-fixes/1686-delete-prefix.md b/.changelog/unreleased/bug-fixes/1686-delete-prefix.md new file mode 100644 index 0000000000..dc8a2dd175 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/1686-delete-prefix.md @@ -0,0 +1,3 @@ +- PoS: ensure that the size of genesis validator set + is limited by the `max_validator_slots` parameter. + ([\#1686](https://github.com/anoma/namada/pull/1686)) \ No newline at end of file From 1a4eb06ab6b77dcc5def29ab04a30964013b9e63 Mon Sep 17 00:00:00 2001 From: brentstone Date: Mon, 10 Jul 2023 10:30:09 -0400 Subject: [PATCH 5/5] improve error handling for `set_initial_validators` --- apps/src/lib/node/ledger/shell/init_chain.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/src/lib/node/ledger/shell/init_chain.rs b/apps/src/lib/node/ledger/shell/init_chain.rs index cb696f665f..9c41d54ad2 100644 --- a/apps/src/lib/node/ledger/shell/init_chain.rs +++ b/apps/src/lib/node/ledger/shell/init_chain.rs @@ -245,11 +245,11 @@ where &implicit_vp_code_path, ); // set the initial validators set - Ok(self.set_initial_validators( + self.set_initial_validators( &staking_token, genesis.validators, &genesis.pos_params, - )) + ) } /// Initialize genesis established accounts @@ -460,7 +460,7 @@ where staking_token: &Address, validators: Vec, pos_params: &PosParams, - ) -> response::InitChain { + ) -> Result { let mut response = response::InitChain::default(); // PoS system depends on epoch being initialized. Write the total // genesis staking token balance to storage after @@ -473,13 +473,11 @@ where current_epoch, ); - let total_nam = - read_total_supply(&self.wl_storage, staking_token).unwrap(); + let total_nam = read_total_supply(&self.wl_storage, staking_token)?; // At this stage in the chain genesis, the PoS address balance is the // same as the number of staked tokens let total_staked_nam = - read_balance(&self.wl_storage, staking_token, &address::POS) - .unwrap(); + read_balance(&self.wl_storage, staking_token, &address::POS)?; tracing::info!( "Genesis total native tokens: {}.", @@ -505,7 +503,7 @@ where .expect("Must be able to set genesis validator set"); debug_assert!(!response.validators.is_empty()); - response + Ok(response) } }