Skip to content

Commit 6b4ee35

Browse files
committed
Extract aggregate_work_info function
1 parent b172e19 commit 6b4ee35

File tree

1 file changed

+86
-61
lines changed

1 file changed

+86
-61
lines changed

core/src/consensus/tendermint/engine.rs

Lines changed: 86 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ use crate::views::HeaderView;
4747
use crate::BlockId;
4848
use rlp::Encodable;
4949

50+
#[derive(Default)]
51+
struct WorkInfo {
52+
proposed: usize,
53+
missed: usize,
54+
signed: u64,
55+
}
56+
5057
impl ConsensusEngine for Tendermint {
5158
fn name(&self) -> &str {
5259
"Tendermint"
@@ -146,26 +153,15 @@ impl ConsensusEngine for Tendermint {
146153
0 => {}
147154
1 => {
148155
let rewards = stake::v1::drain_current_rewards(block.state_mut())?;
149-
let start_of_the_current_term = block_number;
150-
let start_of_the_previous_term = {
151-
let end_of_the_two_level_previous_term = client
152-
.last_term_finished_block_num((metadata.last_term_finished_block_num() - 1).into())
153-
.unwrap();
154-
155-
end_of_the_two_level_previous_term + 1
156-
};
157-
158156
let banned = stake::Banned::load_from_state(block.state())?;
159157
let start_of_the_current_term_header =
160158
encoded::Header::new(block.header().clone().rlp_bytes().to_vec());
161159

162-
let pending_rewards = calculate_pending_rewards_of_the_previous_term(
160+
let pending_rewards = calculate_pending_rewards_of_the_term(
163161
&*client,
164162
&*self.validators,
165163
rewards,
166-
start_of_the_current_term,
167164
start_of_the_current_term_header,
168-
start_of_the_previous_term,
169165
&banned,
170166
)?;
171167

@@ -241,28 +237,18 @@ impl ConsensusEngine for Tendermint {
241237
let start_of_the_current_term = metadata.last_term_finished_block_num() + 1;
242238

243239
if term > 1 {
244-
let start_of_the_previous_term = {
245-
let end_of_the_two_level_previous_term = client
246-
.last_term_finished_block_num((metadata.last_term_finished_block_num() - 1).into())
247-
.unwrap();
248-
249-
end_of_the_two_level_previous_term + 1
250-
};
251-
252240
let banned = stake::Banned::load_from_state(block.state())?;
253241
let start_of_the_current_term_header = if block_number == start_of_the_current_term {
254242
encoded::Header::new(block.header().clone().rlp_bytes().to_vec())
255243
} else {
256244
client.block_header(&start_of_the_current_term.into()).unwrap()
257245
};
258246

259-
let pending_rewards = calculate_pending_rewards_of_the_previous_term(
247+
let pending_rewards = calculate_pending_rewards_of_the_term(
260248
&*client,
261249
&*self.validators,
262250
rewards,
263-
start_of_the_current_term,
264251
start_of_the_current_term_header,
265-
start_of_the_previous_term,
266252
&banned,
267253
)?;
268254

@@ -425,64 +411,79 @@ fn inactive_validators(
425411
validators.into_iter().collect()
426412
}
427413

428-
fn calculate_pending_rewards_of_the_previous_term(
414+
// Aggregate the validators' work info of a term
415+
fn aggregate_work_info(
429416
chain: &dyn ConsensusClient,
430417
validators: &dyn ValidatorSet,
431-
rewards: BTreeMap<Address, u64>,
432-
start_of_the_current_term: u64,
433-
start_of_the_current_term_header: encoded::Header,
434-
start_of_the_previous_term: u64,
435-
banned: &stake::Banned,
436-
) -> Result<HashMap<Address, u64>, Error> {
437-
// XXX: It's okay because we don't have a plan to increasing the maximum number of validators.
438-
// However, it's better to use the correct number.
439-
const MAX_NUM_OF_VALIDATORS: usize = 30;
440-
let mut pending_rewards = HashMap::<Address, u64>::with_capacity(MAX_NUM_OF_VALIDATORS);
441-
let mut missed_signatures = HashMap::<Address, (usize, usize)>::with_capacity(MAX_NUM_OF_VALIDATORS);
442-
let mut signed_blocks = HashMap::<Address, usize>::with_capacity(MAX_NUM_OF_VALIDATORS);
418+
start_of_the_next_term_header: encoded::Header,
419+
) -> Result<HashMap<Address, WorkInfo>, Error> {
420+
let mut work_info = HashMap::<Address, WorkInfo>::new();
421+
422+
let start_of_the_current_term = {
423+
let end_of_the_last_term =
424+
chain.last_term_finished_block_num((start_of_the_next_term_header.number() - 2).into()).unwrap();
443425

444-
let mut header = start_of_the_current_term_header;
426+
end_of_the_last_term + 1
427+
};
428+
let mut header = start_of_the_next_term_header;
445429
let mut parent_validators = {
446-
let grand_parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
447-
validators.addresses(&grand_parent_header.parent_hash())
430+
let parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
431+
validators.addresses(&parent_header.parent_hash())
448432
};
449-
while start_of_the_previous_term != header.number() {
433+
while start_of_the_current_term != header.number() {
450434
for index in TendermintSealView::new(&header.seal()).bitset()?.true_index_iter() {
451435
let signer = *parent_validators.get(index).expect("The seal must be the signature of the validator");
452-
*signed_blocks.entry(signer).or_default() += 1;
436+
work_info.entry(signer).or_default().signed += 1;
453437
}
454438

455439
header = chain.block_header(&header.parent_hash().into()).unwrap();
456440
parent_validators = {
457441
// The seal of the current block has the signatures of the parent block.
458442
// It needs the hash of the grand parent block to find the validators of the parent block.
459-
let grand_parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
460-
validators.addresses(&grand_parent_header.parent_hash())
443+
let parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
444+
validators.addresses(&parent_header.parent_hash())
461445
};
462446

463447
let author = header.author();
464-
let (proposed, missed) = missed_signatures.entry(author).or_default();
465-
*proposed += 1;
466-
*missed += parent_validators.len() - TendermintSealView::new(&header.seal()).bitset()?.count();
448+
let info = work_info.entry(author).or_default();
449+
info.proposed += 1;
450+
info.missed += parent_validators.len() - TendermintSealView::new(&header.seal()).bitset()?.count();
467451
}
468452

453+
Ok(work_info)
454+
}
455+
456+
fn calculate_pending_rewards_of_the_term(
457+
chain: &dyn ConsensusClient,
458+
validators: &dyn ValidatorSet,
459+
rewards: BTreeMap<Address, u64>,
460+
start_of_the_next_term_header: encoded::Header,
461+
banned: &stake::Banned,
462+
) -> Result<HashMap<Address, u64>, Error> {
463+
// XXX: It's okay because we don't have a plan to increasing the maximum number of validators.
464+
// However, it's better to use the correct number.
465+
const MAX_NUM_OF_VALIDATORS: usize = 30;
466+
let work_info = aggregate_work_info(chain, validators, start_of_the_next_term_header)?;
467+
let mut pending_rewards = HashMap::<Address, u64>::with_capacity(MAX_NUM_OF_VALIDATORS);
468+
469469
let mut reduced_rewards = 0;
470470

471471
// Penalty disloyal validators
472-
let number_of_blocks_in_term = start_of_the_current_term - start_of_the_previous_term;
472+
let number_of_blocks_in_term: usize = work_info.values().map(|info| info.proposed).sum();
473473
for (address, intermediate_reward) in rewards {
474474
if banned.is_banned(&address) {
475475
reduced_rewards += intermediate_reward;
476476
continue
477477
}
478-
let number_of_signatures = u64::try_from(*signed_blocks.get(&address).unwrap()).unwrap();
479-
let final_block_rewards = final_rewards(intermediate_reward, number_of_signatures, number_of_blocks_in_term);
478+
let number_of_signatures = work_info.get(&address).unwrap().signed;
479+
let final_block_rewards =
480+
final_rewards(intermediate_reward, number_of_signatures, u64::try_from(number_of_blocks_in_term).unwrap());
480481
reduced_rewards += intermediate_reward - final_block_rewards;
481482
pending_rewards.insert(address, final_block_rewards);
482483
}
483484

484485
// Give additional rewards
485-
give_additional_rewards(reduced_rewards, missed_signatures, |address, reward| {
486+
give_additional_rewards(reduced_rewards, work_info, |address, reward| {
486487
let prev = pending_rewards.entry(*address).or_default();
487488
*prev += reward;
488489
Ok(())
@@ -525,12 +526,12 @@ fn final_rewards(intermediate_reward: u64, number_of_signatures: u64, number_of_
525526

526527
fn give_additional_rewards<F: FnMut(&Address, u64) -> Result<(), Error>>(
527528
mut reduced_rewards: u64,
528-
missed_signatures: HashMap<Address, (usize, usize)>,
529+
work_info: HashMap<Address, WorkInfo>,
529530
mut f: F,
530531
) -> Result<(), Error> {
531-
let sorted_validators = missed_signatures
532+
let sorted_validators = work_info
532533
.into_iter()
533-
.map(|(address, (proposed, missed))| (address, Ratio::new(missed, proposed)))
534+
.map(|(address, info)| (address, Ratio::new(info.missed, info.proposed)))
534535
// When one sees the Ratio crate's Order trait implementation, he/she can easily realize that the
535536
// comparing routine is erroneous. It inversely compares denominators when the numerators are the same.
536537
// That's problematic when it makes comparisons between ratios such as Ratio{numer: 0, denom:2} and Ratio{numer: 0, denom: 3}.
@@ -689,20 +690,44 @@ mod tests {
689690
let addr12 = Address::random();
690691
let addr20 = Address::random();
691692
let addr21 = Address::random();
692-
let missed_signatures = HashMap::from_iter(
693+
let work_info = HashMap::from_iter(
693694
vec![
694-
(addr00, (30, 28)),
695-
(addr10, (60, 59)),
696-
(addr11, (120, 118)),
697-
(addr12, (120, 118)),
698-
(addr20, (60, 60)),
699-
(addr21, (120, 120)),
695+
(addr00, WorkInfo {
696+
proposed: 30,
697+
missed: 28,
698+
signed: 0,
699+
}),
700+
(addr10, WorkInfo {
701+
proposed: 60,
702+
missed: 59,
703+
signed: 0,
704+
}),
705+
(addr11, WorkInfo {
706+
proposed: 120,
707+
missed: 118,
708+
signed: 0,
709+
}),
710+
(addr12, WorkInfo {
711+
proposed: 120,
712+
missed: 118,
713+
signed: 0,
714+
}),
715+
(addr20, WorkInfo {
716+
proposed: 60,
717+
missed: 60,
718+
signed: 0,
719+
}),
720+
(addr21, WorkInfo {
721+
proposed: 120,
722+
missed: 120,
723+
signed: 0,
724+
}),
700725
]
701726
.into_iter(),
702727
);
703728

704729
let mut result = HashMap::with_capacity(7);
705-
give_additional_rewards(reduced_rewards, missed_signatures, |address, reward| {
730+
give_additional_rewards(reduced_rewards, work_info, |address, reward| {
706731
assert_eq!(None, result.insert(*address, reward));
707732
Ok(())
708733
})

0 commit comments

Comments
 (0)