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 }