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