Skip to content

Commit 33152a2

Browse files
committedDec 10, 2019
Get tendermint validators with CurrentValidators
1 parent ab7fcf1 commit 33152a2

File tree

4 files changed

+112
-39
lines changed

4 files changed

+112
-39
lines changed
 

‎core/src/consensus/stake/action_data.rs

+10
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,16 @@ impl CurrentValidators {
432432
pub fn update(&mut self, validators: Vec<Validator>) {
433433
self.0 = validators;
434434
}
435+
436+
pub fn addresses(&self) -> Vec<Address> {
437+
self.0.iter().rev().map(|v| public_to_address(&v.pubkey)).collect()
438+
}
439+
440+
pub fn get_validator(&self, index: usize) -> &Validator {
441+
let len = self.0.len();
442+
// NOTE: validator list is reversed when reading a validator by index
443+
self.0.iter().nth_back(index % len).unwrap()
444+
}
435445
}
436446

437447
impl Deref for CurrentValidators {

‎core/src/consensus/tendermint/engine.rs

+33-6
Original file line numberDiff line numberDiff line change
@@ -459,10 +459,30 @@ fn calculate_pending_rewards_of_the_previous_term(
459459
let mut missed_signatures = HashMap::<Address, (usize, usize)>::with_capacity(MAX_NUM_OF_VALIDATORS);
460460
let mut signed_blocks = HashMap::<Address, usize>::with_capacity(MAX_NUM_OF_VALIDATORS);
461461

462+
let era = {
463+
let end_of_the_current_term_header = chain
464+
.block_header(&start_of_the_current_term_header.parent_hash().into())
465+
.expect("The parent of the term end block must exist");
466+
let state = chain
467+
.state_at(end_of_the_current_term_header.parent_hash().into())
468+
.expect("The state at parent of the term end block must exist");
469+
let metadata = state.metadata()?.expect("Metadata of the term end block should exist");
470+
metadata.term_params().map_or(0, |p| p.era())
471+
};
472+
462473
let mut header = start_of_the_current_term_header;
463474
let mut parent_validators = {
464-
let grand_parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
465-
validators.addresses(&grand_parent_header.parent_hash())
475+
match era {
476+
0 => {
477+
let grand_parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
478+
validators.addresses(&grand_parent_header.parent_hash())
479+
}
480+
1 => {
481+
let state = chain.state_at(header.parent_hash().into()).expect("The block's state must exist");
482+
stake::CurrentValidators::load_from_state(&state)?.addresses()
483+
}
484+
_ => unimplemented!(),
485+
}
466486
};
467487
while start_of_the_previous_term != header.number() {
468488
for index in TendermintSealView::new(&header.seal()).bitset()?.true_index_iter() {
@@ -472,10 +492,17 @@ fn calculate_pending_rewards_of_the_previous_term(
472492

473493
header = chain.block_header(&header.parent_hash().into()).unwrap();
474494
parent_validators = {
475-
// The seal of the current block has the signatures of the parent block.
476-
// It needs the hash of the grand parent block to find the validators of the parent block.
477-
let grand_parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
478-
validators.addresses(&grand_parent_header.parent_hash())
495+
match era {
496+
0 => {
497+
let grand_parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
498+
validators.addresses(&grand_parent_header.parent_hash())
499+
}
500+
1 => {
501+
let state = chain.state_at(header.hash().into()).expect("The block's state must exist");
502+
stake::CurrentValidators::load_from_state(&state)?.addresses()
503+
}
504+
_ => unimplemented!(),
505+
}
479506
};
480507

481508
let author = header.author();

‎core/src/consensus/tendermint/worker.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use super::backup::{backup, restore, BackupView};
3535
use super::message::*;
3636
use super::network;
3737
use super::params::TimeGapParams;
38-
use super::stake::CUSTOM_ACTION_HANDLER_ID;
38+
use super::stake::{CurrentValidators, CUSTOM_ACTION_HANDLER_ID};
3939
use super::types::{Height, Proposal, Step, TendermintSealView, TendermintState, TwoThirdsMajority, View};
4040
use super::vote_collector::{DoubleVote, VoteCollector};
4141
use super::vote_regression_checker::VoteRegressionChecker;
@@ -1244,13 +1244,19 @@ impl Worker {
12441244
};
12451245

12461246
let mut voted_validators = BitSet::new();
1247-
let grand_parent_hash = self
1248-
.client()
1249-
.block_header(&(*header.parent_hash()).into())
1250-
.expect("The parent block must exist")
1251-
.parent_hash();
1247+
let parent = self.client().block_header(&(*header.parent_hash()).into()).expect("The parent block must exist");
1248+
let grand_parent_hash = parent.parent_hash();
12521249
for (bitset_index, signature) in seal_view.signatures()? {
1253-
let public = self.validators.get(&grand_parent_hash, bitset_index);
1250+
let public = {
1251+
let state = self.client().state_at(parent.hash().into()).expect("The parent state must exist");
1252+
let validators = CurrentValidators::load_from_state(&state)?;
1253+
// This happens when era == 0
1254+
if validators.is_empty() {
1255+
self.validators.get(&grand_parent_hash, bitset_index)
1256+
} else {
1257+
*validators.get_validator(bitset_index).pubkey()
1258+
}
1259+
};
12541260
if !verify_schnorr(&public, &signature, &precommit_vote_on.hash())? {
12551261
let address = public_to_address(&public);
12561262
return Err(EngineError::BlockNotAuthorized(address.to_owned()).into())
@@ -1263,7 +1269,7 @@ impl Worker {
12631269
if header.number() == 1 {
12641270
return Ok(())
12651271
}
1266-
self.validators.check_enough_votes(&grand_parent_hash, &voted_validators)?;
1272+
self.validators.check_enough_votes_with_header(&parent.decode(), &voted_validators)?;
12671273
Ok(())
12681274
}
12691275

‎core/src/consensus/validator_set/dynamic_validator.rs

+55-25
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ use std::sync::{Arc, Weak};
1818

1919
use ckey::{public_to_address, Address, Public};
2020
use ctypes::util::unexpected::OutOfBounds;
21-
use ctypes::BlockHash;
21+
use ctypes::{BlockHash, Header};
2222
use parking_lot::RwLock;
2323

2424
use super::{RoundRobinValidator, ValidatorSet};
2525
use crate::client::ConsensusClient;
2626
use crate::consensus::bit_set::BitSet;
27-
use crate::consensus::stake::{get_validators, Validator};
27+
use crate::consensus::stake::{get_validators, CurrentValidators, Validator};
2828
use crate::consensus::EngineError;
2929

3030
/// Validator set containing a known set of public keys.
@@ -77,6 +77,58 @@ impl DynamicValidator {
7777
(prev_proposer_index + proposed_view + 1) % num_validators
7878
}
7979
}
80+
81+
pub fn check_enough_votes_with_validators(
82+
&self,
83+
validators: &[Validator],
84+
votes: &BitSet,
85+
) -> Result<(), EngineError> {
86+
let mut voted_delegation = 0u64;
87+
let n_validators = validators.len();
88+
for index in votes.true_index_iter() {
89+
assert!(index < n_validators);
90+
let validator = validators.get(index).ok_or_else(|| {
91+
EngineError::ValidatorNotExist {
92+
height: 0, // FIXME
93+
index,
94+
}
95+
})?;
96+
voted_delegation += validator.delegation();
97+
}
98+
let total_delegation: u64 = validators.iter().map(Validator::delegation).sum();
99+
if voted_delegation * 3 > total_delegation * 2 {
100+
Ok(())
101+
} else {
102+
let threshold = total_delegation as usize * 2 / 3;
103+
Err(EngineError::BadSealFieldSize(OutOfBounds {
104+
min: Some(threshold),
105+
max: Some(total_delegation as usize),
106+
found: voted_delegation as usize,
107+
}))
108+
}
109+
}
110+
111+
pub fn check_enough_votes_with_header(&self, header: &Header, votes: &BitSet) -> Result<(), EngineError> {
112+
let client: Arc<dyn ConsensusClient> =
113+
self.client.read().as_ref().and_then(Weak::upgrade).expect("Client is not initialized");
114+
115+
let validators = {
116+
match client.state_at(header.hash().into()).map(|s| CurrentValidators::load_from_state(&s)) {
117+
Some(Ok(current_validators)) if !current_validators.is_empty() => {
118+
let mut result = (*current_validators).clone();
119+
result.reverse();
120+
Some(result)
121+
}
122+
_ => self.validators(*header.parent_hash()),
123+
}
124+
};
125+
126+
if let Some(validators) = validators {
127+
self.check_enough_votes_with_validators(&validators, votes)
128+
} else {
129+
self.initial_list.check_enough_votes(header.parent_hash(), votes)
130+
}
131+
}
80132
}
81133

82134
impl ValidatorSet for DynamicValidator {
@@ -145,29 +197,7 @@ impl ValidatorSet for DynamicValidator {
145197

146198
fn check_enough_votes(&self, parent: &BlockHash, votes: &BitSet) -> Result<(), EngineError> {
147199
if let Some(validators) = self.validators(*parent) {
148-
let mut voted_delegation = 0u64;
149-
let n_validators = validators.len();
150-
for index in votes.true_index_iter() {
151-
assert!(index < n_validators);
152-
let validator = validators.get(index).ok_or_else(|| {
153-
EngineError::ValidatorNotExist {
154-
height: 0, // FIXME
155-
index,
156-
}
157-
})?;
158-
voted_delegation += validator.delegation();
159-
}
160-
let total_delegation: u64 = validators.iter().map(Validator::delegation).sum();
161-
if voted_delegation * 3 > total_delegation * 2 {
162-
Ok(())
163-
} else {
164-
let threshold = total_delegation as usize * 2 / 3;
165-
Err(EngineError::BadSealFieldSize(OutOfBounds {
166-
min: Some(threshold),
167-
max: Some(total_delegation as usize),
168-
found: voted_delegation as usize,
169-
}))
170-
}
200+
self.check_enough_votes_with_validators(&validators, votes)
171201
} else {
172202
self.initial_list.check_enough_votes(parent, votes)
173203
}

0 commit comments

Comments
 (0)