github.com/tacshi/go-ethereum@v0.0.0-20230616113857-84a434e20921/trie/trie_test.go (about) 1 // Copyright 2014 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 trie 18 19 import ( 20 "bytes" 21 crand "crypto/rand" 22 "encoding/binary" 23 "errors" 24 "fmt" 25 "hash" 26 "math/big" 27 "math/rand" 28 "reflect" 29 "testing" 30 "testing/quick" 31 32 "github.com/davecgh/go-spew/spew" 33 "github.com/tacshi/go-ethereum/common" 34 "github.com/tacshi/go-ethereum/core/rawdb" 35 "github.com/tacshi/go-ethereum/core/types" 36 "github.com/tacshi/go-ethereum/crypto" 37 "github.com/tacshi/go-ethereum/ethdb" 38 "github.com/tacshi/go-ethereum/rlp" 39 "golang.org/x/crypto/sha3" 40 ) 41 42 func init() { 43 spew.Config.Indent = " " 44 spew.Config.DisableMethods = false 45 } 46 47 func TestEmptyTrie(t *testing.T) { 48 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 49 res := trie.Hash() 50 exp := types.EmptyRootHash 51 if res != exp { 52 t.Errorf("expected %x got %x", exp, res) 53 } 54 } 55 56 func TestNull(t *testing.T) { 57 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 58 key := make([]byte, 32) 59 value := []byte("test") 60 trie.Update(key, value) 61 if !bytes.Equal(trie.Get(key), value) { 62 t.Fatal("wrong value") 63 } 64 } 65 66 func TestMissingRoot(t *testing.T) { 67 root := common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") 68 trie, err := New(TrieID(root), NewDatabase(rawdb.NewMemoryDatabase())) 69 if trie != nil { 70 t.Error("New returned non-nil trie for invalid root") 71 } 72 if _, ok := err.(*MissingNodeError); !ok { 73 t.Errorf("New returned wrong error: %v", err) 74 } 75 } 76 77 func TestMissingNodeDisk(t *testing.T) { testMissingNode(t, false) } 78 func TestMissingNodeMemonly(t *testing.T) { testMissingNode(t, true) } 79 80 func testMissingNode(t *testing.T, memonly bool) { 81 diskdb := rawdb.NewMemoryDatabase() 82 triedb := NewDatabase(diskdb) 83 84 trie := NewEmpty(triedb) 85 updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") 86 updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") 87 root, nodes := trie.Commit(false) 88 triedb.Update(NewWithNodeSet(nodes)) 89 if !memonly { 90 triedb.Commit(root, false) 91 } 92 93 trie, _ = New(TrieID(root), triedb) 94 _, err := trie.TryGet([]byte("120000")) 95 if err != nil { 96 t.Errorf("Unexpected error: %v", err) 97 } 98 trie, _ = New(TrieID(root), triedb) 99 _, err = trie.TryGet([]byte("120099")) 100 if err != nil { 101 t.Errorf("Unexpected error: %v", err) 102 } 103 trie, _ = New(TrieID(root), triedb) 104 _, err = trie.TryGet([]byte("123456")) 105 if err != nil { 106 t.Errorf("Unexpected error: %v", err) 107 } 108 trie, _ = New(TrieID(root), triedb) 109 err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) 110 if err != nil { 111 t.Errorf("Unexpected error: %v", err) 112 } 113 trie, _ = New(TrieID(root), triedb) 114 err = trie.TryDelete([]byte("123456")) 115 if err != nil { 116 t.Errorf("Unexpected error: %v", err) 117 } 118 119 hash := common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9") 120 if memonly { 121 delete(triedb.dirties, hash) 122 } else { 123 diskdb.Delete(hash[:]) 124 } 125 126 trie, _ = New(TrieID(root), triedb) 127 _, err = trie.TryGet([]byte("120000")) 128 if _, ok := err.(*MissingNodeError); !ok { 129 t.Errorf("Wrong error: %v", err) 130 } 131 trie, _ = New(TrieID(root), triedb) 132 _, err = trie.TryGet([]byte("120099")) 133 if _, ok := err.(*MissingNodeError); !ok { 134 t.Errorf("Wrong error: %v", err) 135 } 136 trie, _ = New(TrieID(root), triedb) 137 _, err = trie.TryGet([]byte("123456")) 138 if err != nil { 139 t.Errorf("Unexpected error: %v", err) 140 } 141 trie, _ = New(TrieID(root), triedb) 142 err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) 143 if _, ok := err.(*MissingNodeError); !ok { 144 t.Errorf("Wrong error: %v", err) 145 } 146 trie, _ = New(TrieID(root), triedb) 147 err = trie.TryDelete([]byte("123456")) 148 if _, ok := err.(*MissingNodeError); !ok { 149 t.Errorf("Wrong error: %v", err) 150 } 151 } 152 153 func TestInsert(t *testing.T) { 154 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 155 156 updateString(trie, "doe", "reindeer") 157 updateString(trie, "dog", "puppy") 158 updateString(trie, "dogglesworth", "cat") 159 160 exp := common.HexToHash("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3") 161 root := trie.Hash() 162 if root != exp { 163 t.Errorf("case 1: exp %x got %x", exp, root) 164 } 165 166 trie = NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 167 updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") 168 169 exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") 170 root, _ = trie.Commit(false) 171 if root != exp { 172 t.Errorf("case 2: exp %x got %x", exp, root) 173 } 174 } 175 176 func TestGet(t *testing.T) { 177 db := NewDatabase(rawdb.NewMemoryDatabase()) 178 trie := NewEmpty(db) 179 updateString(trie, "doe", "reindeer") 180 updateString(trie, "dog", "puppy") 181 updateString(trie, "dogglesworth", "cat") 182 183 for i := 0; i < 2; i++ { 184 res := getString(trie, "dog") 185 if !bytes.Equal(res, []byte("puppy")) { 186 t.Errorf("expected puppy got %x", res) 187 } 188 unknown := getString(trie, "unknown") 189 if unknown != nil { 190 t.Errorf("expected nil got %x", unknown) 191 } 192 if i == 1 { 193 return 194 } 195 root, nodes := trie.Commit(false) 196 db.Update(NewWithNodeSet(nodes)) 197 trie, _ = New(TrieID(root), db) 198 } 199 } 200 201 func TestDelete(t *testing.T) { 202 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 203 vals := []struct{ k, v string }{ 204 {"do", "verb"}, 205 {"ether", "wookiedoo"}, 206 {"horse", "stallion"}, 207 {"shaman", "horse"}, 208 {"doge", "coin"}, 209 {"ether", ""}, 210 {"dog", "puppy"}, 211 {"shaman", ""}, 212 } 213 for _, val := range vals { 214 if val.v != "" { 215 updateString(trie, val.k, val.v) 216 } else { 217 deleteString(trie, val.k) 218 } 219 } 220 221 hash := trie.Hash() 222 exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") 223 if hash != exp { 224 t.Errorf("expected %x got %x", exp, hash) 225 } 226 } 227 228 func TestEmptyValues(t *testing.T) { 229 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 230 231 vals := []struct{ k, v string }{ 232 {"do", "verb"}, 233 {"ether", "wookiedoo"}, 234 {"horse", "stallion"}, 235 {"shaman", "horse"}, 236 {"doge", "coin"}, 237 {"ether", ""}, 238 {"dog", "puppy"}, 239 {"shaman", ""}, 240 } 241 for _, val := range vals { 242 updateString(trie, val.k, val.v) 243 } 244 245 hash := trie.Hash() 246 exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") 247 if hash != exp { 248 t.Errorf("expected %x got %x", exp, hash) 249 } 250 } 251 252 func TestReplication(t *testing.T) { 253 triedb := NewDatabase(rawdb.NewMemoryDatabase()) 254 trie := NewEmpty(triedb) 255 vals := []struct{ k, v string }{ 256 {"do", "verb"}, 257 {"ether", "wookiedoo"}, 258 {"horse", "stallion"}, 259 {"shaman", "horse"}, 260 {"doge", "coin"}, 261 {"dog", "puppy"}, 262 {"somethingveryoddindeedthis is", "myothernodedata"}, 263 } 264 for _, val := range vals { 265 updateString(trie, val.k, val.v) 266 } 267 exp, nodes := trie.Commit(false) 268 triedb.Update(NewWithNodeSet(nodes)) 269 270 // create a new trie on top of the database and check that lookups work. 271 trie2, err := New(TrieID(exp), triedb) 272 if err != nil { 273 t.Fatalf("can't recreate trie at %x: %v", exp, err) 274 } 275 for _, kv := range vals { 276 if string(getString(trie2, kv.k)) != kv.v { 277 t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) 278 } 279 } 280 hash, nodes := trie2.Commit(false) 281 if hash != exp { 282 t.Errorf("root failure. expected %x got %x", exp, hash) 283 } 284 285 // recreate the trie after commit 286 if nodes != nil { 287 triedb.Update(NewWithNodeSet(nodes)) 288 } 289 trie2, err = New(TrieID(hash), triedb) 290 if err != nil { 291 t.Fatalf("can't recreate trie at %x: %v", exp, err) 292 } 293 // perform some insertions on the new trie. 294 vals2 := []struct{ k, v string }{ 295 {"do", "verb"}, 296 {"ether", "wookiedoo"}, 297 {"horse", "stallion"}, 298 // {"shaman", "horse"}, 299 // {"doge", "coin"}, 300 // {"ether", ""}, 301 // {"dog", "puppy"}, 302 // {"somethingveryoddindeedthis is", "myothernodedata"}, 303 // {"shaman", ""}, 304 } 305 for _, val := range vals2 { 306 updateString(trie2, val.k, val.v) 307 } 308 if hash := trie2.Hash(); hash != exp { 309 t.Errorf("root failure. expected %x got %x", exp, hash) 310 } 311 } 312 313 func TestLargeValue(t *testing.T) { 314 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 315 trie.Update([]byte("key1"), []byte{99, 99, 99, 99}) 316 trie.Update([]byte("key2"), bytes.Repeat([]byte{1}, 32)) 317 trie.Hash() 318 } 319 320 // TestRandomCases tests som cases that were found via random fuzzing 321 func TestRandomCases(t *testing.T) { 322 var rt = []randTestStep{ 323 {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 0 324 {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 1 325 {op: 0, key: common.Hex2Bytes("d51b182b95d677e5f1c82508c0228de96b73092d78ce78b2230cd948674f66fd1483bd"), value: common.Hex2Bytes("0000000000000002")}, // step 2 326 {op: 2, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("")}, // step 3 327 {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 4 328 {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 5 329 {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 6 330 {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 7 331 {op: 0, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("0000000000000008")}, // step 8 332 {op: 0, key: common.Hex2Bytes("d51b182b95d677e5f1c82508c0228de96b73092d78ce78b2230cd948674f66fd1483bd"), value: common.Hex2Bytes("0000000000000009")}, // step 9 333 {op: 2, key: common.Hex2Bytes("fd"), value: common.Hex2Bytes("")}, // step 10 334 {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 11 335 {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 12 336 {op: 0, key: common.Hex2Bytes("fd"), value: common.Hex2Bytes("000000000000000d")}, // step 13 337 {op: 6, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 14 338 {op: 1, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("")}, // step 15 339 {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 16 340 {op: 0, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("0000000000000011")}, // step 17 341 {op: 5, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 18 342 {op: 3, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 19 343 {op: 0, key: common.Hex2Bytes("d51b182b95d677e5f1c82508c0228de96b73092d78ce78b2230cd948674f66fd1483bd"), value: common.Hex2Bytes("0000000000000014")}, // step 20 344 {op: 0, key: common.Hex2Bytes("d51b182b95d677e5f1c82508c0228de96b73092d78ce78b2230cd948674f66fd1483bd"), value: common.Hex2Bytes("0000000000000015")}, // step 21 345 {op: 0, key: common.Hex2Bytes("c2a38512b83107d665c65235b0250002882ac2022eb00711552354832c5f1d030d0e408e"), value: common.Hex2Bytes("0000000000000016")}, // step 22 346 {op: 5, key: common.Hex2Bytes(""), value: common.Hex2Bytes("")}, // step 23 347 {op: 1, key: common.Hex2Bytes("980c393656413a15c8da01978ed9f89feb80b502f58f2d640e3a2f5f7a99a7018f1b573befd92053ac6f78fca4a87268"), value: common.Hex2Bytes("")}, // step 24 348 {op: 1, key: common.Hex2Bytes("fd"), value: common.Hex2Bytes("")}, // step 25 349 } 350 runRandTest(rt) 351 } 352 353 // randTest performs random trie operations. 354 // Instances of this test are created by Generate. 355 type randTest []randTestStep 356 357 type randTestStep struct { 358 op int 359 key []byte // for opUpdate, opDelete, opGet 360 value []byte // for opUpdate 361 err error // for debugging 362 } 363 364 const ( 365 opUpdate = iota 366 opDelete 367 opGet 368 opHash 369 opCommit 370 opItercheckhash 371 opNodeDiff 372 opProve 373 opMax // boundary value, not an actual op 374 ) 375 376 func (randTest) Generate(r *rand.Rand, size int) reflect.Value { 377 var allKeys [][]byte 378 genKey := func() []byte { 379 if len(allKeys) < 2 || r.Intn(100) < 10 { 380 // new key 381 key := make([]byte, r.Intn(50)) 382 r.Read(key) 383 allKeys = append(allKeys, key) 384 return key 385 } 386 // use existing key 387 return allKeys[r.Intn(len(allKeys))] 388 } 389 390 var steps randTest 391 for i := 0; i < size; i++ { 392 step := randTestStep{op: r.Intn(opMax)} 393 switch step.op { 394 case opUpdate: 395 step.key = genKey() 396 step.value = make([]byte, 8) 397 binary.BigEndian.PutUint64(step.value, uint64(i)) 398 case opGet, opDelete, opProve: 399 step.key = genKey() 400 } 401 steps = append(steps, step) 402 } 403 return reflect.ValueOf(steps) 404 } 405 406 func runRandTest(rt randTest) bool { 407 var ( 408 triedb = NewDatabase(rawdb.NewMemoryDatabase()) 409 tr = NewEmpty(triedb) 410 values = make(map[string]string) // tracks content of the trie 411 origTrie = NewEmpty(triedb) 412 ) 413 tr.tracer = newTracer() 414 415 for i, step := range rt { 416 // fmt.Printf("{op: %d, key: common.Hex2Bytes(\"%x\"), value: common.Hex2Bytes(\"%x\")}, // step %d\n", 417 // step.op, step.key, step.value, i) 418 419 switch step.op { 420 case opUpdate: 421 tr.Update(step.key, step.value) 422 values[string(step.key)] = string(step.value) 423 case opDelete: 424 tr.Delete(step.key) 425 delete(values, string(step.key)) 426 case opGet: 427 v := tr.Get(step.key) 428 want := values[string(step.key)] 429 if string(v) != want { 430 rt[i].err = fmt.Errorf("mismatch for key %#x, got %#x want %#x", step.key, v, want) 431 } 432 case opProve: 433 hash := tr.Hash() 434 if hash == types.EmptyRootHash { 435 continue 436 } 437 proofDb := rawdb.NewMemoryDatabase() 438 err := tr.Prove(step.key, 0, proofDb) 439 if err != nil { 440 rt[i].err = fmt.Errorf("failed for proving key %#x, %v", step.key, err) 441 } 442 _, err = VerifyProof(hash, step.key, proofDb) 443 if err != nil { 444 rt[i].err = fmt.Errorf("failed for verifying key %#x, %v", step.key, err) 445 } 446 case opHash: 447 tr.Hash() 448 case opCommit: 449 root, nodes := tr.Commit(true) 450 // Validity the returned nodeset 451 if nodes != nil { 452 for path, node := range nodes.updates.nodes { 453 blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) 454 got := node.prev 455 if !bytes.Equal(blob, got) { 456 rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, got, blob) 457 panic(rt[i].err) 458 } 459 } 460 for path, prev := range nodes.deletes { 461 blob, _, _ := origTrie.TryGetNode(hexToCompact([]byte(path))) 462 if !bytes.Equal(blob, prev) { 463 rt[i].err = fmt.Errorf("prevalue mismatch for 0x%x, got 0x%x want 0x%x", path, prev, blob) 464 return false 465 } 466 } 467 } 468 if nodes != nil { 469 triedb.Update(NewWithNodeSet(nodes)) 470 } 471 newtr, err := New(TrieID(root), triedb) 472 if err != nil { 473 rt[i].err = err 474 return false 475 } 476 tr = newtr 477 478 // Enable node tracing. Resolve the root node again explicitly 479 // since it's not captured at the beginning. 480 tr.tracer = newTracer() 481 tr.resolveAndTrack(root.Bytes(), nil) 482 483 origTrie = tr.Copy() 484 case opItercheckhash: 485 checktr := NewEmpty(triedb) 486 it := NewIterator(tr.NodeIterator(nil)) 487 for it.Next() { 488 checktr.Update(it.Key, it.Value) 489 } 490 if tr.Hash() != checktr.Hash() { 491 rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") 492 } 493 case opNodeDiff: 494 var ( 495 inserted = tr.tracer.insertList() 496 deleted = tr.tracer.deleteList() 497 origIter = origTrie.NodeIterator(nil) 498 curIter = tr.NodeIterator(nil) 499 origSeen = make(map[string]struct{}) 500 curSeen = make(map[string]struct{}) 501 ) 502 for origIter.Next(true) { 503 if origIter.Leaf() { 504 continue 505 } 506 origSeen[string(origIter.Path())] = struct{}{} 507 } 508 for curIter.Next(true) { 509 if curIter.Leaf() { 510 continue 511 } 512 curSeen[string(curIter.Path())] = struct{}{} 513 } 514 var ( 515 insertExp = make(map[string]struct{}) 516 deleteExp = make(map[string]struct{}) 517 ) 518 for path := range curSeen { 519 _, present := origSeen[path] 520 if !present { 521 insertExp[path] = struct{}{} 522 } 523 } 524 for path := range origSeen { 525 _, present := curSeen[path] 526 if !present { 527 deleteExp[path] = struct{}{} 528 } 529 } 530 if len(insertExp) != len(inserted) { 531 rt[i].err = fmt.Errorf("insert set mismatch") 532 } 533 if len(deleteExp) != len(deleted) { 534 rt[i].err = fmt.Errorf("delete set mismatch") 535 } 536 for _, insert := range inserted { 537 if _, present := insertExp[string(insert)]; !present { 538 rt[i].err = fmt.Errorf("missing inserted node") 539 } 540 } 541 for _, del := range deleted { 542 if _, present := deleteExp[string(del)]; !present { 543 rt[i].err = fmt.Errorf("missing deleted node") 544 } 545 } 546 } 547 // Abort the test on error. 548 if rt[i].err != nil { 549 return false 550 } 551 } 552 return true 553 } 554 555 func TestRandom(t *testing.T) { 556 if err := quick.Check(runRandTest, nil); err != nil { 557 if cerr, ok := err.(*quick.CheckError); ok { 558 t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In)) 559 } 560 t.Fatal(err) 561 } 562 } 563 564 func BenchmarkGet(b *testing.B) { benchGet(b) } 565 func BenchmarkUpdateBE(b *testing.B) { benchUpdate(b, binary.BigEndian) } 566 func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } 567 568 const benchElemCount = 20000 569 570 func benchGet(b *testing.B) { 571 triedb := NewDatabase(rawdb.NewMemoryDatabase()) 572 trie := NewEmpty(triedb) 573 k := make([]byte, 32) 574 for i := 0; i < benchElemCount; i++ { 575 binary.LittleEndian.PutUint64(k, uint64(i)) 576 trie.Update(k, k) 577 } 578 binary.LittleEndian.PutUint64(k, benchElemCount/2) 579 580 b.ResetTimer() 581 for i := 0; i < b.N; i++ { 582 trie.Get(k) 583 } 584 b.StopTimer() 585 } 586 587 func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { 588 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 589 k := make([]byte, 32) 590 b.ReportAllocs() 591 for i := 0; i < b.N; i++ { 592 e.PutUint64(k, uint64(i)) 593 trie.Update(k, k) 594 } 595 return trie 596 } 597 598 // Benchmarks the trie hashing. Since the trie caches the result of any operation, 599 // we cannot use b.N as the number of hashing rounds, since all rounds apart from 600 // the first one will be NOOP. As such, we'll use b.N as the number of account to 601 // insert into the trie before measuring the hashing. 602 // BenchmarkHash-6 288680 4561 ns/op 682 B/op 9 allocs/op 603 // BenchmarkHash-6 275095 4800 ns/op 685 B/op 9 allocs/op 604 // pure hasher: 605 // BenchmarkHash-6 319362 4230 ns/op 675 B/op 9 allocs/op 606 // BenchmarkHash-6 257460 4674 ns/op 689 B/op 9 allocs/op 607 // With hashing in-between and pure hasher: 608 // BenchmarkHash-6 225417 7150 ns/op 982 B/op 12 allocs/op 609 // BenchmarkHash-6 220378 6197 ns/op 983 B/op 12 allocs/op 610 // same with old hasher 611 // BenchmarkHash-6 229758 6437 ns/op 981 B/op 12 allocs/op 612 // BenchmarkHash-6 212610 7137 ns/op 986 B/op 12 allocs/op 613 func BenchmarkHash(b *testing.B) { 614 // Create a realistic account trie to hash. We're first adding and hashing N 615 // entries, then adding N more. 616 addresses, accounts := makeAccounts(2 * b.N) 617 // Insert the accounts into the trie and hash it 618 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 619 i := 0 620 for ; i < len(addresses)/2; i++ { 621 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 622 } 623 trie.Hash() 624 for ; i < len(addresses); i++ { 625 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 626 } 627 b.ResetTimer() 628 b.ReportAllocs() 629 //trie.hashRoot(nil, nil) 630 trie.Hash() 631 } 632 633 // Benchmarks the trie Commit following a Hash. Since the trie caches the result of any operation, 634 // we cannot use b.N as the number of hashing rounds, since all rounds apart from 635 // the first one will be NOOP. As such, we'll use b.N as the number of account to 636 // insert into the trie before measuring the hashing. 637 func BenchmarkCommitAfterHash(b *testing.B) { 638 b.Run("no-onleaf", func(b *testing.B) { 639 benchmarkCommitAfterHash(b, false) 640 }) 641 b.Run("with-onleaf", func(b *testing.B) { 642 benchmarkCommitAfterHash(b, true) 643 }) 644 } 645 646 func benchmarkCommitAfterHash(b *testing.B, collectLeaf bool) { 647 // Make the random benchmark deterministic 648 addresses, accounts := makeAccounts(b.N) 649 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 650 for i := 0; i < len(addresses); i++ { 651 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 652 } 653 // Insert the accounts into the trie and hash it 654 trie.Hash() 655 b.ResetTimer() 656 b.ReportAllocs() 657 trie.Commit(collectLeaf) 658 } 659 660 func TestTinyTrie(t *testing.T) { 661 // Create a realistic account trie to hash 662 _, accounts := makeAccounts(5) 663 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 664 trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3]) 665 if exp, root := common.HexToHash("8c6a85a4d9fda98feff88450299e574e5378e32391f75a055d470ac0653f1005"), trie.Hash(); exp != root { 666 t.Errorf("1: got %x, exp %x", root, exp) 667 } 668 trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001338"), accounts[4]) 669 if exp, root := common.HexToHash("ec63b967e98a5720e7f720482151963982890d82c9093c0d486b7eb8883a66b1"), trie.Hash(); exp != root { 670 t.Errorf("2: got %x, exp %x", root, exp) 671 } 672 trie.Update(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001339"), accounts[4]) 673 if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root { 674 t.Errorf("3: got %x, exp %x", root, exp) 675 } 676 checktr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 677 it := NewIterator(trie.NodeIterator(nil)) 678 for it.Next() { 679 checktr.Update(it.Key, it.Value) 680 } 681 if troot, itroot := trie.Hash(), checktr.Hash(); troot != itroot { 682 t.Fatalf("hash mismatch in opItercheckhash, trie: %x, check: %x", troot, itroot) 683 } 684 } 685 686 func TestCommitAfterHash(t *testing.T) { 687 // Create a realistic account trie to hash 688 addresses, accounts := makeAccounts(1000) 689 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 690 for i := 0; i < len(addresses); i++ { 691 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 692 } 693 // Insert the accounts into the trie and hash it 694 trie.Hash() 695 trie.Commit(false) 696 root := trie.Hash() 697 exp := common.HexToHash("72f9d3f3fe1e1dd7b8936442e7642aef76371472d94319900790053c493f3fe6") 698 if exp != root { 699 t.Errorf("got %x, exp %x", root, exp) 700 } 701 root, _ = trie.Commit(false) 702 if exp != root { 703 t.Errorf("got %x, exp %x", root, exp) 704 } 705 } 706 707 func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) { 708 // Make the random benchmark deterministic 709 random := rand.New(rand.NewSource(0)) 710 // Create a realistic account trie to hash 711 addresses = make([][20]byte, size) 712 for i := 0; i < len(addresses); i++ { 713 data := make([]byte, 20) 714 random.Read(data) 715 copy(addresses[i][:], data) 716 } 717 accounts = make([][]byte, len(addresses)) 718 for i := 0; i < len(accounts); i++ { 719 var ( 720 nonce = uint64(random.Int63()) 721 root = types.EmptyRootHash 722 code = crypto.Keccak256(nil) 723 ) 724 // The big.Rand function is not deterministic with regards to 64 vs 32 bit systems, 725 // and will consume different amount of data from the rand source. 726 //balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) 727 // Therefore, we instead just read via byte buffer 728 numBytes := random.Uint32() % 33 // [0, 32] bytes 729 balanceBytes := make([]byte, numBytes) 730 random.Read(balanceBytes) 731 balance := new(big.Int).SetBytes(balanceBytes) 732 data, _ := rlp.EncodeToBytes(&types.StateAccount{Nonce: nonce, Balance: balance, Root: root, CodeHash: code}) 733 accounts[i] = data 734 } 735 return addresses, accounts 736 } 737 738 // spongeDb is a dummy db backend which accumulates writes in a sponge 739 type spongeDb struct { 740 sponge hash.Hash 741 id string 742 journal []string 743 } 744 745 func (s *spongeDb) Has(key []byte) (bool, error) { panic("implement me") } 746 func (s *spongeDb) Get(key []byte) ([]byte, error) { return nil, errors.New("no such elem") } 747 func (s *spongeDb) Delete(key []byte) error { panic("implement me") } 748 func (s *spongeDb) NewBatch() ethdb.Batch { return &spongeBatch{s} } 749 func (s *spongeDb) NewBatchWithSize(size int) ethdb.Batch { return &spongeBatch{s} } 750 func (s *spongeDb) NewSnapshot() (ethdb.Snapshot, error) { panic("implement me") } 751 func (s *spongeDb) Stat(property string) (string, error) { panic("implement me") } 752 func (s *spongeDb) Compact(start []byte, limit []byte) error { panic("implement me") } 753 func (s *spongeDb) Close() error { return nil } 754 func (s *spongeDb) Put(key []byte, value []byte) error { 755 valbrief := value 756 if len(valbrief) > 8 { 757 valbrief = valbrief[:8] 758 } 759 s.journal = append(s.journal, fmt.Sprintf("%v: PUT([%x...], [%d bytes] %x...)\n", s.id, key[:8], len(value), valbrief)) 760 s.sponge.Write(key) 761 s.sponge.Write(value) 762 return nil 763 } 764 func (s *spongeDb) NewIterator(prefix []byte, start []byte) ethdb.Iterator { panic("implement me") } 765 766 // spongeBatch is a dummy batch which immediately writes to the underlying spongedb 767 type spongeBatch struct { 768 db *spongeDb 769 } 770 771 func (b *spongeBatch) Put(key, value []byte) error { 772 b.db.Put(key, value) 773 return nil 774 } 775 func (b *spongeBatch) Delete(key []byte) error { panic("implement me") } 776 func (b *spongeBatch) ValueSize() int { return 100 } 777 func (b *spongeBatch) Write() error { return nil } 778 func (b *spongeBatch) Reset() {} 779 func (b *spongeBatch) Replay(w ethdb.KeyValueWriter) error { return nil } 780 781 // TestCommitSequence tests that the trie.Commit operation writes the elements of the trie 782 // in the expected order. 783 // The test data was based on the 'master' code, and is basically random. It can be used 784 // to check whether changes to the trie modifies the write order or data in any way. 785 func TestCommitSequence(t *testing.T) { 786 for i, tc := range []struct { 787 count int 788 expWriteSeqHash []byte 789 }{ 790 {20, common.FromHex("873c78df73d60e59d4a2bcf3716e8bfe14554549fea2fc147cb54129382a8066")}, 791 {200, common.FromHex("ba03d891bb15408c940eea5ee3d54d419595102648d02774a0268d892add9c8e")}, 792 {2000, common.FromHex("f7a184f20df01c94f09537401d11e68d97ad0c00115233107f51b9c287ce60c7")}, 793 } { 794 addresses, accounts := makeAccounts(tc.count) 795 // This spongeDb is used to check the sequence of disk-db-writes 796 s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} 797 db := NewDatabase(rawdb.NewDatabase(s)) 798 trie := NewEmpty(db) 799 // Fill the trie with elements 800 for i := 0; i < tc.count; i++ { 801 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 802 } 803 // Flush trie -> database 804 root, nodes := trie.Commit(false) 805 db.Update(NewWithNodeSet(nodes)) 806 // Flush memdb -> disk (sponge) 807 db.Commit(root, false) 808 if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { 809 t.Errorf("test %d, disk write sequence wrong:\ngot %x exp %x\n", i, got, exp) 810 } 811 } 812 } 813 814 // TestCommitSequenceRandomBlobs is identical to TestCommitSequence 815 // but uses random blobs instead of 'accounts' 816 func TestCommitSequenceRandomBlobs(t *testing.T) { 817 for i, tc := range []struct { 818 count int 819 expWriteSeqHash []byte 820 }{ 821 {20, common.FromHex("8e4a01548551d139fa9e833ebc4e66fc1ba40a4b9b7259d80db32cff7b64ebbc")}, 822 {200, common.FromHex("6869b4e7b95f3097a19ddb30ff735f922b915314047e041614df06958fc50554")}, 823 {2000, common.FromHex("444200e6f4e2df49f77752f629a96ccf7445d4698c164f962bbd85a0526ef424")}, 824 } { 825 prng := rand.New(rand.NewSource(int64(i))) 826 // This spongeDb is used to check the sequence of disk-db-writes 827 s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} 828 db := NewDatabase(rawdb.NewDatabase(s)) 829 trie := NewEmpty(db) 830 // Fill the trie with elements 831 for i := 0; i < tc.count; i++ { 832 key := make([]byte, 32) 833 var val []byte 834 // 50% short elements, 50% large elements 835 if prng.Intn(2) == 0 { 836 val = make([]byte, 1+prng.Intn(32)) 837 } else { 838 val = make([]byte, 1+prng.Intn(4096)) 839 } 840 prng.Read(key) 841 prng.Read(val) 842 trie.Update(key, val) 843 } 844 // Flush trie -> database 845 root, nodes := trie.Commit(false) 846 db.Update(NewWithNodeSet(nodes)) 847 // Flush memdb -> disk (sponge) 848 db.Commit(root, false) 849 if got, exp := s.sponge.Sum(nil), tc.expWriteSeqHash; !bytes.Equal(got, exp) { 850 t.Fatalf("test %d, disk write sequence wrong:\ngot %x exp %x\n", i, got, exp) 851 } 852 } 853 } 854 855 func TestCommitSequenceStackTrie(t *testing.T) { 856 for count := 1; count < 200; count++ { 857 prng := rand.New(rand.NewSource(int64(count))) 858 // This spongeDb is used to check the sequence of disk-db-writes 859 s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"} 860 db := NewDatabase(rawdb.NewDatabase(s)) 861 trie := NewEmpty(db) 862 // Another sponge is used for the stacktrie commits 863 stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} 864 stTrie := NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { 865 rawdb.WriteTrieNode(stackTrieSponge, owner, path, hash, blob, db.Scheme()) 866 }) 867 // Fill the trie with elements 868 for i := 0; i < count; i++ { 869 // For the stack trie, we need to do inserts in proper order 870 key := make([]byte, 32) 871 binary.BigEndian.PutUint64(key, uint64(i)) 872 var val []byte 873 // 50% short elements, 50% large elements 874 if prng.Intn(2) == 0 { 875 val = make([]byte, 1+prng.Intn(32)) 876 } else { 877 val = make([]byte, 1+prng.Intn(1024)) 878 } 879 prng.Read(val) 880 trie.TryUpdate(key, val) 881 stTrie.TryUpdate(key, val) 882 } 883 // Flush trie -> database 884 root, nodes := trie.Commit(false) 885 // Flush memdb -> disk (sponge) 886 db.Update(NewWithNodeSet(nodes)) 887 db.Commit(root, false) 888 // And flush stacktrie -> disk 889 stRoot, err := stTrie.Commit() 890 if err != nil { 891 t.Fatalf("Failed to commit stack trie %v", err) 892 } 893 if stRoot != root { 894 t.Fatalf("root wrong, got %x exp %x", stRoot, root) 895 } 896 if got, exp := stackTrieSponge.sponge.Sum(nil), s.sponge.Sum(nil); !bytes.Equal(got, exp) { 897 // Show the journal 898 t.Logf("Expected:") 899 for i, v := range s.journal { 900 t.Logf("op %d: %v", i, v) 901 } 902 t.Logf("Stacktrie:") 903 for i, v := range stackTrieSponge.journal { 904 t.Logf("op %d: %v", i, v) 905 } 906 t.Fatalf("test %d, disk write sequence wrong:\ngot %x exp %x\n", count, got, exp) 907 } 908 } 909 } 910 911 // TestCommitSequenceSmallRoot tests that a trie which is essentially only a 912 // small (<32 byte) shortnode with an included value is properly committed to a 913 // database. 914 // This case might not matter, since in practice, all keys are 32 bytes, which means 915 // that even a small trie which contains a leaf will have an extension making it 916 // not fit into 32 bytes, rlp-encoded. However, it's still the correct thing to do. 917 func TestCommitSequenceSmallRoot(t *testing.T) { 918 s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"} 919 db := NewDatabase(rawdb.NewDatabase(s)) 920 trie := NewEmpty(db) 921 // Another sponge is used for the stacktrie commits 922 stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} 923 stTrie := NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { 924 rawdb.WriteTrieNode(stackTrieSponge, owner, path, hash, blob, db.Scheme()) 925 }) 926 // Add a single small-element to the trie(s) 927 key := make([]byte, 5) 928 key[0] = 1 929 trie.TryUpdate(key, []byte{0x1}) 930 stTrie.TryUpdate(key, []byte{0x1}) 931 // Flush trie -> database 932 root, nodes := trie.Commit(false) 933 // Flush memdb -> disk (sponge) 934 db.Update(NewWithNodeSet(nodes)) 935 db.Commit(root, false) 936 // And flush stacktrie -> disk 937 stRoot, err := stTrie.Commit() 938 if err != nil { 939 t.Fatalf("Failed to commit stack trie %v", err) 940 } 941 if stRoot != root { 942 t.Fatalf("root wrong, got %x exp %x", stRoot, root) 943 } 944 945 t.Logf("root: %x\n", stRoot) 946 if got, exp := stackTrieSponge.sponge.Sum(nil), s.sponge.Sum(nil); !bytes.Equal(got, exp) { 947 t.Fatalf("test, disk write sequence wrong:\ngot %x exp %x\n", got, exp) 948 } 949 } 950 951 // BenchmarkCommitAfterHashFixedSize benchmarks the Commit (after Hash) of a fixed number of updates to a trie. 952 // This benchmark is meant to capture the difference on efficiency of small versus large changes. Typically, 953 // storage tries are small (a couple of entries), whereas the full post-block account trie update is large (a couple 954 // of thousand entries) 955 func BenchmarkHashFixedSize(b *testing.B) { 956 b.Run("10", func(b *testing.B) { 957 b.StopTimer() 958 acc, add := makeAccounts(20) 959 for i := 0; i < b.N; i++ { 960 benchmarkHashFixedSize(b, acc, add) 961 } 962 }) 963 b.Run("100", func(b *testing.B) { 964 b.StopTimer() 965 acc, add := makeAccounts(100) 966 for i := 0; i < b.N; i++ { 967 benchmarkHashFixedSize(b, acc, add) 968 } 969 }) 970 971 b.Run("1K", func(b *testing.B) { 972 b.StopTimer() 973 acc, add := makeAccounts(1000) 974 for i := 0; i < b.N; i++ { 975 benchmarkHashFixedSize(b, acc, add) 976 } 977 }) 978 b.Run("10K", func(b *testing.B) { 979 b.StopTimer() 980 acc, add := makeAccounts(10000) 981 for i := 0; i < b.N; i++ { 982 benchmarkHashFixedSize(b, acc, add) 983 } 984 }) 985 b.Run("100K", func(b *testing.B) { 986 b.StopTimer() 987 acc, add := makeAccounts(100000) 988 for i := 0; i < b.N; i++ { 989 benchmarkHashFixedSize(b, acc, add) 990 } 991 }) 992 } 993 994 func benchmarkHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { 995 b.ReportAllocs() 996 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 997 for i := 0; i < len(addresses); i++ { 998 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 999 } 1000 // Insert the accounts into the trie and hash it 1001 b.StartTimer() 1002 trie.Hash() 1003 b.StopTimer() 1004 } 1005 1006 func BenchmarkCommitAfterHashFixedSize(b *testing.B) { 1007 b.Run("10", func(b *testing.B) { 1008 b.StopTimer() 1009 acc, add := makeAccounts(20) 1010 for i := 0; i < b.N; i++ { 1011 benchmarkCommitAfterHashFixedSize(b, acc, add) 1012 } 1013 }) 1014 b.Run("100", func(b *testing.B) { 1015 b.StopTimer() 1016 acc, add := makeAccounts(100) 1017 for i := 0; i < b.N; i++ { 1018 benchmarkCommitAfterHashFixedSize(b, acc, add) 1019 } 1020 }) 1021 1022 b.Run("1K", func(b *testing.B) { 1023 b.StopTimer() 1024 acc, add := makeAccounts(1000) 1025 for i := 0; i < b.N; i++ { 1026 benchmarkCommitAfterHashFixedSize(b, acc, add) 1027 } 1028 }) 1029 b.Run("10K", func(b *testing.B) { 1030 b.StopTimer() 1031 acc, add := makeAccounts(10000) 1032 for i := 0; i < b.N; i++ { 1033 benchmarkCommitAfterHashFixedSize(b, acc, add) 1034 } 1035 }) 1036 b.Run("100K", func(b *testing.B) { 1037 b.StopTimer() 1038 acc, add := makeAccounts(100000) 1039 for i := 0; i < b.N; i++ { 1040 benchmarkCommitAfterHashFixedSize(b, acc, add) 1041 } 1042 }) 1043 } 1044 1045 func benchmarkCommitAfterHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { 1046 b.ReportAllocs() 1047 trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) 1048 for i := 0; i < len(addresses); i++ { 1049 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 1050 } 1051 // Insert the accounts into the trie and hash it 1052 trie.Hash() 1053 b.StartTimer() 1054 trie.Commit(false) 1055 b.StopTimer() 1056 } 1057 1058 func BenchmarkDerefRootFixedSize(b *testing.B) { 1059 b.Run("10", func(b *testing.B) { 1060 b.StopTimer() 1061 acc, add := makeAccounts(20) 1062 for i := 0; i < b.N; i++ { 1063 benchmarkDerefRootFixedSize(b, acc, add) 1064 } 1065 }) 1066 b.Run("100", func(b *testing.B) { 1067 b.StopTimer() 1068 acc, add := makeAccounts(100) 1069 for i := 0; i < b.N; i++ { 1070 benchmarkDerefRootFixedSize(b, acc, add) 1071 } 1072 }) 1073 1074 b.Run("1K", func(b *testing.B) { 1075 b.StopTimer() 1076 acc, add := makeAccounts(1000) 1077 for i := 0; i < b.N; i++ { 1078 benchmarkDerefRootFixedSize(b, acc, add) 1079 } 1080 }) 1081 b.Run("10K", func(b *testing.B) { 1082 b.StopTimer() 1083 acc, add := makeAccounts(10000) 1084 for i := 0; i < b.N; i++ { 1085 benchmarkDerefRootFixedSize(b, acc, add) 1086 } 1087 }) 1088 b.Run("100K", func(b *testing.B) { 1089 b.StopTimer() 1090 acc, add := makeAccounts(100000) 1091 for i := 0; i < b.N; i++ { 1092 benchmarkDerefRootFixedSize(b, acc, add) 1093 } 1094 }) 1095 } 1096 1097 func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { 1098 b.ReportAllocs() 1099 triedb := NewDatabase(rawdb.NewMemoryDatabase()) 1100 trie := NewEmpty(triedb) 1101 for i := 0; i < len(addresses); i++ { 1102 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 1103 } 1104 h := trie.Hash() 1105 _, nodes := trie.Commit(false) 1106 triedb.Update(NewWithNodeSet(nodes)) 1107 b.StartTimer() 1108 triedb.Dereference(h) 1109 b.StopTimer() 1110 } 1111 1112 func getString(trie *Trie, k string) []byte { 1113 return trie.Get([]byte(k)) 1114 } 1115 1116 func updateString(trie *Trie, k, v string) { 1117 trie.Update([]byte(k), []byte(v)) 1118 } 1119 1120 func deleteString(trie *Trie, k string) { 1121 trie.Delete([]byte(k)) 1122 } 1123 1124 func TestDecodeNode(t *testing.T) { 1125 t.Parallel() 1126 var ( 1127 hash = make([]byte, 20) 1128 elems = make([]byte, 20) 1129 ) 1130 for i := 0; i < 5000000; i++ { 1131 crand.Read(hash) 1132 crand.Read(elems) 1133 decodeNode(hash, elems) 1134 } 1135 }