github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/trie/trie_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:45</date> 10 //</624450123639820288> 11 12 13 package trie 14 15 import ( 16 "bytes" 17 "encoding/binary" 18 "errors" 19 "fmt" 20 "io/ioutil" 21 "math/big" 22 "math/rand" 23 "os" 24 "reflect" 25 "testing" 26 "testing/quick" 27 28 "github.com/davecgh/go-spew/spew" 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/ethdb" 32 "github.com/ethereum/go-ethereum/rlp" 33 ) 34 35 func init() { 36 spew.Config.Indent = " " 37 spew.Config.DisableMethods = false 38 } 39 40 //用于测试 41 func newEmpty() *Trie { 42 trie, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase())) 43 return trie 44 } 45 46 func TestEmptyTrie(t *testing.T) { 47 var trie Trie 48 res := trie.Hash() 49 exp := emptyRoot 50 if res != common.Hash(exp) { 51 t.Errorf("expected %x got %x", exp, res) 52 } 53 } 54 55 func TestNull(t *testing.T) { 56 var trie Trie 57 key := make([]byte, 32) 58 value := []byte("test") 59 trie.Update(key, value) 60 if !bytes.Equal(trie.Get(key), value) { 61 t.Fatal("wrong value") 62 } 63 } 64 65 func TestMissingRoot(t *testing.T) { 66 trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(ethdb.NewMemDatabase())) 67 if trie != nil { 68 t.Error("New returned non-nil trie for invalid root") 69 } 70 if _, ok := err.(*MissingNodeError); !ok { 71 t.Errorf("New returned wrong error: %v", err) 72 } 73 } 74 75 func TestMissingNodeDisk(t *testing.T) { testMissingNode(t, false) } 76 func TestMissingNodeMemonly(t *testing.T) { testMissingNode(t, true) } 77 78 func testMissingNode(t *testing.T, memonly bool) { 79 diskdb := ethdb.NewMemDatabase() 80 triedb := NewDatabase(diskdb) 81 82 trie, _ := New(common.Hash{}, triedb) 83 updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") 84 updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") 85 root, _ := trie.Commit(nil) 86 if !memonly { 87 triedb.Commit(root, true) 88 } 89 90 trie, _ = New(root, triedb) 91 _, err := trie.TryGet([]byte("120000")) 92 if err != nil { 93 t.Errorf("Unexpected error: %v", err) 94 } 95 trie, _ = New(root, triedb) 96 _, err = trie.TryGet([]byte("120099")) 97 if err != nil { 98 t.Errorf("Unexpected error: %v", err) 99 } 100 trie, _ = New(root, triedb) 101 _, err = trie.TryGet([]byte("123456")) 102 if err != nil { 103 t.Errorf("Unexpected error: %v", err) 104 } 105 trie, _ = New(root, triedb) 106 err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) 107 if err != nil { 108 t.Errorf("Unexpected error: %v", err) 109 } 110 trie, _ = New(root, triedb) 111 err = trie.TryDelete([]byte("123456")) 112 if err != nil { 113 t.Errorf("Unexpected error: %v", err) 114 } 115 116 hash := common.HexToHash("0xe1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9") 117 if memonly { 118 delete(triedb.dirties, hash) 119 } else { 120 diskdb.Delete(hash[:]) 121 } 122 123 trie, _ = New(root, triedb) 124 _, err = trie.TryGet([]byte("120000")) 125 if _, ok := err.(*MissingNodeError); !ok { 126 t.Errorf("Wrong error: %v", err) 127 } 128 trie, _ = New(root, triedb) 129 _, err = trie.TryGet([]byte("120099")) 130 if _, ok := err.(*MissingNodeError); !ok { 131 t.Errorf("Wrong error: %v", err) 132 } 133 trie, _ = New(root, triedb) 134 _, err = trie.TryGet([]byte("123456")) 135 if err != nil { 136 t.Errorf("Unexpected error: %v", err) 137 } 138 trie, _ = New(root, triedb) 139 err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) 140 if _, ok := err.(*MissingNodeError); !ok { 141 t.Errorf("Wrong error: %v", err) 142 } 143 trie, _ = New(root, triedb) 144 err = trie.TryDelete([]byte("123456")) 145 if _, ok := err.(*MissingNodeError); !ok { 146 t.Errorf("Wrong error: %v", err) 147 } 148 } 149 150 func TestInsert(t *testing.T) { 151 trie := newEmpty() 152 153 updateString(trie, "doe", "reindeer") 154 updateString(trie, "dog", "puppy") 155 updateString(trie, "dogglesworth", "cat") 156 157 exp := common.HexToHash("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3") 158 root := trie.Hash() 159 if root != exp { 160 t.Errorf("exp %x got %x", exp, root) 161 } 162 163 trie = newEmpty() 164 updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") 165 166 exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") 167 root, err := trie.Commit(nil) 168 if err != nil { 169 t.Fatalf("commit error: %v", err) 170 } 171 if root != exp { 172 t.Errorf("exp %x got %x", exp, root) 173 } 174 } 175 176 func TestGet(t *testing.T) { 177 trie := newEmpty() 178 updateString(trie, "doe", "reindeer") 179 updateString(trie, "dog", "puppy") 180 updateString(trie, "dogglesworth", "cat") 181 182 for i := 0; i < 2; i++ { 183 res := getString(trie, "dog") 184 if !bytes.Equal(res, []byte("puppy")) { 185 t.Errorf("expected puppy got %x", res) 186 } 187 188 unknown := getString(trie, "unknown") 189 if unknown != nil { 190 t.Errorf("expected nil got %x", unknown) 191 } 192 193 if i == 1 { 194 return 195 } 196 trie.Commit(nil) 197 } 198 } 199 200 func TestDelete(t *testing.T) { 201 trie := newEmpty() 202 vals := []struct{ k, v string }{ 203 {"do", "verb"}, 204 {"ether", "wookiedoo"}, 205 {"horse", "stallion"}, 206 {"shaman", "horse"}, 207 {"doge", "coin"}, 208 {"ether", ""}, 209 {"dog", "puppy"}, 210 {"shaman", ""}, 211 } 212 for _, val := range vals { 213 if val.v != "" { 214 updateString(trie, val.k, val.v) 215 } else { 216 deleteString(trie, val.k) 217 } 218 } 219 220 hash := trie.Hash() 221 exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") 222 if hash != exp { 223 t.Errorf("expected %x got %x", exp, hash) 224 } 225 } 226 227 func TestEmptyValues(t *testing.T) { 228 trie := newEmpty() 229 230 vals := []struct{ k, v string }{ 231 {"do", "verb"}, 232 {"ether", "wookiedoo"}, 233 {"horse", "stallion"}, 234 {"shaman", "horse"}, 235 {"doge", "coin"}, 236 {"ether", ""}, 237 {"dog", "puppy"}, 238 {"shaman", ""}, 239 } 240 for _, val := range vals { 241 updateString(trie, val.k, val.v) 242 } 243 244 hash := trie.Hash() 245 exp := common.HexToHash("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84") 246 if hash != exp { 247 t.Errorf("expected %x got %x", exp, hash) 248 } 249 } 250 251 func TestReplication(t *testing.T) { 252 trie := newEmpty() 253 vals := []struct{ k, v string }{ 254 {"do", "verb"}, 255 {"ether", "wookiedoo"}, 256 {"horse", "stallion"}, 257 {"shaman", "horse"}, 258 {"doge", "coin"}, 259 {"dog", "puppy"}, 260 {"somethingveryoddindeedthis is", "myothernodedata"}, 261 } 262 for _, val := range vals { 263 updateString(trie, val.k, val.v) 264 } 265 exp, err := trie.Commit(nil) 266 if err != nil { 267 t.Fatalf("commit error: %v", err) 268 } 269 270 //在数据库顶部创建一个新的trie,并检查查找是否有效。 271 trie2, err := New(exp, trie.db) 272 if err != nil { 273 t.Fatalf("can't recreate trie at %x: %v", exp, err) 274 } 275 for _, kv := range vals { 276 if string(getString(trie2, kv.k)) != kv.v { 277 t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) 278 } 279 } 280 hash, err := trie2.Commit(nil) 281 if err != nil { 282 t.Fatalf("commit error: %v", err) 283 } 284 if hash != exp { 285 t.Errorf("root failure. expected %x got %x", exp, hash) 286 } 287 288 //对新的trie执行一些插入操作。 289 vals2 := []struct{ k, v string }{ 290 {"do", "verb"}, 291 {"ether", "wookiedoo"}, 292 {"horse", "stallion"}, 293 //“萨满”、“马”, 294 //“狗”,“硬币”, 295 //{“醚”、“}” 296 //“狗”,“小狗”, 297 //“有什么特别的地方是”,“我的孩子”, 298 //{“萨满”、“}” 299 } 300 for _, val := range vals2 { 301 updateString(trie2, val.k, val.v) 302 } 303 if hash := trie2.Hash(); hash != exp { 304 t.Errorf("root failure. expected %x got %x", exp, hash) 305 } 306 } 307 308 func TestLargeValue(t *testing.T) { 309 trie := newEmpty() 310 trie.Update([]byte("key1"), []byte{99, 99, 99, 99}) 311 trie.Update([]byte("key2"), bytes.Repeat([]byte{1}, 32)) 312 trie.Hash() 313 } 314 315 type countingDB struct { 316 ethdb.Database 317 gets map[string]int 318 } 319 320 func (db *countingDB) Get(key []byte) ([]byte, error) { 321 db.gets[string(key)]++ 322 return db.Database.Get(key) 323 } 324 325 //testcacheUnload检查解码后的节点是否在 326 //一定数量的提交操作。 327 func TestCacheUnload(t *testing.T) { 328 //用两个分支创建测试trie。 329 trie := newEmpty() 330 key1 := "---------------------------------" 331 key2 := "---some other branch" 332 updateString(trie, key1, "this is the branch of key1.") 333 updateString(trie, key2, "this is the branch of key2.") 334 335 root, _ := trie.Commit(nil) 336 trie.db.Commit(root, true) 337 338 //重复提交trie并访问key1。 339 //包含它的分支从数据库加载两次: 340 //在第0次和第6次迭代中。 341 diskdb := &countingDB{Database: trie.db.diskdb, gets: make(map[string]int)} 342 triedb := NewDatabase(diskdb) 343 trie, _ = New(root, triedb) 344 trie.SetCacheLimit(5) 345 for i := 0; i < 12; i++ { 346 getString(trie, key1) 347 trie.Commit(nil) 348 } 349 //检查它是否装了两次。 350 for dbkey, count := range diskdb.gets { 351 if count != 2 { 352 t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 2) 353 } 354 } 355 } 356 357 //randtest执行随机trie操作。 358 //此测试的实例由generate创建。 359 type randTest []randTestStep 360 361 type randTestStep struct { 362 op int 363 key []byte //对于opupdate、opdelete、opget 364 value []byte //为了更新 365 err error //用于调试 366 } 367 368 const ( 369 opUpdate = iota 370 opDelete 371 opGet 372 opCommit 373 opHash 374 opReset 375 opItercheckhash 376 opCheckCacheInvariant 377 opMax //边界值,不是实际操作 378 ) 379 380 func (randTest) Generate(r *rand.Rand, size int) reflect.Value { 381 var allKeys [][]byte 382 genKey := func() []byte { 383 if len(allKeys) < 2 || r.Intn(100) < 10 { 384 //新密钥 385 key := make([]byte, r.Intn(50)) 386 r.Read(key) 387 allKeys = append(allKeys, key) 388 return key 389 } 390 //使用现有密钥 391 return allKeys[r.Intn(len(allKeys))] 392 } 393 394 var steps randTest 395 for i := 0; i < size; i++ { 396 step := randTestStep{op: r.Intn(opMax)} 397 switch step.op { 398 case opUpdate: 399 step.key = genKey() 400 step.value = make([]byte, 8) 401 binary.BigEndian.PutUint64(step.value, uint64(i)) 402 case opGet, opDelete: 403 step.key = genKey() 404 } 405 steps = append(steps, step) 406 } 407 return reflect.ValueOf(steps) 408 } 409 410 func runRandTest(rt randTest) bool { 411 triedb := NewDatabase(ethdb.NewMemDatabase()) 412 413 tr, _ := New(common.Hash{}, triedb) 414 values := make(map[string]string) //跟踪trie的内容 415 416 for i, step := range rt { 417 switch step.op { 418 case opUpdate: 419 tr.Update(step.key, step.value) 420 values[string(step.key)] = string(step.value) 421 case opDelete: 422 tr.Delete(step.key) 423 delete(values, string(step.key)) 424 case opGet: 425 v := tr.Get(step.key) 426 want := values[string(step.key)] 427 if string(v) != want { 428 rt[i].err = fmt.Errorf("mismatch for key 0x%x, got 0x%x want 0x%x", step.key, v, want) 429 } 430 case opCommit: 431 _, rt[i].err = tr.Commit(nil) 432 case opHash: 433 tr.Hash() 434 case opReset: 435 hash, err := tr.Commit(nil) 436 if err != nil { 437 rt[i].err = err 438 return false 439 } 440 newtr, err := New(hash, triedb) 441 if err != nil { 442 rt[i].err = err 443 return false 444 } 445 tr = newtr 446 case opItercheckhash: 447 checktr, _ := New(common.Hash{}, triedb) 448 it := NewIterator(tr.NodeIterator(nil)) 449 for it.Next() { 450 checktr.Update(it.Key, it.Value) 451 } 452 if tr.Hash() != checktr.Hash() { 453 rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") 454 } 455 case opCheckCacheInvariant: 456 rt[i].err = checkCacheInvariant(tr.root, nil, tr.cachegen, false, 0) 457 } 458 //出错时中止测试。 459 if rt[i].err != nil { 460 return false 461 } 462 } 463 return true 464 } 465 466 func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) error { 467 var children []node 468 var flag nodeFlag 469 switch n := n.(type) { 470 case *shortNode: 471 flag = n.flags 472 children = []node{n.Val} 473 case *fullNode: 474 flag = n.flags 475 children = n.Children[:] 476 default: 477 return nil 478 } 479 480 errorf := func(format string, args ...interface{}) error { 481 msg := fmt.Sprintf(format, args...) 482 msg += fmt.Sprintf("\nat depth %d node %s", depth, spew.Sdump(n)) 483 msg += fmt.Sprintf("parent: %s", spew.Sdump(parent)) 484 return errors.New(msg) 485 } 486 if flag.gen > parentCachegen { 487 return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen) 488 } 489 if depth > 0 && !parentDirty && flag.dirty { 490 return errorf("cache invariant violation: %d > %d\n", flag.gen, parentCachegen) 491 } 492 for _, child := range children { 493 if err := checkCacheInvariant(child, n, flag.gen, flag.dirty, depth+1); err != nil { 494 return err 495 } 496 } 497 return nil 498 } 499 500 func TestRandom(t *testing.T) { 501 if err := quick.Check(runRandTest, nil); err != nil { 502 if cerr, ok := err.(*quick.CheckError); ok { 503 t.Fatalf("random test iteration %d failed: %s", cerr.Count, spew.Sdump(cerr.In)) 504 } 505 t.Fatal(err) 506 } 507 } 508 509 func BenchmarkGet(b *testing.B) { benchGet(b, false) } 510 func BenchmarkGetDB(b *testing.B) { benchGet(b, true) } 511 func BenchmarkUpdateBE(b *testing.B) { benchUpdate(b, binary.BigEndian) } 512 func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } 513 514 const benchElemCount = 20000 515 516 func benchGet(b *testing.B, commit bool) { 517 trie := new(Trie) 518 if commit { 519 _, tmpdb := tempDB() 520 trie, _ = New(common.Hash{}, tmpdb) 521 } 522 k := make([]byte, 32) 523 for i := 0; i < benchElemCount; i++ { 524 binary.LittleEndian.PutUint64(k, uint64(i)) 525 trie.Update(k, k) 526 } 527 binary.LittleEndian.PutUint64(k, benchElemCount/2) 528 if commit { 529 trie.Commit(nil) 530 } 531 532 b.ResetTimer() 533 for i := 0; i < b.N; i++ { 534 trie.Get(k) 535 } 536 b.StopTimer() 537 538 if commit { 539 ldb := trie.db.diskdb.(*ethdb.LDBDatabase) 540 ldb.Close() 541 os.RemoveAll(ldb.Path()) 542 } 543 } 544 545 func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { 546 trie := newEmpty() 547 k := make([]byte, 32) 548 for i := 0; i < b.N; i++ { 549 e.PutUint64(k, uint64(i)) 550 trie.Update(k, k) 551 } 552 return trie 553 } 554 555 //测试trie散列。由于trie缓存任何操作的结果, 556 //我们不能用b.n作为散列rouns的数目,因为除了 557 //第一个将是noop。因此,我们将使用B.N作为 558 //在测量散列之前插入trie。 559 func BenchmarkHash(b *testing.B) { 560 //使随机基准具有确定性 561 random := rand.New(rand.NewSource(0)) 562 563 //创建一个真实的帐户trie to hash 564 addresses := make([][20]byte, b.N) 565 for i := 0; i < len(addresses); i++ { 566 for j := 0; j < len(addresses[i]); j++ { 567 addresses[i][j] = byte(random.Intn(256)) 568 } 569 } 570 accounts := make([][]byte, len(addresses)) 571 for i := 0; i < len(accounts); i++ { 572 var ( 573 nonce = uint64(random.Int63()) 574 balance = new(big.Int).Rand(random, new(big.Int).Exp(common.Big2, common.Big256, nil)) 575 root = emptyRoot 576 code = crypto.Keccak256(nil) 577 ) 578 accounts[i], _ = rlp.EncodeToBytes([]interface{}{nonce, balance, root, code}) 579 } 580 //将帐户插入trie并散列它 581 trie := newEmpty() 582 for i := 0; i < len(addresses); i++ { 583 trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) 584 } 585 b.ResetTimer() 586 b.ReportAllocs() 587 trie.Hash() 588 } 589 590 func tempDB() (string, *Database) { 591 dir, err := ioutil.TempDir("", "trie-bench") 592 if err != nil { 593 panic(fmt.Sprintf("can't create temporary directory: %v", err)) 594 } 595 diskdb, err := ethdb.NewLDBDatabase(dir, 256, 0) 596 if err != nil { 597 panic(fmt.Sprintf("can't create temporary database: %v", err)) 598 } 599 return dir, NewDatabase(diskdb) 600 } 601 602 func getString(trie *Trie, k string) []byte { 603 return trie.Get([]byte(k)) 604 } 605 606 func updateString(trie *Trie, k, v string) { 607 trie.Update([]byte(k), []byte(v)) 608 } 609 610 func deleteString(trie *Trie, k string) { 611 trie.Delete([]byte(k)) 612 } 613