github.com/dominant-strategies/go-quai@v0.28.2/trie/stacktrie_test.go (about)

     1  package trie
     2  
     3  import (
     4  	"bytes"
     5  	"math/big"
     6  	"testing"
     7  
     8  	"github.com/dominant-strategies/go-quai/common"
     9  	"github.com/dominant-strategies/go-quai/crypto"
    10  	"github.com/dominant-strategies/go-quai/ethdb/memorydb"
    11  )
    12  
    13  func TestSizeBug(t *testing.T) {
    14  	st := NewStackTrie(nil)
    15  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
    16  
    17  	leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
    18  	value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
    19  
    20  	nt.TryUpdate(leaf, value)
    21  	st.TryUpdate(leaf, value)
    22  
    23  	if nt.Hash() != st.Hash() {
    24  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
    25  	}
    26  }
    27  
    28  func TestEmptyBug(t *testing.T) {
    29  	st := NewStackTrie(nil)
    30  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
    31  
    32  	//leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
    33  	//value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
    34  	kvs := []struct {
    35  		K string
    36  		V string
    37  	}{
    38  		{K: "405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace", V: "9496f4ec2bf9dab484cac6be589e8417d84781be08"},
    39  		{K: "40edb63a35fcf86c08022722aa3287cdd36440d671b4918131b2514795fefa9c", V: "01"},
    40  		{K: "b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6", V: "947a30f7736e48d6599356464ba4c150d8da0302ff"},
    41  		{K: "c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b", V: "02"},
    42  	}
    43  
    44  	for _, kv := range kvs {
    45  		nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    46  		st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    47  	}
    48  
    49  	if nt.Hash() != st.Hash() {
    50  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
    51  	}
    52  }
    53  
    54  func TestValLength56(t *testing.T) {
    55  	st := NewStackTrie(nil)
    56  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
    57  
    58  	//leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
    59  	//value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
    60  	kvs := []struct {
    61  		K string
    62  		V string
    63  	}{
    64  		{K: "405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace", V: "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"},
    65  	}
    66  
    67  	for _, kv := range kvs {
    68  		nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    69  		st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    70  	}
    71  
    72  	if nt.Hash() != st.Hash() {
    73  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
    74  	}
    75  }
    76  
    77  // TestUpdateSmallNodes tests a case where the leaves are small (both key and value),
    78  // which causes a lot of node-within-node. This case was found via fuzzing.
    79  func TestUpdateSmallNodes(t *testing.T) {
    80  	st := NewStackTrie(nil)
    81  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
    82  	kvs := []struct {
    83  		K string
    84  		V string
    85  	}{
    86  		{"63303030", "3041"}, // stacktrie.Update
    87  		{"65", "3000"},       // stacktrie.Update
    88  	}
    89  	for _, kv := range kvs {
    90  		nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    91  		st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    92  	}
    93  	if nt.Hash() != st.Hash() {
    94  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
    95  	}
    96  }
    97  
    98  // TestUpdateVariableKeys contains a case which stacktrie fails: when keys of different
    99  // sizes are used, and the second one has the same prefix as the first, then the
   100  // stacktrie fails, since it's unable to 'expand' on an already added leaf.
   101  // For all practical purposes, this is fine, since keys are fixed-size length
   102  // in account and storage tries.
   103  //
   104  // The test is marked as 'skipped', and exists just to have the behaviour documented.
   105  // This case was found via fuzzing.
   106  func TestUpdateVariableKeys(t *testing.T) {
   107  	t.SkipNow()
   108  	st := NewStackTrie(nil)
   109  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
   110  	kvs := []struct {
   111  		K string
   112  		V string
   113  	}{
   114  		{"0x33303534636532393561313031676174", "303030"},
   115  		{"0x3330353463653239356131303167617430", "313131"},
   116  	}
   117  	for _, kv := range kvs {
   118  		nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
   119  		st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
   120  	}
   121  	if nt.Hash() != st.Hash() {
   122  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
   123  	}
   124  }
   125  
   126  // TestStacktrieNotModifyValues checks that inserting blobs of data into the
   127  // stacktrie does not mutate the blobs
   128  func TestStacktrieNotModifyValues(t *testing.T) {
   129  	st := NewStackTrie(nil)
   130  	{ // Test a very small trie
   131  		// Give it the value as a slice with large backing alloc,
   132  		// so if the stacktrie tries to append, it won't have to realloc
   133  		value := make([]byte, 1, 100)
   134  		value[0] = 0x2
   135  		want := common.CopyBytes(value)
   136  		st.TryUpdate([]byte{0x01}, value)
   137  		st.Hash()
   138  		if have := value; !bytes.Equal(have, want) {
   139  			t.Fatalf("tiny trie: have %#x want %#x", have, want)
   140  		}
   141  		st = NewStackTrie(nil)
   142  	}
   143  	// Test with a larger trie
   144  	keyB := big.NewInt(1)
   145  	keyDelta := big.NewInt(1)
   146  	var vals [][]byte
   147  	getValue := func(i int) []byte {
   148  		if i%2 == 0 { // large
   149  			return crypto.Keccak256(big.NewInt(int64(i)).Bytes())
   150  		} else { //small
   151  			return big.NewInt(int64(i)).Bytes()
   152  		}
   153  	}
   154  	for i := 0; i < 1000; i++ {
   155  		key := common.BigToHash(keyB)
   156  		value := getValue(i)
   157  		st.TryUpdate(key.Bytes(), value)
   158  		vals = append(vals, value)
   159  		keyB = keyB.Add(keyB, keyDelta)
   160  		keyDelta.Add(keyDelta, common.Big1)
   161  	}
   162  	st.Hash()
   163  	for i := 0; i < 1000; i++ {
   164  		want := getValue(i)
   165  
   166  		have := vals[i]
   167  		if !bytes.Equal(have, want) {
   168  			t.Fatalf("item %d, have %#x want %#x", i, have, want)
   169  		}
   170  
   171  	}
   172  }
   173  
   174  // TestStacktrieSerialization tests that the stacktrie works well if we
   175  // serialize/unserialize it a lot
   176  func TestStacktrieSerialization(t *testing.T) {
   177  	var (
   178  		st       = NewStackTrie(nil)
   179  		nt, _    = New(common.Hash{}, NewDatabase(memorydb.New()))
   180  		keyB     = big.NewInt(1)
   181  		keyDelta = big.NewInt(1)
   182  		vals     [][]byte
   183  		keys     [][]byte
   184  	)
   185  	getValue := func(i int) []byte {
   186  		if i%2 == 0 { // large
   187  			return crypto.Keccak256(big.NewInt(int64(i)).Bytes())
   188  		} else { //small
   189  			return big.NewInt(int64(i)).Bytes()
   190  		}
   191  	}
   192  	for i := 0; i < 10; i++ {
   193  		vals = append(vals, getValue(i))
   194  		keys = append(keys, common.BigToHash(keyB).Bytes())
   195  		keyB = keyB.Add(keyB, keyDelta)
   196  		keyDelta.Add(keyDelta, common.Big1)
   197  	}
   198  	for i, k := range keys {
   199  		nt.TryUpdate(k, common.CopyBytes(vals[i]))
   200  	}
   201  
   202  	for i, k := range keys {
   203  		blob, err := st.MarshalBinary()
   204  		if err != nil {
   205  			t.Fatal(err)
   206  		}
   207  		newSt, err := NewFromBinary(blob, nil)
   208  		if err != nil {
   209  			t.Fatal(err)
   210  		}
   211  		st = newSt
   212  		st.TryUpdate(k, common.CopyBytes(vals[i]))
   213  	}
   214  	if have, want := st.Hash(), nt.Hash(); have != want {
   215  		t.Fatalf("have %#x want %#x", have, want)
   216  	}
   217  }