mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
triedb/pathdb: polish code
This commit is contained in:
parent
cbea4a770a
commit
c6bfbdef7c
4 changed files with 52 additions and 32 deletions
|
|
@ -255,8 +255,9 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database {
|
||||||
// mandatory. This ensures that uncovered flat states are not accessed,
|
// mandatory. This ensures that uncovered flat states are not accessed,
|
||||||
// even if background generation is not allowed. If permitted, the generation
|
// even if background generation is not allowed. If permitted, the generation
|
||||||
// might be scheduled.
|
// might be scheduled.
|
||||||
db.setStateGenerator()
|
if err := db.setStateGenerator(); err != nil {
|
||||||
|
log.Crit("Failed to setup the generator", "err", err)
|
||||||
|
}
|
||||||
fields := config.fields()
|
fields := config.fields()
|
||||||
if db.isVerkle {
|
if db.isVerkle {
|
||||||
fields = append(fields, "verkle", true)
|
fields = append(fields, "verkle", true)
|
||||||
|
|
@ -316,10 +317,13 @@ func (db *Database) repairHistory() error {
|
||||||
|
|
||||||
// setStateGenerator loads the state generation progress marker and potentially
|
// setStateGenerator loads the state generation progress marker and potentially
|
||||||
// resume the state generation if it's permitted.
|
// resume the state generation if it's permitted.
|
||||||
func (db *Database) setStateGenerator() {
|
func (db *Database) setStateGenerator() error {
|
||||||
// Load the state snapshot generation progress marker to prevent access
|
// Load the state snapshot generation progress marker to prevent access
|
||||||
// to uncovered states.
|
// to uncovered states.
|
||||||
generator, root := loadGenerator(db.diskdb)
|
generator, root, err := loadGenerator(db.diskdb, db.hasher)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if generator == nil {
|
if generator == nil {
|
||||||
// Initialize an empty generator to rebuild the state snapshot from scratch
|
// Initialize an empty generator to rebuild the state snapshot from scratch
|
||||||
generator = &journalGenerator{
|
generator = &journalGenerator{
|
||||||
|
|
@ -330,7 +334,7 @@ func (db *Database) setStateGenerator() {
|
||||||
// The generator will be left as nil in disk layer for representing the whole
|
// The generator will be left as nil in disk layer for representing the whole
|
||||||
// state snapshot is available for accessing.
|
// state snapshot is available for accessing.
|
||||||
if generator.Done {
|
if generator.Done {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
var origin uint64
|
var origin uint64
|
||||||
if len(generator.Marker) >= 8 {
|
if len(generator.Marker) >= 8 {
|
||||||
|
|
@ -345,18 +349,24 @@ func (db *Database) setStateGenerator() {
|
||||||
}
|
}
|
||||||
dl := db.tree.bottom()
|
dl := db.tree.bottom()
|
||||||
|
|
||||||
|
// Disable the background snapshot building in these circumstances:
|
||||||
|
// - the database is opened in read only mode
|
||||||
|
// - the snapshot build is explicitly disabled
|
||||||
|
// - the database is opened in verkle tree mode
|
||||||
|
noBuild := db.readOnly || db.config.SnapshotNoBuild || db.isVerkle
|
||||||
|
|
||||||
// Construct the generator and link it to the disk layer, ensuring that the
|
// Construct the generator and link it to the disk layer, ensuring that the
|
||||||
// generation progress is resolved to prevent accessing uncovered states
|
// generation progress is resolved to prevent accessing uncovered states
|
||||||
// regardless of whether background state snapshot generation is allowed.
|
// regardless of whether background state snapshot generation is allowed.
|
||||||
noBuild := db.readOnly || db.config.SnapshotNoBuild || db.isVerkle
|
|
||||||
dl.setGenerator(newGenerator(db.diskdb, noBuild, generator.Marker, stats))
|
dl.setGenerator(newGenerator(db.diskdb, noBuild, generator.Marker, stats))
|
||||||
|
|
||||||
// Short circuit if the background generation is not permitted
|
// Short circuit if the background generation is not permitted
|
||||||
if noBuild || db.waitSync {
|
if noBuild || db.waitSync {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
stats.log("Starting snapshot generation", root, generator.Marker)
|
stats.log("Starting snapshot generation", root, generator.Marker)
|
||||||
dl.generator.run(root)
|
dl.generator.run(root)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update adds a new layer into the tree, if that can be linked to an existing
|
// Update adds a new layer into the tree, if that can be linked to an existing
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,19 @@ import (
|
||||||
|
|
||||||
// diskLayer is a low level persistent layer built on top of a key-value store.
|
// diskLayer is a low level persistent layer built on top of a key-value store.
|
||||||
type diskLayer struct {
|
type diskLayer struct {
|
||||||
root common.Hash // Immutable, root hash to which this layer was made for
|
root common.Hash // Immutable, root hash to which this layer was made for
|
||||||
id uint64 // Immutable, corresponding state id
|
id uint64 // Immutable, corresponding state id
|
||||||
db *Database // Path-based trie database
|
db *Database // Path-based trie database
|
||||||
|
|
||||||
|
// These two caches must be maintained separately, because the key
|
||||||
|
// for the root node of the storage trie (accountHash) is identical
|
||||||
|
// to the key for the account data.
|
||||||
nodes *fastcache.Cache // GC friendly memory cache of clean nodes
|
nodes *fastcache.Cache // GC friendly memory cache of clean nodes
|
||||||
states *fastcache.Cache // GC friendly memory cache of clean states
|
states *fastcache.Cache // GC friendly memory cache of clean states
|
||||||
buffer *buffer // Dirty buffer to aggregate writes of nodes and states
|
|
||||||
stale bool // Signals that the layer became stale (state progressed)
|
buffer *buffer // Dirty buffer to aggregate writes of nodes and states
|
||||||
lock sync.RWMutex // Lock used to protect stale flag and genMarker
|
stale bool // Signals that the layer became stale (state progressed)
|
||||||
|
lock sync.RWMutex // Lock used to protect stale flag and genMarker
|
||||||
|
|
||||||
// The generator is set if the state snapshot was not fully completed
|
// The generator is set if the state snapshot was not fully completed
|
||||||
generator *generator
|
generator *generator
|
||||||
|
|
|
||||||
|
|
@ -80,9 +80,10 @@ func writeStates(batch ethdb.Batch, genMarker []byte, accountData map[common.Has
|
||||||
slots int
|
slots int
|
||||||
)
|
)
|
||||||
for addrHash, blob := range accountData {
|
for addrHash, blob := range accountData {
|
||||||
// Skip any account not covered yet by the snapshot. The account
|
// Skip any account not yet covered by the snapshot. The account
|
||||||
// at generation position (addrHash == genMarker[:common.HashLength])
|
// at the generation marker position (addrHash == genMarker[:common.HashLength])
|
||||||
// should be updated.
|
// should still be updated, as it would be skipped in the next
|
||||||
|
// generation cycle.
|
||||||
if genMarker != nil && bytes.Compare(addrHash[:], genMarker) > 0 {
|
if genMarker != nil && bytes.Compare(addrHash[:], genMarker) > 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -107,9 +108,10 @@ func writeStates(batch ethdb.Batch, genMarker []byte, accountData map[common.Has
|
||||||
midAccount := genMarker != nil && bytes.Equal(addrHash[:], genMarker[:common.HashLength])
|
midAccount := genMarker != nil && bytes.Equal(addrHash[:], genMarker[:common.HashLength])
|
||||||
|
|
||||||
for storageHash, blob := range storages {
|
for storageHash, blob := range storages {
|
||||||
// Skip any slot not covered yet by the snapshot. The storage slot
|
// Skip any storage slot not yet covered by the snapshot. The storage slot
|
||||||
// at generation position (addrHash == genMarker[:common.HashLength]
|
// at the generation marker position (addrHash == genMarker[:common.HashLength]
|
||||||
// and storageHash == genMarker[common.HashLength:]) should be updated.
|
// and storageHash == genMarker[common.HashLength:]) should still be updated,
|
||||||
|
// as it would be skipped in the next generation cycle.
|
||||||
if midAccount && bytes.Compare(storageHash[:], genMarker[common.HashLength:]) > 0 {
|
if midAccount && bytes.Compare(storageHash[:], genMarker[common.HashLength:]) > 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
@ -106,36 +105,40 @@ type journalGenerator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadGenerator loads the state generation progress marker from the database.
|
// loadGenerator loads the state generation progress marker from the database.
|
||||||
func loadGenerator(db ethdb.KeyValueReader) (*journalGenerator, common.Hash) {
|
func loadGenerator(db ethdb.KeyValueReader, hash nodeHasher) (*journalGenerator, common.Hash, error) {
|
||||||
trieRoot := types.EmptyRootHash
|
trieRoot, err := hash(rawdb.ReadAccountTrieNode(db, nil))
|
||||||
if blob := rawdb.ReadAccountTrieNode(db, nil); len(blob) > 0 {
|
if err != nil {
|
||||||
trieRoot = crypto.Keccak256Hash(blob)
|
return nil, common.Hash{}, err
|
||||||
}
|
}
|
||||||
// State generation progress marker is lost, rebuild it
|
// State generation progress marker is lost, rebuild it
|
||||||
blob := rawdb.ReadSnapshotGenerator(db)
|
blob := rawdb.ReadSnapshotGenerator(db)
|
||||||
if len(blob) == 0 {
|
if len(blob) == 0 {
|
||||||
log.Info("State snapshot generator is not found")
|
log.Info("State snapshot generator is not found")
|
||||||
return nil, trieRoot
|
return nil, trieRoot, nil
|
||||||
}
|
}
|
||||||
// State generation progress marker is not compatible, rebuild it
|
// State generation progress marker is not compatible, rebuild it
|
||||||
var generator journalGenerator
|
var generator journalGenerator
|
||||||
if err := rlp.DecodeBytes(blob, &generator); err != nil {
|
if err := rlp.DecodeBytes(blob, &generator); err != nil {
|
||||||
log.Info("State snapshot generator is not compatible")
|
log.Info("State snapshot generator is not compatible")
|
||||||
return nil, trieRoot
|
return nil, trieRoot, nil
|
||||||
}
|
}
|
||||||
// The state snapshot is inconsistent with the trie data and needs to be rebuilt.
|
// The state snapshot is inconsistent with the trie data and must
|
||||||
// Note: The SnapshotRoot and SnapshotGenerator are always consistent with each
|
// be rebuilt.
|
||||||
// other, no matter in the legacy state snapshot or the path database.
|
//
|
||||||
|
// Note: The SnapshotRoot and SnapshotGenerator are always consistent
|
||||||
|
// with each other, both in the legacy state snapshot and the path database.
|
||||||
|
// Therefore, if the SnapshotRoot does not match the trie root,
|
||||||
|
// the entire generator is considered stale and must be discarded.
|
||||||
stateRoot := rawdb.ReadSnapshotRoot(db)
|
stateRoot := rawdb.ReadSnapshotRoot(db)
|
||||||
if trieRoot != stateRoot {
|
if trieRoot != stateRoot {
|
||||||
log.Info("State snapshot is not consistent with trie", "trie", trieRoot, "state", stateRoot)
|
log.Info("State snapshot is not consistent", "trie", trieRoot, "state", stateRoot)
|
||||||
return nil, trieRoot
|
return nil, trieRoot, nil
|
||||||
}
|
}
|
||||||
// Slice null-ness is lost after rlp decoding, reset it back to empty
|
// Slice null-ness is lost after rlp decoding, reset it back to empty
|
||||||
if !generator.Done && generator.Marker == nil {
|
if !generator.Done && generator.Marker == nil {
|
||||||
generator.Marker = []byte{}
|
generator.Marker = []byte{}
|
||||||
}
|
}
|
||||||
return &generator, trieRoot
|
return &generator, trieRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadLayers loads a pre-existing state layer backed by a key-value store.
|
// loadLayers loads a pre-existing state layer backed by a key-value store.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue