Skip to content

Commit cf7a45a

Browse files
committed
Extract aggregate_work_info function
1 parent 4292086 commit cf7a45a

File tree

1 file changed

+85
-49
lines changed

1 file changed

+85
-49
lines changed

core/src/consensus/tendermint/engine.rs

Lines changed: 85 additions & 49 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"
@@ -193,28 +200,18 @@ impl ConsensusEngine for Tendermint {
193200
let start_of_the_current_term = metadata.last_term_finished_block_num() + 1;
194201

195202
if term > 1 {
196-
let start_of_the_previous_term = {
197-
let end_of_the_two_level_previous_term = client
198-
.last_term_finished_block_num((metadata.last_term_finished_block_num() - 1).into())
199-
.unwrap();
200-
201-
end_of_the_two_level_previous_term + 1
202-
};
203-
204203
let banned = stake::Banned::load_from_state(block.state())?;
205204
let start_of_the_current_term_header = if block_number == start_of_the_current_term {
206205
encoded::Header::new(block.header().clone().rlp_bytes().to_vec())
207206
} else {
208207
client.block_header(&start_of_the_current_term.into()).unwrap()
209208
};
210209

211-
let pending_rewards = calculate_pending_rewards_of_the_previous_term(
210+
let pending_rewards = calculate_pending_rewards_of_the_term(
212211
&*client,
213212
&*self.validators,
214213
rewards,
215-
start_of_the_current_term,
216214
start_of_the_current_term_header,
217-
start_of_the_previous_term,
218215
&banned,
219216
)?;
220217

@@ -356,64 +353,79 @@ fn inactive_validators(
356353
validators.into_iter().collect()
357354
}
358355

359-
fn calculate_pending_rewards_of_the_previous_term(
356+
// Aggregate the validators' work info of a term
357+
fn aggregate_work_info(
360358
chain: &dyn ConsensusClient,
361359
validators: &dyn ValidatorSet,
362-
rewards: BTreeMap<Address, u64>,
363-
start_of_the_current_term: u64,
364-
start_of_the_current_term_header: encoded::Header,
365-
start_of_the_previous_term: u64,
366-
banned: &stake::Banned,
367-
) -> Result<HashMap<Address, u64>, Error> {
368-
// XXX: It's okay because we don't have a plan to increasing the maximum number of validators.
369-
// However, it's better to use the correct number.
370-
const MAX_NUM_OF_VALIDATORS: usize = 30;
371-
let mut pending_rewards = HashMap::<Address, u64>::with_capacity(MAX_NUM_OF_VALIDATORS);
372-
let mut missed_signatures = HashMap::<Address, (usize, usize)>::with_capacity(MAX_NUM_OF_VALIDATORS);
373-
let mut signed_blocks = HashMap::<Address, usize>::with_capacity(MAX_NUM_OF_VALIDATORS);
360+
start_of_the_next_term_header: encoded::Header,
361+
) -> Result<HashMap<Address, WorkInfo>, Error> {
362+
let mut work_info = HashMap::<Address, WorkInfo>::new();
363+
364+
let start_of_the_current_term = {
365+
let end_of_the_last_term =
366+
chain.last_term_finished_block_num((start_of_the_next_term_header.number() - 2).into()).unwrap();
374367

375-
let mut header = start_of_the_current_term_header;
368+
end_of_the_last_term + 1
369+
};
370+
let mut header = start_of_the_next_term_header;
376371
let mut parent_validators = {
377-
let grand_parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
378-
validators.addresses(&grand_parent_header.parent_hash())
372+
let parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
373+
validators.addresses(&parent_header.parent_hash())
379374
};
380-
while start_of_the_previous_term != header.number() {
375+
while start_of_the_current_term != header.number() {
381376
for index in TendermintSealView::new(&header.seal()).bitset()?.true_index_iter() {
382377
let signer = *parent_validators.get(index).expect("The seal must be the signature of the validator");
383-
*signed_blocks.entry(signer).or_default() += 1;
378+
work_info.entry(signer).or_default().signed += 1;
384379
}
385380

386381
header = chain.block_header(&header.parent_hash().into()).unwrap();
387382
parent_validators = {
388383
// The seal of the current block has the signatures of the parent block.
389384
// It needs the hash of the grand parent block to find the validators of the parent block.
390-
let grand_parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
391-
validators.addresses(&grand_parent_header.parent_hash())
385+
let parent_header = chain.block_header(&header.parent_hash().into()).unwrap();
386+
validators.addresses(&parent_header.parent_hash())
392387
};
393388

394389
let author = header.author();
395-
let (proposed, missed) = missed_signatures.entry(author).or_default();
396-
*proposed += 1;
397-
*missed += parent_validators.len() - TendermintSealView::new(&header.seal()).bitset()?.count();
390+
let info = work_info.entry(author).or_default();
391+
info.proposed += 1;
392+
info.missed += parent_validators.len() - TendermintSealView::new(&header.seal()).bitset()?.count();
398393
}
399394

395+
Ok(work_info)
396+
}
397+
398+
fn calculate_pending_rewards_of_the_term(
399+
chain: &dyn ConsensusClient,
400+
validators: &dyn ValidatorSet,
401+
rewards: BTreeMap<Address, u64>,
402+
start_of_the_next_term_header: encoded::Header,
403+
banned: &stake::Banned,
404+
) -> Result<HashMap<Address, u64>, Error> {
405+
// XXX: It's okay because we don't have a plan to increasing the maximum number of validators.
406+
// However, it's better to use the correct number.
407+
const MAX_NUM_OF_VALIDATORS: usize = 30;
408+
let work_info = aggregate_work_info(chain, validators, start_of_the_next_term_header)?;
409+
let mut pending_rewards = HashMap::<Address, u64>::with_capacity(MAX_NUM_OF_VALIDATORS);
410+
400411
let mut reduced_rewards = 0;
401412

402413
// Penalty disloyal validators
403-
let number_of_blocks_in_term = start_of_the_current_term - start_of_the_previous_term;
414+
let number_of_blocks_in_term: usize = work_info.values().map(|info| info.proposed).sum();
404415
for (address, intermediate_reward) in rewards {
405416
if banned.is_banned(&address) {
406417
reduced_rewards += intermediate_reward;
407418
continue
408419
}
409-
let number_of_signatures = u64::try_from(*signed_blocks.get(&address).unwrap()).unwrap();
410-
let final_block_rewards = final_rewards(intermediate_reward, number_of_signatures, number_of_blocks_in_term);
420+
let number_of_signatures = work_info.get(&address).unwrap().signed;
421+
let final_block_rewards =
422+
final_rewards(intermediate_reward, number_of_signatures, u64::try_from(number_of_blocks_in_term).unwrap());
411423
reduced_rewards += intermediate_reward - final_block_rewards;
412424
pending_rewards.insert(address, final_block_rewards);
413425
}
414426

415427
// Give additional rewards
416-
give_additional_rewards(reduced_rewards, missed_signatures, |address, reward| {
428+
give_additional_rewards(reduced_rewards, work_info, |address, reward| {
417429
let prev = pending_rewards.entry(*address).or_default();
418430
*prev += reward;
419431
Ok(())
@@ -456,12 +468,12 @@ fn final_rewards(intermediate_reward: u64, number_of_signatures: u64, number_of_
456468

457469
fn give_additional_rewards<F: FnMut(&Address, u64) -> Result<(), Error>>(
458470
mut reduced_rewards: u64,
459-
missed_signatures: HashMap<Address, (usize, usize)>,
471+
work_info: HashMap<Address, WorkInfo>,
460472
mut f: F,
461473
) -> Result<(), Error> {
462-
let sorted_validators = missed_signatures
474+
let sorted_validators = work_info
463475
.into_iter()
464-
.map(|(address, (proposed, missed))| (address, Ratio::new(missed, proposed)))
476+
.map(|(address, info)| (address, Ratio::new(info.missed, info.proposed)))
465477
// When one sees the Ratio crate's Order trait implementation, he/she can easily realize that the
466478
// comparing routine is erroneous. It inversely compares denominators when the numerators are the same.
467479
// That's problematic when it makes comparisons between ratios such as Ratio{numer: 0, denom:2} and Ratio{numer: 0, denom: 3}.
@@ -620,20 +632,44 @@ mod tests {
620632
let addr12 = Address::random();
621633
let addr20 = Address::random();
622634
let addr21 = Address::random();
623-
let missed_signatures = HashMap::from_iter(
635+
let work_info = HashMap::from_iter(
624636
vec![
625-
(addr00, (30, 28)),
626-
(addr10, (60, 59)),
627-
(addr11, (120, 118)),
628-
(addr12, (120, 118)),
629-
(addr20, (60, 60)),
630-
(addr21, (120, 120)),
637+
(addr00, WorkInfo {
638+
proposed: 30,
639+
missed: 28,
640+
signed: 0,
641+
}),
642+
(addr10, WorkInfo {
643+
proposed: 60,
644+
missed: 59,
645+
signed: 0,
646+
}),
647+
(addr11, WorkInfo {
648+
proposed: 120,
649+
missed: 118,
650+
signed: 0,
651+
}),
652+
(addr12, WorkInfo {
653+
proposed: 120,
654+
missed: 118,
655+
signed: 0,
656+
}),
657+
(addr20, WorkInfo {
658+
proposed: 60,
659+
missed: 60,
660+
signed: 0,
661+
}),
662+
(addr21, WorkInfo {
663+
proposed: 120,
664+
missed: 120,
665+
signed: 0,
666+
}),
631667
]
632668
.into_iter(),
633669
);
634670

635671
let mut result = HashMap::with_capacity(7);
636-
give_additional_rewards(reduced_rewards, missed_signatures, |address, reward| {
672+
give_additional_rewards(reduced_rewards, work_info, |address, reward| {
637673
assert_eq!(None, result.insert(*address, reward));
638674
Ok(())
639675
})

0 commit comments

Comments
 (0)