github.com/klaytn/klaytn@v1.12.1/storage/statedb/trie_test.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2014 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from trie/trie_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package statedb 22 23 import ( 24 "bytes" 25 "encoding/binary" 26 "fmt" 27 "math/big" 28 "math/rand" 29 "os" 30 "reflect" 31 "testing" 32 "testing/quick" 33 34 "github.com/davecgh/go-spew/spew" 35 "github.com/klaytn/klaytn/blockchain/types/account" 36 "github.com/klaytn/klaytn/blockchain/types/accountkey" 37 "github.com/klaytn/klaytn/common" 38 "github.com/klaytn/klaytn/crypto" 39 "github.com/klaytn/klaytn/rlp" 40 "github.com/klaytn/klaytn/storage/database" 41 "github.com/stretchr/testify/assert" 42 ) 43 44 func init() { 45 spew.Config.Indent = " " 46 spew.Config.DisableMethods = false 47 } 48 49 // Used for testing 50 func newEmptyTrie() *Trie { 51 trie, _ := NewTrie(common.Hash{}, NewDatabase(database.NewMemoryDBManager()), nil) 52 return trie 53 } 54 55 func TestEmptyTrie(t *testing.T) { 56 var trie Trie 57 res := trie.Hash() 58 exp := emptyRoot 59 if res != common.Hash(exp) { 60 t.Errorf("expected %x got %x", exp, res) 61 } 62 } 63 64 func TestNull(t *testing.T) { 65 var trie Trie 66 key := make([]byte, 32) 67 value := []byte("test") 68 trie.Update(key, value) 69 if !bytes.Equal(trie.Get(key), value) { 70 t.Fatal("wrong value") 71 } 72 } 73 74 func TestMissingRoot(t *testing.T) { 75 trie, err := NewTrie(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(database.NewMemoryDBManager()), nil) 76 if trie != nil { 77 t.Error("NewTrie returned non-nil trie for invalid root") 78 } 79 if _, ok := err.(*MissingNodeError); !ok { 80 t.Errorf("NewTrie returned wrong error: %v", err) 81 } 82 } 83 84 func TestMissingNodeDisk(t *testing.T) { testMissingNode(t, false) } 85 func TestMissingNodeMemonly(t *testing.T) { testMissingNode(t, true) } 86 87 func testMissingNode(t *testing.T, memonly bool) { 88 dbm := database.NewMemoryDBManager() 89 triedb := NewDatabase(dbm) 90 91 trie, _ := NewTrie(common.Hash{}, triedb, nil) 92 updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") 93 updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") 94 root, _ := trie.Commit(nil) 95 if !memonly { 96 triedb.Commit(root, true, 0) 97 } 98 99 trie, _ = NewTrie(root, triedb, nil) 100 _, err := trie.TryGet([]byte("120000")) 101 if err != nil { 102 t.Errorf("Unexpected error: %v", err) 103 } 104 trie, _ = NewTrie(root, triedb, nil) 105 _, err = trie.TryGet([]byte("120099")) 106 if err != nil { 107 t.Errorf("Unexpected error: %v", err) 108 } 109 trie, _ = NewTrie(root, triedb, nil) 110 _, err = trie.TryGet([]byte("123456")) 111 if err != nil { 112 t.Errorf("Unexpected error: %v", err) 113 } 114 trie, _ = NewTrie(root, triedb, nil) 115 err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) 116 if err != nil { 117 t.Errorf("Unexpected error: %v", err) 118 } 119 trie, _ = NewTrie(root, triedb, nil) 120 err = trie.TryDelete([]byte("123456")) 121 if err != nil { 122 t.Errorf("Unexpected error: %v", err) 123 } 124 125 hash := common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9").ExtendZero() 126 if memonly { 127 delete(triedb.nodes, hash) 128 } else { 129 dbm.DeleteTrieNode(hash) 130 } 131 132 trie, _ = NewTrie(root, triedb, nil) 133 _, err = trie.TryGet([]byte("120000")) 134 if _, ok := err.(*MissingNodeError); !ok { 135 t.Errorf("Wrong error: %v", err) 136 } 137 trie, _ = NewTrie(root, triedb, nil) 138 _, err = trie.TryGet([]byte("120099")) 139 if _, ok := err.(*MissingNodeError); !ok { 140 t.Errorf("Wrong error: %v", err) 141 } 142 trie, _ = NewTrie(root, triedb, nil) 143 _, err = trie.TryGet([]byte("123456")) 144 if err != nil { 145 t.Errorf("Unexpected error: %v", err) 146 } 147 trie, _ = NewTrie(root, triedb, nil) 148 err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) 149 if _, ok := err.(*MissingNodeError); !ok { 150 t.Errorf("Wrong error: %v", err) 151 } 152 trie, _ = NewTrie(root, triedb, nil) 153 err = trie.TryDelete([]byte("123456")) 154 if _, ok := err.(*MissingNodeError); !ok { 155 t.Errorf("Wrong error: %v", err) 156 } 157 } 158 159 func TestInsert(t *testing.T) { 160 trie := newEmptyTrie() 161 162 updateString(trie, "doe", "reindeer") 163 updateString(trie, "dog", "puppy") 164 updateString(trie, "dogglesworth", "cat") 165 166 exp := common.HexToHash("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3") 167 root := trie.Hash() 168 if root != exp { 169 t.Errorf("exp %x got %x", exp, root) 170 } 171 172 trie = newEmptyTrie() 173 updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") 174 175 exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") 176 root, err := trie.Commit(nil) 177 if err != nil { 178 t.Fatalf("commit error: %v", err) 179 } 180 if root != exp { 181 t.Errorf("exp %x got %x", exp, root) 182 } 183 } 184 185 func TestGet(t *testing.T) { 186 trie := newEmptyTrie() 187 updateString(trie, "doe", "reindeer") 188 updateString(trie, "dog", "puppy") 189 updateString(trie, "dogglesworth", "cat") 190 191 for i := 0; i < 2; i++ { 192 res := getString(trie, "dog") 193 if !bytes.Equal(res, []byte("puppy")) { 194 t.Errorf("expected puppy got %x", res) 195 } 196 197 unknown := getString(trie, "unknown") 198 if unknown != nil { 199 t.Errorf("expected nil got %x", unknown) 200 } 201 202 if i == 1 { 203 return 204 } 205 trie.Commit(nil) 206 } 207 } 208 209 func TestDelete(t *testing.T) { 210 trie := newEmptyTrie() 211 vals := []struct{ k, v string }{ 212 {"do", "verb"}, 213 {"klaytn", "wookiedoo"}, 214 {"horse", "stallion"}, 215 {"shaman", "horse"}, 216 {"doge", "coin"}, 217 {"klaytn", ""}, 218 {"dog", "puppy"}, 219 {"shaman", ""}, 220 } 221 for _, val := range vals { 222 if val.v != "" { 223 updateString(trie, val.k, val.v) 224 } else { 225 deleteString(trie, val.k) 226 } 227 } 228 229 hash := trie.Hash() 230 exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") 231 if hash != exp { 232 t.Errorf("expected %x got %x", exp, hash) 233 } 234 } 235 236 func TestEmptyValues(t *testing.T) { 237 trie := newEmptyTrie() 238 239 vals := []struct{ k, v string }{ 240 {"do", "verb"}, 241 {"klaytn", "wookiedoo"}, 242 {"horse", "stallion"}, 243 {"shaman", "horse"}, 244 {"doge", "coin"}, 245 {"klaytn", ""}, 246 {"dog", "puppy"}, 247 {"shaman", ""}, 248 } 249 for _, val := range vals { 250 updateString(trie, val.k, val.v) 251 } 252 253 hash := trie.Hash() 254 exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") 255 if hash != exp { 256 t.Errorf("expected %x got %x", exp, hash) 257 } 258 } 259 260 func TestReplication(t *testing.T) { 261 trie := newEmptyTrie() 262 vals := []struct{ k, v string }{ 263 {"do", "verb"}, 264 {"klaytn", "wookiedoo"}, 265 {"horse", "stallion"}, 266 {"shaman", "horse"}, 267 {"doge", "coin"}, 268 {"dog", "puppy"}, 269 {"somethingveryoddindeedthis is", "myothernodedata"}, 270 } 271 for _, val := range vals { 272 updateString(trie, val.k, val.v) 273 } 274 exp, err := trie.Commit(nil) 275 if err != nil { 276 t.Fatalf("commit error: %v", err) 277 } 278 279 // create a new trie on top of the database and check that lookups work. 280 trie2, err := NewTrie(exp, trie.db, nil) 281 if err != nil { 282 t.Fatalf("can't recreate trie at %x: %v", exp, err) 283 } 284 for _, kv := range vals { 285 if string(getString(trie2, kv.k)) != kv.v { 286 t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) 287 } 288 } 289 hash, err := trie2.Commit(nil) 290 if err != nil { 291 t.Fatalf("commit error: %v", err) 292 } 293 if hash != exp { 294 t.Errorf("root failure. expected %x got %x", exp, hash) 295 } 296 297 // perform some insertions on the new trie. 298 vals2 := []struct{ k, v string }{ 299 {"do", "verb"}, 300 {"klaytn", "wookiedoo"}, 301 {"horse", "stallion"}, 302 // {"shaman", "horse"}, 303 // {"doge", "coin"}, 304 // {"klaytn", ""}, 305 // {"dog", "puppy"}, 306 // {"somethingveryoddindeedthis is", "myothernodedata"}, 307 // {"shaman", ""}, 308 } 309 for _, val := range vals2 { 310 updateString(trie2, val.k, val.v) 311 } 312 if hash := trie2.Hash(); hash != exp { 313 t.Errorf("root failure. expected %x got %x", exp, hash) 314 } 315 } 316 317 func TestLargeValue(t *testing.T) { 318 trie := newEmptyTrie() 319 trie.Update([]byte("key1"), []byte{99, 99, 99, 99}) 320 trie.Update([]byte("key2"), bytes.Repeat([]byte{1}, 32)) 321 trie.Hash() 322 } 323 324 func TestStorageTrie(t *testing.T) { 325 newStorageTrie := func(pruning bool) *Trie { 326 dbm := database.NewMemoryDBManager() 327 if pruning { 328 dbm.WritePruningEnabled() 329 } 330 db := NewDatabase(dbm) 331 trie, _ := NewStorageTrie(common.ExtHash{}, db, nil) 332 updateString(trie, "doe", "reindeer") 333 return trie 334 } 335 336 // non-pruning storage trie returns Legacy ExtHash for root 337 trie := newStorageTrie(false) 338 root := trie.HashExt() 339 assert.True(t, root.IsZeroExtended()) 340 341 trie = newStorageTrie(false) 342 root, _ = trie.CommitExt(nil) 343 assert.True(t, root.IsZeroExtended()) 344 345 // pruning storage trie returns non-Legacy ExtHash for root 346 trie = newStorageTrie(true) 347 root = trie.HashExt() 348 assert.False(t, root.IsZeroExtended()) 349 350 trie = newStorageTrie(true) 351 root, _ = trie.CommitExt(nil) 352 assert.False(t, root.IsZeroExtended()) 353 } 354 355 func TestPruningByUpdate(t *testing.T) { 356 dbm := database.NewMemoryDBManager() 357 dbm.WritePruningEnabled() 358 db := NewDatabase(dbm) 359 hasnode := func(hash common.ExtHash) bool { ok, _ := dbm.HasTrieNode(hash); return ok } 360 common.ResetExtHashCounterForTest(0xccccddddeeee00) 361 362 trie, _ := NewTrie(common.Hash{}, db, &TrieOpts{PruningBlockNumber: 1}) 363 nodehash1 := common.HexToExtHash("05ae693aac2107336a79309e0c60b24a7aac6aa3edecaef593921500d33c63c400000000000000") 364 nodehash2 := common.HexToExtHash("f226ef598ed9195f2211546cf5b2860dc27b4da07ff7ab5108ee68107f0c9d00ccccddddeeee01") 365 366 // Test that extension and branch nodes are correctly pruned via Update. 367 // - extension <05ae693aac2107336a79309e0c60b24a7aac6aa3edecaef593921500d33c63c400000000000045> 368 // - branch <f226ef598ed9195f2211546cf5b2860dc27b4da07ff7ab5108ee68107f0c9d00ccccddddeeee01> 369 // - [5]value "reindeer" 370 // - [7]value "puppy" 371 // By inserting "dogglesworth", both extension and branch nodes are affected, hence pruning the both. 372 373 // Update and commit to store the nodes 374 updateString(trie, "doe", "reindeer") 375 updateString(trie, "dog", "puppy") 376 trie.Commit(nil) 377 db.Cap(0) 378 379 // The nodes still exist 380 assert.True(t, hasnode(nodehash1)) 381 assert.True(t, hasnode(nodehash2)) 382 383 // Trigger pruning 384 updateString(trie, "dogglesworth", "cat") 385 trie.Commit(nil) 386 db.Cap(0) 387 388 // Those nodes and the only those nodes are scheduled to be deleted 389 expectedMarks := []database.PruningMark{ 390 {Number: 1, Hash: nodehash1}, 391 {Number: 1, Hash: nodehash2}, 392 } 393 marks := dbm.ReadPruningMarks(0, 0) 394 assert.Equal(t, expectedMarks, marks) 395 396 // The nodes are deleted 397 dbm.PruneTrieNodes(marks) 398 assert.False(t, hasnode(nodehash1)) 399 assert.False(t, hasnode(nodehash2)) 400 } 401 402 func TestPruningByDelete(t *testing.T) { 403 dbm := database.NewMemoryDBManager() 404 dbm.WritePruningEnabled() 405 db := NewDatabase(dbm) 406 hasnode := func(hash common.ExtHash) bool { ok, _ := dbm.HasTrieNode(hash); return ok } 407 common.ResetExtHashCounterForTest(0xccccddddeeee00) 408 409 trie, _ := NewTrie(common.Hash{}, db, &TrieOpts{PruningBlockNumber: 1}) 410 nodehash1 := common.HexToExtHash("05ae693aac2107336a79309e0c60b24a7aac6aa3edecaef593921500d33c63c400000000000000") 411 nodehash2 := common.HexToExtHash("f226ef598ed9195f2211546cf5b2860dc27b4da07ff7ab5108ee68107f0c9d00ccccddddeeee01") 412 413 // Test that extension and branch nodes are correctly pruned via Delete. 414 // - extension <05ae693aac2107336a79309e0c60b24a7aac6aa3edecaef593921500d33c63c400000000000045> 415 // - branch <f226ef598ed9195f2211546cf5b2860dc27b4da07ff7ab5108ee68107f0c9d00ccccddddeeee01> 416 // - [5]value "reindeer" 417 // - [7]value "puppy" 418 // By deleting "doe", both extension and branch nodes are affected, hence pruning the both. 419 420 // Update and commit to store the nodes 421 updateString(trie, "doe", "reindeer") 422 updateString(trie, "dog", "puppy") 423 trie.Commit(nil) 424 db.Cap(0) 425 426 // The nodes still exist 427 assert.True(t, hasnode(nodehash1)) 428 assert.True(t, hasnode(nodehash2)) 429 430 // Trigger pruning 431 deleteString(trie, "doe") 432 trie.Commit(nil) 433 db.Cap(0) 434 435 // Those nodes and the only those nodes are scheduled to be deleted 436 expectedMarks := []database.PruningMark{ 437 {Number: 1, Hash: nodehash1}, 438 {Number: 1, Hash: nodehash2}, 439 } 440 marks := dbm.ReadPruningMarks(0, 0) 441 assert.Equal(t, expectedMarks, marks) 442 443 // The nodes are deleted 444 dbm.PruneTrieNodes(marks) 445 assert.False(t, hasnode(nodehash1)) 446 assert.False(t, hasnode(nodehash2)) 447 } 448 449 type countingDB struct { 450 database.DBManager 451 gets map[string]int 452 } 453 454 //func (db *countingDB) Get(key []byte) ([]byte, error) { 455 // db.gets[string(key)]++ 456 // return db.Database.Get(key) 457 //} 458 459 // randTest performs random trie operations. 460 // Instances of this test are created by Generate. 461 type randTest []randTestStep 462 463 type randTestStep struct { 464 op int 465 key []byte // for opUpdate, opDelete, opGet 466 value []byte // for opUpdate 467 err error // for debugging 468 } 469 470 const ( 471 opUpdate = iota 472 opDelete 473 opGet 474 opCommit 475 opHash 476 opReset 477 opItercheckhash 478 opMax // boundary value, not an actual op 479 ) 480 481 func (randTest) Generate(r *rand.Rand, size int) reflect.Value { 482 var allKeys [][]byte 483 genKey := func() []byte { 484 if len(allKeys) < 2 || r.Intn(100) < 10 { 485 // new key 486 key := make([]byte, r.Intn(50)) 487 r.Read(key) 488 allKeys = append(allKeys, key) 489 return key 490 } 491 // use existing key 492 return allKeys[r.Intn(len(allKeys))] 493 } 494 495 var steps randTest 496 for i := 0; i < size; i++ { 497 step := randTestStep{op: r.Intn(opMax)} 498 switch step.op { 499 case opUpdate: 500 step.key = genKey() 501 step.value = make([]byte, 8) 502 binary.BigEndian.PutUint64(step.value, uint64(i)) 503 case opGet, opDelete: 504 step.key = genKey() 505 } 506 steps = append(steps, step) 507 } 508 return reflect.ValueOf(steps) 509 } 510 511 func runRandTest(rt randTest) bool { 512 triedb := NewDatabase(database.NewMemoryDBManager()) 513 514 tr, _ := NewTrie(common.Hash{}, triedb, nil) 515 values := make(map[string]string) // tracks content of the trie 516 517 for i, step := range rt { 518 switch step.op { 519 case opUpdate: 520 tr.Update(step.key, step.value) 521 values[string(step.key)] = string(step.value) 522 case opDelete: 523 tr.Delete(step.key) 524 delete(values, string(step.key)) 525 case opGet: 526 v := tr.Get(step.key) 527 want := values[string(step.key)] 528 if string(v) != want { 529 rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want) 530 } 531 case opCommit: 532 _, rt[i].err = tr.Commit(nil) 533 case opHash: 534 tr.Hash() 535 case opReset: 536 hash, err := tr.Commit(nil) 537 if err != nil { 538 rt[i].err = err 539 return false 540 } 541 newtr, err := NewTrie(hash, triedb, nil) 542 if err != nil { 543 rt[i].err = err 544 return false 545 } 546 tr = newtr 547 case opItercheckhash: 548 checktr, _ := NewTrie(common.Hash{}, triedb, nil) 549 it := NewIterator(tr.NodeIterator(nil)) 550 for it.Next() { 551 checktr.Update(it.Key, it.Value) 552 } 553 if tr.Hash() != checktr.Hash() { 554 rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") 555 } 556 } 557 // Abort the test on error. 558 if rt[i].err != nil { 559 return false 560 } 561 } 562 return true 563 } 564 565 func TestRandom(t *testing.T) { 566 if err := quick.Check(runRandTest, nil); err != nil { 567 if cerr, ok := err.(*quick.CheckError); ok { 568 t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In)) 569 } 570 t.Fatal(err) 571 } 572 } 573 574 func BenchmarkGet(b *testing.B) { benchGet(b, false) } 575 func BenchmarkGetDB(b *testing.B) { benchGet(b, true) } 576 func BenchmarkUpdateBE(b *testing.B) { benchUpdate(b, binary.BigEndian) } 577 func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } 578 579 const benchElemCount = 20000 580 581 func benchGet(b *testing.B, commit bool) { 582 trie := new(Trie) 583 584 if commit { 585 dbDir, tmpdb := tempDB() 586 trie, _ = NewTrie(common.Hash{}, tmpdb, nil) 587 588 defer os.RemoveAll(dbDir) 589 defer tmpdb.diskDB.Close() 590 } 591 592 k := make([]byte, 32) 593 for i := 0; i < benchElemCount; i++ { 594 binary.LittleEndian.PutUint64(k, uint64(i)) 595 trie.Update(k, k) 596 } 597 binary.LittleEndian.PutUint64(k, benchElemCount/2) 598 if commit { 599 trie.Commit(nil) 600 } 601 602 b.ResetTimer() 603 for i := 0; i < b.N; i++ { 604 trie.Get(k) 605 } 606 b.StopTimer() 607 } 608 609 func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { 610 trie := newEmptyTrie() 611 k := make([]byte, 32) 612 for i := 0; i < b.N; i++ { 613 e.PutUint64(k, uint64(i)) 614 trie.Update(k, k) 615 } 616 return trie 617 } 618 619 // Benchmarks the trie hashing. Since the trie caches the result of any operation, 620 // we cannot use b.N as the number of hashing rouns, since all rounds apart from 621 // the first one will be NOOP. As such, we'll use b.N as the number of account to 622 // insert into the trie before measuring the hashing. 623 func BenchmarkHash(b *testing.B) { 624 // Make the random benchmark deterministic 625 random := rand.New(rand.NewSource(0)) 626 627 // Create a realistic account trie to hash 628 addresses := make([][20]byte, b.N) 629 for i := 0; i < len(addresses); i++ { 630 for j := 0; j < len(addresses[i]); j++ { 631 addresses[i][j] = byte(random.Intn(256)) 632 } 633 } 634 accounts := make([][]byte, len(addresses)) 635 for i := 0; i < len(accounts); i++ { 636 var ( 637 nonce = uint64(random.Int63()) 638 balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) 639 root = emptyRoot 640 code = crypto.Keccak256(nil) 641 ) 642 accounts[i], _ = rlp.EncodeToBytes([]interface{}{nonce, balance, root, code}) 643 } 644 // Insert the accounts into the trie and hash it 645 trie := newEmptyTrie() 646 for i := 0; i < len(addresses); i++ { 647 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 648 } 649 b.ResetTimer() 650 b.ReportAllocs() 651 trie.Hash() 652 } 653 654 // Benchmarks the trie Commit following a Hash. Since the trie caches the result of any operation, 655 // we cannot use b.N as the number of hashing rounds, since all rounds apart from 656 // the first one will be NOOP. As such, we'll use b.N as the number of account to 657 // insert into the trie before measuring the hashing. 658 func BenchmarkCommitAfterHash(b *testing.B) { 659 b.Run("no-onleaf", func(b *testing.B) { 660 benchmarkCommitAfterHash(b) 661 }) 662 } 663 664 func benchmarkCommitAfterHash(b *testing.B) { 665 // Make the random benchmark deterministic 666 addresses, accounts := makeAccounts(b.N) 667 trie, _ := NewTrie(common.Hash{}, NewDatabase(database.NewMemoryDBManager()), nil) 668 for i := 0; i < len(addresses); i++ { 669 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 670 } 671 // Insert the accounts into the trie and hash it 672 trie.Hash() 673 b.ResetTimer() 674 b.ReportAllocs() 675 trie.Commit(nil) 676 } 677 678 func tempDB() (string, *Database) { 679 dir, err := os.MkdirTemp("", "trie-bench") 680 if err != nil { 681 panic(fmt.Sprintf("can't create temporary directory: %v", err)) 682 } 683 dbc := &database.DBConfig{Dir: dir, DBType: database.LevelDB, LevelDBCacheSize: 256, OpenFilesLimit: 0} 684 diskDB := database.NewDBManager(dbc) 685 return dir, NewDatabase(diskDB) 686 } 687 688 func genExternallyOwnedAccount(nonce uint64, balance *big.Int) (account.Account, error) { 689 return account.NewAccountWithMap(account.ExternallyOwnedAccountType, map[account.AccountValueKeyType]interface{}{ 690 account.AccountValueKeyNonce: nonce, 691 account.AccountValueKeyBalance: balance, 692 account.AccountValueKeyHumanReadable: false, 693 account.AccountValueKeyAccountKey: accountkey.NewAccountKeyLegacy(), 694 }) 695 } 696 697 func makeAccounts(size int) (addresses [][20]byte, accounts [][]byte) { 698 // Make the random benchmark deterministic 699 random := rand.New(rand.NewSource(0)) 700 // Create a realistic account trie to hash 701 addresses = make([][20]byte, size) 702 for i := 0; i < len(addresses); i++ { 703 data := make([]byte, 20) 704 random.Read(data) 705 copy(addresses[i][:], data) 706 } 707 accounts = make([][]byte, len(addresses)) 708 for i := 0; i < len(accounts); i++ { 709 // The big.Rand function is not deterministic with regards to 64 vs 32 bit systems, 710 // and will consume different amount of data from the rand source. 711 // balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) 712 // Therefore, we instead just read via byte buffer 713 numBytes := random.Uint32() % 33 // [0, 32] bytes 714 balanceBytes := make([]byte, numBytes) 715 random.Read(balanceBytes) 716 acc, _ := genExternallyOwnedAccount(uint64(i), big.NewInt(int64(i))) 717 serializer := account.NewAccountSerializerWithAccount(acc) 718 data, _ := rlp.EncodeToBytes(serializer) 719 accounts[i] = data 720 } 721 return addresses, accounts 722 } 723 724 // BenchmarkCommitAfterHashFixedSize benchmarks the Commit (after Hash) of a fixed number of updates to a trie. 725 // This benchmark is meant to capture the difference on efficiency of small versus large changes. Typically, 726 // storage tries are small (a couple of entries), whereas the full post-block account trie update is large (a couple 727 // of thousand entries) 728 func BenchmarkHashFixedSize(b *testing.B) { 729 b.Run("10", func(b *testing.B) { 730 b.StopTimer() 731 acc, add := makeAccounts(20) 732 for i := 0; i < b.N; i++ { 733 benchmarkHashFixedSize(b, acc, add) 734 } 735 }) 736 b.Run("100", func(b *testing.B) { 737 b.StopTimer() 738 acc, add := makeAccounts(100) 739 for i := 0; i < b.N; i++ { 740 benchmarkHashFixedSize(b, acc, add) 741 } 742 }) 743 744 b.Run("1K", func(b *testing.B) { 745 b.StopTimer() 746 acc, add := makeAccounts(1000) 747 for i := 0; i < b.N; i++ { 748 benchmarkHashFixedSize(b, acc, add) 749 } 750 }) 751 b.Run("10K", func(b *testing.B) { 752 b.StopTimer() 753 acc, add := makeAccounts(10000) 754 for i := 0; i < b.N; i++ { 755 benchmarkHashFixedSize(b, acc, add) 756 } 757 }) 758 b.Run("100K", func(b *testing.B) { 759 b.StopTimer() 760 acc, add := makeAccounts(100000) 761 for i := 0; i < b.N; i++ { 762 benchmarkHashFixedSize(b, acc, add) 763 } 764 }) 765 } 766 767 func benchmarkHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { 768 b.ReportAllocs() 769 trie, _ := NewTrie(common.Hash{}, NewDatabase(database.NewMemoryDBManager()), nil) 770 for i := 0; i < len(addresses); i++ { 771 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 772 } 773 // Insert the accounts into the trie and hash it 774 b.StartTimer() 775 trie.Hash() 776 b.StopTimer() 777 } 778 779 func BenchmarkCommitAfterHashFixedSize(b *testing.B) { 780 b.Run("10", func(b *testing.B) { 781 b.StopTimer() 782 acc, add := makeAccounts(20) 783 for i := 0; i < b.N; i++ { 784 benchmarkCommitAfterHashFixedSize(b, acc, add) 785 } 786 }) 787 b.Run("100", func(b *testing.B) { 788 b.StopTimer() 789 acc, add := makeAccounts(100) 790 for i := 0; i < b.N; i++ { 791 benchmarkCommitAfterHashFixedSize(b, acc, add) 792 } 793 }) 794 795 b.Run("1K", func(b *testing.B) { 796 b.StopTimer() 797 acc, add := makeAccounts(1000) 798 for i := 0; i < b.N; i++ { 799 benchmarkCommitAfterHashFixedSize(b, acc, add) 800 } 801 }) 802 b.Run("10K", func(b *testing.B) { 803 b.StopTimer() 804 acc, add := makeAccounts(10000) 805 for i := 0; i < b.N; i++ { 806 benchmarkCommitAfterHashFixedSize(b, acc, add) 807 } 808 }) 809 b.Run("100K", func(b *testing.B) { 810 b.StopTimer() 811 acc, add := makeAccounts(100000) 812 for i := 0; i < b.N; i++ { 813 benchmarkCommitAfterHashFixedSize(b, acc, add) 814 } 815 }) 816 } 817 818 func benchmarkCommitAfterHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { 819 b.ReportAllocs() 820 trie, _ := NewTrie(common.Hash{}, NewDatabase(database.NewMemoryDBManager()), nil) 821 for i := 0; i < len(addresses); i++ { 822 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 823 } 824 // Insert the accounts into the trie and hash it 825 trie.Hash() 826 b.StartTimer() 827 trie.Commit(nil) 828 b.StopTimer() 829 } 830 831 func BenchmarkDerefRootFixedSize(b *testing.B) { 832 b.Run("10", func(b *testing.B) { 833 b.StopTimer() 834 acc, add := makeAccounts(20) 835 for i := 0; i < b.N; i++ { 836 benchmarkDerefRootFixedSize(b, acc, add) 837 } 838 }) 839 b.Run("100", func(b *testing.B) { 840 b.StopTimer() 841 acc, add := makeAccounts(100) 842 for i := 0; i < b.N; i++ { 843 benchmarkDerefRootFixedSize(b, acc, add) 844 } 845 }) 846 847 b.Run("1K", func(b *testing.B) { 848 b.StopTimer() 849 acc, add := makeAccounts(1000) 850 for i := 0; i < b.N; i++ { 851 benchmarkDerefRootFixedSize(b, acc, add) 852 } 853 }) 854 b.Run("10K", func(b *testing.B) { 855 b.StopTimer() 856 acc, add := makeAccounts(10000) 857 for i := 0; i < b.N; i++ { 858 benchmarkDerefRootFixedSize(b, acc, add) 859 } 860 }) 861 b.Run("100K", func(b *testing.B) { 862 b.StopTimer() 863 acc, add := makeAccounts(100000) 864 for i := 0; i < b.N; i++ { 865 benchmarkDerefRootFixedSize(b, acc, add) 866 } 867 }) 868 } 869 870 func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { 871 b.ReportAllocs() 872 triedb := NewDatabase(database.NewMemoryDBManager()) 873 trie, _ := NewTrie(common.Hash{}, triedb, nil) 874 for i := 0; i < len(addresses); i++ { 875 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 876 } 877 h := trie.Hash() 878 trie.Commit(nil) 879 //_, nodes := trie.Commit(nil) 880 //triedb.Update(NewWithNodeSet(nodes)) 881 b.StartTimer() 882 triedb.Dereference(h) 883 b.StopTimer() 884 } 885 886 func getString(trie *Trie, k string) []byte { 887 return trie.Get([]byte(k)) 888 } 889 890 func updateString(trie *Trie, k, v string) { 891 trie.Update([]byte(k), []byte(v)) 892 } 893 894 func deleteString(trie *Trie, k string) { 895 trie.Delete([]byte(k)) 896 } 897 898 func TestDecodeNode(t *testing.T) { 899 t.Parallel() 900 var ( 901 hash = make([]byte, 20) 902 elems = make([]byte, 20) 903 ) 904 for i := 0; i < 5000000; i++ { 905 rand.Read(hash) 906 rand.Read(elems) 907 decodeNode(hash, elems) 908 } 909 }