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 }