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"
)
// 0: initial version
// 1: destruct flag in diff layer is removed
const journalVersion uint64 = 1
const (
journalInitVersion uint64 = 0 // initial version
journalCurrentVersion uint64 = 1 // current version, with destruct flag (in diff layers) removed
)
// journalGenerator is a disk layer entry containing the generator progress marker.
type journalGenerator struct {
@ -50,6 +51,11 @@ type journalGenerator struct {
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.
type journalAccount struct {
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)
return errors.New("failed to resolve journal version")
}
if version != journalVersion {
log.Warn("Discarded the snapshot journal with wrong version", "required", journalVersion, "got", version)
if version != journalInitVersion && version != journalCurrentVersion {
log.Warn("Discarded journal with wrong version", "required", journalCurrentVersion, "got", version)
return errors.New("wrong journal version")
}
// 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)
}
// 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 {
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
journal := new(bytes.Buffer)
if err := rlp.Encode(journal, journalVersion); err != nil {
if err := rlp.Encode(journal, journalCurrentVersion); err != nil {
return common.Hash{}, err
}
diskroot := t.diskRoot()