Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

triedb/pathdb: support v0 journal format #368

Merged
merged 4 commits into from
Aug 22, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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