github.com/CommerciumBlockchain/go-commercium@v0.0.0-20220709212705-b46438a77516/trie/stacktrie_test.go (about)

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