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 }