Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(providers): collect BlockState before constructing DB provider #11338

Merged
merged 2 commits into from
Sep 30, 2024

Conversation

Rjected
Copy link
Member

@Rjected Rjected commented Sep 30, 2024

Changes from #11265 that fix a race condition in the builder

The race condition is between the builder and tree, with the following order of events:

  • The builder is trying to get a state provider for a block, with anchor = block N
  • The persistence task finishes, and cleans up block N+1 from the in memory state
  • The builder fetches calls CanonicalInmemoryState::state_provider. In the current code this results in a DB provider for block N, and BlockState for N+2, ..., meaning there is a gap for block N+1, which no longer exists in CanonicalInMemoryState.

This happens because the anchor hash is determined before block N+1 is persisted. The BlockState is still valid, but we should not be re-fetching the state.

This PR re-uses the BlockState that is used to determine the anchor hash, and introduces a new method state_provider_from_state that allows this reuse.

@Rjected Rjected added C-bug An unexpected or incorrect behavior A-db Related to the database A-block-building Related to block building A-blockchain-tree Related to sidechains, reorgs and pending blocks labels Sep 30, 2024
@rkrasiuk
Copy link
Member

tyty, will approve after trace cleanup

let anchor_hash = state.anchor().hash;
trace!(target: "providers::blockchain", ?anchor_hash, "Fetching historical provider for block hash");
let latest_historical = self.database.history_by_block_hash(anchor_hash)?;
Copy link
Member

Choose a reason for hiding this comment

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

can there still be a race condition here between the moment anchor hash was set on BlockState and the moment when we actually retrieve the state provider? does it matter here?

Copy link
Member Author

Choose a reason for hiding this comment

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

can there still be a race condition here between the moment anchor hash was set on BlockState and the moment when we actually retrieve the state provider? does it matter here?

I think so, although only for reorgs afaict. When the DB state only moves forward this should not be a problem. Take for example a reorg which removes one block from the DB. The race is:

  • we fetch the state
  • anchor is removed from DB, replaced with another block
  • now we call history_by_block_hash on something that does not exist

The only idea I can come up with to fix it, is to store ExecutedBlocks like we do TrieUpdates before finalization.

@Rjected Rjected force-pushed the dan/block-state-provider-race-condition branch from c743be2 to 32b3697 Compare September 30, 2024 15:10
@Rjected
Copy link
Member Author

Rjected commented Sep 30, 2024

cc @rkrasiuk traces removed

Copy link
Collaborator

@mattsse mattsse left a comment

Choose a reason for hiding this comment

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

uffff

@@ -177,7 +177,7 @@ impl<N: ProviderNodeTypes> BlockchainProvider2<N> {
let state = state.as_ref();
let anchor_hash = state.anchor().hash;
let latest_historical = self.database.history_by_block_hash(anchor_hash)?;
Ok(self.canonical_in_memory_state.state_provider(state.hash(), latest_historical))
Ok(self.canonical_in_memory_state.state_provider_from_state(state, latest_historical))
Copy link
Collaborator

Choose a reason for hiding this comment

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

ah massive yikes

crates/chain-state/src/in_memory.rs Outdated Show resolved Hide resolved
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
@Rjected Rjected force-pushed the dan/block-state-provider-race-condition branch from d72977d to d9e663e Compare September 30, 2024 15:33
@Rjected Rjected added this pull request to the merge queue Sep 30, 2024
Merged via the queue into main with commit 09f0526 Sep 30, 2024
35 checks passed
@Rjected Rjected deleted the dan/block-state-provider-race-condition branch September 30, 2024 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-block-building Related to block building A-blockchain-tree Related to sidechains, reorgs and pending blocks A-db Related to the database C-bug An unexpected or incorrect behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants