diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index bd6aeaa6ab..d7def882f1 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -371,8 +371,7 @@ func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error if err != nil { return err } - dl, err = dl.revert(h, loader) - if err != nil { + if err = dl.revert(h, loader); err != nil { return err } // reset layer with newly created disk layer. It must be diff --git a/triedb/pathdb/difflayer.go b/triedb/pathdb/difflayer.go index 6b87883482..d7e0168a5d 100644 --- a/triedb/pathdb/difflayer.go +++ b/triedb/pathdb/difflayer.go @@ -152,5 +152,8 @@ func diffToDisk(layer *diffLayer, force bool) (layer, error) { if !ok { panic(fmt.Sprintf("unknown layer type: %T", layer.parentLayer())) } - return disk.commit(layer, force) + if err := disk.commit(layer, force); err != nil { + return nil, err + } + return disk, nil } diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index 964ad2ef77..7856573399 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -152,7 +152,7 @@ func (dl *diskLayer) update(root common.Hash, id uint64, block uint64, nodes map // commit merges the given bottom-most diff layer into the node buffer // and returns a newly constructed disk layer. Note the current disk // layer must be tagged as stale first to prevent re-access. -func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { +func (dl *diskLayer) commit(bottom *diffLayer, force bool) error { dl.lock.Lock() defer dl.lock.Unlock() @@ -166,13 +166,13 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { if dl.db.freezer != nil { err := writeHistory(dl.db.freezer, bottom) if err != nil { - return nil, err + return err } // Determine if the persisted history object has exceeded the configured // limitation, set the overflow as true if so. tail, err := dl.db.freezer.Tail() if err != nil { - return nil, err + return err } limit := dl.db.config.StateHistory if limit != 0 && bottom.stateID()-tail > limit { @@ -194,7 +194,8 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { // Construct a new disk layer by merging the nodes from the provided diff // layer, and flush the content in disk layer if there are too many nodes // cached. The clean cache is inherited from the original disk layer. - ndl := newDiskLayer(bottom.root, bottom.stateID(), dl.db, dl.cleans, dl.buffer.commit(bottom.nodes)) + dl.buffer.commit(bottom.nodes) + dl.root, dl.id = bottom.root, bottom.stateID() // In a unique scenario where the ID of the oldest history object (after tail // truncation) surpasses the persisted state ID, we take the necessary action @@ -203,35 +204,35 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { if !force && rawdb.ReadPersistentStateID(dl.db.diskdb) < oldest { force = true } - if err := ndl.buffer.flush(ndl.db.diskdb, ndl.cleans, ndl.id, force); err != nil { - return nil, err + if err := dl.buffer.flush(dl.db.diskdb, dl.cleans, dl.id, force); err != nil { + return err } // To remove outdated history objects from the end, we set the 'tail' parameter // to 'oldest-1' due to the offset between the freezer index and the history ID. if overflow { - pruned, err := truncateFromTail(ndl.db.diskdb, ndl.db.freezer, oldest-1) + pruned, err := truncateFromTail(dl.db.diskdb, dl.db.freezer, oldest-1) if err != nil { - return nil, err + return err } log.Debug("Pruned state history", "items", pruned, "tailid", oldest) } - return ndl, nil + return nil } // revert applies the given state history and return a reverted disk layer. -func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) (*diskLayer, error) { +func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) error { if h.meta.root != dl.rootHash() { - return nil, errUnexpectedHistory + return errUnexpectedHistory } if dl.id == 0 { - return nil, fmt.Errorf("%w: zero state id", errStateUnrecoverable) + return fmt.Errorf("%w: zero state id", errStateUnrecoverable) } // Apply the reverse state changes upon the current state. This must // be done before holding the lock in order to access state in "this" // layer. nodes, err := triestate.Apply(h.meta.parent, h.meta.root, h.accounts, h.storages, loader) if err != nil { - return nil, err + return err } // Mark the diskLayer as stale before applying any mutations on top. dl.lock.Lock() @@ -247,7 +248,7 @@ func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) (*diskLayer if !dl.buffer.empty() { err := dl.buffer.revert(dl.db.diskdb, nodes) if err != nil { - return nil, err + return err } } else { batch := dl.db.diskdb.NewBatch() @@ -257,7 +258,10 @@ func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) (*diskLayer log.Crit("Failed to write states", "err", err) } } - return newDiskLayer(h.meta.parent, dl.id-1, dl.db, dl.cleans, dl.buffer), nil + + dl.root, dl.id = h.meta.parent, dl.id-1 + + return nil } // setBufferSize sets the node buffer size to the provided value. diff --git a/triedb/pathdb/layertree.go b/triedb/pathdb/layertree.go index d314779910..fd1404a1bf 100644 --- a/triedb/pathdb/layertree.go +++ b/triedb/pathdb/layertree.go @@ -35,6 +35,8 @@ import ( type layerTree struct { lock sync.RWMutex layers map[common.Hash]layer + + origin *diskLayer } // newLayerTree constructs the layerTree with the given head layer. @@ -52,6 +54,9 @@ func (tree *layerTree) reset(head layer) { var layers = make(map[common.Hash]layer) for head != nil { + if disk, ok := head.(*diskLayer); ok { + tree.origin = disk + } layers[head.rootHash()] = head head = head.parentLayer() } @@ -131,6 +136,7 @@ func (tree *layerTree) cap(root common.Hash, layers int) error { if err != nil { return err } + tree.origin = base.(*diskLayer) // Replace the entire layer tree with the flat base tree.layers = map[common.Hash]layer{base.rootHash(): base} return nil @@ -161,6 +167,7 @@ func (tree *layerTree) cap(root common.Hash, layers int) error { diff.lock.Unlock() return err } + tree.origin = base.(*diskLayer) tree.layers[base.rootHash()] = base diff.parent = base @@ -201,14 +208,10 @@ func (tree *layerTree) bottom() *diskLayer { if len(tree.layers) == 0 { return nil // Shouldn't happen, empty tree } - // pick a random one as the entry point - var current layer - for _, layer := range tree.layers { - current = layer - break + + if tree.origin == nil { + return nil } - for current.parentLayer() != nil { - current = current.parentLayer() - } - return current.(*diskLayer) + + return tree.origin }