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