github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/triedb/pathdb/journal.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package pathdb
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  	"fmt"
    23  	"io"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/core/rawdb"
    28  	"github.com/ethereum/go-ethereum/core/types"
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  	"github.com/ethereum/go-ethereum/log"
    31  	"github.com/ethereum/go-ethereum/rlp"
    32  	"github.com/ethereum/go-ethereum/trie/trienode"
    33  	"github.com/ethereum/go-ethereum/trie/triestate"
    34  )
    35  
    36  var (
    37  	errMissJournal       = errors.New("journal not found")
    38  	errMissVersion       = errors.New("version not found")
    39  	errUnexpectedVersion = errors.New("unexpected journal version")
    40  	errMissDiskRoot      = errors.New("disk layer root not found")
    41  	errUnmatchedJournal  = errors.New("unmatched journal")
    42  )
    43  
    44  // journalVersion ensures that an incompatible journal is detected and discarded.
    45  //
    46  // Changelog:
    47  //
    48  // - Version 0: initial version
    49  // - Version 1: storage.Incomplete field is removed
    50  const journalVersion uint64 = 1
    51  
    52  // journalNode represents a trie node persisted in the journal.
    53  type journalNode struct {
    54  	Path []byte // Path of the node in the trie
    55  	Blob []byte // RLP-encoded trie node blob, nil means the node is deleted
    56  }
    57  
    58  // journalNodes represents a list trie nodes belong to a single account
    59  // or the main account trie.
    60  type journalNodes struct {
    61  	Owner common.Hash
    62  	Nodes []journalNode
    63  }
    64  
    65  // journalAccounts represents a list accounts belong to the layer.
    66  type journalAccounts struct {
    67  	Addresses []common.Address
    68  	Accounts  [][]byte
    69  }
    70  
    71  // journalStorage represents a list of storage slots belong to an account.
    72  type journalStorage struct {
    73  	Account common.Address
    74  	Hashes  []common.Hash
    75  	Slots   [][]byte
    76  }
    77  
    78  // loadJournal tries to parse the layer journal from the disk.
    79  func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) {
    80  	journal := rawdb.ReadTrieJournal(db.diskdb)
    81  	if len(journal) == 0 {
    82  		return nil, errMissJournal
    83  	}
    84  	r := rlp.NewStream(bytes.NewReader(journal), 0)
    85  
    86  	// Firstly, resolve the first element as the journal version
    87  	version, err := r.Uint64()
    88  	if err != nil {
    89  		return nil, errMissVersion
    90  	}
    91  	if version != journalVersion {
    92  		return nil, fmt.Errorf("%w want %d got %d", errUnexpectedVersion, journalVersion, version)
    93  	}
    94  	// Secondly, resolve the disk layer root, ensure it's continuous
    95  	// with disk layer. Note now we can ensure it's the layer journal
    96  	// correct version, so we expect everything can be resolved properly.
    97  	var root common.Hash
    98  	if err := r.Decode(&root); err != nil {
    99  		return nil, errMissDiskRoot
   100  	}
   101  	// The journal is not matched with persistent state, discard them.
   102  	// It can happen that geth crashes without persisting the journal.
   103  	if !bytes.Equal(root.Bytes(), diskRoot.Bytes()) {
   104  		return nil, fmt.Errorf("%w want %x got %x", errUnmatchedJournal, root, diskRoot)
   105  	}
   106  	// Load the disk layer from the journal
   107  	base, err := db.loadDiskLayer(r)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	// Load all the diff layers from the journal
   112  	head, err := db.loadDiffLayer(base, r)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	log.Debug("Loaded layer journal", "diskroot", diskRoot, "diffhead", head.rootHash())
   117  	return head, nil
   118  }
   119  
   120  // loadLayers loads a pre-existing state layer backed by a key-value store.
   121  func (db *Database) loadLayers() layer {
   122  	// Retrieve the root node of persistent state.
   123  	var root = types.EmptyRootHash
   124  	if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 {
   125  		root = crypto.Keccak256Hash(blob)
   126  	}
   127  	// Load the layers by resolving the journal
   128  	head, err := db.loadJournal(root)
   129  	if err == nil {
   130  		return head
   131  	}
   132  	// journal is not matched(or missing) with the persistent state, discard
   133  	// it. Display log for discarding journal, but try to avoid showing
   134  	// useless information when the db is created from scratch.
   135  	if !(root == types.EmptyRootHash && errors.Is(err, errMissJournal)) {
   136  		log.Info("Failed to load journal, discard it", "err", err)
   137  	}
   138  	// Return single layer with persistent state.
   139  	return newDiskLayer(root, rawdb.ReadPersistentStateID(db.diskdb), db, nil, newNodeBuffer(db.bufferSize, nil, 0))
   140  }
   141  
   142  // loadDiskLayer reads the binary blob from the layer journal, reconstructing
   143  // a new disk layer on it.
   144  func (db *Database) loadDiskLayer(r *rlp.Stream) (layer, error) {
   145  	// Resolve disk layer root
   146  	var root common.Hash
   147  	if err := r.Decode(&root); err != nil {
   148  		return nil, fmt.Errorf("load disk root: %v", err)
   149  	}
   150  	// Resolve the state id of disk layer, it can be different
   151  	// with the persistent id tracked in disk, the id distance
   152  	// is the number of transitions aggregated in disk layer.
   153  	var id uint64
   154  	if err := r.Decode(&id); err != nil {
   155  		return nil, fmt.Errorf("load state id: %v", err)
   156  	}
   157  	stored := rawdb.ReadPersistentStateID(db.diskdb)
   158  	if stored > id {
   159  		return nil, fmt.Errorf("invalid state id: stored %d resolved %d", stored, id)
   160  	}
   161  	// Resolve nodes cached in node buffer
   162  	var encoded []journalNodes
   163  	if err := r.Decode(&encoded); err != nil {
   164  		return nil, fmt.Errorf("load disk nodes: %v", err)
   165  	}
   166  	nodes := make(map[common.Hash]map[string]*trienode.Node)
   167  	for _, entry := range encoded {
   168  		subset := make(map[string]*trienode.Node)
   169  		for _, n := range entry.Nodes {
   170  			if len(n.Blob) > 0 {
   171  				subset[string(n.Path)] = trienode.New(crypto.Keccak256Hash(n.Blob), n.Blob)
   172  			} else {
   173  				subset[string(n.Path)] = trienode.NewDeleted()
   174  			}
   175  		}
   176  		nodes[entry.Owner] = subset
   177  	}
   178  	// Calculate the internal state transitions by id difference.
   179  	base := newDiskLayer(root, id, db, nil, newNodeBuffer(db.bufferSize, nodes, id-stored))
   180  	return base, nil
   181  }
   182  
   183  // loadDiffLayer reads the next sections of a layer journal, reconstructing a new
   184  // diff and verifying that it can be linked to the requested parent.
   185  func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) {
   186  	// Read the next diff journal entry
   187  	var root common.Hash
   188  	if err := r.Decode(&root); err != nil {
   189  		// The first read may fail with EOF, marking the end of the journal
   190  		if err == io.EOF {
   191  			return parent, nil
   192  		}
   193  		return nil, fmt.Errorf("load diff root: %v", err)
   194  	}
   195  	var block uint64
   196  	if err := r.Decode(&block); err != nil {
   197  		return nil, fmt.Errorf("load block number: %v", err)
   198  	}
   199  	// Read in-memory trie nodes from journal
   200  	var encoded []journalNodes
   201  	if err := r.Decode(&encoded); err != nil {
   202  		return nil, fmt.Errorf("load diff nodes: %v", err)
   203  	}
   204  	nodes := make(map[common.Hash]map[string]*trienode.Node)
   205  	for _, entry := range encoded {
   206  		subset := make(map[string]*trienode.Node)
   207  		for _, n := range entry.Nodes {
   208  			if len(n.Blob) > 0 {
   209  				subset[string(n.Path)] = trienode.New(crypto.Keccak256Hash(n.Blob), n.Blob)
   210  			} else {
   211  				subset[string(n.Path)] = trienode.NewDeleted()
   212  			}
   213  		}
   214  		nodes[entry.Owner] = subset
   215  	}
   216  	// Read state changes from journal
   217  	var (
   218  		jaccounts journalAccounts
   219  		jstorages []journalStorage
   220  		accounts  = make(map[common.Address][]byte)
   221  		storages  = make(map[common.Address]map[common.Hash][]byte)
   222  	)
   223  	if err := r.Decode(&jaccounts); err != nil {
   224  		return nil, fmt.Errorf("load diff accounts: %v", err)
   225  	}
   226  	for i, addr := range jaccounts.Addresses {
   227  		accounts[addr] = jaccounts.Accounts[i]
   228  	}
   229  	if err := r.Decode(&jstorages); err != nil {
   230  		return nil, fmt.Errorf("load diff storages: %v", err)
   231  	}
   232  	for _, entry := range jstorages {
   233  		set := make(map[common.Hash][]byte)
   234  		for i, h := range entry.Hashes {
   235  			if len(entry.Slots[i]) > 0 {
   236  				set[h] = entry.Slots[i]
   237  			} else {
   238  				set[h] = nil
   239  			}
   240  		}
   241  		storages[entry.Account] = set
   242  	}
   243  	return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, nodes, triestate.New(accounts, storages)), r)
   244  }
   245  
   246  // journal implements the layer interface, marshaling the un-flushed trie nodes
   247  // along with layer meta data into provided byte buffer.
   248  func (dl *diskLayer) journal(w io.Writer) error {
   249  	dl.lock.RLock()
   250  	defer dl.lock.RUnlock()
   251  
   252  	// Ensure the layer didn't get stale
   253  	if dl.stale {
   254  		return errSnapshotStale
   255  	}
   256  	// Step one, write the disk root into the journal.
   257  	if err := rlp.Encode(w, dl.root); err != nil {
   258  		return err
   259  	}
   260  	// Step two, write the corresponding state id into the journal
   261  	if err := rlp.Encode(w, dl.id); err != nil {
   262  		return err
   263  	}
   264  	// Step three, write all unwritten nodes into the journal
   265  	nodes := make([]journalNodes, 0, len(dl.buffer.nodes))
   266  	for owner, subset := range dl.buffer.nodes {
   267  		entry := journalNodes{Owner: owner}
   268  		for path, node := range subset {
   269  			entry.Nodes = append(entry.Nodes, journalNode{Path: []byte(path), Blob: node.Blob})
   270  		}
   271  		nodes = append(nodes, entry)
   272  	}
   273  	if err := rlp.Encode(w, nodes); err != nil {
   274  		return err
   275  	}
   276  	log.Debug("Journaled pathdb disk layer", "root", dl.root, "nodes", len(dl.buffer.nodes))
   277  	return nil
   278  }
   279  
   280  // journal implements the layer interface, writing the memory layer contents
   281  // into a buffer to be stored in the database as the layer journal.
   282  func (dl *diffLayer) journal(w io.Writer) error {
   283  	dl.lock.RLock()
   284  	defer dl.lock.RUnlock()
   285  
   286  	// journal the parent first
   287  	if err := dl.parent.journal(w); err != nil {
   288  		return err
   289  	}
   290  	// Everything below was journaled, persist this layer too
   291  	if err := rlp.Encode(w, dl.root); err != nil {
   292  		return err
   293  	}
   294  	if err := rlp.Encode(w, dl.block); err != nil {
   295  		return err
   296  	}
   297  	// Write the accumulated trie nodes into buffer
   298  	nodes := make([]journalNodes, 0, len(dl.nodes))
   299  	for owner, subset := range dl.nodes {
   300  		entry := journalNodes{Owner: owner}
   301  		for path, node := range subset {
   302  			entry.Nodes = append(entry.Nodes, journalNode{Path: []byte(path), Blob: node.Blob})
   303  		}
   304  		nodes = append(nodes, entry)
   305  	}
   306  	if err := rlp.Encode(w, nodes); err != nil {
   307  		return err
   308  	}
   309  	// Write the accumulated state changes into buffer
   310  	var jacct journalAccounts
   311  	for addr, account := range dl.states.Accounts {
   312  		jacct.Addresses = append(jacct.Addresses, addr)
   313  		jacct.Accounts = append(jacct.Accounts, account)
   314  	}
   315  	if err := rlp.Encode(w, jacct); err != nil {
   316  		return err
   317  	}
   318  	storage := make([]journalStorage, 0, len(dl.states.Storages))
   319  	for addr, slots := range dl.states.Storages {
   320  		entry := journalStorage{Account: addr}
   321  		for slotHash, slot := range slots {
   322  			entry.Hashes = append(entry.Hashes, slotHash)
   323  			entry.Slots = append(entry.Slots, slot)
   324  		}
   325  		storage = append(storage, entry)
   326  	}
   327  	if err := rlp.Encode(w, storage); err != nil {
   328  		return err
   329  	}
   330  	log.Debug("Journaled pathdb diff layer", "root", dl.root, "parent", dl.parent.rootHash(), "id", dl.stateID(), "block", dl.block, "nodes", len(dl.nodes))
   331  	return nil
   332  }
   333  
   334  // Journal commits an entire diff hierarchy to disk into a single journal entry.
   335  // This is meant to be used during shutdown to persist the layer without
   336  // flattening everything down (bad for reorgs). And this function will mark the
   337  // database as read-only to prevent all following mutation to disk.
   338  func (db *Database) Journal(root common.Hash) error {
   339  	// Retrieve the head layer to journal from.
   340  	l := db.tree.get(root)
   341  	if l == nil {
   342  		return fmt.Errorf("triedb layer [%#x] missing", root)
   343  	}
   344  	disk := db.tree.bottom()
   345  	if l, ok := l.(*diffLayer); ok {
   346  		log.Info("Persisting dirty state to disk", "head", l.block, "root", root, "layers", l.id-disk.id+disk.buffer.layers)
   347  	} else { // disk layer only on noop runs (likely) or deep reorgs (unlikely)
   348  		log.Info("Persisting dirty state to disk", "root", root, "layers", disk.buffer.layers)
   349  	}
   350  	start := time.Now()
   351  
   352  	// Run the journaling
   353  	db.lock.Lock()
   354  	defer db.lock.Unlock()
   355  
   356  	// Short circuit if the database is in read only mode.
   357  	if db.readOnly {
   358  		return errDatabaseReadOnly
   359  	}
   360  	// Firstly write out the metadata of journal
   361  	journal := new(bytes.Buffer)
   362  	if err := rlp.Encode(journal, journalVersion); err != nil {
   363  		return err
   364  	}
   365  	// Secondly write out the state root in disk, ensure all layers
   366  	// on top are continuous with disk.
   367  	diskRoot := types.EmptyRootHash
   368  	if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 {
   369  		diskRoot = crypto.Keccak256Hash(blob)
   370  	}
   371  	if err := rlp.Encode(journal, diskRoot); err != nil {
   372  		return err
   373  	}
   374  	// Finally write out the journal of each layer in reverse order.
   375  	if err := l.journal(journal); err != nil {
   376  		return err
   377  	}
   378  	// Store the journal into the database and return
   379  	rawdb.WriteTrieJournal(db.diskdb, journal.Bytes())
   380  
   381  	// Set the db in read only mode to reject all following mutations
   382  	db.readOnly = true
   383  	log.Info("Persisted dirty state to disk", "size", common.StorageSize(journal.Len()), "elapsed", common.PrettyDuration(time.Since(start)))
   384  	return nil
   385  }