-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Conversation
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)?; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 ExecutedBlock
s like we do TrieUpdates
before finalization.
c743be2
to
32b3697
Compare
cc @rkrasiuk traces removed |
There was a problem hiding this 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)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah massive yikes
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
d72977d
to
d9e663e
Compare
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:
N
N+1
from the in memory stateCanonicalInmemoryState::state_provider
. In the current code this results in a DB provider for blockN
, andBlockState
forN+2, ...
, meaning there is a gap for blockN+1
, which no longer exists inCanonicalInMemoryState
.This happens because the anchor hash is determined before block
N+1
is persisted. TheBlockState
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 methodstate_provider_from_state
that allows this reuse.