From c3923cd8d106c098c96eb26127725c8470b41568 Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Tue, 10 Dec 2019 16:39:40 +0900 Subject: [PATCH 1/4] Use genesis state to read network_id --- core/src/client/client.rs | 13 +++++---- core/src/client/mod.rs | 4 +-- core/src/client/test_client.rs | 8 +++--- core/src/consensus/tendermint/worker.rs | 2 +- foundry/run_node.rs | 6 ++--- rpc/src/v1/impls/account.rs | 18 ++++++------- rpc/src/v1/impls/chain.rs | 36 ++++++++----------------- rpc/src/v1/impls/engine.rs | 2 +- rpc/src/v1/impls/mempool.rs | 8 +++--- 9 files changed, 39 insertions(+), 58 deletions(-) diff --git a/core/src/client/client.rs b/core/src/client/client.rs index af82080363..cfd0e8a7ac 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -481,6 +481,10 @@ impl StateInfo for Client { } impl EngineInfo for Client { + fn network_id(&self) -> NetworkId { + self.common_params(BlockId::Earliest).expect("Genesis state must exist").network_id() + } + fn common_params(&self, block_id: BlockId) -> Option { self.state_info(block_id.into()).map(|state| { state @@ -518,7 +522,7 @@ impl EngineInfo for Client { } fn possible_authors(&self, block_number: Option) -> Result>, EngineError> { - let network_id = self.common_params(BlockId::Latest).unwrap().network_id(); + let network_id = self.network_id(); if block_number == Some(0) { let genesis_author = self.block_header(&0.into()).expect("genesis block").author(); return Ok(Some(vec![PlatformAddress::new_v1(network_id, genesis_author)])) @@ -572,8 +576,7 @@ impl BlockChainTrait for Client { } fn genesis_accounts(&self) -> Vec { - // XXX: What should we do if the network id has been changed - let network_id = self.common_params(BlockId::Latest).unwrap().network_id(); + let network_id = self.network_id(); self.genesis_accounts.iter().map(|addr| PlatformAddress::new_v1(network_id, *addr)).collect() } @@ -896,10 +899,6 @@ impl MiningBlockChainClient for Client { fn register_immune_users(&self, immune_user_vec: Vec
) { self.importer.miner.register_immune_users(immune_user_vec) } - - fn get_network_id(&self) -> NetworkId { - self.common_params(BlockId::Latest).unwrap().network_id() - } } impl ChainTimeInfo for Client { diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 681edb2680..f38dbdf58c 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -88,6 +88,7 @@ pub trait BlockChainTrait { } pub trait EngineInfo: Send + Sync { + fn network_id(&self) -> NetworkId; fn common_params(&self, block_id: BlockId) -> Option; fn metadata_seq(&self, block_id: BlockId) -> Option; fn block_reward(&self, block_number: u64) -> u64; @@ -284,9 +285,6 @@ pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + FindActionH /// Append designated users to the immune user list. fn register_immune_users(&self, immune_user_vec: Vec
); - - /// Returns network id. - fn get_network_id(&self) -> NetworkId; } /// Provides methods to access database. diff --git a/core/src/client/test_client.rs b/core/src/client/test_client.rs index 723a294c3d..ac6a5259ee 100644 --- a/core/src/client/test_client.rs +++ b/core/src/client/test_client.rs @@ -380,10 +380,6 @@ impl MiningBlockChainClient for TestBlockChainClient { fn register_immune_users(&self, immune_user_vec: Vec
) { self.miner.register_immune_users(immune_user_vec) } - - fn get_network_id(&self) -> NetworkId { - NetworkId::default() - } } impl AccountData for TestBlockChainClient { @@ -636,6 +632,10 @@ impl super::EngineClient for TestBlockChainClient { } impl EngineInfo for TestBlockChainClient { + fn network_id(&self) -> NetworkId { + self.scheme.engine.machine().genesis_common_params().network_id() + } + fn common_params(&self, _block_id: BlockId) -> Option { Some(*self.scheme.engine.machine().genesis_common_params()) } diff --git a/core/src/consensus/tendermint/worker.rs b/core/src/consensus/tendermint/worker.rs index 7453142639..fe5e5d089b 100644 --- a/core/src/consensus/tendermint/worker.rs +++ b/core/src/consensus/tendermint/worker.rs @@ -1475,7 +1475,7 @@ impl Worker { } fn report_double_vote(&self, double: &DoubleVote) { - let network_id = self.client().common_params(BlockId::Latest).unwrap().network_id(); + let network_id = self.client().network_id(); let seq = match self.signer.address() { Some(address) => self.client().latest_seq(address), None => { diff --git a/foundry/run_node.rs b/foundry/run_node.rs index da04e16f30..f5017394cc 100644 --- a/foundry/run_node.rs +++ b/foundry/run_node.rs @@ -21,8 +21,8 @@ use std::time::{SystemTime, UNIX_EPOCH}; use ccore::snapshot_notify; use ccore::{ - AccountProvider, AccountProviderError, BlockId, ChainNotify, ClientConfig, ClientService, EngineInfo, EngineType, - Miner, MinerService, Scheme, NUM_COLUMNS, + AccountProvider, AccountProviderError, ChainNotify, ClientConfig, ClientService, EngineInfo, EngineType, Miner, + MinerService, Scheme, NUM_COLUMNS, }; use cdiscovery::{Config, Discovery}; use ckey::{Address, NetworkId, PlatformAddress}; @@ -264,7 +264,7 @@ pub fn run_node(matches: &ArgMatches<'_>) -> Result<(), String> { let network_config = config.network_config()?; // XXX: What should we do if the network id has been changed. let c = client.client(); - let network_id = c.common_params(BlockId::Number(0)).unwrap().network_id(); + let network_id = c.network_id(); let routing_table = RoutingTable::new(); let service = network_start(network_id, timer_loop, &network_config, Arc::clone(&routing_table))?; diff --git a/rpc/src/v1/impls/account.rs b/rpc/src/v1/impls/account.rs index a4c16207e9..fa10fbc063 100644 --- a/rpc/src/v1/impls/account.rs +++ b/rpc/src/v1/impls/account.rs @@ -18,8 +18,8 @@ use std::convert::TryInto; use std::sync::Arc; use std::time::Duration; -use ccore::{AccountData, AccountProvider, BlockId, EngineInfo, MinerService, MiningBlockChainClient, TermInfo}; -use ckey::{NetworkId, Password, PlatformAddress, Signature}; +use ccore::{AccountData, AccountProvider, EngineInfo, MinerService, MiningBlockChainClient, TermInfo}; +use ckey::{Password, PlatformAddress, Signature}; use ctypes::transaction::IncompleteTransaction; use jsonrpc_core::Result; use parking_lot::Mutex; @@ -46,11 +46,6 @@ where miner, } } - - fn network_id(&self) -> NetworkId { - // XXX: What should we do if the network id has been changed - self.client.common_params(BlockId::Latest).unwrap().network_id() - } } impl Account for AccountClient @@ -62,7 +57,10 @@ where self.account_provider .get_list() .map(|addresses| { - addresses.into_iter().map(|address| PlatformAddress::new_v1(self.network_id(), address)).collect() + addresses + .into_iter() + .map(|address| PlatformAddress::new_v1(self.client.network_id(), address)) + .collect() }) .map_err(account_provider) } @@ -70,13 +68,13 @@ where fn create_account(&self, passphrase: Option) -> Result { let (address, _) = self.account_provider.new_account_and_public(&passphrase.unwrap_or_default()).map_err(account_provider)?; - Ok(PlatformAddress::new_v1(self.network_id(), address)) + Ok(PlatformAddress::new_v1(self.client.network_id(), address)) } fn create_account_from_secret(&self, secret: H256, passphrase: Option) -> Result { self.account_provider .insert_account(secret.into(), &passphrase.unwrap_or_default()) - .map(|address| PlatformAddress::new_v1(self.network_id(), address)) + .map(|address| PlatformAddress::new_v1(self.client.network_id(), address)) .map_err(account_provider) } diff --git a/rpc/src/v1/impls/chain.rs b/rpc/src/v1/impls/chain.rs index b68a585140..c7078332d7 100644 --- a/rpc/src/v1/impls/chain.rs +++ b/rpc/src/v1/impls/chain.rs @@ -128,10 +128,11 @@ where return Ok(None) } let block_id = block_number.map(BlockId::from).unwrap_or(BlockId::Latest); - Ok(self.client.get_text(transaction_hash, block_id).map_err(errors::transaction_state)?.map(|text| { - let parent_block_id = block_number.map(|n| (n - 1).into()).unwrap_or(BlockId::ParentOfLatest); - Text::from_core(text, self.client.common_params(parent_block_id).unwrap().network_id()) - })) + Ok(self + .client + .get_text(transaction_hash, block_id) + .map_err(errors::transaction_state)? + .map(|text| Text::from_core(text, self.client.network_id()))) } fn get_asset( @@ -178,8 +179,7 @@ where fn get_regular_key_owner(&self, public: Public, block_number: Option) -> Result> { let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); Ok(self.client.regular_key_owner(&public_to_address(&public), block_id.into()).and_then(|address| { - let parent_block_id = block_number.map(|n| (n - 1).into()).unwrap_or(BlockId::ParentOfLatest); - let network_id = self.client.common_params(parent_block_id).unwrap().network_id(); + let network_id = self.client.network_id(); Some(PlatformAddress::new_v1(network_id, address)) })) } @@ -206,8 +206,7 @@ where fn get_shard_owners(&self, shard_id: ShardId, block_number: Option) -> Result>> { let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); Ok(self.client.shard_owners(shard_id, block_id.into()).map(|owners| { - let parent_block_id = block_number.map(|n| (n - 1).into()).unwrap_or(BlockId::ParentOfLatest); - let network_id = self.client.common_params(parent_block_id).unwrap().network_id(); + let network_id = self.client.network_id(); owners.into_iter().map(|owner| PlatformAddress::new_v1(network_id, owner)).collect() })) } @@ -215,8 +214,7 @@ where fn get_shard_users(&self, shard_id: ShardId, block_number: Option) -> Result>> { let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); Ok(self.client.shard_users(shard_id, block_id.into()).map(|users| { - let parent_block_id = block_number.map(|n| (n - 1).into()).unwrap_or(BlockId::ParentOfLatest); - let network_id = self.client.common_params(parent_block_id).unwrap().network_id(); + let network_id = self.client.network_id(); users.into_iter().map(|user| PlatformAddress::new_v1(network_id, user)).collect() })) } @@ -239,26 +237,14 @@ where fn get_block_by_number(&self, block_number: u64) -> Result> { let id = BlockId::Number(block_number); - Ok(self.client.block(&id).map(|block| { - let block_id_to_read_params = if block_number == 0 { - 0.into() - } else { - (block_number - 1).into() - }; - Block::from_core(block.decode(), self.client.common_params(block_id_to_read_params).unwrap().network_id()) - })) + Ok(self.client.block(&id).map(|block| Block::from_core(block.decode(), self.client.network_id()))) } fn get_block_by_hash(&self, block_hash: BlockHash) -> Result> { let id = BlockId::Hash(block_hash); Ok(self.client.block(&id).map(|block| { let block = block.decode(); - let block_id_to_read_params = if block.header.number() == 0 { - 0.into() - } else { - (*block.header.parent_hash()).into() - }; - Block::from_core(block, self.client.common_params(block_id_to_read_params).unwrap().network_id()) + Block::from_core(block, self.client.network_id()) })) } @@ -301,7 +287,7 @@ where } fn get_network_id(&self) -> Result { - Ok(self.client.common_params(BlockId::Latest).unwrap().network_id()) + Ok(self.client.network_id()) } fn get_common_params(&self, block_number: Option) -> Result> { diff --git a/rpc/src/v1/impls/engine.rs b/rpc/src/v1/impls/engine.rs index f106f29346..730ec09073 100644 --- a/rpc/src/v1/impls/engine.rs +++ b/rpc/src/v1/impls/engine.rs @@ -62,7 +62,7 @@ where Ok(None) } else { // XXX: What should we do if the network id has been changed - let network_id = self.client.common_params(BlockId::Latest).unwrap().network_id(); + let network_id = self.client.network_id(); Ok(Some(PlatformAddress::new_v1(network_id, author))) } } diff --git a/rpc/src/v1/impls/mempool.rs b/rpc/src/v1/impls/mempool.rs index ed021f1c8d..ab78c740e8 100644 --- a/rpc/src/v1/impls/mempool.rs +++ b/rpc/src/v1/impls/mempool.rs @@ -16,7 +16,7 @@ use std::sync::Arc; -use ccore::{BlockChainClient, MiningBlockChainClient, SignedTransaction}; +use ccore::{BlockChainClient, EngineInfo, MiningBlockChainClient, SignedTransaction}; use cjson::bytes::Bytes; use ckey::{Address, PlatformAddress}; use ctypes::{Tracker, TxHash}; @@ -42,7 +42,7 @@ impl MempoolClient { impl Mempool for MempoolClient where - C: BlockChainClient + MiningBlockChainClient + 'static, + C: BlockChainClient + MiningBlockChainClient + EngineInfo + 'static, { fn send_signed_transaction(&self, raw: Bytes) -> Result { Rlp::new(&raw.into_vec()) @@ -82,7 +82,7 @@ where fn get_banned_accounts(&self) -> Result> { let malicious_user_vec = self.client.get_malicious_users(); - let network_id = self.client.get_network_id(); + let network_id = self.client.network_id(); Ok(malicious_user_vec.into_iter().map(|address| PlatformAddress::new_v1(network_id, address)).collect()) } @@ -102,7 +102,7 @@ where fn get_immune_accounts(&self) -> Result> { let immune_user_vec = self.client.get_immune_users(); - let network_id = self.client.get_network_id(); + let network_id = self.client.network_id(); Ok(immune_user_vec.into_iter().map(|address| PlatformAddress::new_v1(network_id, address)).collect()) } From 9be6c7f8310e2e938ce7be8b01dfd8a5da17b7cb Mon Sep 17 00:00:00 2001 From: Joonmo Yang Date: Fri, 27 Dec 2019 18:37:56 +0900 Subject: [PATCH 2/4] Introduce PreviousValidators PreviousValidators represent the list of validators whose signatures should be included in this block. Its value is the same as the CurrentValidators of the previous block's state, and the NextValidators of the grandparent block's state. --- core/src/consensus/stake/action_data.rs | 33 +++++++++++++++++++++++++ core/src/consensus/stake/mod.rs | 2 +- core/src/consensus/tendermint/engine.rs | 10 +++++--- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/core/src/consensus/stake/action_data.rs b/core/src/consensus/stake/action_data.rs index 7c59dc9135..c5f39f6ab2 100644 --- a/core/src/consensus/stake/action_data.rs +++ b/core/src/consensus/stake/action_data.rs @@ -449,6 +449,39 @@ impl From for Vec { } } +#[derive(Debug)] +pub struct PreviousValidators(Vec); +impl PreviousValidators { + pub fn load_from_state(state: &TopLevelState) -> StateResult { + let key = &*CURRENT_VALIDATORS_KEY; + let validators = state.action_data(&key)?.map(|data| decode_list(&data)).unwrap_or_default(); + + Ok(Self(validators)) + } + + pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { + let key = &*CURRENT_VALIDATORS_KEY; + if !self.is_empty() { + state.update_action_data(&key, encode_list(&self.0).to_vec())?; + } else { + state.remove_action_data(&key); + } + Ok(()) + } + + pub fn update(&mut self, validators: Vec) { + self.0 = validators; + } +} + +impl Deref for PreviousValidators { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + #[derive(Default, Debug, PartialEq)] pub struct IntermediateRewards { current: BTreeMap, diff --git a/core/src/consensus/stake/mod.rs b/core/src/consensus/stake/mod.rs index 513f8a693c..3a9bcef653 100644 --- a/core/src/consensus/stake/mod.rs +++ b/core/src/consensus/stake/mod.rs @@ -33,7 +33,7 @@ use parking_lot::RwLock; use primitives::{Bytes, H256}; use rlp::{Decodable, Rlp}; -pub use self::action_data::{Banned, CurrentValidators, NextValidators, Validator}; +pub use self::action_data::{Banned, CurrentValidators, NextValidators, PreviousValidators, Validator}; use self::action_data::{Candidates, Delegation, IntermediateRewards, Jail, ReleaseResult, StakeAccount, Stakeholders}; pub use self::actions::Action; pub use self::distribute::fee_distribute; diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index 61b0eaafaf..12c51959cb 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -153,9 +153,13 @@ impl ConsensusEngine for Tendermint { match term { 0 => {} _ => { - let mut validators = stake::CurrentValidators::load_from_state(block.state())?; - validators.update(stake::NextValidators::load_from_state(block.state())?.clone()); - validators.save_to_state(block.state_mut())?; + let mut previous_validators = stake::PreviousValidators::load_from_state(block.state())?; + previous_validators.update(stake::CurrentValidators::load_from_state(block.state())?.clone()); + previous_validators.save_to_state(block.state_mut())?; + + let mut current_validators = stake::CurrentValidators::load_from_state(block.state())?; + current_validators.update(stake::NextValidators::load_from_state(block.state())?.clone()); + current_validators.save_to_state(block.state_mut())?; } } From 42a365ce1dba5774dec23049ad70b63c5e798c68 Mon Sep 17 00:00:00 2001 From: Joonmo Yang Date: Fri, 27 Dec 2019 06:38:39 +0900 Subject: [PATCH 3/4] Fix tendermint to use CurrentValidators CurrentValidators was introduced to tendermint, but it wasn't used by some part of our implementation. This patch doesn't fix all of them, but important parts are filled in. --- core/src/consensus/stake/action_data.rs | 10 +++ core/src/consensus/tendermint/engine.rs | 15 ++-- core/src/consensus/tendermint/worker.rs | 15 ++-- .../validator_set/dynamic_validator.rs | 75 ++++++++++++++++++- core/src/consensus/validator_set/mod.rs | 2 + .../consensus/validator_set/validator_list.rs | 4 + 6 files changed, 106 insertions(+), 15 deletions(-) diff --git a/core/src/consensus/stake/action_data.rs b/core/src/consensus/stake/action_data.rs index c5f39f6ab2..7fbbcf414d 100644 --- a/core/src/consensus/stake/action_data.rs +++ b/core/src/consensus/stake/action_data.rs @@ -433,6 +433,10 @@ impl CurrentValidators { pub fn update(&mut self, validators: Vec) { self.0 = validators; } + + pub fn addresses(&self) -> Vec
{ + self.0.iter().rev().map(|v| public_to_address(&v.pubkey)).collect() + } } impl Deref for CurrentValidators { @@ -482,6 +486,12 @@ impl Deref for PreviousValidators { } } +impl From for Vec { + fn from(val: PreviousValidators) -> Self { + val.0 + } +} + #[derive(Default, Debug, PartialEq)] pub struct IntermediateRewards { current: BTreeMap, diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index 12c51959cb..4074b7d02d 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -400,20 +400,21 @@ fn aggregate_work_info( end_of_the_last_term + 1 }; let mut header = start_of_the_next_term_header; - let mut parent_validators = validators.current_addresses(&header.parent_hash()); while start_of_the_current_term != header.number() { + let parent = chain.block_header(&header.parent_hash().into()).unwrap(); + let current_validators = validators.current_addresses(&parent.hash()); + let previous_validators = validators.previous_addresses(&parent.hash()); for index in TendermintSealView::new(&header.seal()).bitset()?.true_index_iter() { - let signer = *parent_validators.get(index).expect("The seal must be the signature of the validator"); + let signer = *current_validators.get(index).expect("The seal must be the signature of the validator"); work_info.entry(signer).or_default().signed += 1; } - header = chain.block_header(&header.parent_hash().into()).unwrap(); - parent_validators = validators.current_addresses(&header.parent_hash()); - - let author = header.author(); + let author = parent.author(); let info = work_info.entry(author).or_default(); info.proposed += 1; - info.missed += parent_validators.len() - TendermintSealView::new(&header.seal()).bitset()?.count(); + info.missed += previous_validators.len() - TendermintSealView::new(&header.seal()).bitset()?.count(); + + header = parent; } Ok(work_info) diff --git a/core/src/consensus/tendermint/worker.rs b/core/src/consensus/tendermint/worker.rs index fe5e5d089b..b1248b3a03 100644 --- a/core/src/consensus/tendermint/worker.rs +++ b/core/src/consensus/tendermint/worker.rs @@ -1248,13 +1248,14 @@ impl Worker { }; let mut voted_validators = BitSet::new(); - let grand_parent_hash = self - .client() - .block_header(&(*header.parent_hash()).into()) - .expect("The parent block must exist") - .parent_hash(); + let parent_hash = header.parent_hash(); + let grand_parent_hash = + self.client().block_header(&(*parent_hash).into()).expect("The parent block must exist").parent_hash(); for (bitset_index, signature) in seal_view.signatures()? { - let public = self.validators.get(&grand_parent_hash, bitset_index); + let public = match self.validators.get_current(header.parent_hash(), bitset_index) { + Some(p) => p, + None => self.validators.get(&grand_parent_hash, bitset_index), + }; if !verify_schnorr(&public, &signature, &precommit_vote_on.hash())? { let address = public_to_address(&public); return Err(EngineError::BlockNotAuthorized(address.to_owned()).into()) @@ -1267,7 +1268,7 @@ impl Worker { if header.number() == 1 { return Ok(()) } - self.validators.check_enough_votes(&grand_parent_hash, &voted_validators)?; + self.validators.check_enough_votes_with_current(&parent_hash, &voted_validators)?; Ok(()) } diff --git a/core/src/consensus/validator_set/dynamic_validator.rs b/core/src/consensus/validator_set/dynamic_validator.rs index 19fa775db8..6f9fd29568 100644 --- a/core/src/consensus/validator_set/dynamic_validator.rs +++ b/core/src/consensus/validator_set/dynamic_validator.rs @@ -24,7 +24,7 @@ use parking_lot::RwLock; use super::{RoundRobinValidator, ValidatorSet}; use crate::client::ConsensusClient; use crate::consensus::bit_set::BitSet; -use crate::consensus::stake::{CurrentValidators, NextValidators, Validator}; +use crate::consensus::stake::{CurrentValidators, NextValidators, PreviousValidators, Validator}; use crate::consensus::EngineError; /// Validator set containing a known set of public keys. @@ -87,6 +87,29 @@ impl DynamicValidator { } } + fn previous_validators(&self, hash: BlockHash) -> Option> { + let client: Arc = + self.client.read().as_ref().and_then(Weak::upgrade).expect("Client is not initialized"); + let block_id = hash.into(); + let term_id = client.current_term_id(block_id).expect( + "valdators() is called when creating a block or verifying a block. + Minor creates a block only when the parent block is imported. + The n'th block is verified only when the parent block is imported.", + ); + if term_id == 0 { + return None + } + let state = client.state_at(block_id)?; + let validators = PreviousValidators::load_from_state(&state).unwrap(); + if validators.is_empty() { + None + } else { + let mut validators: Vec<_> = validators.into(); + validators.reverse(); + Some(validators) + } + } + fn validators_pubkey(&self, hash: BlockHash) -> Option> { self.next_validators(hash).map(|validators| validators.into_iter().map(|val| *val.pubkey()).collect()) } @@ -95,6 +118,10 @@ impl DynamicValidator { self.current_validators(hash).map(|validators| validators.into_iter().map(|val| *val.pubkey()).collect()) } + fn previous_validators_pubkey(&self, hash: BlockHash) -> Option> { + self.previous_validators(hash).map(|validators| validators.into_iter().map(|val| *val.pubkey()).collect()) + } + pub fn proposer_index(&self, parent: BlockHash, prev_proposer_index: usize, proposed_view: usize) -> usize { if let Some(validators) = self.next_validators(parent) { let num_validators = validators.len(); @@ -104,6 +131,44 @@ impl DynamicValidator { (prev_proposer_index + proposed_view + 1) % num_validators } } + + pub fn get_current(&self, hash: &BlockHash, index: usize) -> Option { + let validators = self.current_validators_pubkey(*hash)?; + let n_validators = validators.len(); + Some(*validators.get(index % n_validators).unwrap()) + } + + pub fn check_enough_votes_with_current(&self, hash: &BlockHash, votes: &BitSet) -> Result<(), EngineError> { + if let Some(validators) = self.current_validators(*hash) { + let mut voted_delegation = 0u64; + let n_validators = validators.len(); + for index in votes.true_index_iter() { + assert!(index < n_validators); + let validator = validators.get(index).ok_or_else(|| { + EngineError::ValidatorNotExist { + height: 0, // FIXME + index, + } + })?; + voted_delegation += validator.delegation(); + } + let total_delegation: u64 = validators.iter().map(Validator::delegation).sum(); + if voted_delegation * 3 > total_delegation * 2 { + Ok(()) + } else { + let threshold = total_delegation as usize * 2 / 3; + Err(EngineError::BadSealFieldSize(OutOfBounds { + min: Some(threshold), + max: Some(total_delegation as usize), + found: voted_delegation as usize, + })) + } + } else { + let client = self.client.read().as_ref().and_then(Weak::upgrade).expect("Client is not initialized"); + let header = client.block_header(&(*hash).into()).unwrap(); + self.check_enough_votes(&header.parent_hash(), votes) + } + } } impl ValidatorSet for DynamicValidator { @@ -208,6 +273,14 @@ impl ValidatorSet for DynamicValidator { *client_lock = Some(client); } + fn previous_addresses(&self, hash: &BlockHash) -> Vec
{ + if let Some(validators) = self.previous_validators_pubkey(*hash) { + validators.iter().map(public_to_address).collect() + } else { + self.initial_list.previous_addresses(hash) + } + } + fn current_addresses(&self, hash: &BlockHash) -> Vec
{ if let Some(validators) = self.current_validators_pubkey(*hash) { validators.iter().map(public_to_address).collect() diff --git a/core/src/consensus/validator_set/mod.rs b/core/src/consensus/validator_set/mod.rs index 835d0ecda5..c2b17eb7c9 100644 --- a/core/src/consensus/validator_set/mod.rs +++ b/core/src/consensus/validator_set/mod.rs @@ -57,6 +57,8 @@ pub trait ValidatorSet: Send + Sync { /// Allows blockchain state access. fn register_client(&self, _client: Weak) {} + fn previous_addresses(&self, _hash: &BlockHash) -> Vec
; + fn current_addresses(&self, _hash: &BlockHash) -> Vec
; fn next_addresses(&self, _hash: &BlockHash) -> Vec
; diff --git a/core/src/consensus/validator_set/validator_list.rs b/core/src/consensus/validator_set/validator_list.rs index 9f4fa278f2..4245a2b077 100644 --- a/core/src/consensus/validator_set/validator_list.rs +++ b/core/src/consensus/validator_set/validator_list.rs @@ -105,6 +105,10 @@ impl ValidatorSet for RoundRobinValidator { *self.client.write() = Some(client); } + fn previous_addresses(&self, _hash: &BlockHash) -> Vec
{ + self.validators.iter().map(public_to_address).collect() + } + fn current_addresses(&self, _hash: &BlockHash) -> Vec
{ self.validators.iter().map(public_to_address).collect() } From 451278d60e5c6efc41e8a559f13ed840c7b5a21b Mon Sep 17 00:00:00 2001 From: Joonmo Yang Date: Fri, 27 Dec 2019 06:43:12 +0900 Subject: [PATCH 4/4] Don't do anything at the 1th term's open 1th term open doesn't require any reward distribution since the 0th term is static validator consensus --- core/src/consensus/tendermint/engine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index 4074b7d02d..318ab153a4 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -165,7 +165,7 @@ impl ConsensusEngine for Tendermint { if block_number == metadata.last_term_finished_block_num() + 1 { match term { - 0 => {} + 0 | 1 => {} _ => { let rewards = stake::drain_current_rewards(block.state_mut())?; let banned = stake::Banned::load_from_state(block.state())?;