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