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