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