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