github.com/MetalBlockchain/subnet-evm@v0.4.9/trie/test_trie.go (about)

     1  // (c) 2021-2022, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package trie
     5  
     6  import (
     7  	cryptoRand "crypto/rand"
     8  	"encoding/binary"
     9  	"math/big"
    10  	"math/rand"
    11  	"testing"
    12  
    13  	"github.com/MetalBlockchain/metalgo/utils/wrappers"
    14  	"github.com/MetalBlockchain/subnet-evm/accounts/keystore"
    15  	"github.com/MetalBlockchain/subnet-evm/core/types"
    16  
    17  	"github.com/ethereum/go-ethereum/common"
    18  	"github.com/ethereum/go-ethereum/rlp"
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  // GenerateTrie creates a trie with [numKeys] key-value pairs inside of [trieDB].
    23  // Returns the root of the generated trie, the slice of keys inserted into the trie in lexicographical
    24  // order, and the slice of corresponding values.
    25  // GenerateTrie reads from [rand] and the caller should call rand.Seed(n) for deterministic results
    26  func GenerateTrie(t *testing.T, trieDB *Database, numKeys int, keySize int) (common.Hash, [][]byte, [][]byte) {
    27  	if keySize < wrappers.LongLen+1 {
    28  		t.Fatal("key size must be at least 9 bytes (8 bytes for uint64 and 1 random byte)")
    29  	}
    30  	testTrie := NewEmpty(trieDB)
    31  
    32  	keys, values := FillTrie(t, numKeys, keySize, testTrie)
    33  
    34  	// Commit the root to [trieDB]
    35  	root, nodes, err := testTrie.Commit(false)
    36  	assert.NoError(t, err)
    37  	err = trieDB.Update(NewWithNodeSet(nodes))
    38  	assert.NoError(t, err)
    39  	err = trieDB.Commit(root, false, nil)
    40  	assert.NoError(t, err)
    41  
    42  	return root, keys, values
    43  }
    44  
    45  // FillTrie fills a given trie with [numKeys] number of keys, each of size [keySize]
    46  // returns inserted keys and values
    47  // FillTrie reads from [rand] and the caller should call rand.Seed(n) for deterministic results
    48  func FillTrie(t *testing.T, numKeys int, keySize int, testTrie *Trie) ([][]byte, [][]byte) {
    49  	keys := make([][]byte, 0, numKeys)
    50  	values := make([][]byte, 0, numKeys)
    51  
    52  	// Generate key-value pairs
    53  	for i := 0; i < numKeys; i++ {
    54  		key := make([]byte, keySize)
    55  		binary.BigEndian.PutUint64(key[:wrappers.LongLen], uint64(i+1))
    56  		_, err := rand.Read(key[wrappers.LongLen:])
    57  		assert.NoError(t, err)
    58  
    59  		value := make([]byte, rand.Intn(128)+128) // min 128 bytes, max 256 bytes
    60  		_, err = rand.Read(value)
    61  		assert.NoError(t, err)
    62  
    63  		if err = testTrie.TryUpdate(key, value); err != nil {
    64  			t.Fatal("error updating trie", err)
    65  		}
    66  
    67  		keys = append(keys, key)
    68  		values = append(values, value)
    69  	}
    70  	return keys, values
    71  }
    72  
    73  // AssertTrieConsistency ensures given trieDB [a] and [b] both have the same
    74  // non-empty trie at [root]. (all key/value pairs must be equal)
    75  func AssertTrieConsistency(t testing.TB, root common.Hash, a, b *Database, onLeaf func(key, val []byte) error) {
    76  	trieA, err := New(common.Hash{}, root, a)
    77  	if err != nil {
    78  		t.Fatalf("error creating trieA, root=%s, err=%v", root, err)
    79  	}
    80  	trieB, err := New(common.Hash{}, root, b)
    81  	if err != nil {
    82  		t.Fatalf("error creating trieB, root=%s, err=%v", root, err)
    83  	}
    84  
    85  	itA := NewIterator(trieA.NodeIterator(nil))
    86  	itB := NewIterator(trieB.NodeIterator(nil))
    87  	count := 0
    88  	for itA.Next() && itB.Next() {
    89  		count++
    90  		assert.Equal(t, itA.Key, itB.Key)
    91  		assert.Equal(t, itA.Value, itB.Value)
    92  		if onLeaf != nil {
    93  			if err := onLeaf(itA.Key, itA.Value); err != nil {
    94  				t.Fatalf("error in onLeaf callback: %v", err)
    95  			}
    96  		}
    97  	}
    98  	assert.NoError(t, itA.Err)
    99  	assert.NoError(t, itB.Err)
   100  	assert.False(t, itA.Next())
   101  	assert.False(t, itB.Next())
   102  	assert.Greater(t, count, 0)
   103  }
   104  
   105  // CorruptTrie deletes every [n]th trie node from the trie given by [root] from the trieDB.
   106  // Assumes that the trie given by root can be iterated without issue.
   107  func CorruptTrie(t *testing.T, trieDB *Database, root common.Hash, n int) {
   108  	batch := trieDB.DiskDB().NewBatch()
   109  	// next delete some trie nodes
   110  	tr, err := New(common.Hash{}, root, trieDB)
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  
   115  	nodeIt := tr.NodeIterator(nil)
   116  	count := 0
   117  	for nodeIt.Next(true) {
   118  		count++
   119  		if count%n == 0 && nodeIt.Hash() != (common.Hash{}) {
   120  			if err := batch.Delete(nodeIt.Hash().Bytes()); err != nil {
   121  				t.Fatal(err)
   122  			}
   123  		}
   124  	}
   125  	if err := nodeIt.Error(); err != nil {
   126  		t.Fatal(err)
   127  	}
   128  
   129  	if err := batch.Write(); err != nil {
   130  		t.Fatal(err)
   131  	}
   132  }
   133  
   134  // FillAccounts adds [numAccounts] randomly generated accounts to the secure trie at [root] and commits it to [trieDB].
   135  // [onAccount] is called if non-nil (so the caller can modify the account before it is stored in the secure trie).
   136  // returns the new trie root and a map of funded keys to StateAccount structs.
   137  func FillAccounts(
   138  	t *testing.T, trieDB *Database, root common.Hash, numAccounts int,
   139  	onAccount func(*testing.T, int, types.StateAccount) types.StateAccount,
   140  ) (common.Hash, map[*keystore.Key]*types.StateAccount) {
   141  	var (
   142  		minBalance  = big.NewInt(3000000000000000000)
   143  		randBalance = big.NewInt(1000000000000000000)
   144  		maxNonce    = 10
   145  		accounts    = make(map[*keystore.Key]*types.StateAccount, numAccounts)
   146  	)
   147  
   148  	tr, err := NewStateTrie(common.Hash{}, root, trieDB)
   149  	if err != nil {
   150  		t.Fatalf("error opening trie: %v", err)
   151  	}
   152  
   153  	for i := 0; i < numAccounts; i++ {
   154  		acc := types.StateAccount{
   155  			Nonce:    uint64(rand.Intn(maxNonce)),
   156  			Balance:  new(big.Int).Add(minBalance, randBalance),
   157  			CodeHash: types.EmptyCodeHash[:],
   158  			Root:     types.EmptyRootHash,
   159  		}
   160  		if onAccount != nil {
   161  			acc = onAccount(t, i, acc)
   162  		}
   163  
   164  		accBytes, err := rlp.EncodeToBytes(&acc)
   165  		if err != nil {
   166  			t.Fatalf("failed to rlp encode account: %v", err)
   167  		}
   168  
   169  		key, err := keystore.NewKey(cryptoRand.Reader)
   170  		if err != nil {
   171  			t.Fatal(err)
   172  		}
   173  		if err = tr.TryUpdate(key.Address[:], accBytes); err != nil {
   174  			t.Fatalf("error updating trie with account, address=%s, err=%v", key.Address, err)
   175  		}
   176  		accounts[key] = &acc
   177  	}
   178  
   179  	newRoot, nodes, err := tr.Commit(false)
   180  	if err != nil {
   181  		t.Fatalf("error committing trie: %v", err)
   182  	}
   183  	if err := trieDB.Update(NewWithNodeSet(nodes)); err != nil {
   184  		t.Fatalf("error updating trieDB: %v", err)
   185  	}
   186  	if err := trieDB.Commit(newRoot, false, nil); err != nil {
   187  		t.Fatalf("error committing trieDB: %v", err)
   188  	}
   189  	return newRoot, accounts
   190  }