github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/core/types/hashing_test.go (about)

     1  // Copyright 2021 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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-ethereum 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-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types_test
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"math/big"
    24  	mrand "math/rand"
    25  	"testing"
    26  
    27  	"github.com/ethw3/go-ethereuma/common"
    28  	"github.com/ethw3/go-ethereuma/common/hexutil"
    29  	"github.com/ethw3/go-ethereuma/core/rawdb"
    30  	"github.com/ethw3/go-ethereuma/core/types"
    31  	"github.com/ethw3/go-ethereuma/crypto"
    32  	"github.com/ethw3/go-ethereuma/rlp"
    33  	"github.com/ethw3/go-ethereuma/trie"
    34  )
    35  
    36  func TestDeriveSha(t *testing.T) {
    37  	txs, err := genTxs(0)
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	for len(txs) < 1000 {
    42  		exp := types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())))
    43  		got := types.DeriveSha(txs, trie.NewStackTrie(nil))
    44  		if !bytes.Equal(got[:], exp[:]) {
    45  			t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp)
    46  		}
    47  		newTxs, err := genTxs(uint64(len(txs) + 1))
    48  		if err != nil {
    49  			t.Fatal(err)
    50  		}
    51  		txs = append(txs, newTxs...)
    52  	}
    53  }
    54  
    55  // TestEIP2718DeriveSha tests that the input to the DeriveSha function is correct.
    56  func TestEIP2718DeriveSha(t *testing.T) {
    57  	for _, tc := range []struct {
    58  		rlpData string
    59  		exp     string
    60  	}{
    61  		{
    62  			rlpData: "0xb8a701f8a486796f6c6f763380843b9aca008262d4948a8eafb1cf62bfbeb1741769dae1a9dd479961928080f838f7940000000000000000000000000000000000001337e1a0000000000000000000000000000000000000000000000000000000000000000080a0775101f92dcca278a56bfe4d613428624a1ebfc3cd9e0bcc1de80c41455b9021a06c9deac205afe7b124907d4ba54a9f46161498bd3990b90d175aac12c9a40ee9",
    63  			exp:     "01 01f8a486796f6c6f763380843b9aca008262d4948a8eafb1cf62bfbeb1741769dae1a9dd479961928080f838f7940000000000000000000000000000000000001337e1a0000000000000000000000000000000000000000000000000000000000000000080a0775101f92dcca278a56bfe4d613428624a1ebfc3cd9e0bcc1de80c41455b9021a06c9deac205afe7b124907d4ba54a9f46161498bd3990b90d175aac12c9a40ee9\n80 01f8a486796f6c6f763380843b9aca008262d4948a8eafb1cf62bfbeb1741769dae1a9dd479961928080f838f7940000000000000000000000000000000000001337e1a0000000000000000000000000000000000000000000000000000000000000000080a0775101f92dcca278a56bfe4d613428624a1ebfc3cd9e0bcc1de80c41455b9021a06c9deac205afe7b124907d4ba54a9f46161498bd3990b90d175aac12c9a40ee9\n",
    64  		},
    65  	} {
    66  		d := &hashToHumanReadable{}
    67  		var t1, t2 types.Transaction
    68  		rlp.DecodeBytes(common.FromHex(tc.rlpData), &t1)
    69  		rlp.DecodeBytes(common.FromHex(tc.rlpData), &t2)
    70  		txs := types.Transactions{&t1, &t2}
    71  		types.DeriveSha(txs, d)
    72  		if tc.exp != string(d.data) {
    73  			t.Fatalf("Want\n%v\nhave:\n%v", tc.exp, string(d.data))
    74  		}
    75  	}
    76  }
    77  
    78  func BenchmarkDeriveSha200(b *testing.B) {
    79  	txs, err := genTxs(200)
    80  	if err != nil {
    81  		b.Fatal(err)
    82  	}
    83  	var exp common.Hash
    84  	var got common.Hash
    85  	b.Run("std_trie", func(b *testing.B) {
    86  		b.ResetTimer()
    87  		b.ReportAllocs()
    88  		for i := 0; i < b.N; i++ {
    89  			exp = types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())))
    90  		}
    91  	})
    92  
    93  	b.Run("stack_trie", func(b *testing.B) {
    94  		b.ResetTimer()
    95  		b.ReportAllocs()
    96  		for i := 0; i < b.N; i++ {
    97  			got = types.DeriveSha(txs, trie.NewStackTrie(nil))
    98  		}
    99  	})
   100  	if got != exp {
   101  		b.Errorf("got %x exp %x", got, exp)
   102  	}
   103  }
   104  
   105  func TestFuzzDeriveSha(t *testing.T) {
   106  	// increase this for longer runs -- it's set to quite low for travis
   107  	rndSeed := mrand.Int()
   108  	for i := 0; i < 10; i++ {
   109  		seed := rndSeed + i
   110  		exp := types.DeriveSha(newDummy(i), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())))
   111  		got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil))
   112  		if !bytes.Equal(got[:], exp[:]) {
   113  			printList(newDummy(seed))
   114  			t.Fatalf("seed %d: got %x exp %x", seed, got, exp)
   115  		}
   116  	}
   117  }
   118  
   119  // TestDerivableList contains testcases found via fuzzing
   120  func TestDerivableList(t *testing.T) {
   121  	type tcase []string
   122  	tcs := []tcase{
   123  		{
   124  			"0xc041",
   125  		},
   126  		{
   127  			"0xf04cf757812428b0763112efb33b6f4fad7deb445e",
   128  			"0xf04cf757812428b0763112efb33b6f4fad7deb445e",
   129  		},
   130  		{
   131  			"0xca410605310cdc3bb8d4977ae4f0143df54a724ed873457e2272f39d66e0460e971d9d",
   132  			"0x6cd850eca0a7ac46bb1748d7b9cb88aa3bd21c57d852c28198ad8fa422c4595032e88a4494b4778b36b944fe47a52b8c5cd312910139dfcb4147ab8e972cc456bcb063f25dd78f54c4d34679e03142c42c662af52947d45bdb6e555751334ace76a5080ab5a0256a1d259855dfc5c0b8023b25befbb13fd3684f9f755cbd3d63544c78ee2001452dd54633a7593ade0b183891a0a4e9c7844e1254005fbe592b1b89149a502c24b6e1dca44c158aebedf01beae9c30cabe16a",
   133  			"0x14abd5c47c0be87b0454596baad2",
   134  			"0xca410605310cdc3bb8d4977ae4f0143df54a724ed873457e2272f39d66e0460e971d9d",
   135  		},
   136  	}
   137  	for i, tc := range tcs[1:] {
   138  		exp := types.DeriveSha(flatList(tc), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())))
   139  		got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil))
   140  		if !bytes.Equal(got[:], exp[:]) {
   141  			t.Fatalf("case %d: got %x exp %x", i, got, exp)
   142  		}
   143  	}
   144  }
   145  
   146  func genTxs(num uint64) (types.Transactions, error) {
   147  	key, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	var addr = crypto.PubkeyToAddress(key.PublicKey)
   152  	newTx := func(i uint64) (*types.Transaction, error) {
   153  		signer := types.NewEIP155Signer(big.NewInt(18))
   154  		utx := types.NewTransaction(i, addr, new(big.Int), 0, new(big.Int).SetUint64(10000000), nil)
   155  		tx, err := types.SignTx(utx, signer, key)
   156  		return tx, err
   157  	}
   158  	var txs types.Transactions
   159  	for i := uint64(0); i < num; i++ {
   160  		tx, err := newTx(i)
   161  		if err != nil {
   162  			return nil, err
   163  		}
   164  		txs = append(txs, tx)
   165  	}
   166  	return txs, nil
   167  }
   168  
   169  type dummyDerivableList struct {
   170  	len  int
   171  	seed int
   172  }
   173  
   174  func newDummy(seed int) *dummyDerivableList {
   175  	d := &dummyDerivableList{}
   176  	src := mrand.NewSource(int64(seed))
   177  	// don't use lists longer than 4K items
   178  	d.len = int(src.Int63() & 0x0FFF)
   179  	d.seed = seed
   180  	return d
   181  }
   182  
   183  func (d *dummyDerivableList) Len() int {
   184  	return d.len
   185  }
   186  
   187  func (d *dummyDerivableList) EncodeIndex(i int, w *bytes.Buffer) {
   188  	src := mrand.NewSource(int64(d.seed + i))
   189  	// max item size 256, at least 1 byte per item
   190  	size := 1 + src.Int63()&0x00FF
   191  	io.CopyN(w, mrand.New(src), size)
   192  }
   193  
   194  func printList(l types.DerivableList) {
   195  	fmt.Printf("list length: %d\n", l.Len())
   196  	fmt.Printf("{\n")
   197  	for i := 0; i < l.Len(); i++ {
   198  		var buf bytes.Buffer
   199  		l.EncodeIndex(i, &buf)
   200  		fmt.Printf("\"%#x\",\n", buf.Bytes())
   201  	}
   202  	fmt.Printf("},\n")
   203  }
   204  
   205  type flatList []string
   206  
   207  func (f flatList) Len() int {
   208  	return len(f)
   209  }
   210  func (f flatList) EncodeIndex(i int, w *bytes.Buffer) {
   211  	w.Write(hexutil.MustDecode(f[i]))
   212  }
   213  
   214  type hashToHumanReadable struct {
   215  	data []byte
   216  }
   217  
   218  func (d *hashToHumanReadable) Reset() {
   219  	d.data = make([]byte, 0)
   220  }
   221  
   222  func (d *hashToHumanReadable) Update(i []byte, i2 []byte) {
   223  	l := fmt.Sprintf("%x %x\n", i, i2)
   224  	d.data = append(d.data, []byte(l)...)
   225  }
   226  
   227  func (d *hashToHumanReadable) Hash() common.Hash {
   228  	return common.Hash{}
   229  }