Skip to content

Commit

Permalink
triedb/pathdb: support v0 journal format (#368)
Browse files Browse the repository at this point in the history
* triedb/pathdb: support v0 journal format

* Update triedb/pathdb/journal.go - use %w in Errorf

* triedb/pathdb: add warn log when loading legacy v0 journal

* triedb/pathdb: flatten journal.go code

Co-authored-by: Sebastian Stammler <[email protected]>

---------

Co-authored-by: Sebastian Stammler <[email protected]>
  • Loading branch information
protolambda and sebastianst authored Aug 22, 2024
1 parent e8b286a commit 5c2e758
Showing 1 changed file with 36 additions and 7 deletions.
43 changes: 36 additions & 7 deletions triedb/pathdb/journal.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ var (
//
// - Version 0: initial version
// - Version 1: storage.Incomplete field is removed
const journalVersion uint64 = 1
const (
journalVersion uint64 = 1
journalVersionV0 uint64 = 0
)

// journalNode represents a trie node persisted in the journal.
type journalNode struct {
Expand Down Expand Up @@ -75,6 +78,14 @@ type journalStorage struct {
Slots [][]byte
}

// journalStorageV0 represents a journal version 0 storage update.
type journalStorageV0 struct {
Incomplete bool // In V0, to handle self-destructs, the stateDB would abort a storage-diff if it got too large.
Account common.Address
Hashes []common.Hash
Slots [][]byte
}

// loadJournal tries to parse the layer journal from the disk.
func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) {
journal := rawdb.ReadTrieJournal(db.diskdb)
Expand All @@ -88,7 +99,7 @@ func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) {
if err != nil {
return nil, errMissVersion
}
if version != journalVersion {
if version != journalVersionV0 && version != journalVersion {
return nil, fmt.Errorf("%w want %d got %d", errUnexpectedVersion, journalVersion, version)
}
// Secondly, resolve the disk layer root, ensure it's continuous
Expand All @@ -109,7 +120,7 @@ func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) {
return nil, err
}
// Load all the diff layers from the journal
head, err := db.loadDiffLayer(base, r)
head, err := db.loadDiffLayer(base, r, version)
if err != nil {
return nil, err
}
Expand All @@ -120,7 +131,7 @@ func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) {
// loadLayers loads a pre-existing state layer backed by a key-value store.
func (db *Database) loadLayers() layer {
// Retrieve the root node of persistent state.
var root = types.EmptyRootHash
root := types.EmptyRootHash
if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 {
root = crypto.Keccak256Hash(blob)
}
Expand Down Expand Up @@ -182,7 +193,7 @@ func (db *Database) loadDiskLayer(r *rlp.Stream) (layer, error) {

// loadDiffLayer reads the next sections of a layer journal, reconstructing a new
// diff and verifying that it can be linked to the requested parent.
func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) {
func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream, layerJournalVersion uint64) (layer, error) {
// Read the next diff journal entry
var root common.Hash
if err := r.Decode(&root); err != nil {
Expand Down Expand Up @@ -226,7 +237,25 @@ func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) {
for i, addr := range jaccounts.Addresses {
accounts[addr] = jaccounts.Accounts[i]
}
if err := r.Decode(&jstorages); err != nil {
if layerJournalVersion == journalVersionV0 {
log.Warn("loading legacy v0 journal")
var jstoragesV0 []journalStorageV0
if err := r.Decode(&jstoragesV0); err != nil {
return nil, fmt.Errorf("load diff storages: %w", err)
}
jstorages = make([]journalStorage, 0, len(jstoragesV0))
for _, st := range jstoragesV0 {
if st.Incomplete { // Storage diff entries that are complete are compatible with the journal v1 type.
log.Warn("legacy v0 diff layer shows incomplete storage-diff write, cannot recover this, have to drop journal")
return nil, fmt.Errorf("legacy v0 diff layer with incomplete storage-diff: %w", errUnexpectedVersion)
}
jstorages = append(jstorages, journalStorage{
Account: st.Account,
Hashes: st.Hashes,
Slots: st.Slots,
})
}
} else if err := r.Decode(&jstorages); err != nil {
return nil, fmt.Errorf("load diff storages: %v", err)
}
for _, entry := range jstorages {
Expand All @@ -240,7 +269,7 @@ func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) {
}
storages[entry.Account] = set
}
return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, nodes, triestate.New(accounts, storages)), r)
return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, nodes, triestate.New(accounts, storages)), r, layerJournalVersion)
}

// journal implements the layer interface, marshaling the un-flushed trie nodes
Expand Down

0 comments on commit 5c2e758

Please sign in to comment.