github.com/aquanetwork/aquachain@v1.7.8/trie/trie_test.go (about) 1 // Copyright 2014 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain 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 aquachain 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 aquachain 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 "gitlab.com/aquachain/aquachain/aquadb" 34 "gitlab.com/aquachain/aquachain/common" 35 "gitlab.com/aquachain/aquachain/crypto" 36 "gitlab.com/aquachain/aquachain/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 := aquadb.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 := aquadb.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 := aquadb.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.nodes, 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 aquadb.Database 323 gets map[string]int 324 } 325 326 func (db *countingDB) Get(key []byte) ([]byte, error) { 327 db.gets[string(key)]++ 328 return db.Database.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 db := &countingDB{Database: trie.db.diskdb, gets: make(map[string]int)} 348 trie, _ = New(root, NewDatabase(db)) 349 trie.SetCacheLimit(5) 350 for i := 0; i < 12; i++ { 351 getString(trie, key1) 352 trie.Commit(nil) 353 } 354 // Check that it got loaded two times. 355 for dbkey, count := range db.gets { 356 if count != 2 { 357 t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 2) 358 } 359 } 360 } 361 362 // randTest performs random trie operations. 363 // Instances of this test are created by Generate. 364 type randTest []randTestStep 365 366 type randTestStep struct { 367 op int 368 key []byte // for opUpdate, opDelete, opGet 369 value []byte // for opUpdate 370 err error // for debugging 371 } 372 373 const ( 374 opUpdate = iota 375 opDelete 376 opGet 377 opCommit 378 opHash 379 opReset 380 opItercheckhash 381 opCheckCacheInvariant 382 opMax // boundary value, not an actual op 383 ) 384 385 func (randTest) Generate(r *rand.Rand, size int) reflect.Value { 386 var allKeys [][]byte 387 genKey := func() []byte { 388 if len(allKeys) < 2 || r.Intn(100) < 10 { 389 // new key 390 key := make([]byte, r.Intn(50)) 391 r.Read(key) 392 allKeys = append(allKeys, key) 393 return key 394 } 395 // use existing key 396 return allKeys[r.Intn(len(allKeys))] 397 } 398 399 var steps randTest 400 for i := 0; i < size; i++ { 401 step := randTestStep{op: r.Intn(opMax)} 402 switch step.op { 403 case opUpdate: 404 step.key = genKey() 405 step.value = make([]byte, 8) 406 binary.BigEndian.PutUint64(step.value, uint64(i)) 407 case opGet, opDelete: 408 step.key = genKey() 409 } 410 steps = append(steps, step) 411 } 412 return reflect.ValueOf(steps) 413 } 414 415 func runRandTest(rt randTest) bool { 416 diskdb := aquadb.NewMemDatabase() 417 triedb := NewDatabase(diskdb) 418 419 tr, _ := New(common.Hash{}, triedb) 420 values := make(map[string]string) // tracks content of the trie 421 422 for i, step := range rt { 423 switch step.op { 424 case opUpdate: 425 tr.Update(step.key, step.value) 426 values[string(step.key)] = string(step.value) 427 case opDelete: 428 tr.Delete(step.key) 429 delete(values, string(step.key)) 430 case opGet: 431 v := tr.Get(step.key) 432 want := values[string(step.key)] 433 if string(v) != want { 434 rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want) 435 } 436 case opCommit: 437 _, rt[i].err = tr.Commit(nil) 438 case opHash: 439 tr.Hash() 440 case opReset: 441 hash, err := tr.Commit(nil) 442 if err != nil { 443 rt[i].err = err 444 return false 445 } 446 newtr, err := New(hash, triedb) 447 if err != nil { 448 rt[i].err = err 449 return false 450 } 451 tr = newtr 452 case opItercheckhash: 453 checktr, _ := New(common.Hash{}, triedb) 454 it := NewIterator(tr.NodeIterator(nil)) 455 for it.Next() { 456 checktr.Update(it.Key, it.Value) 457 } 458 if tr.Hash() != checktr.Hash() { 459 rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") 460 } 461 case opCheckCacheInvariant: 462 rt[i].err = checkCacheInvariant(tr.root, nil, tr.cachegen, false, 0) 463 } 464 // Abort the test on error. 465 if rt[i].err != nil { 466 return false 467 } 468 } 469 return true 470 } 471 472 func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) error { 473 var children []node 474 var flag nodeFlag 475 switch n := n.(type) { 476 case *shortNode: 477 flag = n.flags 478 children = []node{n.Val} 479 case *fullNode: 480 flag = n.flags 481 children = n.Children[:] 482 default: 483 return nil 484 } 485 486 errorf := func(format string, args ...interface{}) error { 487 msg := fmt.Sprintf(format, args...) 488 msg += fmt.Sprintf("\nat depth %d node %s", depth, spew.Sdump(n)) 489 msg += fmt.Sprintf("parent: %s", spew.Sdump(parent)) 490 return errors.New(msg) 491 } 492 if flag.gen > parentCachegen { 493 return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen) 494 } 495 if depth > 0 && !parentDirty && flag.dirty { 496 return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen) 497 } 498 for _, child := range children { 499 if err := checkCacheInvariant(child, n, flag.gen, flag.dirty, depth+1); err != nil { 500 return err 501 } 502 } 503 return nil 504 } 505 506 func TestRandom(t *testing.T) { 507 if err := quick.Check(runRandTest, nil); err != nil { 508 if cerr, ok := err.(*quick.CheckError); ok { 509 t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In)) 510 } 511 t.Fatal(err) 512 } 513 } 514 515 func BenchmarkGet(b *testing.B) { benchGet(b, false) } 516 func BenchmarkGetDB(b *testing.B) { benchGet(b, true) } 517 func BenchmarkUpdateBE(b *testing.B) { benchUpdate(b, binary.BigEndian) } 518 func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } 519 520 const benchElemCount = 20000 521 522 func benchGet(b *testing.B, commit bool) { 523 trie := new(Trie) 524 if commit { 525 _, tmpdb := tempDB() 526 trie, _ = New(common.Hash{}, tmpdb) 527 } 528 k := make([]byte, 32) 529 for i := 0; i < benchElemCount; i++ { 530 binary.LittleEndian.PutUint64(k, uint64(i)) 531 trie.Update(k, k) 532 } 533 binary.LittleEndian.PutUint64(k, benchElemCount/2) 534 if commit { 535 trie.Commit(nil) 536 } 537 538 b.ResetTimer() 539 for i := 0; i < b.N; i++ { 540 trie.Get(k) 541 } 542 b.StopTimer() 543 544 if commit { 545 ldb := trie.db.diskdb.(*aquadb.LDBDatabase) 546 ldb.Close() 547 os.RemoveAll(ldb.Path()) 548 } 549 } 550 551 func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { 552 trie := newEmpty() 553 k := make([]byte, 32) 554 for i := 0; i < b.N; i++ { 555 e.PutUint64(k, uint64(i)) 556 trie.Update(k, k) 557 } 558 return trie 559 } 560 561 // Benchmarks the trie hashing. Since the trie caches the result of any operation, 562 // we cannot use b.N as the number of hashing rouns, since all rounds apart from 563 // the first one will be NOOP. As such, we'll use b.N as the number of account to 564 // insert into the trie before measuring the hashing. 565 func BenchmarkHash(b *testing.B) { 566 // Make the random benchmark deterministic 567 random := rand.New(rand.NewSource(0)) 568 569 // Create a realistic account trie to hash 570 addresses := make([][20]byte, b.N) 571 for i := 0; i < len(addresses); i++ { 572 for j := 0; j < len(addresses[i]); j++ { 573 addresses[i][j] = byte(random.Intn(256)) 574 } 575 } 576 accounts := make([][]byte, len(addresses)) 577 for i := 0; i < len(accounts); i++ { 578 var ( 579 nonce = uint64(random.Int63()) 580 balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) 581 root = emptyRoot 582 code = crypto.Keccak256(nil) 583 ) 584 accounts[i], _ = rlp.EncodeToBytes([]interface{}{nonce, balance, root, code}) 585 } 586 // Insert the accounts into the trie and hash it 587 trie := newEmpty() 588 for i := 0; i < len(addresses); i++ { 589 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 590 } 591 b.ResetTimer() 592 b.ReportAllocs() 593 trie.Hash() 594 } 595 596 func tempDB() (string, *Database) { 597 dir, err := ioutil.TempDir("", "trie-bench") 598 if err != nil { 599 panic(fmt.Sprintf("can't create temporary directory: %v", err)) 600 } 601 diskdb, err := aquadb.NewLDBDatabase(dir, 256, 0) 602 if err != nil { 603 panic(fmt.Sprintf("can't create temporary database: %v", err)) 604 } 605 return dir, NewDatabase(diskdb) 606 } 607 608 func getString(trie *Trie, k string) []byte { 609 return trie.Get([]byte(k)) 610 } 611 612 func updateString(trie *Trie, k, v string) { 613 trie.Update([]byte(k), []byte(v)) 614 } 615 616 func deleteString(trie *Trie, k string) { 617 trie.Delete([]byte(k)) 618 }