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