github.com/core-coin/go-core/v2@v2.1.9/trie/stacktrie_test.go (about)

     1  // Copyright 2020 by the Authors
     2  // This file is part of the go-core library.
     3  //
     4  // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package trie
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"math/big"
    23  	mrand "math/rand"
    24  	"testing"
    25  
    26  	"github.com/core-coin/go-core/v2/xcbdb/memorydb"
    27  
    28  	"github.com/core-coin/go-core/v2/common"
    29  	"github.com/core-coin/go-core/v2/common/hexutil"
    30  	"github.com/core-coin/go-core/v2/core/types"
    31  	"github.com/core-coin/go-core/v2/crypto"
    32  )
    33  
    34  func TestSizeBug(t *testing.T) {
    35  	st := NewStackTrie(nil)
    36  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
    37  
    38  	leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
    39  	value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
    40  
    41  	nt.TryUpdate(leaf, value)
    42  	st.TryUpdate(leaf, value)
    43  
    44  	if nt.Hash() != st.Hash() {
    45  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
    46  	}
    47  }
    48  
    49  func TestEmptyBug(t *testing.T) {
    50  	st := NewStackTrie(nil)
    51  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
    52  
    53  	//leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
    54  	//value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
    55  	kvs := []struct {
    56  		K string
    57  		V string
    58  	}{
    59  		{K: "405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace", V: "9496f4ec2bf9dab484cac6be589e8417d84781be08"},
    60  		{K: "40edb63a35fcf86c08022722aa3287cdd36440d671b4918131b2514795fefa9c", V: "01"},
    61  		{K: "b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6", V: "947a30f7736e48d6599356464ba4c150d8da0302ff"},
    62  		{K: "c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b", V: "02"},
    63  	}
    64  
    65  	for _, kv := range kvs {
    66  		nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    67  		st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    68  	}
    69  
    70  	if nt.Hash() != st.Hash() {
    71  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
    72  	}
    73  }
    74  
    75  func TestValLength56(t *testing.T) {
    76  	st := NewStackTrie(nil)
    77  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
    78  
    79  	//leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
    80  	//value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3")
    81  	kvs := []struct {
    82  		K string
    83  		V string
    84  	}{
    85  		{K: "405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace", V: "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"},
    86  	}
    87  
    88  	for _, kv := range kvs {
    89  		nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    90  		st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
    91  	}
    92  
    93  	if nt.Hash() != st.Hash() {
    94  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
    95  	}
    96  }
    97  
    98  func genTxs(num uint64) (types.Transactions, error) {
    99  	key, err := crypto.UnmarshalPrivateKeyHex("ab856a9af6b0b651dd2f43b5e12193652ec1701c4da6f1c0d2a366ac4b9dabc9433ef09e41ca129552bd2c029086d9b03604de872a3b343204")
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	newTx := func(i uint64) (*types.Transaction, error) {
   104  		signer := types.NewNucleusSigner(big.NewInt(18))
   105  		tx, err := types.SignTx(types.NewTransaction(i, key.Address(), new(big.Int), 0, new(big.Int).SetUint64(10000000), nil), signer, key)
   106  		return tx, err
   107  	}
   108  	var txs types.Transactions
   109  	for i := uint64(0); i < num; i++ {
   110  		tx, err := newTx(i)
   111  		if err != nil {
   112  			return nil, err
   113  		}
   114  		txs = append(txs, tx)
   115  	}
   116  	return txs, nil
   117  }
   118  
   119  func TestDeriveSha(t *testing.T) {
   120  	txs, err := genTxs(0)
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	for len(txs) < 1000 {
   125  		exp := types.DeriveSha(txs, newEmpty())
   126  		got := types.DeriveSha(txs, NewStackTrie(nil))
   127  		if !bytes.Equal(got[:], exp[:]) {
   128  			t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp)
   129  		}
   130  		newTxs, err := genTxs(uint64(len(txs) + 1))
   131  		if err != nil {
   132  			t.Fatal(err)
   133  		}
   134  		txs = append(txs, newTxs...)
   135  	}
   136  }
   137  
   138  func BenchmarkDeriveSha200(b *testing.B) {
   139  	txs, err := genTxs(200)
   140  	if err != nil {
   141  		b.Fatal(err)
   142  	}
   143  	var exp common.Hash
   144  	var got common.Hash
   145  	b.Run("std_trie", func(b *testing.B) {
   146  		b.ResetTimer()
   147  		b.ReportAllocs()
   148  		for i := 0; i < b.N; i++ {
   149  			exp = types.DeriveSha(txs, newEmpty())
   150  		}
   151  	})
   152  
   153  	b.Run("stack_trie", func(b *testing.B) {
   154  		b.ResetTimer()
   155  		b.ReportAllocs()
   156  		for i := 0; i < b.N; i++ {
   157  			got = types.DeriveSha(txs, NewStackTrie(nil))
   158  		}
   159  	})
   160  	if got != exp {
   161  		b.Errorf("got %x exp %x", got, exp)
   162  	}
   163  }
   164  
   165  type dummyDerivableList struct {
   166  	len  int
   167  	seed int
   168  }
   169  
   170  func newDummy(seed int) *dummyDerivableList {
   171  	d := &dummyDerivableList{}
   172  	src := mrand.NewSource(int64(seed))
   173  	// don't use lists longer than 4K items
   174  	d.len = int(src.Int63() & 0x0FFF)
   175  	d.seed = seed
   176  	return d
   177  }
   178  
   179  func (d *dummyDerivableList) Len() int {
   180  	return d.len
   181  }
   182  
   183  func (d *dummyDerivableList) GetRlp(i int) []byte {
   184  	src := mrand.NewSource(int64(d.seed + i))
   185  	// max item size 256, at least 1 byte per item
   186  	size := 1 + src.Int63()&0x00FF
   187  	data := make([]byte, size)
   188  	_, err := mrand.New(src).Read(data)
   189  	if err != nil {
   190  		panic(err)
   191  	}
   192  	return data
   193  }
   194  
   195  func printList(l types.DerivableList) {
   196  	fmt.Printf("list length: %d\n", l.Len())
   197  	fmt.Printf("{\n")
   198  	for i := 0; i < l.Len(); i++ {
   199  		v := l.GetRlp(i)
   200  		fmt.Printf("\"0x%x\",\n", v)
   201  	}
   202  	fmt.Printf("},\n")
   203  }
   204  
   205  func TestFuzzDeriveSha(t *testing.T) {
   206  	// increase this for longer runs -- it's set to quite low for travis
   207  	rndSeed := mrand.Int()
   208  	for i := 0; i < 10; i++ {
   209  		seed := rndSeed + i
   210  		exp := types.DeriveSha(newDummy(i), newEmpty())
   211  		got := types.DeriveSha(newDummy(i), NewStackTrie(nil))
   212  		if !bytes.Equal(got[:], exp[:]) {
   213  			printList(newDummy(seed))
   214  			t.Fatalf("seed %d: got %x exp %x", seed, got, exp)
   215  		}
   216  	}
   217  }
   218  
   219  type flatList struct {
   220  	rlpvals []string
   221  }
   222  
   223  func newFlatList(rlpvals []string) *flatList {
   224  	return &flatList{rlpvals}
   225  }
   226  func (f *flatList) Len() int {
   227  	return len(f.rlpvals)
   228  }
   229  func (f *flatList) GetRlp(i int) []byte {
   230  	return hexutil.MustDecode(f.rlpvals[i])
   231  }
   232  
   233  // TestDerivableList contains testcases found via fuzzing
   234  func TestDerivableList(t *testing.T) {
   235  	type tcase []string
   236  	tcs := []tcase{
   237  		{
   238  			"0xc041",
   239  		},
   240  		{
   241  			"0xf04cf757812428b0763112efb33b6f4fad7deb445e",
   242  			"0xf04cf757812428b0763112efb33b6f4fad7deb445e",
   243  		},
   244  		{
   245  			"0xca410605310cdc3bb8d4977ae4f0143df54a724ed873457e2272f39d66e0460e971d9d",
   246  			"0x6cd850eca0a7ac46bb1748d7b9cb88aa3bd21c57d852c28198ad8fa422c4595032e88a4494b4778b36b944fe47a52b8c5cd312910139dfcb4147ab8e972cc456bcb063f25dd78f54c4d34679e03142c42c662af52947d45bdb6e555751334ace76a5080ab5a0256a1d259855dfc5c0b8023b25befbb13fd3684f9f755cbd3d63544c78ee2001452dd54633a7593ade0b183891a0a4e9c7844e1254005fbe592b1b89149a502c24b6e1dca44c158aebedf01beae9c30cabe16a",
   247  			"0x14abd5c47c0be87b0454596baad2",
   248  			"0xca410605310cdc3bb8d4977ae4f0143df54a724ed873457e2272f39d66e0460e971d9d",
   249  		},
   250  	}
   251  	for i, tc := range tcs[1:] {
   252  		exp := types.DeriveSha(newFlatList(tc), newEmpty())
   253  		got := types.DeriveSha(newFlatList(tc), NewStackTrie(nil))
   254  		if !bytes.Equal(got[:], exp[:]) {
   255  			t.Fatalf("case %d: got %x exp %x", i, got, exp)
   256  		}
   257  	}
   258  }
   259  
   260  // TestUpdateSmallNodes tests a case where the leaves are small (both key and value),
   261  // which causes a lot of node-within-node. This case was found via fuzzing.
   262  func TestUpdateSmallNodes(t *testing.T) {
   263  	st := NewStackTrie(nil)
   264  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
   265  	kvs := []struct {
   266  		K string
   267  		V string
   268  	}{
   269  		{"63303030", "3041"}, // stacktrie.Update
   270  		{"65", "3000"},       // stacktrie.Update
   271  	}
   272  	for _, kv := range kvs {
   273  		nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
   274  		st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
   275  	}
   276  	if nt.Hash() != st.Hash() {
   277  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
   278  	}
   279  }
   280  
   281  // TestUpdateVariableKeys contains a case which stacktrie fails: when keys of different
   282  // sizes are used, and the second one has the same prefix as the first, then the
   283  // stacktrie fails, since it's unable to 'expand' on an already added leaf.
   284  // For all practical purposes, this is fine, since keys are fixed-size length
   285  // in account and storage tries.
   286  //
   287  // The test is marked as 'skipped', and exists just to have the behaviour documented.
   288  // This case was found via fuzzing.
   289  func TestUpdateVariableKeys(t *testing.T) {
   290  	t.SkipNow()
   291  	st := NewStackTrie(nil)
   292  	nt, _ := New(common.Hash{}, NewDatabase(memorydb.New()))
   293  	kvs := []struct {
   294  		K string
   295  		V string
   296  	}{
   297  		{"0x33303534636532393561313031676174", "303030"},
   298  		{"0x3330353463653239356131303167617430", "313131"},
   299  	}
   300  	for _, kv := range kvs {
   301  		nt.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
   302  		st.TryUpdate(common.FromHex(kv.K), common.FromHex(kv.V))
   303  	}
   304  	if nt.Hash() != st.Hash() {
   305  		t.Fatalf("error %x != %x", st.Hash(), nt.Hash())
   306  	}
   307  }