github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/evmstore/utils.go (about)

     1  package evmstore
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  
     9  	"github.com/unicornultrafoundation/go-helios/u2udb"
    10  	"github.com/unicornultrafoundation/go-helios/u2udb/table"
    11  	"github.com/unicornultrafoundation/go-helios/utils/simplewlru"
    12  	"github.com/unicornultrafoundation/go-u2u/common"
    13  	"github.com/unicornultrafoundation/go-u2u/core/rawdb"
    14  	"github.com/unicornultrafoundation/go-u2u/core/state"
    15  	"github.com/unicornultrafoundation/go-u2u/core/types"
    16  	"github.com/unicornultrafoundation/go-u2u/crypto"
    17  	"github.com/unicornultrafoundation/go-u2u/log"
    18  	"github.com/unicornultrafoundation/go-u2u/rlp"
    19  
    20  	"github.com/unicornultrafoundation/go-u2u/utils/iodb"
    21  )
    22  
    23  var (
    24  	// EmptyCode is the known hash of the empty EVM bytecode.
    25  	EmptyCode = crypto.Keccak256(nil)
    26  
    27  	emptyCodeHash = common.BytesToHash(EmptyCode)
    28  	emptyHash     = common.Hash{}
    29  )
    30  
    31  func (s *Store) CheckEvm(forEachState func(func(root common.Hash) (found bool, err error)), onlyRoots bool) error {
    32  	log.Info("Checking every node hash")
    33  	nodeIt := s.table.Evm.NewIterator(nil, nil)
    34  	defer nodeIt.Release()
    35  	for nodeIt.Next() {
    36  		if len(nodeIt.Key()) != 32 {
    37  			continue
    38  		}
    39  		calcHash := crypto.Keccak256(nodeIt.Value())
    40  		if !bytes.Equal(nodeIt.Key(), calcHash) {
    41  			log.Crit("Malformed node record", "exp", common.Bytes2Hex(calcHash), "got", common.Bytes2Hex(nodeIt.Key()))
    42  		}
    43  	}
    44  
    45  	log.Info("Checking every code hash")
    46  	codeIt := table.New(s.table.Evm, []byte("c")).NewIterator(nil, nil)
    47  	defer codeIt.Release()
    48  	for codeIt.Next() {
    49  		if len(codeIt.Key()) != 32 {
    50  			continue
    51  		}
    52  		calcHash := crypto.Keccak256(codeIt.Value())
    53  		if !bytes.Equal(codeIt.Key(), calcHash) {
    54  			log.Crit("Malformed code record", "exp", common.Bytes2Hex(calcHash), "got", common.Bytes2Hex(codeIt.Key()))
    55  		}
    56  	}
    57  
    58  	log.Info("Checking every preimage")
    59  	preimageIt := table.New(s.table.Evm, []byte("secure-key-")).NewIterator(nil, nil)
    60  	defer preimageIt.Release()
    61  	for preimageIt.Next() {
    62  		if len(preimageIt.Key()) != 32 {
    63  			continue
    64  		}
    65  		calcHash := crypto.Keccak256(preimageIt.Value())
    66  		if !bytes.Equal(preimageIt.Key(), calcHash) {
    67  			log.Crit("Malformed preimage record", "exp", common.Bytes2Hex(calcHash), "got", common.Bytes2Hex(preimageIt.Key()))
    68  		}
    69  	}
    70  
    71  	if onlyRoots {
    72  		log.Info("Checking presence of every root")
    73  	} else {
    74  		log.Info("Checking presence of every node")
    75  	}
    76  	var (
    77  		visitedHashes   = make([]common.Hash, 0, 1000000)
    78  		visitedI        = 0
    79  		checkedCache, _ = simplewlru.New(100000000, 100000000)
    80  		cached          = func(h common.Hash) bool {
    81  			_, ok := checkedCache.Get(h)
    82  			return ok
    83  		}
    84  	)
    85  	visited := func(h common.Hash, priority int) {
    86  		base := 100000 * priority
    87  		if visitedI%(1<<(len(visitedHashes)/base)) == 0 {
    88  			visitedHashes = append(visitedHashes, h)
    89  		}
    90  		visitedI++
    91  	}
    92  	forEachState(func(root common.Hash) (found bool, err error) {
    93  		stateTrie, err := s.EvmState.OpenTrie(root)
    94  		found = stateTrie != nil && err == nil
    95  		if !found || onlyRoots {
    96  			return
    97  		}
    98  
    99  		// check existence of every code hash and root of every storage trie
   100  		stateIt := stateTrie.NodeIterator(nil)
   101  		for stateItSkip := false; stateIt.Next(!stateItSkip); {
   102  			stateItSkip = false
   103  			if stateIt.Hash() != emptyHash {
   104  				if cached(stateIt.Hash()) {
   105  					stateItSkip = true
   106  					continue
   107  				}
   108  				visited(stateIt.Hash(), 2)
   109  			}
   110  
   111  			if stateIt.Leaf() {
   112  				addrHash := common.BytesToHash(stateIt.LeafKey())
   113  
   114  				var account state.Account
   115  				if err = rlp.Decode(bytes.NewReader(stateIt.LeafBlob()), &account); err != nil {
   116  					err = fmt.Errorf("Failed to decode accoun as %s addr: %s", addrHash.String(), err.Error())
   117  					return
   118  				}
   119  
   120  				codeHash := common.BytesToHash(account.CodeHash)
   121  				if codeHash != emptyCodeHash && !cached(codeHash) {
   122  					code, _ := s.EvmState.ContractCode(addrHash, codeHash)
   123  					if code == nil {
   124  						err = fmt.Errorf("failed to get code %s at %s addr", codeHash.String(), addrHash.String())
   125  						return
   126  					}
   127  					checkedCache.Add(codeHash, true, 1)
   128  				}
   129  
   130  				if account.Root != types.EmptyRootHash && !cached(account.Root) {
   131  					storageTrie, storageErr := s.EvmState.OpenStorageTrie(addrHash, account.Root)
   132  					if storageErr != nil {
   133  						err = fmt.Errorf("failed to open storage trie %s at %s addr: %s", account.Root.String(), addrHash.String(), storageErr.Error())
   134  						return
   135  					}
   136  					storageIt := storageTrie.NodeIterator(nil)
   137  					for storageItSkip := false; storageIt.Next(!storageItSkip); {
   138  						storageItSkip = false
   139  						if storageIt.Hash() != emptyHash {
   140  							if cached(storageIt.Hash()) {
   141  								storageItSkip = true
   142  								continue
   143  							}
   144  							visited(storageIt.Hash(), 1)
   145  						}
   146  					}
   147  					if storageIt.Error() != nil {
   148  						err = fmt.Errorf("EVM storage trie %s at %s addr iteration error: %s", account.Root.String(), addrHash.String(), storageIt.Error())
   149  						return
   150  					}
   151  				}
   152  			}
   153  		}
   154  
   155  		if stateIt.Error() != nil {
   156  			err = fmt.Errorf("EVM state trie %s iteration error: %s", root.String(), stateIt.Error())
   157  			return
   158  		}
   159  		for _, h := range visitedHashes {
   160  			checkedCache.Add(h, true, 1)
   161  		}
   162  		visitedHashes = visitedHashes[:0]
   163  
   164  		return
   165  	})
   166  
   167  	return nil
   168  }
   169  
   170  func (s *Store) ImportEvm(r io.Reader) error {
   171  	it := iodb.NewIterator(r)
   172  	defer it.Release()
   173  	batch := &restrictedEvmBatch{s.table.Evm.NewBatch()}
   174  	defer batch.Reset()
   175  	for it.Next() {
   176  		err := batch.Put(it.Key(), it.Value())
   177  		if err != nil {
   178  			return err
   179  		}
   180  		if batch.ValueSize() > u2udb.IdealBatchSize {
   181  			err := batch.Write()
   182  			if err != nil {
   183  				return err
   184  			}
   185  			batch.Reset()
   186  		}
   187  	}
   188  	return batch.Write()
   189  }
   190  
   191  type restrictedEvmBatch struct {
   192  	u2udb.Batch
   193  }
   194  
   195  func IsMptKey(key []byte) bool {
   196  	return len(key) == common.HashLength ||
   197  		(bytes.HasPrefix(key, rawdb.CodePrefix) && len(key) == len(rawdb.CodePrefix)+common.HashLength)
   198  }
   199  
   200  func IsPreimageKey(key []byte) bool {
   201  	preimagePrefix := []byte("secure-key-")
   202  	return bytes.HasPrefix(key, preimagePrefix) && len(key) == (len(preimagePrefix)+common.HashLength)
   203  }
   204  
   205  func (v *restrictedEvmBatch) Put(key []byte, value []byte) error {
   206  	if !IsMptKey(key) && !IsPreimageKey(key) {
   207  		return errors.New("not expected prefix for EVM history dump")
   208  	}
   209  	return v.Batch.Put(key, value)
   210  }