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