This commit is contained in:
rjl493456442 2024-11-25 20:45:15 +08:00 committed by GitHub
commit 4cb0261c93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 6 deletions

View File

@ -33,9 +33,10 @@ import (
"github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb"
) )
// 0: initial version const (
// 1: destruct flag in diff layer is removed journalInitVersion uint64 = 0 // initial version
const journalVersion uint64 = 1 journalCurrentVersion uint64 = 1 // current version, with destruct flag (in diff layers) removed
)
// journalGenerator is a disk layer entry containing the generator progress marker. // journalGenerator is a disk layer entry containing the generator progress marker.
type journalGenerator struct { type journalGenerator struct {
@ -50,6 +51,11 @@ type journalGenerator struct {
Storage uint64 Storage uint64
} }
// journalDestruct is an account deletion entry in a diffLayer's disk journal.
type journalDestruct struct {
Hash common.Hash
}
// journalAccount is an account entry in a diffLayer's disk journal. // journalAccount is an account entry in a diffLayer's disk journal.
type journalAccount struct { type journalAccount struct {
Hash common.Hash Hash common.Hash
@ -285,8 +291,8 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
log.Warn("Failed to resolve the journal version", "error", err) log.Warn("Failed to resolve the journal version", "error", err)
return errors.New("failed to resolve journal version") return errors.New("failed to resolve journal version")
} }
if version != journalVersion { if version != journalInitVersion && version != journalCurrentVersion {
log.Warn("Discarded the snapshot journal with wrong version", "required", journalVersion, "got", version) log.Warn("Discarded journal with wrong version", "required", journalCurrentVersion, "got", version)
return errors.New("wrong journal version") return errors.New("wrong journal version")
} }
// Secondly, resolve the disk layer root, ensure it's continuous // Secondly, resolve the disk layer root, ensure it's continuous
@ -316,6 +322,36 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
} }
return fmt.Errorf("load diff root: %v", err) return fmt.Errorf("load diff root: %v", err)
} }
// If a legacy journal is detected, decode the destruct set from the stream.
// The destruct set has been deprecated. If the journal contains non-empty
// destruct set, then it is deemed incompatible.
//
// Since self-destruction has been deprecated following the cancun fork,
// the destruct set is expected to be nil for layers above the fork block.
// However, an exception occurs during contract deployment: pre-funded accounts
// may self-destruct, causing accounts with non-zero balances to be removed
// from the state. For example,
// https://etherscan.io/tx/0xa087333d83f0cd63b96bdafb686462e1622ce25f40bd499e03efb1051f31fe49).
//
// For nodes with a fully synced state, the legacy journal is likely compatible
// with the updated definition, eliminating the need for regeneration. Unfortunately,
// nodes performing a full sync of historical chain segments or encountering
// pre-funded account deletions may face incompatibilities, leading to automatic
// snapshot regeneration.
//
// This approach minimizes snapshot regeneration for Geth nodes upgrading from a
// legacy version that are already synced. The workaround can be safely removed
// after the next hard fork.
if version == journalInitVersion {
var destructs []journalDestruct
if err := r.Decode(&destructs); err != nil {
return fmt.Errorf("load diff destructs: %v", err)
}
if len(destructs) > 0 {
log.Warn("Incompatible legacy journal detected", "version", journalInitVersion)
return fmt.Errorf("incompatible legacy journal detected")
}
}
if err := r.Decode(&accounts); err != nil { if err := r.Decode(&accounts); err != nil {
return fmt.Errorf("load diff accounts: %v", err) return fmt.Errorf("load diff accounts: %v", err)
} }

View File

@ -641,7 +641,7 @@ func (t *Tree) Journal(root common.Hash) (common.Hash, error) {
// Firstly write out the metadata of journal // Firstly write out the metadata of journal
journal := new(bytes.Buffer) journal := new(bytes.Buffer)
if err := rlp.Encode(journal, journalVersion); err != nil { if err := rlp.Encode(journal, journalCurrentVersion); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
diskroot := t.diskRoot() diskroot := t.diskRoot()