@@ -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"
@@ -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
526527fn 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