@@ -47,6 +47,13 @@ use crate::views::HeaderView;
4747use crate :: BlockId ;
4848use rlp:: Encodable ;
4949
50+ #[ derive( Default ) ]
51+ struct WorkInfo {
52+ proposed : usize ,
53+ missed : usize ,
54+ signed : u64 ,
55+ }
56+
5057impl 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
457469fn 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