github.com/m3shine/gochain@v2.2.26+incompatible/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 "encoding/binary" 22 "errors" 23 "fmt" 24 "io/ioutil" 25 "math/big" 26 "math/rand" 27 "os" 28 "reflect" 29 "testing" 30 "testing/quick" 31 32 "github.com/davecgh/go-spew/spew" 33 "github.com/gochain-io/gochain/common" 34 "github.com/gochain-io/gochain/crypto" 35 "github.com/gochain-io/gochain/ethdb" 36 "github.com/gochain-io/gochain/rlp" 37 ) 38 39 func init() { 40 spew.Config.Indent = " " 41 spew.Config.DisableMethods = false 42 } 43 44 // Used for testing 45 func newEmpty() *Trie { 46 diskdb := ethdb.NewMemDatabase() 47 trie, _ := New(common.Hash{}, NewDatabase(diskdb)) 48 return trie 49 } 50 51 func TestEmptyTrie(t *testing.T) { 52 var trie Trie 53 res := trie.Hash() 54 exp := emptyRoot 55 if res != common.Hash(exp) { 56 t.Errorf("expected %x got %x", exp, res) 57 } 58 } 59 60 func TestNull(t *testing.T) { 61 var trie Trie 62 key := make([]byte, 32) 63 value := []byte("test") 64 trie.Update(key, value) 65 if !bytes.Equal(trie.Get(key), value) { 66 t.Fatal("wrong value") 67 } 68 } 69 70 func TestMissingRoot(t *testing.T) { 71 diskdb := ethdb.NewMemDatabase() 72 trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(diskdb)) 73 if trie != nil { 74 t.Error("New returned non-nil trie for invalid root") 75 } 76 if _, ok := err.(*MissingNodeError); !ok { 77 t.Errorf("New returned wrong error: %v", err) 78 } 79 } 80 81 func TestMissingNodeDisk(t *testing.T) { testMissingNode(t, false) } 82 func TestMissingNodeMemonly(t *testing.T) { testMissingNode(t, true) } 83 84 func testMissingNode(t *testing.T, memonly bool) { 85 diskdb := ethdb.NewMemDatabase() 86 triedb := NewDatabase(diskdb) 87 88 trie, _ := New(common.Hash{}, triedb) 89 updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") 90 updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") 91 root, _ := trie.Commit(nil) 92 if !memonly { 93 triedb.Commit(root, true) 94 } 95 96 trie, _ = New(root, triedb) 97 _, err := trie.TryGet([]byte("120000")) 98 if err != nil { 99 t.Errorf("Unexpected error: %v", err) 100 } 101 trie, _ = New(root, triedb) 102 _, err = trie.TryGet([]byte("120099")) 103 if err != nil { 104 t.Errorf("Unexpected error: %v", err) 105 } 106 trie, _ = New(root, triedb) 107 _, err = trie.TryGet([]byte("123456")) 108 if err != nil { 109 t.Errorf("Unexpected error: %v", err) 110 } 111 trie, _ = New(root, triedb) 112 err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) 113 if err != nil { 114 t.Errorf("Unexpected error: %v", err) 115 } 116 trie, _ = New(root, triedb) 117 err = trie.TryDelete([]byte("123456")) 118 if err != nil { 119 t.Errorf("Unexpected error: %v", err) 120 } 121 122 hash := common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9") 123 if memonly { 124 delete(triedb.dirties, hash) 125 } else { 126 diskdb.Delete(hash[:]) 127 } 128 129 trie, _ = New(root, triedb) 130 _, err = trie.TryGet([]byte("120000")) 131 if _, ok := err.(*MissingNodeError); !ok { 132 t.Errorf("Wrong error: %v", err) 133 } 134 trie, _ = New(root, triedb) 135 _, err = trie.TryGet([]byte("120099")) 136 if _, ok := err.(*MissingNodeError); !ok { 137 t.Errorf("Wrong error: %v", err) 138 } 139 trie, _ = New(root, triedb) 140 _, err = trie.TryGet([]byte("123456")) 141 if err != nil { 142 t.Errorf("Unexpected error: %v", err) 143 } 144 trie, _ = New(root, triedb) 145 err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) 146 if _, ok := err.(*MissingNodeError); !ok { 147 t.Errorf("Wrong error: %v", err) 148 } 149 trie, _ = New(root, triedb) 150 err = trie.TryDelete([]byte("123456")) 151 if _, ok := err.(*MissingNodeError); !ok { 152 t.Errorf("Wrong error: %v", err) 153 } 154 } 155 156 func TestInsert(t *testing.T) { 157 trie := newEmpty() 158 159 updateString(trie, "doe", "reindeer") 160 updateString(trie, "dog", "puppy") 161 updateString(trie, "dogglesworth", "cat") 162 163 exp := common.HexToHash("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3") 164 root := trie.Hash() 165 if root != exp { 166 t.Errorf("exp %x got %x", exp, root) 167 } 168 169 trie = newEmpty() 170 updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") 171 172 exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") 173 root, err := trie.Commit(nil) 174 if err != nil { 175 t.Fatalf("commit error: %v", err) 176 } 177 if root != exp { 178 t.Errorf("exp %x got %x", exp, root) 179 } 180 } 181 182 func TestGet(t *testing.T) { 183 trie := newEmpty() 184 updateString(trie, "doe", "reindeer") 185 updateString(trie, "dog", "puppy") 186 updateString(trie, "dogglesworth", "cat") 187 188 for i := 0; i < 2; i++ { 189 res := getString(trie, "dog") 190 if !bytes.Equal(res, []byte("puppy")) { 191 t.Errorf("expected puppy got %x", res) 192 } 193 194 unknown := getString(trie, "unknown") 195 if unknown != nil { 196 t.Errorf("expected nil got %x", unknown) 197 } 198 199 if i == 1 { 200 return 201 } 202 trie.Commit(nil) 203 } 204 } 205 206 func TestDelete(t *testing.T) { 207 trie := newEmpty() 208 vals := []struct{ k, v string }{ 209 {"do", "verb"}, 210 {"ether", "wookiedoo"}, 211 {"horse", "stallion"}, 212 {"shaman", "horse"}, 213 {"doge", "coin"}, 214 {"ether", ""}, 215 {"dog", "puppy"}, 216 {"shaman", ""}, 217 } 218 for _, val := range vals { 219 if val.v != "" { 220 updateString(trie, val.k, val.v) 221 } else { 222 deleteString(trie, val.k) 223 } 224 } 225 226 hash := trie.Hash() 227 exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") 228 if hash != exp { 229 t.Errorf("expected %x got %x", exp, hash) 230 } 231 } 232 233 func TestEmptyValues(t *testing.T) { 234 trie := newEmpty() 235 236 vals := []struct{ k, v string }{ 237 {"do", "verb"}, 238 {"ether", "wookiedoo"}, 239 {"horse", "stallion"}, 240 {"shaman", "horse"}, 241 {"doge", "coin"}, 242 {"ether", ""}, 243 {"dog", "puppy"}, 244 {"shaman", ""}, 245 } 246 for _, val := range vals { 247 updateString(trie, val.k, val.v) 248 } 249 250 hash := trie.Hash() 251 exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") 252 if hash != exp { 253 t.Errorf("expected %x got %x", exp, hash) 254 } 255 } 256 257 func TestReplication(t *testing.T) { 258 trie := newEmpty() 259 vals := []struct{ k, v string }{ 260 {"do", "verb"}, 261 {"ether", "wookiedoo"}, 262 {"horse", "stallion"}, 263 {"shaman", "horse"}, 264 {"doge", "coin"}, 265 {"dog", "puppy"}, 266 {"somethingveryoddindeedthis is", "myothernodedata"}, 267 } 268 for _, val := range vals { 269 updateString(trie, val.k, val.v) 270 } 271 exp, err := trie.Commit(nil) 272 if err != nil { 273 t.Fatalf("commit error: %v", err) 274 } 275 276 // create a new trie on top of the database and check that lookups work. 277 trie2, err := New(exp, trie.db) 278 if err != nil { 279 t.Fatalf("can't recreate trie at %x: %v", exp, err) 280 } 281 for _, kv := range vals { 282 if string(getString(trie2, kv.k)) != kv.v { 283 t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) 284 } 285 } 286 hash, err := trie2.Commit(nil) 287 if err != nil { 288 t.Fatalf("commit error: %v", err) 289 } 290 if hash != exp { 291 t.Errorf("root failure. expected %x got %x", exp, hash) 292 } 293 294 // perform some insertions on the new trie. 295 vals2 := []struct{ k, v string }{ 296 {"do", "verb"}, 297 {"ether", "wookiedoo"}, 298 {"horse", "stallion"}, 299 // {"shaman", "horse"}, 300 // {"doge", "coin"}, 301 // {"ether", ""}, 302 // {"dog", "puppy"}, 303 // {"somethingveryoddindeedthis is", "myothernodedata"}, 304 // {"shaman", ""}, 305 } 306 for _, val := range vals2 { 307 updateString(trie2, val.k, val.v) 308 } 309 if hash := trie2.Hash(); hash != exp { 310 t.Errorf("root failure. expected %x got %x", exp, hash) 311 } 312 } 313 314 func TestLargeValue(t *testing.T) { 315 trie := newEmpty() 316 trie.Update([]byte("key1"), []byte{99, 99, 99, 99}) 317 trie.Update([]byte("key2"), bytes.Repeat([]byte{1}, 32)) 318 trie.Hash() 319 } 320 321 type countingDB struct { 322 common.Table 323 gets map[string]int 324 } 325 326 func (db *countingDB) Get(key []byte) ([]byte, error) { 327 db.gets[string(key)]++ 328 return db.Table.Get(key) 329 } 330 331 // TestCacheUnload checks that decoded nodes are unloaded after a 332 // certain number of commit operations. 333 func TestCacheUnload(t *testing.T) { 334 // Create test trie with two branches. 335 trie := newEmpty() 336 key1 := "---------------------------------" 337 key2 := "---some other branch" 338 updateString(trie, key1, "this is the branch of key1.") 339 updateString(trie, key2, "this is the branch of key2.") 340 341 root, _ := trie.Commit(nil) 342 trie.db.Commit(root, true) 343 344 // Commit the trie repeatedly and access key1. 345 // The branch containing it is loaded from DB exactly two times: 346 // in the 0th and 6th iteration. 347 diskdb := &countingDB{Table: trie.db.diskdb, gets: make(map[string]int)} 348 triedb := NewDatabase(diskdb) 349 trie, _ = New(root, triedb) 350 trie.SetCacheLimit(5) 351 for i := 0; i < 12; i++ { 352 getString(trie, key1) 353 trie.Commit(nil) 354 } 355 // Check that it got loaded two times. 356 for dbkey, count := range diskdb.gets { 357 if count != 2 { 358 t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 2) 359 } 360 } 361 } 362 363 // randTest performs random trie operations. 364 // Instances of this test are created by Generate. 365 type randTest []randTestStep 366 367 type randTestStep struct { 368 op int 369 key []byte // for opUpdate, opDelete, opGet 370 value []byte // for opUpdate 371 err error // for debugging 372 } 373 374 const ( 375 opUpdate = iota 376 opDelete 377 opGet 378 opCommit 379 opHash 380 opReset 381 opItercheckhash 382 opCheckCacheInvariant 383 opMax // boundary value, not an actual op 384 ) 385 386 func (randTest) Generate(r *rand.Rand, size int) reflect.Value { 387 var allKeys [][]byte 388 genKey := func() []byte { 389 if len(allKeys) < 2 || r.Intn(100) < 10 { 390 // new key 391 key := make([]byte, r.Intn(50)) 392 r.Read(key) 393 allKeys = append(allKeys, key) 394 return key 395 } 396 // use existing key 397 return allKeys[r.Intn(len(allKeys))] 398 } 399 400 var steps randTest 401 for i := 0; i < size; i++ { 402 step := randTestStep{op: r.Intn(opMax)} 403 switch step.op { 404 case opUpdate: 405 step.key = genKey() 406 step.value = make([]byte, 8) 407 binary.BigEndian.PutUint64(step.value, uint64(i)) 408 case opGet, opDelete: 409 step.key = genKey() 410 } 411 steps = append(steps, step) 412 } 413 return reflect.ValueOf(steps) 414 } 415 416 func runRandTest(rt randTest) bool { 417 diskdb := ethdb.NewMemDatabase() 418 triedb := NewDatabase(diskdb) 419 420 tr, _ := New(common.Hash{}, triedb) 421 values := make(map[string]string) // tracks content of the trie 422 423 for i, step := range rt { 424 switch step.op { 425 case opUpdate: 426 tr.Update(step.key, step.value) 427 values[string(step.key)] = string(step.value) 428 case opDelete: 429 tr.Delete(step.key) 430 delete(values, string(step.key)) 431 case opGet: 432 v := tr.Get(step.key) 433 want := values[string(step.key)] 434 if string(v) != want { 435 rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want) 436 } 437 case opCommit: 438 _, rt[i].err = tr.Commit(nil) 439 case opHash: 440 tr.Hash() 441 case opReset: 442 hash, err := tr.Commit(nil) 443 if err != nil { 444 rt[i].err = err 445 return false 446 } 447 newtr, err := New(hash, triedb) 448 if err != nil { 449 rt[i].err = err 450 return false 451 } 452 tr = newtr 453 case opItercheckhash: 454 checktr, _ := New(common.Hash{}, triedb) 455 it := NewIterator(tr.NodeIterator(nil)) 456 for it.Next() { 457 checktr.Update(it.Key, it.Value) 458 } 459 if tr.Hash() != checktr.Hash() { 460 rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") 461 } 462 case opCheckCacheInvariant: 463 rt[i].err = checkCacheInvariant(tr.root, nil, tr.cachegen, false, 0) 464 } 465 // Abort the test on error. 466 if rt[i].err != nil { 467 return false 468 } 469 } 470 return true 471 } 472 473 func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) error { 474 var children []node 475 var flag nodeFlag 476 switch n := n.(type) { 477 case *shortNode: 478 flag = n.flags 479 children = []node{n.Val} 480 case *fullNode: 481 flag = n.flags 482 children = n.Children[:] 483 default: 484 return nil 485 } 486 487 errorf := func(format string, args ...interface{}) error { 488 msg := fmt.Sprintf(format, args...) 489 msg += fmt.Sprintf("\nat depth %d node %s", depth, spew.Sdump(n)) 490 msg += fmt.Sprintf("parent: %s", spew.Sdump(parent)) 491 return errors.New(msg) 492 } 493 if flag.gen > parentCachegen { 494 return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen) 495 } 496 if depth > 0 && !parentDirty && flag.dirty { 497 return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen) 498 } 499 for _, child := range children { 500 if err := checkCacheInvariant(child, n, flag.gen, flag.dirty, depth+1); err != nil { 501 return err 502 } 503 } 504 return nil 505 } 506 507 func TestRandom(t *testing.T) { 508 if err := quick.Check(runRandTest, nil); err != nil { 509 if cerr, ok := err.(*quick.CheckError); ok { 510 t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In)) 511 } 512 t.Fatal(err) 513 } 514 } 515 516 func BenchmarkGet(b *testing.B) { benchGet(b, false) } 517 func BenchmarkGetDB(b *testing.B) { benchGet(b, true) } 518 func BenchmarkUpdateBE(b *testing.B) { benchUpdate(b, binary.BigEndian) } 519 func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } 520 521 const benchElemCount = 20000 522 523 func benchGet(b *testing.B, commit bool) { 524 trie := new(Trie) 525 if commit { 526 _, tmpdb := tempDB() 527 trie, _ = New(common.Hash{}, tmpdb) 528 } 529 k := make([]byte, 32) 530 for i := 0; i < benchElemCount; i++ { 531 binary.LittleEndian.PutUint64(k, uint64(i)) 532 trie.Update(k, k) 533 } 534 binary.LittleEndian.PutUint64(k, benchElemCount/2) 535 if commit { 536 trie.Commit(nil) 537 } 538 539 b.ResetTimer() 540 for i := 0; i < b.N; i++ { 541 trie.Get(k) 542 } 543 b.StopTimer() 544 545 if commit { 546 ldb := trie.db.diskdb.(*ethdb.Table) 547 ldb.Close() 548 os.RemoveAll(ldb.Path) 549 } 550 } 551 552 func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { 553 trie := newEmpty() 554 k := make([]byte, 32) 555 for i := 0; i < b.N; i++ { 556 e.PutUint64(k, uint64(i)) 557 trie.Update(k, k) 558 } 559 return trie 560 } 561 562 // Benchmarks the trie hashing. Since the trie caches the result of any operation, 563 // we cannot use b.N as the number of hashing rouns, since all rounds apart from 564 // the first one will be NOOP. As such, we'll use b.N as the number of account to 565 // insert into the trie before measuring the hashing. 566 func BenchmarkHash(b *testing.B) { 567 // Make the random benchmark deterministic 568 random := rand.New(rand.NewSource(0)) 569 570 // Create a realistic account trie to hash 571 addresses := make([][20]byte, b.N) 572 for i := 0; i < len(addresses); i++ { 573 for j := 0; j < len(addresses[i]); j++ { 574 addresses[i][j] = byte(random.Intn(256)) 575 } 576 } 577 accounts := make([][]byte, len(addresses)) 578 for i := 0; i < len(accounts); i++ { 579 var ( 580 nonce = uint64(random.Int63()) 581 balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) 582 root = emptyRoot 583 code = crypto.Keccak256(nil) 584 ) 585 accounts[i], _ = rlp.EncodeToBytes([]interface{}{nonce, balance, root, code}) 586 } 587 // Insert the accounts into the trie and hash it 588 trie := newEmpty() 589 for i := 0; i < len(addresses); i++ { 590 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 591 } 592 b.ResetTimer() 593 b.ReportAllocs() 594 trie.Hash() 595 } 596 597 func tempDB() (string, *Database) { 598 dir, err := ioutil.TempDir("", "trie-bench") 599 if err != nil { 600 panic(fmt.Sprintf("can't create temporary directory: %v", err)) 601 } 602 diskDB := ethdb.NewDB(dir) 603 if err := diskDB.Open(); err != nil { 604 panic(fmt.Sprintf("can't create temporary database: %v", err)) 605 } 606 return dir, NewDatabase(diskDB.GlobalTable()) 607 } 608 609 func getString(trie *Trie, k string) []byte { 610 return trie.Get([]byte(k)) 611 } 612 613 func updateString(trie *Trie, k, v string) { 614 trie.Update([]byte(k), []byte(v)) 615 } 616 617 func deleteString(trie *Trie, k string) { 618 trie.Delete([]byte(k)) 619 }