Skip to content

Conversation

mediocregopher
Copy link
Collaborator

Closes #18517

This PR primarily targets the unwind_trie_state_range provider method, which is used by the engine API to unwind the db during reorgs.

This method was previously also potentially used by the unwind pipeline stage, but only in an else block which should never get hit anymore. This else block was replaced with an error.

unwind_trie_state_range was previously recomputing trie updates using a StateRoot calculation, but it is now able to skip that step and simply read trie updates from the trie changeset tables instead. To make applying these updates easier the write_trie_updates method is superceded by write_trie_updates_sorted.

@github-project-automation github-project-automation bot moved this to Backlog in Reth Tracker Oct 6, 2025
@github-actions github-actions bot added A-db Related to the database A-trie Related to Merkle Patricia Trie implementation C-enhancement New feature or request labels Oct 6, 2025
@mediocregopher mediocregopher force-pushed the mediocregopher/18517-trie-cs-unwind branch from bdaeb41 to 70d24d4 Compare October 6, 2025 16:25
self.write_trie_updates_sorted(&trie_revert)?;

// Clear trie changesets which have been unwound.
self.clear_trie_changesets_from(*range.start())?;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@shekhirin you mentioned in a previous PR that we don't want to have deletion from changesets done on a range, but this method only accepts a range. Do you think it's fine to leave this like this? or better to re-introduce clear_trie_changesets_from?

@mediocregopher mediocregopher marked this pull request as ready for review October 6, 2025 16:33
Copy link
Member

@Rjected Rjected left a comment

Choose a reason for hiding this comment

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

I like that this makes things simpler, I have a question and suggestion for a helper method but otherwise this looks good to me

Comment on lines +357 to +358
let trie_revert = self.trie_reverts(range.clone())?;
self.write_trie_updates_sorted(&trie_revert)?;
Copy link
Member

Choose a reason for hiding this comment

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

nice, i like that this is now just a call to a provider fn

///
/// Returns the number of entries modified.
fn write_trie_updates_sorted(&self, trie_updates: &TrieUpdatesSorted) -> ProviderResult<usize> {
if trie_updates.account_nodes.is_empty() && trie_updates.storage_tries.is_empty() {
Copy link
Member

Choose a reason for hiding this comment

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

could probably just introduce TrieUpdatesSorted::is_empty

Comment on lines +62 to +90
// Sanity check that we have static files available to unwind to the target block.
let highest_static_file_block =
provider_factory.static_file_provider().get_highest_static_files().max_block_num();
if highest_static_file_block
.filter(|highest_static_file_block| *highest_static_file_block > target)
.is_none()
{
return Err(eyre::eyre!("static files not available for target block {target}, highest is {highest_static_file_block:?}"));
}

// Move all applicable data from database to static files.
pipeline.move_to_static_files()?;
if self.offline {
info!(target: "reth::cli", "Performing an unwind for offline-only data!");
}

pipeline.unwind(target, None)?;
if let Some(highest_static_file_block) = highest_static_file_block {
info!(target: "reth::cli", ?target, ?highest_static_file_block, "Executing a pipeline unwind.");
} else {
info!(target: "reth::cli", ?target, "Executing a database unwind.");
let provider = provider_factory.provider_rw()?;
info!(target: "reth::cli", ?target, "Executing a pipeline unwind.");
}
info!(target: "reth::cli", prune_config=?config.prune, "Using prune settings");

provider
.remove_block_and_execution_above(target)
.map_err(|err| eyre::eyre!("Transaction error on unwind: {err}"))?;
// This will build an offline-only pipeline if the `offline` flag is enabled
let mut pipeline =
self.build_pipeline(config, provider_factory, components.evm_config().clone())?;

// update finalized block if needed
let last_saved_finalized_block_number = provider.last_finalized_block_number()?;
if last_saved_finalized_block_number.is_none_or(|f| f > target) {
provider.save_finalized_block_number(target)?;
}
// Move all applicable data from database to static files.
pipeline.move_to_static_files()?;

provider.commit()?;
}
pipeline.unwind(target, None)?;
Copy link
Member

@Rjected Rjected Oct 6, 2025

Choose a reason for hiding this comment

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

is the reasoning behind this, that currently we pretty much always have static files and will now always be doing a pipeline unwind?

@github-project-automation github-project-automation bot moved this from Backlog to In Progress in Reth Tracker Oct 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-db Related to the database A-trie Related to Merkle Patricia Trie implementation C-enhancement New feature or request
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

2 participants