Skip to content

Conversation

@UlyanaAndrukhiv
Copy link
Contributor

Close: #8204

Context

This PR implements the following checks to criteria validation:

  • Validate required executor IDs (ensure that all executor IDs provided through the criteria actually exist among the known execution nodes).
  • Validate required executor IDs count (ensure that the required executor number does not exceed the actual number of available executors).
  • Return error when the block is sealed but criteria cannot be met (if the block is already sealed and the provided criteria still cannot be satisfied, return an error to the user indicating that the criteria cannot be met).

Additional updates:

  • Added tests.
  • Updated error handling for fork-aware endpoints.

@UlyanaAndrukhiv UlyanaAndrukhiv self-assigned this Dec 5, 2025
@UlyanaAndrukhiv UlyanaAndrukhiv marked this pull request as ready for review December 5, 2025 14:06
@UlyanaAndrukhiv UlyanaAndrukhiv requested a review from a team as a code owner December 5, 2025 14:06
}
}

func (e *RequiredExecutorsCountExceededError) Error() string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a good idea to also include Unwrap methods to allow errors.Is and errors.As to work when the returned error is wrapped.

return nil, fmt.Errorf("failed to retrieve execution IDs: %w", err)
}

err = e.validateRequiredExecutors(criteria.RequiredExecutors, executorIdentities)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we're validating that the executors exist in the identity table, I think we need to use state.AtBlockID() to get the executors for the specific block queried. ENs generally don't change often, but this is more correct.

Comment on lines +106 to +117
sealedHeader, err := e.state.Sealed().Head()
if err != nil {
return nil, fmt.Errorf("failed to lookup sealed header: %w", err)
}
header, err := e.headers.ByBlockID(blockID)
if err != nil {
return nil, fmt.Errorf("failed to get header by block ID %v: %w", blockID, err)
}
// If block is sealed and criteria cannot be met return an error
if header.Height <= sealedHeader.Height && len(subsetENs) < len(criteria.RequiredExecutors) {
return nil, optimistic_sync.NewCriteriaNotMetError(blockID)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check assumes that the provided block is finalized, but I don't think that's enforced anywhere. this requires an additional lookup of BlockIDByHeight to determine if the finalized blockID matches the provided blockID. if it is, the following check is OK. if it's not, then the requested block conflicts with a finalized (or sealed) block, which should also return a sentinel error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a nice user experience addition, but we should avoid doing the db lookups unless len(subsetENs) < len(criteria.RequiredExecutors)

required flow.IdentifierList,
available flow.IdentityList,
) error {
if len(available) < len(required) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should include a check that AgreeingExecutorsCount is less than the available executors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DataAvailability] add a check for executors passed by a client

4 participants