@@ -583,11 +583,11 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
583583 if common_ancestor_height < min_allowed_height {
584584 let tip_block_height = self . get_best_block_index ( ) ?. block_height ( ) ;
585585
586- return Err ( CheckBlockError :: AttemptedToAddBlockBeforeReorgLimit (
586+ return Err ( CheckBlockError :: AttemptedToAddBlockBeforeReorgLimit {
587587 common_ancestor_height,
588588 tip_block_height,
589589 min_allowed_height,
590- ) ) ;
590+ } ) ;
591591 }
592592
593593 Ok ( ( ) )
@@ -618,8 +618,45 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
618618 Ok ( parent_block_index)
619619 }
620620
621+ /// This function is intended to be used in check_block and check_block_header.
622+ ///
623+ /// Return true if the block already exists in the chainstate and has an "ok" status
624+ /// with the validation stage CheckBlockOk or later.
625+ /// If it has a non-"ok" status, return an error.
626+ /// If the block is new, or if its validation stage is below CheckBlockOk (i.e. it's Unchecked),
627+ /// return false.
628+ fn skip_check_block_because_block_exists_and_is_checked (
629+ & self ,
630+ block_id : & Id < Block > ,
631+ ) -> Result < bool , CheckBlockError > {
632+ if let Some ( block_index) = self . get_block_index ( block_id) ? {
633+ let status = block_index. status ( ) ;
634+
635+ if status. is_ok ( ) {
636+ let checked = status. last_valid_stage ( ) >= BlockValidationStage :: CheckBlockOk ;
637+ Ok ( checked)
638+ } else {
639+ Err ( CheckBlockError :: InvalidBlockAlreadyProcessed ( * block_id) )
640+ }
641+ } else {
642+ Ok ( false )
643+ }
644+ }
645+
621646 #[ log_error]
622647 pub fn check_block_header ( & self , header : & SignedBlockHeader ) -> Result < ( ) , CheckBlockError > {
648+ let header = WithId :: new ( header) ;
649+ if self . skip_check_block_because_block_exists_and_is_checked ( & WithId :: id ( & header) ) ? {
650+ return Ok ( ( ) ) ;
651+ }
652+
653+ self . check_block_header_impl ( & header)
654+ }
655+
656+ fn check_block_header_impl (
657+ & self ,
658+ header : & WithId < & SignedBlockHeader > ,
659+ ) -> Result < ( ) , CheckBlockError > {
623660 let parent_block_index = self . check_block_parent ( header) ?;
624661 self . check_header_size ( header) ?;
625662 self . enforce_checkpoints ( header) ?;
@@ -681,7 +718,7 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
681718 ensure ! (
682719 block_timestamp. as_duration_since_epoch( ) <= current_time_as_secs + max_future_offset,
683720 CheckBlockError :: BlockFromTheFuture {
684- block_id: header . block_id ( ) ,
721+ block_id: WithId :: id ( header ) ,
685722 block_timestamp,
686723 current_time
687724 } ,
@@ -852,7 +889,14 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
852889
853890 #[ log_error]
854891 pub fn check_block ( & self , block : & WithId < Block > ) -> Result < ( ) , CheckBlockError > {
855- self . check_block_header ( block. header ( ) ) ?;
892+ let header_with_id = WithId :: as_sub_obj ( block) ;
893+ if self
894+ . skip_check_block_because_block_exists_and_is_checked ( & WithId :: id ( & header_with_id) ) ?
895+ {
896+ return Ok ( ( ) ) ;
897+ }
898+
899+ self . check_block_header_impl ( & header_with_id) ?;
856900
857901 self . check_block_size ( block) . map_err ( CheckBlockError :: BlockSizeError ) ?;
858902
0 commit comments