Support reconstruction of historical states from snapshots
Description
Lighthouse has a flag (--reconstruct-historic-states) this flag allows the node to reconstruct all the historical states at any point in time, including after a snapshot sync. This allows for the node to be up and operational quickly while, in the background, recreating the historical states that allows it to return old data (i.e. archive node).
We'll need a way to specify the genesis state (or some state to start generating from). If checkpoint sync is used our anchor state will be from close to chain tip. For built-in network definitions we can provide that genesis state automatically (same as the default initial state we would have used). Will need a custom CLI arg for custom networks.
Then create a new service to regenerate historic states:
- Get the genesis state (use same mechanism as we do for loading --initial-state)
- Check the genesis state root matches the state root from block 0
- Iterate through finalized blocks in the database (forwards), applying each block to the state with
spec.replayValidatedBlock - After each block, check if it's been more than
--data-storage-archive-frequencyslots since the last state was stored, if so store this new state.
Note that storing the state probably means adding a new method to StorageUpdateChannel and Database and it will eventually call KvStoreFinalizedDao.FinalizedUpdater.addFinalizedState
Once we have the basics working, some follow up improvements:
- Hook the new service in so Teku starts it after the
HistoricalBlockSyncServicecompletes downloading all historic blocks.HistoricalBlockSyncServiceis probably the right place to hook this in since it knows when it's done. - Store the finalized state roots as well. We can probably reuse
StateRootRecorderwhich is used when importing blocks during a normal sync. - Handle restarts while part way through reconstructing historic states.
- Suggest that each time we record a state, we also update a variable with the last state generated
- When starting up if the variable is set, we can start from that last state rather than from genesis
- Need to set the variable to a special value to indicate we've completed regeneration
Also in terms of where to put the new service, it probably makes sense to put it in a package alongside HIstoricalBlockFetcher in :beacon:sync.
TODO: Implement doStop() method in ReconstructHistoricalStatesService class properly
TODO: Also need to record the finalized state roots
TODO: Add testing for service
closed too early, lets check our feature definition of done...
Docs written, options unhidden. All done. :tada: