Merge pull request #1116 from maticnetwork/arpit/v1.2.2-beta-candidate

Geth Merge v1.12.2 Hotfixes
This commit is contained in:
Arpit Temani 2024-01-11 10:56:45 +05:30 committed by GitHub
commit 70bebc9335
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 13 additions and 100 deletions

View file

@ -57,7 +57,6 @@ const (
// Config includes all the configurations for pruning. // Config includes all the configurations for pruning.
type Config struct { type Config struct {
Datadir string // The directory of the state database Datadir string // The directory of the state database
Cachedir string // The directory of state clean cache
BloomSize uint64 // The Megabytes of memory allocated to bloom-filter BloomSize uint64 // The Megabytes of memory allocated to bloom-filter
} }
@ -86,14 +85,12 @@ func NewPruner(db ethdb.Database, config Config) (*Pruner, error) {
if headBlock == nil { if headBlock == nil {
return nil, errors.New("failed to load head block") return nil, errors.New("failed to load head block")
} }
snapconfig := snapshot.Config{ snapconfig := snapshot.Config{
CacheSize: 256, CacheSize: 256,
Recovery: false, Recovery: false,
NoBuild: true, NoBuild: true,
AsyncBuild: false, AsyncBuild: false,
} }
snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root()) snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root())
if err != nil { if err != nil {
return nil, err // The relevant snapshot(s) might not exist return nil, err // The relevant snapshot(s) might not exist
@ -103,12 +100,10 @@ func NewPruner(db ethdb.Database, config Config) (*Pruner, error) {
log.Warn("Sanitizing bloomfilter size", "provided(MB)", config.BloomSize, "updated(MB)", 256) log.Warn("Sanitizing bloomfilter size", "provided(MB)", config.BloomSize, "updated(MB)", 256)
config.BloomSize = 256 config.BloomSize = 256
} }
stateBloom, err := newStateBloomWithSize(config.BloomSize) stateBloom, err := newStateBloomWithSize(config.BloomSize)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Pruner{ return &Pruner{
config: config, config: config,
chainHeader: headBlock.Header(), chainHeader: headBlock.Header(),
@ -134,7 +129,6 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta
batch = maindb.NewBatch() batch = maindb.NewBatch()
iter = maindb.NewIterator(nil, nil) iter = maindb.NewIterator(nil, nil)
) )
for iter.Next() { for iter.Next() {
key := iter.Key() key := iter.Key()
@ -148,7 +142,6 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta
if isCode { if isCode {
checkKey = codeKey checkKey = codeKey
} }
if _, exist := middleStateRoots[common.BytesToHash(checkKey)]; exist { if _, exist := middleStateRoots[common.BytesToHash(checkKey)]; exist {
log.Debug("Forcibly delete the middle state roots", "hash", common.BytesToHash(checkKey)) log.Debug("Forcibly delete the middle state roots", "hash", common.BytesToHash(checkKey))
} else { } else {
@ -156,26 +149,21 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta
continue continue
} }
} }
count += 1 count += 1
size += common.StorageSize(len(key) + len(iter.Value())) size += common.StorageSize(len(key) + len(iter.Value()))
batch.Delete(key) batch.Delete(key)
var eta time.Duration // Realistically will never remain uninited var eta time.Duration // Realistically will never remain uninited
if done := binary.BigEndian.Uint64(key[:8]); done > 0 { if done := binary.BigEndian.Uint64(key[:8]); done > 0 {
var ( var (
left = math.MaxUint64 - binary.BigEndian.Uint64(key[:8]) left = math.MaxUint64 - binary.BigEndian.Uint64(key[:8])
speed = done/uint64(time.Since(pstart)/time.Millisecond+1) + 1 // +1s to avoid division by zero speed = done/uint64(time.Since(pstart)/time.Millisecond+1) + 1 // +1s to avoid division by zero
) )
eta = time.Duration(left/speed) * time.Millisecond eta = time.Duration(left/speed) * time.Millisecond
} }
if time.Since(logged) > 8*time.Second { if time.Since(logged) > 8*time.Second {
log.Info("Pruning state data", "nodes", count, "size", size, log.Info("Pruning state data", "nodes", count, "size", size,
"elapsed", common.PrettyDuration(time.Since(pstart)), "eta", common.PrettyDuration(eta)) "elapsed", common.PrettyDuration(time.Since(pstart)), "eta", common.PrettyDuration(eta))
logged = time.Now() logged = time.Now()
} }
// Recreate the iterator after every batch commit in order // Recreate the iterator after every batch commit in order
@ -189,12 +177,10 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta
} }
} }
} }
if batch.ValueSize() > 0 { if batch.ValueSize() > 0 {
batch.Write() batch.Write()
batch.Reset() batch.Reset()
} }
iter.Release() iter.Release()
log.Info("Pruned state data", "nodes", count, "size", size, "elapsed", common.PrettyDuration(time.Since(pstart))) log.Info("Pruned state data", "nodes", count, "size", size, "elapsed", common.PrettyDuration(time.Since(pstart)))
@ -221,19 +207,15 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta
// Note for small pruning, the compaction is skipped. // Note for small pruning, the compaction is skipped.
if count >= rangeCompactionThreshold { if count >= rangeCompactionThreshold {
cstart := time.Now() cstart := time.Now()
for b := 0x00; b <= 0xf0; b += 0x10 { for b := 0x00; b <= 0xf0; b += 0x10 {
var ( var (
start = []byte{byte(b)} start = []byte{byte(b)}
end = []byte{byte(b + 0x10)} end = []byte{byte(b + 0x10)}
) )
if b == 0xf0 { if b == 0xf0 {
end = nil end = nil
} }
log.Info("Compacting database", "range", fmt.Sprintf("%#x-%#x", start, end), "elapsed", common.PrettyDuration(time.Since(cstart))) log.Info("Compacting database", "range", fmt.Sprintf("%#x-%#x", start, end), "elapsed", common.PrettyDuration(time.Since(cstart)))
if err := maindb.Compact(start, end); err != nil { if err := maindb.Compact(start, end); err != nil {
log.Error("Database compaction failed", "error", err) log.Error("Database compaction failed", "error", err)
return err return err
@ -241,16 +223,13 @@ func prune(snaptree *snapshot.Tree, root common.Hash, maindb ethdb.Database, sta
} }
log.Info("Database compaction finished", "elapsed", common.PrettyDuration(time.Since(cstart))) log.Info("Database compaction finished", "elapsed", common.PrettyDuration(time.Since(cstart)))
} }
log.Info("State pruning successful", "pruned", size, "elapsed", common.PrettyDuration(time.Since(start))) log.Info("State pruning successful", "pruned", size, "elapsed", common.PrettyDuration(time.Since(start)))
return nil return nil
} }
// Prune deletes all historical state nodes except the nodes belong to the // Prune deletes all historical state nodes except the nodes belong to the
// specified state version. If user doesn't specify the state version, use // specified state version. If user doesn't specify the state version, use
// the bottom-most snapshot diff layer as the target. // the bottom-most snapshot diff layer as the target.
// nolint:nestif
func (p *Pruner) Prune(root common.Hash) error { func (p *Pruner) Prune(root common.Hash) error {
// If the state bloom filter is already committed previously, // If the state bloom filter is already committed previously,
// reuse it for pruning instead of generating a new one. It's // reuse it for pruning instead of generating a new one. It's
@ -260,9 +239,8 @@ func (p *Pruner) Prune(root common.Hash) error {
if err != nil { if err != nil {
return err return err
} }
if stateBloomRoot != (common.Hash{}) { if stateBloomRoot != (common.Hash{}) {
return RecoverPruning(p.config.Datadir, p.db, p.config.Cachedir) return RecoverPruning(p.config.Datadir, p.db)
} }
// If the target state root is not specified, use the HEAD-127 as the // If the target state root is not specified, use the HEAD-127 as the
// target. The reason for picking it is: // target. The reason for picking it is:
@ -287,8 +265,8 @@ func (p *Pruner) Prune(root common.Hash) error {
// is the presence of root can indicate the presence of the // is the presence of root can indicate the presence of the
// entire trie. // entire trie.
if !rawdb.HasLegacyTrieNode(p.db, root) { if !rawdb.HasLegacyTrieNode(p.db, root) {
// The special case is for clique based networks(goerli and // The special case is for clique based networks(goerli
// some other private networks), it's possible that two // and some other private networks), it's possible that two
// consecutive blocks will have same root. In this case snapshot // consecutive blocks will have same root. In this case snapshot
// difflayer won't be created. So HEAD-127 may not paired with // difflayer won't be created. So HEAD-127 may not paired with
// head-127 layer. Instead the paired layer is higher than the // head-127 layer. Instead the paired layer is higher than the
@ -299,23 +277,18 @@ func (p *Pruner) Prune(root common.Hash) error {
// state available, but we don't want to use the topmost state // state available, but we don't want to use the topmost state
// as the pruning target. // as the pruning target.
var found bool var found bool
for i := len(layers) - 2; i >= 2; i-- { for i := len(layers) - 2; i >= 2; i-- {
if rawdb.HasLegacyTrieNode(p.db, layers[i].Root()) { if rawdb.HasLegacyTrieNode(p.db, layers[i].Root()) {
root = layers[i].Root() root = layers[i].Root()
found = true found = true
log.Info("Selecting middle-layer as the pruning target", "root", root, "depth", i) log.Info("Selecting middle-layer as the pruning target", "root", root, "depth", i)
break break
} }
} }
if !found { if !found {
if len(layers) > 0 { if len(layers) > 0 {
return errors.New("no snapshot paired state") return errors.New("no snapshot paired state")
} }
return fmt.Errorf("associated state[%x] is not present", root) return fmt.Errorf("associated state[%x] is not present", root)
} }
} else { } else {
@ -325,27 +298,18 @@ func (p *Pruner) Prune(root common.Hash) error {
log.Info("Selecting user-specified state as the pruning target", "root", root) log.Info("Selecting user-specified state as the pruning target", "root", root)
} }
} }
// Before start the pruning, delete the clean trie cache first.
// It's necessary otherwise in the next restart we will hit the
// deleted state root in the "clean cache" so that the incomplete
// state is picked for usage.
deleteCleanTrieCache(p.config.Cachedir)
// All the state roots of the middle layer should be forcibly pruned, // All the state roots of the middle layer should be forcibly pruned,
// otherwise the dangling state will be left. // otherwise the dangling state will be left.
middleRoots := make(map[common.Hash]struct{}) middleRoots := make(map[common.Hash]struct{})
for _, layer := range layers { for _, layer := range layers {
if layer.Root() == root { if layer.Root() == root {
break break
} }
middleRoots[layer.Root()] = struct{}{} middleRoots[layer.Root()] = struct{}{}
} }
// Traverse the target state, re-construct the whole state trie and // Traverse the target state, re-construct the whole state trie and
// commit to the given bloom filter. // commit to the given bloom filter.
start := time.Now() start := time.Now()
if err := snapshot.GenerateTrie(p.snaptree, root, p.db, p.stateBloom); err != nil { if err := snapshot.GenerateTrie(p.snaptree, root, p.db, p.stateBloom); err != nil {
return err return err
} }
@ -354,17 +318,13 @@ func (p *Pruner) Prune(root common.Hash) error {
if err := extractGenesis(p.db, p.stateBloom); err != nil { if err := extractGenesis(p.db, p.stateBloom); err != nil {
return err return err
} }
filterName := bloomFilterName(p.config.Datadir, root) filterName := bloomFilterName(p.config.Datadir, root)
log.Info("Writing state bloom to disk", "name", filterName) log.Info("Writing state bloom to disk", "name", filterName)
if err := p.stateBloom.Commit(filterName, filterName+stateBloomFileTempSuffix); err != nil { if err := p.stateBloom.Commit(filterName, filterName+stateBloomFileTempSuffix); err != nil {
return err return err
} }
log.Info("State bloom filter committed", "name", filterName) log.Info("State bloom filter committed", "name", filterName)
return prune(p.snaptree, root, p.db, p.stateBloom, filterName, middleRoots, start) return prune(p.snaptree, root, p.db, p.stateBloom, filterName, middleRoots, start)
} }
@ -375,16 +335,14 @@ func (p *Pruner) Prune(root common.Hash) error {
// pruning can be resumed. What's more if the bloom filter is constructed, the // pruning can be resumed. What's more if the bloom filter is constructed, the
// pruning **has to be resumed**. Otherwise a lot of dangling nodes may be left // pruning **has to be resumed**. Otherwise a lot of dangling nodes may be left
// in the disk. // in the disk.
func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) error { func RecoverPruning(datadir string, db ethdb.Database) error {
stateBloomPath, stateBloomRoot, err := findBloomFilter(datadir) stateBloomPath, stateBloomRoot, err := findBloomFilter(datadir)
if err != nil { if err != nil {
return err return err
} }
if stateBloomPath == "" { if stateBloomPath == "" {
return nil // nothing to recover return nil // nothing to recover
} }
headBlock := rawdb.ReadHeadBlock(db) headBlock := rawdb.ReadHeadBlock(db)
if headBlock == nil { if headBlock == nil {
return errors.New("failed to load head block") return errors.New("failed to load head block")
@ -403,25 +361,16 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err
NoBuild: true, NoBuild: true,
AsyncBuild: false, AsyncBuild: false,
} }
snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root()) snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root())
if err != nil { if err != nil {
return err // The relevant snapshot(s) might not exist return err // The relevant snapshot(s) might not exist
} }
stateBloom, err := NewStateBloomFromDisk(stateBloomPath) stateBloom, err := NewStateBloomFromDisk(stateBloomPath)
if err != nil { if err != nil {
return err return err
} }
log.Info("Loaded state bloom filter", "path", stateBloomPath) log.Info("Loaded state bloom filter", "path", stateBloomPath)
// Before start the pruning, delete the clean trie cache first.
// It's necessary otherwise in the next restart we will hit the
// deleted state root in the "clean cache" so that the incomplete
// state is picked for usage.
deleteCleanTrieCache(trieCachePath)
// All the state roots of the middle layers should be forcibly pruned, // All the state roots of the middle layers should be forcibly pruned,
// otherwise the dangling state will be left. // otherwise the dangling state will be left.
var ( var (
@ -429,21 +378,17 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err
layers = snaptree.Snapshots(headBlock.Root(), 128, true) layers = snaptree.Snapshots(headBlock.Root(), 128, true)
middleRoots = make(map[common.Hash]struct{}) middleRoots = make(map[common.Hash]struct{})
) )
for _, layer := range layers { for _, layer := range layers {
if layer.Root() == stateBloomRoot { if layer.Root() == stateBloomRoot {
found = true found = true
break break
} }
middleRoots[layer.Root()] = struct{}{} middleRoots[layer.Root()] = struct{}{}
} }
if !found { if !found {
log.Error("Pruning target state is not existent") log.Error("Pruning target state is not existent")
return errors.New("non-existent target state") return errors.New("non-existent target state")
} }
return prune(snaptree, stateBloomRoot, db, stateBloom, stateBloomPath, middleRoots, time.Now()) return prune(snaptree, stateBloomRoot, db, stateBloom, stateBloomPath, middleRoots, time.Now())
} }
@ -454,17 +399,14 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
if genesisHash == (common.Hash{}) { if genesisHash == (common.Hash{}) {
return errors.New("missing genesis hash") return errors.New("missing genesis hash")
} }
genesis := rawdb.ReadBlock(db, genesisHash, 0) genesis := rawdb.ReadBlock(db, genesisHash, 0)
if genesis == nil { if genesis == nil {
return errors.New("missing genesis block") return errors.New("missing genesis block")
} }
t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db)) t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db))
if err != nil { if err != nil {
return err return err
} }
accIter, err := t.NodeIterator(nil) accIter, err := t.NodeIterator(nil)
if err != nil { if err != nil {
return err return err
@ -483,15 +425,12 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil { if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil {
return err return err
} }
if acc.Root != types.EmptyRootHash { if acc.Root != types.EmptyRootHash {
id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root) id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root)
storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db)) storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db))
if err != nil { if err != nil {
return err return err
} }
storageIter, err := storageTrie.NodeIterator(nil) storageIter, err := storageTrie.NodeIterator(nil)
if err != nil { if err != nil {
return err return err
@ -502,18 +441,15 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
stateBloom.Put(hash.Bytes(), nil) stateBloom.Put(hash.Bytes(), nil)
} }
} }
if storageIter.Error() != nil { if storageIter.Error() != nil {
return storageIter.Error() return storageIter.Error()
} }
} }
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) { if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
stateBloom.Put(acc.CodeHash, nil) stateBloom.Put(acc.CodeHash, nil)
} }
} }
} }
return accIter.Error() return accIter.Error()
} }
@ -526,7 +462,6 @@ func isBloomFilter(filename string) (bool, common.Hash) {
if strings.HasPrefix(filename, stateBloomFilePrefix) && strings.HasSuffix(filename, stateBloomFileSuffix) { if strings.HasPrefix(filename, stateBloomFilePrefix) && strings.HasSuffix(filename, stateBloomFileSuffix) {
return true, common.HexToHash(filename[len(stateBloomFilePrefix)+1 : len(filename)-len(stateBloomFileSuffix)-1]) return true, common.HexToHash(filename[len(stateBloomFilePrefix)+1 : len(filename)-len(stateBloomFileSuffix)-1])
} }
return false, common.Hash{} return false, common.Hash{}
} }
@ -535,7 +470,6 @@ func findBloomFilter(datadir string) (string, common.Hash, error) {
stateBloomPath string stateBloomPath string
stateBloomRoot common.Hash stateBloomRoot common.Hash
) )
if err := filepath.Walk(datadir, func(path string, info os.FileInfo, err error) error { if err := filepath.Walk(datadir, func(path string, info os.FileInfo, err error) error {
if info != nil && !info.IsDir() { if info != nil && !info.IsDir() {
ok, root := isBloomFilter(path) ok, root := isBloomFilter(path)
@ -548,27 +482,5 @@ func findBloomFilter(datadir string) (string, common.Hash, error) {
}); err != nil { }); err != nil {
return "", common.Hash{}, err return "", common.Hash{}, err
} }
return stateBloomPath, stateBloomRoot, nil return stateBloomPath, stateBloomRoot, nil
} }
const warningLog = `
WARNING!
The clean trie cache is not found. Please delete it by yourself after the
pruning. Remember don't start the Geth without deleting the clean trie cache
otherwise the entire database may be damaged!
Check the command description "geth snapshot prune-state --help" for more details.
`
func deleteCleanTrieCache(path string) {
if !common.FileExist(path) {
log.Warn(warningLog)
return
}
os.RemoveAll(path)
log.Info("Deleted trie clean cache", "path", path)
}

View file

@ -143,7 +143,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, ""); err != nil { if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb); err != nil {
log.Error("Failed to recover state", "error", err) log.Error("Failed to recover state", "error", err)
} }
@ -229,6 +229,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
TrieTimeLimit: config.TrieTimeout, TrieTimeLimit: config.TrieTimeout,
SnapshotLimit: config.SnapshotCache, SnapshotLimit: config.SnapshotCache,
Preimages: config.Preimages, Preimages: config.Preimages,
TriesInMemory: config.TriesInMemory,
} }
) )

