Skip to content

Commit 5ca3333

Browse files
committed
Extract aggregate_work_info function
1 parent b172e19 commit 5ca3333

File tree

1 file changed

+88
-64
lines changed

1 file changed

+88
-64
lines changed

core/src/consensus/tendermint/engine.rs

Lines changed: 88 additions & 64 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: usize,
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,78 @@ 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();
478+
let number_of_signatures = work_info.get(&address).unwrap().signed;
479479
let final_block_rewards = final_rewards(intermediate_reward, number_of_signatures, number_of_blocks_in_term);
480480
reduced_rewards += intermediate_reward - final_block_rewards;
481481
pending_rewards.insert(address, final_block_rewards);
482482
}
483483

484484
// Give additional rewards
485-
give_additional_rewards(reduced_rewards, missed_signatures, |address, reward| {
485+
give_additional_rewards(reduced_rewards, work_info, |address, reward| {
486486
let prev = pending_rewards.entry(*address).or_default();
487487
*prev += reward;
488488
Ok(())
@@ -492,7 +492,7 @@ fn calculate_pending_rewards_of_the_previous_term(
492492
}
493493

494494
/// reward = floor(intermediate_rewards * (a * number_of_signatures / number_of_blocks_in_term + b) / 10)
495-
fn final_rewards(intermediate_reward: u64, number_of_signatures: u64, number_of_blocks_in_term: u64) -> u64 {
495+
fn final_rewards(intermediate_reward: u64, number_of_signatures: usize, number_of_blocks_in_term: usize) -> u64 {
496496
let (a, b) = if number_of_signatures * 3 >= number_of_blocks_in_term * 2 {
497497
// number_of_signatures / number_of_blocks_in_term >= 2 / 3
498498
// x * 3/10 + 7/10
@@ -515,22 +515,22 @@ fn final_rewards(intermediate_reward: u64, number_of_signatures: u64, number_of_
515515
);
516516
(0, 0)
517517
};
518-
let numerator = i128::from(intermediate_reward)
519-
* (a * i128::from(number_of_signatures) + b * i128::from(number_of_blocks_in_term));
518+
let numerator =
519+
i128::from(intermediate_reward) * (a * (number_of_signatures as i128) + b * (number_of_blocks_in_term as i128));
520520
assert!(numerator >= 0);
521-
let denominator = 10 * i128::from(number_of_blocks_in_term);
521+
let denominator = 10 * (number_of_blocks_in_term as i128);
522522
// Rust's division rounds towards zero.
523523
u64::try_from(numerator / denominator).unwrap()
524524
}
525525

526526
fn give_additional_rewards<F: FnMut(&Address, u64) -> Result<(), Error>>(
527527
mut reduced_rewards: u64,
528-
missed_signatures: HashMap<Address, (usize, usize)>,
528+
work_info: HashMap<Address, WorkInfo>,
529529
mut f: F,
530530
) -> Result<(), Error> {
531-
let sorted_validators = missed_signatures
531+
let sorted_validators = work_info
532532
.into_iter()
533-
.map(|(address, (proposed, missed))| (address, Ratio::new(missed, proposed)))
533+
.map(|(address, info)| (address, Ratio::new(info.missed, info.proposed)))
534534
// When one sees the Ratio crate's Order trait implementation, he/she can easily realize that the
535535
// comparing routine is erroneous. It inversely compares denominators when the numerators are the same.
536536
// That's problematic when it makes comparisons between ratios such as Ratio{numer: 0, denom:2} and Ratio{numer: 0, denom: 3}.
@@ -689,20 +689,44 @@ mod tests {
689689
let addr12 = Address::random();
690690
let addr20 = Address::random();
691691
let addr21 = Address::random();
692-
let missed_signatures = HashMap::from_iter(
692+
let work_info = HashMap::from_iter(
693693
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)),
694+
(addr00, WorkInfo {
695+
proposed: 30,
696+
missed: 28,
697+
signed: 0,
698+
}),
699+
(addr10, WorkInfo {
700+
proposed: 60,
701+
missed: 59,
702+
signed: 0,
703+
}),
704+
(addr11, WorkInfo {
705+
proposed: 120,
706+
missed: 118,
707+
signed: 0,
708+
}),
709+
(addr12, WorkInfo {
710+
proposed: 120,
711+
missed: 118,
712+
signed: 0,
713+
}),
714+
(addr20, WorkInfo {
715+
proposed: 60,
716+
missed: 60,
717+
signed: 0,
718+
}),
719+
(addr21, WorkInfo {
720+
proposed: 120,
721+
missed: 120,
722+
signed: 0,
723+
}),
700724
]
701725
.into_iter(),
702726
);
703727

704728
let mut result = HashMap::with_capacity(7);
705-
give_additional_rewards(reduced_rewards, missed_signatures, |address, reward| {
729+
give_additional_rewards(reduced_rewards, work_info, |address, reward| {
706730
assert_eq!(None, result.insert(*address, reward));
707731
Ok(())
708732
})

0 commit comments

Comments
 (0)