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