github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/trie/triestate/state.go (about)

     1  // Copyright 2023 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 triestate
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"sync"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/ethereum/go-ethereum/crypto"
    27  	"github.com/ethereum/go-ethereum/rlp"
    28  	"github.com/ethereum/go-ethereum/trie/trienode"
    29  )
    30  
    31  // Trie is an Ethereum state trie, can be implemented by Ethereum Merkle Patricia
    32  // tree or Verkle tree.
    33  type Trie interface {
    34  	// Get returns the value for key stored in the trie.
    35  	Get(key []byte) ([]byte, error)
    36  
    37  	// Update associates key with value in the trie.
    38  	Update(key, value []byte) error
    39  
    40  	// Delete removes any existing value for key from the trie.
    41  	Delete(key []byte) error
    42  
    43  	// Commit the trie and returns a set of dirty nodes generated along with
    44  	// the new root hash.
    45  	Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
    46  }
    47  
    48  // TrieLoader wraps functions to load tries.
    49  type TrieLoader interface {
    50  	// OpenTrie opens the main account trie.
    51  	OpenTrie(root common.Hash) (Trie, error)
    52  
    53  	// OpenStorageTrie opens the storage trie of an account.
    54  	OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error)
    55  }
    56  
    57  // Set represents a collection of mutated states during a state transition.
    58  // The value refers to the original content of state before the transition
    59  // is made. Nil means that the state was not present previously.
    60  type Set struct {
    61  	Accounts map[common.Address][]byte                 // Mutated account set, nil means the account was not present
    62  	Storages map[common.Address]map[common.Hash][]byte // Mutated storage set, nil means the slot was not present
    63  	size     common.StorageSize                        // Approximate size of set
    64  }
    65  
    66  // New constructs the state set with provided data.
    67  func New(accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) *Set {
    68  	return &Set{
    69  		Accounts: accounts,
    70  		Storages: storages,
    71  	}
    72  }
    73  
    74  // Size returns the approximate memory size occupied by the set.
    75  func (s *Set) Size() common.StorageSize {
    76  	if s.size != 0 {
    77  		return s.size
    78  	}
    79  	for _, account := range s.Accounts {
    80  		s.size += common.StorageSize(common.AddressLength + len(account))
    81  	}
    82  	for _, slots := range s.Storages {
    83  		for _, val := range slots {
    84  			s.size += common.StorageSize(common.HashLength + len(val))
    85  		}
    86  		s.size += common.StorageSize(common.AddressLength)
    87  	}
    88  	return s.size
    89  }
    90  
    91  // context wraps all fields for executing state diffs.
    92  type context struct {
    93  	prevRoot    common.Hash
    94  	postRoot    common.Hash
    95  	accounts    map[common.Address][]byte
    96  	storages    map[common.Address]map[common.Hash][]byte
    97  	accountTrie Trie
    98  	nodes       *trienode.MergedNodeSet
    99  }
   100  
   101  // Apply traverses the provided state diffs, apply them in the associated
   102  // post-state and return the generated dirty trie nodes. The state can be
   103  // loaded via the provided trie loader.
   104  func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, loader TrieLoader) (map[common.Hash]map[string]*trienode.Node, error) {
   105  	tr, err := loader.OpenTrie(postRoot)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	ctx := &context{
   110  		prevRoot:    prevRoot,
   111  		postRoot:    postRoot,
   112  		accounts:    accounts,
   113  		storages:    storages,
   114  		accountTrie: tr,
   115  		nodes:       trienode.NewMergedNodeSet(),
   116  	}
   117  	for addr, account := range accounts {
   118  		var err error
   119  		if len(account) == 0 {
   120  			err = deleteAccount(ctx, loader, addr)
   121  		} else {
   122  			err = updateAccount(ctx, loader, addr)
   123  		}
   124  		if err != nil {
   125  			return nil, fmt.Errorf("failed to revert state, err: %w", err)
   126  		}
   127  	}
   128  	root, result, err := tr.Commit(false)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	if root != prevRoot {
   133  		return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root)
   134  	}
   135  	if err := ctx.nodes.Merge(result); err != nil {
   136  		return nil, err
   137  	}
   138  	return ctx.nodes.Flatten(), nil
   139  }
   140  
   141  // updateAccount the account was present in prev-state, and may or may not
   142  // existent in post-state. Apply the reverse diff and verify if the storage
   143  // root matches the one in prev-state account.
   144  func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error {
   145  	// The account was present in prev-state, decode it from the
   146  	// 'slim-rlp' format bytes.
   147  	h := newHasher()
   148  	defer h.release()
   149  
   150  	addrHash := h.hash(addr.Bytes())
   151  	prev, err := types.FullAccount(ctx.accounts[addr])
   152  	if err != nil {
   153  		return err
   154  	}
   155  	// The account may or may not existent in post-state, try to
   156  	// load it and decode if it's found.
   157  	blob, err := ctx.accountTrie.Get(addrHash.Bytes())
   158  	if err != nil {
   159  		return err
   160  	}
   161  	post := types.NewEmptyStateAccount()
   162  	if len(blob) != 0 {
   163  		if err := rlp.DecodeBytes(blob, &post); err != nil {
   164  			return err
   165  		}
   166  	}
   167  	// Apply all storage changes into the post-state storage trie.
   168  	st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root)
   169  	if err != nil {
   170  		return err
   171  	}
   172  	for key, val := range ctx.storages[addr] {
   173  		var err error
   174  		if len(val) == 0 {
   175  			err = st.Delete(key.Bytes())
   176  		} else {
   177  			err = st.Update(key.Bytes(), val)
   178  		}
   179  		if err != nil {
   180  			return err
   181  		}
   182  	}
   183  	root, result, err := st.Commit(false)
   184  	if err != nil {
   185  		return err
   186  	}
   187  	if root != prev.Root {
   188  		return errors.New("failed to reset storage trie")
   189  	}
   190  	// The returned set can be nil if storage trie is not changed
   191  	// at all.
   192  	if result != nil {
   193  		if err := ctx.nodes.Merge(result); err != nil {
   194  			return err
   195  		}
   196  	}
   197  	// Write the prev-state account into the main trie
   198  	full, err := rlp.EncodeToBytes(prev)
   199  	if err != nil {
   200  		return err
   201  	}
   202  	return ctx.accountTrie.Update(addrHash.Bytes(), full)
   203  }
   204  
   205  // deleteAccount the account was not present in prev-state, and is expected
   206  // to be existent in post-state. Apply the reverse diff and verify if the
   207  // account and storage is wiped out correctly.
   208  func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error {
   209  	// The account must be existent in post-state, load the account.
   210  	h := newHasher()
   211  	defer h.release()
   212  
   213  	addrHash := h.hash(addr.Bytes())
   214  	blob, err := ctx.accountTrie.Get(addrHash.Bytes())
   215  	if err != nil {
   216  		return err
   217  	}
   218  	if len(blob) == 0 {
   219  		return fmt.Errorf("account is non-existent %#x", addrHash)
   220  	}
   221  	var post types.StateAccount
   222  	if err := rlp.DecodeBytes(blob, &post); err != nil {
   223  		return err
   224  	}
   225  	st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root)
   226  	if err != nil {
   227  		return err
   228  	}
   229  	for key, val := range ctx.storages[addr] {
   230  		if len(val) != 0 {
   231  			return errors.New("expect storage deletion")
   232  		}
   233  		if err := st.Delete(key.Bytes()); err != nil {
   234  			return err
   235  		}
   236  	}
   237  	root, result, err := st.Commit(false)
   238  	if err != nil {
   239  		return err
   240  	}
   241  	if root != types.EmptyRootHash {
   242  		return errors.New("failed to clear storage trie")
   243  	}
   244  	// The returned set can be nil if storage trie is not changed
   245  	// at all.
   246  	if result != nil {
   247  		if err := ctx.nodes.Merge(result); err != nil {
   248  			return err
   249  		}
   250  	}
   251  	// Delete the post-state account from the main trie.
   252  	return ctx.accountTrie.Delete(addrHash.Bytes())
   253  }
   254  
   255  // hasher is used to compute the sha256 hash of the provided data.
   256  type hasher struct{ sha crypto.KeccakState }
   257  
   258  var hasherPool = sync.Pool{
   259  	New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} },
   260  }
   261  
   262  func newHasher() *hasher {
   263  	return hasherPool.Get().(*hasher)
   264  }
   265  
   266  func (h *hasher) hash(data []byte) common.Hash {
   267  	return crypto.HashData(h.sha, data)
   268  }
   269  
   270  func (h *hasher) release() {
   271  	hasherPool.Put(h)
   272  }