Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions core/src/client/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<CommonParams> {
self.state_info(block_id.into()).map(|state| {
state
Expand Down Expand Up @@ -518,7 +522,7 @@ impl EngineInfo for Client {
}

fn possible_authors(&self, block_number: Option<u64>) -> Result<Option<Vec<PlatformAddress>>, 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)]))
Expand Down Expand Up @@ -572,8 +576,7 @@ impl BlockChainTrait for Client {
}

fn genesis_accounts(&self) -> Vec<PlatformAddress> {
// 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()
}

Expand Down Expand Up @@ -896,10 +899,6 @@ impl MiningBlockChainClient for Client {
fn register_immune_users(&self, immune_user_vec: Vec<Address>) {
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 {
Expand Down
4 changes: 1 addition & 3 deletions core/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<CommonParams>;
fn metadata_seq(&self, block_id: BlockId) -> Option<u64>;
fn block_reward(&self, block_number: u64) -> u64;
Expand Down Expand Up @@ -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<Address>);

/// Returns network id.
fn get_network_id(&self) -> NetworkId;
}

/// Provides methods to access database.
Expand Down
8 changes: 4 additions & 4 deletions core/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,6 @@ impl MiningBlockChainClient for TestBlockChainClient {
fn register_immune_users(&self, immune_user_vec: Vec<Address>) {
self.miner.register_immune_users(immune_user_vec)
}

fn get_network_id(&self) -> NetworkId {
NetworkId::default()
}
}

impl AccountData for TestBlockChainClient {
Expand Down Expand Up @@ -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<CommonParams> {
Some(*self.scheme.engine.machine().genesis_common_params())
}
Expand Down
43 changes: 43 additions & 0 deletions core/src/consensus/stake/action_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,10 @@ impl CurrentValidators {
pub fn update(&mut self, validators: Vec<Validator>) {
self.0 = validators;
}

pub fn addresses(&self) -> Vec<Address> {
self.0.iter().rev().map(|v| public_to_address(&v.pubkey)).collect()
}
}

impl Deref for CurrentValidators {
Expand All @@ -449,6 +453,45 @@ impl From<CurrentValidators> for Vec<Validator> {
}
}

#[derive(Debug)]
pub struct PreviousValidators(Vec<Validator>);
impl PreviousValidators {
pub fn load_from_state(state: &TopLevelState) -> StateResult<Self> {
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<Validator>) {
self.0 = validators;
}
}

impl Deref for PreviousValidators {
type Target = Vec<Validator>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl From<PreviousValidators> for Vec<Validator> {
fn from(val: PreviousValidators) -> Self {
val.0
}
}

#[derive(Default, Debug, PartialEq)]
pub struct IntermediateRewards {
current: BTreeMap<Address, u64>,
Expand Down
2 changes: 1 addition & 1 deletion core/src/consensus/stake/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
27 changes: 16 additions & 11 deletions core/src/consensus/tendermint/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,19 @@ 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())?;
}
}

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())?;
Expand Down Expand Up @@ -396,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)
Expand Down
17 changes: 9 additions & 8 deletions core/src/consensus/tendermint/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -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(())
}

Expand Down Expand Up @@ -1475,7 +1476,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 => {
Expand Down
75 changes: 74 additions & 1 deletion core/src/consensus/validator_set/dynamic_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -87,6 +87,29 @@ impl DynamicValidator {
}
}

fn previous_validators(&self, hash: BlockHash) -> Option<Vec<Validator>> {
let client: Arc<dyn ConsensusClient> =
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<Vec<Public>> {
self.next_validators(hash).map(|validators| validators.into_iter().map(|val| *val.pubkey()).collect())
}
Expand All @@ -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<Vec<Public>> {
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();
Expand All @@ -104,6 +131,44 @@ impl DynamicValidator {
(prev_proposer_index + proposed_view + 1) % num_validators
}
}

pub fn get_current(&self, hash: &BlockHash, index: usize) -> Option<Public> {
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 {
Expand Down Expand Up @@ -208,6 +273,14 @@ impl ValidatorSet for DynamicValidator {
*client_lock = Some(client);
}

fn previous_addresses(&self, hash: &BlockHash) -> Vec<Address> {
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<Address> {
if let Some(validators) = self.current_validators_pubkey(*hash) {
validators.iter().map(public_to_address).collect()
Expand Down
2 changes: 2 additions & 0 deletions core/src/consensus/validator_set/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ pub trait ValidatorSet: Send + Sync {
/// Allows blockchain state access.
fn register_client(&self, _client: Weak<dyn ConsensusClient>) {}

fn previous_addresses(&self, _hash: &BlockHash) -> Vec<Address>;

fn current_addresses(&self, _hash: &BlockHash) -> Vec<Address>;

fn next_addresses(&self, _hash: &BlockHash) -> Vec<Address>;
Expand Down
4 changes: 4 additions & 0 deletions core/src/consensus/validator_set/validator_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ impl ValidatorSet for RoundRobinValidator {
*self.client.write() = Some(client);
}

fn previous_addresses(&self, _hash: &BlockHash) -> Vec<Address> {
self.validators.iter().map(public_to_address).collect()
}

fn current_addresses(&self, _hash: &BlockHash) -> Vec<Address> {
self.validators.iter().map(public_to_address).collect()
}
Expand Down
6 changes: 3 additions & 3 deletions foundry/run_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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))?;

Expand Down
Loading