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