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