-
Couldn't load subscription status.
- Fork 2k
chore(engine): Remove ConsistentDbView #19188
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
Conversation
1e58915 to
50c3d20
Compare
| /// Input parameters for spawning a dedicated storage multiproof calculation. | ||
| #[derive(Debug)] | ||
| struct StorageMultiproofInput { | ||
| config: MultiProofConfig, |
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.
MultiProofConfig is how we previously conveyed reverts+in-memory overlay to the proof tasks. OverlayStateProvider now does this job, so it's not necessary to convey the config anymore.
The prefix_sets field of the config is no longer applicable either, as we are always generating proofs off a DB state where hashed state and trie tables are at the same block.
| // Use state root task only if prefix sets are empty, otherwise proof generation is | ||
| // too expensive because it requires walking all paths in every proof. | ||
| let spawn_start = Instant::now(); | ||
| let (handle, strategy) = if trie_input.prefix_sets.is_empty() { |
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.
I'm not sure that prefix_sets ever wasn't empty, but it definitely is always empty now
| .ok_or_else(|| ProviderError::BlockHashNotFound(historical.as_hash().unwrap()))?; | ||
|
|
||
| // Retrieve revert state for historical block. | ||
| let (revert_state, revert_trie) = if block_number == best_block_number { |
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.
Reverts are now handled by the OverlayStateProviderFactory, it's only necessary to collect the highest persisted ancestor block number here (so that the OverlayStateProviderFactory knows which block to revert to) and any in-memory overlay data
| pub type FactoryTx<F> = <<F as DatabaseProviderFactory>::DB as Database>::TX; | ||
|
|
||
| /// A trait which can be used to describe any factory-like type which returns a read-only provider. | ||
| pub trait DatabaseProviderROFactory { |
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.
This trait serves multiple purposes:
- Allow passing OverlayStateProviderFactory as a generic throughout the code, which will help keep things flexible in the future.
- By not constraining Provider to
DBProviderhere we don't force OverlayStateProvider to expose its inner TX, which will make it difficult to misuse. - Allows us to constrain the Provider to be
TrieCursorFactory + HashedCursorFactory. The alternative would be defining two new TrieCursorFactoryFactory + HashedCursorFactoryFactory traits, which seemed worse.
crates/trie/parallel/benches/root.rs
Outdated
| } | ||
|
|
||
| let view = ConsistentDbView::new(provider_factory.clone(), None); | ||
| let view = OverlayStateProviderFactory::new(provider_factory.clone()); |
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.
If we could add a blanket implementation for TrieCursorFactory and HashedCursorFactory on DBProvider, then (combined with the DatabaseProviderROFactory blanket implementation in this PR) I don't think wrapping this factory would be necessary. But doing that created some import cycles so I left it alone for now.
|
is this a chore improvement or does it unlock other things? |
When determining the available range of trie changeset data we previously only took into account the StageCheckpoint. This was wrong for two reasons: * The StageCheckpoint can have its inner block range cleared, specifically on unwind or reorgs. So we can't rely on the starting bound being present. * The StageCheckpoint's lower bound doesn't get updated by pruning, only the prune checkpoint does. So in general we'll want to rely on the prune checkpoint.
…iocregopher/18906-rm-consistentdbview
chore but major milestone for us towards simplifying core abstractions which was enabled by #18460 |
16bdc39 to
fe51aef
Compare
|
|
||
| // We rely on the cursor factory to provide whatever DB overlay is necessary to see a | ||
| // consistent view of the database, including the trie tables. Because of this there is no | ||
| // need for an overarching prefix set to invalidate any section of the trie tables, and so | ||
| // we use an empty prefix set. | ||
| let prefix_sets = Arc::new(TriePrefixSetsMut::default()); |
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 prefix_sets be removed from ProofTaskCtx too then?
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.
I think so yes, I had thought it would be good to keep it around in case we wanted to/needed to use it for some future use-case, but at the moment removing it would be possible.
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 do as a follow-up, just nicer to not pass defaults everywhere if it's unused anyway
| }) | ||
| }; | ||
| // Use the higher of the two lower bounds. If neither is available assume unbounded. | ||
| let lower_bound = stage_lower_bound.max(prune_lower_bound).unwrap_or(0); |
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.
Without this change the e2e tests wouldn't complete, because they don't run a pipeline to set the PruneCheckpoint. I think it's fine generally, as we shouldn't ever have a real condition where the PruneCheckpoint wouldn't be set.
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.
I think this is fine
| /// that has proof targets. | ||
| #[derive(Debug)] | ||
| pub struct ParallelProof { | ||
| /// The sorted collection of cached in-memory intermediate trie nodes that |
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.
oh, this was already unused 👍
Co-authored-by: Alexey Shekhirin <[email protected]>
|
|
||
| // Plan the strategy used for state root computation. | ||
| let state_root_plan = self.plan_state_root_computation(&input, &ctx); | ||
| let persisting_kind = state_root_plan.persisting_kind; |
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.
PersistingKind can be removed completely in a follow-up PR
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.
nice
| StateRootStrategy::Parallel, | ||
| ) | ||
| } | ||
| let (handle, strategy) = match self.payload_processor.spawn( |
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.
unrelated to this PR: I don't think self.payload_processor.spawn is actually fallible, should be possible to simplify this even more without a fallback to self.payload_processor.spawn_cache_exclusive, can be done in a follow-up PR
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 we track this @shekhirin
| StateRootStrategy::Parallel | ||
| } | ||
| } else { | ||
| fn plan_state_root_computation(&self) -> StateRootPlan { |
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 be done in a follow-up PR: can just return an enum now, the function is much simpler
| (revert_state, revert_trie) | ||
| }; | ||
|
|
||
| input.append_cached(revert_trie.into(), revert_state); |
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.
checks out, this was needed only for reverting the trie state
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.
LGTM, only nits and follow-ups for cleanup
…rm-consistentdbview
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.
this makes sense to me, also just nits that can be done as a follow up
| // The `hashed_state` argument is already taken into account as part of the overlay, but we | ||
| // need to use the prefix sets which were generated from it to indicate to the | ||
| // ParallelStateRoot which parts of the trie need to be recomputed. | ||
| let prefix_sets = Arc::into_inner(multiproof_config.prefix_sets) | ||
| .expect("MultiProofConfig was never cloned") | ||
| .freeze(); |
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.
the use of into_inner here makes me think we should have a function that constructs a MultiProofConfig from trie input, that gives us back the original prefix sets.
| // Create provider from factory | ||
| let provider = task_ctx | ||
| .factory | ||
| .database_provider_ro() | ||
| .expect("Account worker failed to initialize: unable to create provider"); |
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.
nit for followup - we should make this fn return a Result<()> so we can just propagate this error
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.
awesome
this now unlocks a ton of additional simplifications
| /// A cleared trie input, kept around to be reused so allocations can be minimized. | ||
| trie_input: Option<TrieInput>, |
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.
epic
|
|
||
| // Plan the strategy used for state root computation. | ||
| let state_root_plan = self.plan_state_root_computation(&input, &ctx); | ||
| let persisting_kind = state_root_plan.persisting_kind; |
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.
nice
| let provider = self.provider.database_provider_ro()?; | ||
|
|
||
| let (mut input, block_number) = | ||
| self.compute_trie_input(provider, parent_hash, state, None)?; |
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.
I think all of this is tracked in #19250
| StateRootStrategy::Parallel, | ||
| ) | ||
| } | ||
| let (handle, strategy) = match self.payload_processor.spawn( |
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 we track this @shekhirin
| }) | ||
| }; | ||
| // Use the higher of the two lower bounds. If neither is available assume unbounded. | ||
| let lower_bound = stage_lower_bound.max(prune_lower_bound).unwrap_or(0); |
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.
I think this is fine
This PR replaces usage of ConsistenDbView with the OverlayStateProviderFactory. The OverlayStateProviderFactory will handle reverting both hashed and trie state to the correct target block whenever a new tx is made, as well as applying any necessary in-memory overlay on top of that.