@@ -582,60 +582,80 @@ impl Signer {
582582 }
583583 }
584584
585- /// WARNING: Do NOT call this function PRIOR to check_proposal or block_proposal validation succeeds.
585+ /// WARNING: This is an incomplete check. Do NOT call this function PRIOR to check_proposal or block_proposal validation succeeds.
586586 ///
587587 /// Re-verify a block's chain length against the last signed block within signerdb.
588588 /// This is required in case a block has been approved since the initial checks of the block validation endpoint.
589589 fn check_block_against_signer_db_state (
590- & self ,
590+ & mut self ,
591+ stacks_client : & StacksClient ,
591592 proposed_block : & NakamotoBlock ,
592593 ) -> Option < BlockResponse > {
593594 let signer_signature_hash = proposed_block. header . signer_signature_hash ( ) ;
594595 let proposed_block_consensus_hash = proposed_block. header . consensus_hash ;
596+ // If this is a tenure change block, ensure that it confirms the correct number of blocks from the parent tenure.
597+ if let Some ( tenure_change) = proposed_block. get_tenure_change_tx_payload ( ) {
598+ // Ensure that the tenure change block confirms the expected parent block
599+ match SortitionsView :: check_tenure_change_confirms_parent (
600+ tenure_change,
601+ proposed_block,
602+ & mut self . signer_db ,
603+ stacks_client,
604+ self . proposal_config . tenure_last_block_proposal_timeout ,
605+ ) {
606+ Ok ( true ) => { }
607+ Ok ( false ) => {
608+ return Some (
609+ self . create_block_rejection (
610+ RejectCode :: SortitionViewMismatch ,
611+ proposed_block,
612+ ) ,
613+ )
614+ }
615+ Err ( e) => {
616+ warn ! ( "{self}: Error checking block proposal: {e}" ;
617+ "signer_sighash" => %signer_signature_hash,
618+ "block_id" => %proposed_block. block_id( )
619+ ) ;
620+ return Some (
621+ self . create_block_rejection ( RejectCode :: ConnectivityIssues , proposed_block) ,
622+ ) ;
623+ }
624+ }
625+ }
595626
596- match self . signer_db . get_signer_last_accepted_block ( ) {
627+ // Ensure that the block is the last block in the chain of its current tenure.
628+ match self
629+ . signer_db
630+ . get_last_accepted_block ( & proposed_block_consensus_hash)
631+ {
597632 Ok ( Some ( last_block_info) ) => {
598633 if proposed_block. header . chain_length <= last_block_info. block . header . chain_length {
599- // We do not allow reorgs at any time within the same consensus hash OR of globally accepted blocks
600- let non_reorgable_block = last_block_info. block . header . consensus_hash
601- == proposed_block_consensus_hash
602- || last_block_info. state == BlockState :: GloballyAccepted ;
603- // Is the reorg timeout requirement exceeded?
604- let reorg_timeout_exceeded = last_block_info
605- . signed_self
606- . map ( |signed_over_time| {
607- signed_over_time. saturating_add (
608- self . proposal_config
609- . tenure_last_block_proposal_timeout
610- . as_secs ( ) ,
611- ) <= get_epoch_time_secs ( )
612- } )
613- . unwrap_or ( false ) ;
614- if non_reorgable_block || !reorg_timeout_exceeded {
615- warn ! (
616- "Miner's block proposal does not confirm as many blocks as we expect" ;
617- "proposed_block_consensus_hash" => %proposed_block_consensus_hash,
618- "proposed_block_signer_sighash" => %signer_signature_hash,
619- "proposed_chain_length" => proposed_block. header. chain_length,
620- "expected_at_least" => last_block_info. block. header. chain_length + 1 ,
621- ) ;
622- return Some ( self . create_block_rejection (
623- RejectCode :: SortitionViewMismatch ,
624- proposed_block,
625- ) ) ;
626- }
634+ warn ! (
635+ "Miner's block proposal does not confirm as many blocks as we expect" ;
636+ "proposed_block_consensus_hash" => %proposed_block_consensus_hash,
637+ "proposed_block_signer_sighash" => %signer_signature_hash,
638+ "proposed_chain_length" => proposed_block. header. chain_length,
639+ "expected_at_least" => last_block_info. block. header. chain_length + 1 ,
640+ ) ;
641+ return Some ( self . create_block_rejection (
642+ RejectCode :: SortitionViewMismatch ,
643+ proposed_block,
644+ ) ) ;
627645 }
628- None
629646 }
630- Ok ( _) => None ,
647+ Ok ( _) => { }
631648 Err ( e) => {
632649 warn ! ( "{self}: Failed to check block against signer db: {e}" ;
633650 "signer_sighash" => %signer_signature_hash,
634651 "block_id" => %proposed_block. block_id( )
635652 ) ;
636- Some ( self . create_block_rejection ( RejectCode :: ConnectivityIssues , proposed_block) )
653+ return Some (
654+ self . create_block_rejection ( RejectCode :: ConnectivityIssues , proposed_block) ,
655+ ) ;
637656 }
638657 }
658+ None
639659 }
640660
641661 /// Handle the block validate ok response. Returns our block response if we have one
@@ -684,7 +704,9 @@ impl Signer {
684704 }
685705 } ;
686706
687- if let Some ( block_response) = self . check_block_against_signer_db_state ( & block_info. block ) {
707+ if let Some ( block_response) =
708+ self . check_block_against_signer_db_state ( stacks_client, & block_info. block )
709+ {
688710 // The signer db state has changed. We no longer view this block as valid. Override the validation response.
689711 if let Err ( e) = block_info. mark_locally_rejected ( ) {
690712 if !block_info. has_reached_consensus ( ) {
0 commit comments