View file

@ -1,5 +1,5 @@
Source: bor Source: bor
Version: 1.2.1 Version: 1.2.2
Section: develop Section: develop
Priority: standard Priority: standard
Maintainer: Polygon <release-team@polygon.technology> Maintainer: Polygon <release-team@polygon.technology>

View file

@ -1,5 +1,5 @@
Source: bor Source: bor
Version: 1.2.1 Version: 1.2.2
Section: develop Section: develop
Priority: standard Priority: standard
Maintainer: Polygon <release-team@polygon.technology> Maintainer: Polygon <release-team@polygon.technology>

View file

@ -1,5 +1,5 @@
Source: bor-profile Source: bor-profile
Version: 1.2.1 Version: 1.2.2
Section: develop Section: develop
Priority: standard Priority: standard
Maintainer: Polygon <release-team@polygon.technology> Maintainer: Polygon <release-team@polygon.technology>

View file

@ -1,5 +1,5 @@
Source: bor-profile Source: bor-profile
Version: 1.2.1 Version: 1.2.2
Section: develop Section: develop
Priority: standard Priority: standard
Maintainer: Polygon <release-team@polygon.technology> Maintainer: Polygon <release-team@polygon.technology>

View file

@ -1,5 +1,5 @@
Source: bor-profile Source: bor-profile
Version: 1.2.1 Version: 1.2.2
Section: develop Section: develop
Priority: standard Priority: standard
Maintainer: Polygon <release-team@polygon.technology> Maintainer: Polygon <release-team@polygon.technology>

View file

@ -1,5 +1,5 @@
Source: bor-profile Source: bor-profile
Version: 1.2.1 Version: 1.2.2
Section: develop Section: develop
Priority: standard Priority: standard
Maintainer: Polygon <release-team@polygon.technology> Maintainer: Polygon <release-team@polygon.technology>

View file

@ -23,7 +23,7 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 2 // Minor version component of the current release VersionMinor = 2 // Minor version component of the current release
VersionPatch = 1 // Patch version component of the current release VersionPatch = 2 // Patch version component of the current release
VersionMeta = "" // Version metadata to append to the version string VersionMeta = "" // Version metadata to append to the version string
) )