Skip to content

Fix stale action invalidation in global state manager - #313

Merged
JonoPrest merged 1 commit into
mainfrom
jp/fix-stale-action-invalidation
Nov 1, 2024
Merged

JonoPrest merged 1 commit into
mainfrom
jp/fix-stale-action-invalidation

Conversation

@JonoPrest

@JonoPrest JonoPrest commented Nov 1, 2024 •

Copy link
Copy Markdown
Collaborator

Closes #311

The bug was being caused by a stale action being dispatched (from before the restart after pre registration)

This PR:

  1. Fixes the state id invalidator that is also used in rollbacks
  2. Uses state id to invalidate stale actions after the indexer starts with

@JonoPrest
JonoPrest requested a review from DZakh November 1, 2024 12:50
Comment on lines +38 to +45
and dispatchTask = (self, task: S.task) => {
let stateId = self.state->S.getId
Js.Global.setTimeout(() => {
S.taskReducer(self.state, task, ~dispatchAction=action =>
dispatchAction(~stateId=self.state->S.getId, self, action)
dispatchAction(~stateId, self, action)
)->ignore
}, 0)->ignore
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This was a bug, the state id should be retrieved at the time dispatchTask gets called, not as dispatchAction gets called.

Since S.getId was being called only at dispatchAction it would always pass the latest stateId and there would be no way to invalidate the action against it's state id

@JonoPrest
JonoPrest force-pushed the jp/fix-stale-action-invalidation branch from d102d13 to 0244ba5 Compare November 1, 2024 12:56
} else {
(state, [])
}
(freshState->incrementId, [NextQuery(CheckAllChains)])

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Here the new state increments the state id so that any actions being dispatched from previous invalid state will be invalidated.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice

Comment on lines -657 to -659
//Protect against handling this action twice. It should only be handled once
//when the pre registration is done
if ChainManager.isPreRegisteringDynamicContracts(chainManager) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Removed this if check since it's using the state id invalidator.

@DZakh DZakh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Like the solution 👍

} else {
(state, [])
}
(freshState->incrementId, [NextQuery(CheckAllChains)])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice

Comment on lines +713 to +717
switch (state, action) {
| ({rollbackState: RollingBack(_)}, EventBatchProcessed(_)) => (
{...state, currentlyProcessingBatch: false},
[Rollback],
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could you explain the logic? I can't completely comprehend what's going on here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah sure, it's a bit difficult to follow how the actions/tasks react to each other.

So Rollback action will first get dispatched after block range response when a reorg gets detected here:

} else {
chainFetcher.logger->Logging.childWarn("Reorg detected, rolling back")
Prometheus.incrementReorgsDetected(~chain)
let partitionsCurrentlyFetching =
chainFetcher.partitionsCurrentlyFetching->Set.Int.remove(partitionId)
let chainFetcher = {
...chainFetcher,
partitionsCurrentlyFetching,
}
let chainManager = state.chainManager->ChainManager.setChainFetcher(chainFetcher)
(state->setChainManager(chainManager)->incrementId->setRollingBack(chain), [Rollback])
}

Then on the Rollback task, if it only starts if a batch is not currently processing.

| Rollback =>
//If it isn't processing a batch currently continue with rollback otherwise wait for current batch to finish processing
switch state {
| {currentlyProcessingBatch: false, rollbackState: RollingBack(rollbackChain)} =>
Logging.warn("Executing rollback")

When the EventBatchProcessed action gets dispatched, it will be an invalid action and all we want it to do is set currently processing to false and then dispatch the rollback task again.

I just added an extra check here that rollback state will be RollingBack so that we don't match on this case if it were produced say by this preRegistration feature.

@JonoPrest
JonoPrest force-pushed the jp/fix-stale-action-invalidation branch from d476b6e to e206024 Compare November 1, 2024 14:38
@JonoPrest
JonoPrest enabled auto-merge (rebase) November 1, 2024 14:39
@JonoPrest
JonoPrest merged commit c7b5c22 into main Nov 1, 2024
@JonoPrest
JonoPrest deleted the jp/fix-stale-action-invalidation branch November 1, 2024 14:44
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.

Handler not saving entity properly with preRegisterDynamicContracts

2 participants