github.com/theQRL/go-zond@v0.1.1/trie/triedb/pathdb/testutils.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 pathdb
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  
    23  	"github.com/theQRL/go-zond/common"
    24  	"github.com/theQRL/go-zond/core/types"
    25  	"github.com/theQRL/go-zond/crypto"
    26  	"github.com/theQRL/go-zond/trie/trienode"
    27  	"github.com/theQRL/go-zond/trie/triestate"
    28  	"golang.org/x/exp/slices"
    29  )
    30  
    31  // testHasher is a test utility for computing root hash of a batch of state
    32  // elements. The hash algorithm is to sort all the elements in lexicographical
    33  // order, concat the key and value in turn, and perform hash calculation on
    34  // the concatenated bytes. Except the root hash, a nodeset will be returned
    35  // once Commit is called, which contains all the changes made to hasher.
    36  type testHasher struct {
    37  	owner   common.Hash            // owner identifier
    38  	root    common.Hash            // original root
    39  	dirties map[common.Hash][]byte // dirty states
    40  	cleans  map[common.Hash][]byte // clean states
    41  }
    42  
    43  // newTestHasher constructs a hasher object with provided states.
    44  func newTestHasher(owner common.Hash, root common.Hash, cleans map[common.Hash][]byte) (*testHasher, error) {
    45  	if cleans == nil {
    46  		cleans = make(map[common.Hash][]byte)
    47  	}
    48  	if got, _ := hash(cleans); got != root {
    49  		return nil, fmt.Errorf("state root mismatched, want: %x, got: %x", root, got)
    50  	}
    51  	return &testHasher{
    52  		owner:   owner,
    53  		root:    root,
    54  		dirties: make(map[common.Hash][]byte),
    55  		cleans:  cleans,
    56  	}, nil
    57  }
    58  
    59  // Get returns the value for key stored in the trie.
    60  func (h *testHasher) Get(key []byte) ([]byte, error) {
    61  	hash := common.BytesToHash(key)
    62  	val, ok := h.dirties[hash]
    63  	if ok {
    64  		return val, nil
    65  	}
    66  	return h.cleans[hash], nil
    67  }
    68  
    69  // Update associates key with value in the trie.
    70  func (h *testHasher) Update(key, value []byte) error {
    71  	h.dirties[common.BytesToHash(key)] = common.CopyBytes(value)
    72  	return nil
    73  }
    74  
    75  // Delete removes any existing value for key from the trie.
    76  func (h *testHasher) Delete(key []byte) error {
    77  	h.dirties[common.BytesToHash(key)] = nil
    78  	return nil
    79  }
    80  
    81  // Commit computes the new hash of the states and returns the set with all
    82  // state changes.
    83  func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
    84  	var (
    85  		nodes = make(map[common.Hash][]byte)
    86  		set   = trienode.NewNodeSet(h.owner)
    87  	)
    88  	for hash, val := range h.cleans {
    89  		nodes[hash] = val
    90  	}
    91  	for hash, val := range h.dirties {
    92  		nodes[hash] = val
    93  		if bytes.Equal(val, h.cleans[hash]) {
    94  			continue
    95  		}
    96  		if len(val) == 0 {
    97  			set.AddNode(hash.Bytes(), trienode.NewDeleted())
    98  		} else {
    99  			set.AddNode(hash.Bytes(), trienode.New(crypto.Keccak256Hash(val), val))
   100  		}
   101  	}
   102  	root, blob := hash(nodes)
   103  
   104  	// Include the dirty root node as well.
   105  	if root != types.EmptyRootHash && root != h.root {
   106  		set.AddNode(nil, trienode.New(root, blob))
   107  	}
   108  	if root == types.EmptyRootHash && h.root != types.EmptyRootHash {
   109  		set.AddNode(nil, trienode.NewDeleted())
   110  	}
   111  	return root, set, nil
   112  }
   113  
   114  // hash performs the hash computation upon the provided states.
   115  func hash(states map[common.Hash][]byte) (common.Hash, []byte) {
   116  	var hs []common.Hash
   117  	for hash := range states {
   118  		hs = append(hs, hash)
   119  	}
   120  	slices.SortFunc(hs, common.Hash.Cmp)
   121  
   122  	var input []byte
   123  	for _, hash := range hs {
   124  		if len(states[hash]) == 0 {
   125  			continue
   126  		}
   127  		input = append(input, hash.Bytes()...)
   128  		input = append(input, states[hash]...)
   129  	}
   130  	if len(input) == 0 {
   131  		return types.EmptyRootHash, nil
   132  	}
   133  	return crypto.Keccak256Hash(input), input
   134  }
   135  
   136  type hashLoader struct {
   137  	accounts map[common.Hash][]byte
   138  	storages map[common.Hash]map[common.Hash][]byte
   139  }
   140  
   141  func newHashLoader(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) *hashLoader {
   142  	return &hashLoader{
   143  		accounts: accounts,
   144  		storages: storages,
   145  	}
   146  }
   147  
   148  // OpenTrie opens the main account trie.
   149  func (l *hashLoader) OpenTrie(root common.Hash) (triestate.Trie, error) {
   150  	return newTestHasher(common.Hash{}, root, l.accounts)
   151  }
   152  
   153  // OpenStorageTrie opens the storage trie of an account.
   154  func (l *hashLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) {
   155  	return newTestHasher(addrHash, root, l.storages[addrHash])
   156  }