@@ -110,30 +110,23 @@ func NewFullConsensusState(
110110// candidate.View == certifyingQC.View && candidate.ID() == certifyingQC.BlockID
111111//
112112// NOTE: this function expects that `certifyingQC` has been validated.
113- // Expected errors during normal operations:
114- // - state.OutdatedExtensionError if the candidate block is outdated (e.g. orphaned)
113+ // No errors are expected during normal operations.
115114func (m * FollowerState ) ExtendCertified (ctx context.Context , candidate * flow.Block , certifyingQC * flow.QuorumCertificate ) error {
116115 span , ctx := m .tracer .StartSpanFromContext (ctx , trace .ProtoStateMutatorHeaderExtend )
117116 defer span .End ()
118117
119- // there are no cases where certifyingQC can be nil.
120- if certifyingQC != nil {
121- blockID := candidate .ID ()
122- // sanity check if certifyingQC actually certifies candidate block
123- if certifyingQC .View != candidate .Header .View {
124- return fmt .Errorf ("qc doesn't certify candidate block, expect %d view, got %d" , candidate .Header .View , certifyingQC .View )
125- }
126- if certifyingQC .BlockID != blockID {
127- return fmt .Errorf ("qc doesn't certify candidate block, expect %x blockID, got %x" , blockID , certifyingQC .BlockID )
128- }
118+ blockID := candidate .ID ()
119+ // sanity check if certifyingQC actually certifies candidate block
120+ if certifyingQC .View != candidate .Header .View {
121+ return fmt .Errorf ("qc doesn't certify candidate block, expect %d view, got %d" , candidate .Header .View , certifyingQC .View )
122+ }
123+ if certifyingQC .BlockID != blockID {
124+ return fmt .Errorf ("qc doesn't certify candidate block, expect %x blockID, got %x" , blockID , certifyingQC .BlockID )
129125 }
130126
131- // check if the block header is a valid extension of the finalized state
127+ // check if the block header is a valid extension of parent block
132128 err := m .headerExtend (candidate )
133129 if err != nil {
134- if state .IsOutdatedExtensionError (err ) {
135- return fmt .Errorf ("candidate block is an outdated extension: %w" , err )
136- }
137130 // since we have a QC for this block, it cannot be an invalid extension
138131 return fmt .Errorf ("unexpected invalid block (id=%x) with certifying qc (id=%x): %s" ,
139132 candidate .ID (), certifyingQC .ID (), err .Error ())
@@ -163,12 +156,21 @@ func (m *ParticipantState) Extend(ctx context.Context, candidate *flow.Block) er
163156 span , ctx := m .tracer .StartSpanFromContext (ctx , trace .ProtoStateMutatorExtend )
164157 defer span .End ()
165158
166- // check if the block header is a valid extension of the finalized state
159+ // check if the block header is a valid extension of parent block
167160 err := m .headerExtend (candidate )
168161 if err != nil {
169162 return fmt .Errorf ("header not compliant with chain state: %w" , err )
170163 }
171164
165+ // check if the block header is a valid extension of the finalized state
166+ err = m .checkOutdatedExtension (candidate .Header )
167+ if err != nil {
168+ if state .IsOutdatedExtensionError (err ) {
169+ return fmt .Errorf ("candidate block is an outdated extension: %w" , err )
170+ }
171+ return fmt .Errorf ("could not check if block is an outdated extension: %w" , err )
172+ }
173+
172174 // check if the guarantees in the payload is a valid extension of the finalized state
173175 err = m .guaranteeExtend (ctx , candidate )
174176 if err != nil {
@@ -199,7 +201,6 @@ func (m *ParticipantState) Extend(ctx context.Context, candidate *flow.Block) er
199201// headerExtend verifies the validity of the block header (excluding verification of the
200202// consensus rules). Specifically, we check that the block connects to the last finalized block.
201203// Expected errors during normal operations:
202- // - state.OutdatedExtensionError if the candidate block is outdated (e.g. orphaned)
203204// - state.InvalidExtensionError if the candidate block is invalid
204205func (m * FollowerState ) headerExtend (candidate * flow.Block ) error {
205206 // FIRST: We do some initial cheap sanity checks, like checking the payload
@@ -240,13 +241,17 @@ func (m *FollowerState) headerExtend(candidate *flow.Block) error {
240241 return fmt .Errorf ("validating block's time stamp failed with unexpected error: %w" , err )
241242 }
242243
243- // THIRD: Once we have established the block is valid within itself, and the
244- // block is valid in relation to its parent, we can check whether it is
245- // valid in the context of the entire state. For this, the block needs to
246- // directly connect, through its ancestors, to the last finalized block.
244+ return nil
245+ }
247246
247+ // checkOutdatedExtension checks whether candidate block is
248+ // valid in the context of the entire state. For this, the block needs to
249+ // directly connect, through its ancestors, to the last finalized block.
250+ // Expected errors during normal operations:
251+ // - state.OutdatedExtensionError if the candidate block is outdated (e.g. orphaned)
252+ func (m * ParticipantState ) checkOutdatedExtension (header * flow.Header ) error {
248253 var finalizedHeight uint64
249- err = m .db .View (operation .RetrieveFinalizedHeight (& finalizedHeight ))
254+ err : = m .db .View (operation .RetrieveFinalizedHeight (& finalizedHeight ))
250255 if err != nil {
251256 return fmt .Errorf ("could not retrieve finalized height: %w" , err )
252257 }
@@ -276,7 +281,6 @@ func (m *FollowerState) headerExtend(candidate *flow.Block) error {
276281 }
277282 ancestorID = ancestor .ParentID
278283 }
279-
280284 return nil
281285}
282286
0 commit comments