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