feat: support rewind for versa db

fix: rewind ancient store
This commit is contained in:
joeycli 2024-08-27 15:51:30 +08:00
parent 3e8e74d5c2
commit 0af2fb4324
3 changed files with 164 additions and 99 deletions

@ -424,6 +424,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
// Make sure the state associated with the block is available, or log out
// if there is no available state, waiting for state sync.
head := bc.CurrentBlock()
if bc.triedb.Scheme() != rawdb.VersionScheme {
if !bc.HasState(head.Root) {
if head.Number.Uint64() == 0 {
// The genesis state is missing, which is only possible in the path-based
@ -465,7 +466,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
}
}
} else {
log.Warn("versa db no recovery, rewind in load state")
}
// Ensure that a previous crash in SetHead doesn't leave extra ancients
if bc.triedb.Scheme() != rawdb.VersionScheme {
if frozen, err := bc.db.BlockStore().ItemAmountInAncient(); err == nil && frozen > 0 {
frozen, err = bc.db.BlockStore().Ancients()
if err != nil {
@ -500,6 +505,24 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
}
}
} else {
//TODO:: need consider the offline and inline prune block
frozen, err := bc.db.BlockStore().Ancients()
if err != nil {
return nil, err
}
items, err := bc.db.BlockStore().ItemAmountInAncient()
if err != nil {
return nil, err
}
fullBlock := bc.CurrentBlock()
log.Info("version mode rewind ancient store", "target", fullBlock.Number.Uint64(), "old head", frozen, "items", items, "offset", bc.db.BlockStore().AncientOffSet())
if frozen >= fullBlock.Number.Uint64() {
if _, err = bc.db.BlockStore().TruncateTail(fullBlock.Number.Uint64()); err != nil {
return nil, err
}
}
}
// The first thing the node will do is reconstruct the verification data for
// the head block (ethash cache or clique voting snapshot). Might as well do
// it in advance.
@ -702,6 +725,38 @@ func (bc *BlockChain) getFinalizedNumber(header *types.Header) uint64 {
// loadLastState loads the last known chain state from the database. This method
// assumes that the chain manager mutex is held.
func (bc *BlockChain) loadLastState() error {
// TODO:: before versa db support recovery, only rewind
var headBlock *types.Block
if bc.triedb.Scheme() == rawdb.VersionScheme {
head := rawdb.ReadHeadBlockHash(bc.db)
headBlock = bc.GetBlockByHash(head)
versa := bc.triedb.VersaDB()
archiveVersion, _ := versa.LatestStoreDiskVersionInfo()
// empty chain
if archiveVersion == -1 {
archiveVersion = 0
}
if int64(headBlock.NumberU64()) < archiveVersion {
log.Crit("versa db disk version large than header block", "head number", headBlock.NumberU64(), "versa archive number", archiveVersion)
}
log.Info("begin rewind versa db head", "target", archiveVersion)
for {
if int64(headBlock.NumberU64()) == archiveVersion {
rawdb.WriteCanonicalHash(bc.db, headBlock.Hash(), headBlock.NumberU64())
rawdb.WriteHeadHeaderHash(bc.db, headBlock.Hash())
rawdb.WriteHeadBlockHash(bc.db, headBlock.Hash())
rawdb.WriteHeadFastBlockHash(bc.db, headBlock.Hash())
log.Info("reset versa db head block", "number", headBlock.NumberU64(), "hash", headBlock.Hash())
break
}
headBlock = rawdb.ReadBlock(bc.db, headBlock.ParentHash(), headBlock.NumberU64()-1)
if headBlock == nil {
panic("versa db rewind head is nil")
}
}
} else {
// Restore the last known head block
head := rawdb.ReadHeadBlockHash(bc.db)
if head == (common.Hash{}) {
@ -710,12 +765,14 @@ func (bc *BlockChain) loadLastState() error {
return bc.Reset()
}
// Make sure the entire head block is available
headBlock := bc.GetBlockByHash(head)
headBlock = bc.GetBlockByHash(head)
if headBlock == nil {
// Corrupt or empty database, init from scratch
log.Warn("Head block missing, resetting chain", "hash", head)
return bc.Reset()
}
}
log.Info("load state head block", "number", headBlock.NumberU64())
// Everything seems to be fine, set as the head block
bc.currentBlock.Store(headBlock.Header())

@ -191,6 +191,8 @@ func peerToSyncOp(mode downloader.SyncMode, p *eth.Peer) *chainSyncOp {
}
func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) {
head := cs.handler.chain.CurrentBlock()
if cs.handler.chain.TrieDB().Scheme() != rawdb.VersionScheme {
// If we're in snap sync mode, return that directly
if cs.handler.snapSync.Load() {
block := cs.handler.chain.CurrentSnapBlock()
@ -199,7 +201,7 @@ func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) {
}
// We are probably in full sync, but we might have rewound to before the
// snap sync pivot, check if we should re-enable snap sync.
head := cs.handler.chain.CurrentBlock()
head = cs.handler.chain.CurrentBlock()
if pivot := rawdb.ReadLastPivotNumber(cs.handler.database); pivot != nil {
if head.Number.Uint64() < *pivot {
if rawdb.ReadAncientType(cs.handler.database) == rawdb.PruneFreezerType {
@ -219,6 +221,11 @@ func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) {
log.Info("Reenabled snap sync as chain is stateless")
return downloader.SnapSync, td
}
} else {
if !cs.handler.chain.HasState(head.Root) {
panic("version db not support snap sync")
}
}
// Nope, we're really full syncing
td := cs.handler.chain.GetTd(head.Hash(), head.Number.Uint64())
return downloader.FullSync, td

@ -49,7 +49,8 @@ func (v *VersionDB) Scheme() string {
}
func (v *VersionDB) Initialized(genesisRoot common.Hash) bool {
return v.db.HasState(genesisRoot)
version, _ := v.db.LatestStoreDiskVersionInfo()
return version >= 0
}
func (v *VersionDB) Size() (common.StorageSize, common.StorageSize, common.StorageSize) {