github.com/theQRL/go-zond@v0.1.1/core/state/statedb_test.go (about) 1 // Copyright 2016 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 state 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "errors" 23 "fmt" 24 "math" 25 "math/big" 26 "math/rand" 27 "reflect" 28 "strings" 29 "sync" 30 "testing" 31 "testing/quick" 32 33 "github.com/holiman/uint256" 34 "github.com/theQRL/go-zond/common" 35 "github.com/theQRL/go-zond/core/rawdb" 36 "github.com/theQRL/go-zond/core/state/snapshot" 37 "github.com/theQRL/go-zond/core/types" 38 "github.com/theQRL/go-zond/crypto" 39 "github.com/theQRL/go-zond/rlp" 40 "github.com/theQRL/go-zond/trie" 41 "github.com/theQRL/go-zond/trie/triedb/hashdb" 42 "github.com/theQRL/go-zond/trie/triedb/pathdb" 43 "github.com/theQRL/go-zond/trie/trienode" 44 ) 45 46 // Tests that updating a state trie does not leak any database writes prior to 47 // actually committing the state. 48 func TestUpdateLeaks(t *testing.T) { 49 // Create an empty state database 50 var ( 51 db = rawdb.NewMemoryDatabase() 52 tdb = trie.NewDatabase(db, nil) 53 ) 54 state, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(db, tdb), nil) 55 56 // Update it with some accounts 57 for i := byte(0); i < 255; i++ { 58 addr := common.BytesToAddress([]byte{i}) 59 state.AddBalance(addr, big.NewInt(int64(11*i))) 60 state.SetNonce(addr, uint64(42*i)) 61 if i%2 == 0 { 62 state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) 63 } 64 if i%3 == 0 { 65 state.SetCode(addr, []byte{i, i, i, i, i}) 66 } 67 } 68 69 root := state.IntermediateRoot(false) 70 if err := tdb.Commit(root, false); err != nil { 71 t.Errorf("can not commit trie %v to persistent database", root.Hex()) 72 } 73 74 // Ensure that no data was leaked into the database 75 it := db.NewIterator(nil, nil) 76 for it.Next() { 77 t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value()) 78 } 79 it.Release() 80 } 81 82 // Tests that no intermediate state of an object is stored into the database, 83 // only the one right before the commit. 84 func TestIntermediateLeaks(t *testing.T) { 85 // Create two state databases, one transitioning to the final state, the other final from the beginning 86 transDb := rawdb.NewMemoryDatabase() 87 finalDb := rawdb.NewMemoryDatabase() 88 transNdb := trie.NewDatabase(transDb, nil) 89 finalNdb := trie.NewDatabase(finalDb, nil) 90 transState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(transDb, transNdb), nil) 91 finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil) 92 93 modify := func(state *StateDB, addr common.Address, i, tweak byte) { 94 state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) 95 state.SetNonce(addr, uint64(42*i+tweak)) 96 if i%2 == 0 { 97 state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) 98 state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) 99 } 100 if i%3 == 0 { 101 state.SetCode(addr, []byte{i, i, i, i, i, tweak}) 102 } 103 } 104 105 // Modify the transient state. 106 for i := byte(0); i < 255; i++ { 107 modify(transState, common.Address{i}, i, 0) 108 } 109 // Write modifications to trie. 110 transState.IntermediateRoot(false) 111 112 // Overwrite all the data with new values in the transient database. 113 for i := byte(0); i < 255; i++ { 114 modify(transState, common.Address{i}, i, 99) 115 modify(finalState, common.Address{i}, i, 99) 116 } 117 118 // Commit and cross check the databases. 119 transRoot, err := transState.Commit(0, false) 120 if err != nil { 121 t.Fatalf("failed to commit transition state: %v", err) 122 } 123 if err = transNdb.Commit(transRoot, false); err != nil { 124 t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) 125 } 126 127 finalRoot, err := finalState.Commit(0, false) 128 if err != nil { 129 t.Fatalf("failed to commit final state: %v", err) 130 } 131 if err = finalNdb.Commit(finalRoot, false); err != nil { 132 t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex()) 133 } 134 135 it := finalDb.NewIterator(nil, nil) 136 for it.Next() { 137 key, fvalue := it.Key(), it.Value() 138 tvalue, err := transDb.Get(key) 139 if err != nil { 140 t.Errorf("entry missing from the transition database: %x -> %x", key, fvalue) 141 } 142 if !bytes.Equal(fvalue, tvalue) { 143 t.Errorf("value mismatch at key %x: %x in transition database, %x in final database", key, tvalue, fvalue) 144 } 145 } 146 it.Release() 147 148 it = transDb.NewIterator(nil, nil) 149 for it.Next() { 150 key, tvalue := it.Key(), it.Value() 151 fvalue, err := finalDb.Get(key) 152 if err != nil { 153 t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value()) 154 } 155 if !bytes.Equal(fvalue, tvalue) { 156 t.Errorf("value mismatch at key %x: %x in transition database, %x in final database", key, tvalue, fvalue) 157 } 158 } 159 } 160 161 // TestCopy tests that copying a StateDB object indeed makes the original and 162 // the copy independent of each other. This test is a regression test against 163 // https://github.com/theQRL/go-zond/pull/15549. 164 func TestCopy(t *testing.T) { 165 // Create a random state test to copy and modify "independently" 166 orig, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) 167 168 for i := byte(0); i < 255; i++ { 169 obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 170 obj.AddBalance(big.NewInt(int64(i))) 171 orig.updateStateObject(obj) 172 } 173 orig.Finalise(false) 174 175 // Copy the state 176 copy := orig.Copy() 177 178 // Copy the copy state 179 ccopy := copy.Copy() 180 181 // modify all in memory 182 for i := byte(0); i < 255; i++ { 183 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 184 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 185 ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 186 187 origObj.AddBalance(big.NewInt(2 * int64(i))) 188 copyObj.AddBalance(big.NewInt(3 * int64(i))) 189 ccopyObj.AddBalance(big.NewInt(4 * int64(i))) 190 191 orig.updateStateObject(origObj) 192 copy.updateStateObject(copyObj) 193 ccopy.updateStateObject(copyObj) 194 } 195 196 // Finalise the changes on all concurrently 197 finalise := func(wg *sync.WaitGroup, db *StateDB) { 198 defer wg.Done() 199 db.Finalise(true) 200 } 201 202 var wg sync.WaitGroup 203 wg.Add(3) 204 go finalise(&wg, orig) 205 go finalise(&wg, copy) 206 go finalise(&wg, ccopy) 207 wg.Wait() 208 209 // Verify that the three states have been updated independently 210 for i := byte(0); i < 255; i++ { 211 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 212 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 213 ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 214 215 if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { 216 t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) 217 } 218 if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 { 219 t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want) 220 } 221 if want := big.NewInt(5 * int64(i)); ccopyObj.Balance().Cmp(want) != 0 { 222 t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, ccopyObj.Balance(), want) 223 } 224 } 225 } 226 227 func TestSnapshotRandom(t *testing.T) { 228 config := &quick.Config{MaxCount: 1000} 229 err := quick.Check((*snapshotTest).run, config) 230 if cerr, ok := err.(*quick.CheckError); ok { 231 test := cerr.In[0].(*snapshotTest) 232 t.Errorf("%v:\n%s", test.err, test) 233 } else if err != nil { 234 t.Error(err) 235 } 236 } 237 238 // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes 239 // captured by the snapshot. Instances of this test with pseudorandom content are created 240 // by Generate. 241 // 242 // The test works as follows: 243 // 244 // A new state is created and all actions are applied to it. Several snapshots are taken 245 // in between actions. The test then reverts each snapshot. For each snapshot the actions 246 // leading up to it are replayed on a fresh, empty state. The behaviour of all public 247 // accessor methods on the reverted state must match the return value of the equivalent 248 // methods on the replayed state. 249 type snapshotTest struct { 250 addrs []common.Address // all account addresses 251 actions []testAction // modifications to the state 252 snapshots []int // actions indexes at which snapshot is taken 253 err error // failure details are reported through this field 254 } 255 256 type testAction struct { 257 name string 258 fn func(testAction, *StateDB) 259 args []int64 260 noAddr bool 261 } 262 263 // newTestAction creates a random action that changes state. 264 func newTestAction(addr common.Address, r *rand.Rand) testAction { 265 actions := []testAction{ 266 { 267 name: "SetBalance", 268 fn: func(a testAction, s *StateDB) { 269 s.SetBalance(addr, big.NewInt(a.args[0])) 270 }, 271 args: make([]int64, 1), 272 }, 273 { 274 name: "AddBalance", 275 fn: func(a testAction, s *StateDB) { 276 s.AddBalance(addr, big.NewInt(a.args[0])) 277 }, 278 args: make([]int64, 1), 279 }, 280 { 281 name: "SetNonce", 282 fn: func(a testAction, s *StateDB) { 283 s.SetNonce(addr, uint64(a.args[0])) 284 }, 285 args: make([]int64, 1), 286 }, 287 { 288 name: "SetState", 289 fn: func(a testAction, s *StateDB) { 290 var key, val common.Hash 291 binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) 292 binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) 293 s.SetState(addr, key, val) 294 }, 295 args: make([]int64, 2), 296 }, 297 { 298 name: "SetCode", 299 fn: func(a testAction, s *StateDB) { 300 code := make([]byte, 16) 301 binary.BigEndian.PutUint64(code, uint64(a.args[0])) 302 binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) 303 s.SetCode(addr, code) 304 }, 305 args: make([]int64, 2), 306 }, 307 { 308 name: "CreateAccount", 309 fn: func(a testAction, s *StateDB) { 310 s.CreateAccount(addr) 311 }, 312 }, 313 { 314 name: "SelfDestruct", 315 fn: func(a testAction, s *StateDB) { 316 s.SelfDestruct(addr) 317 }, 318 }, 319 { 320 name: "AddRefund", 321 fn: func(a testAction, s *StateDB) { 322 s.AddRefund(uint64(a.args[0])) 323 }, 324 args: make([]int64, 1), 325 noAddr: true, 326 }, 327 { 328 name: "AddLog", 329 fn: func(a testAction, s *StateDB) { 330 data := make([]byte, 2) 331 binary.BigEndian.PutUint16(data, uint16(a.args[0])) 332 s.AddLog(&types.Log{Address: addr, Data: data}) 333 }, 334 args: make([]int64, 1), 335 }, 336 { 337 name: "AddPreimage", 338 fn: func(a testAction, s *StateDB) { 339 preimage := []byte{1} 340 hash := common.BytesToHash(preimage) 341 s.AddPreimage(hash, preimage) 342 }, 343 args: make([]int64, 1), 344 }, 345 { 346 name: "AddAddressToAccessList", 347 fn: func(a testAction, s *StateDB) { 348 s.AddAddressToAccessList(addr) 349 }, 350 }, 351 { 352 name: "AddSlotToAccessList", 353 fn: func(a testAction, s *StateDB) { 354 s.AddSlotToAccessList(addr, 355 common.Hash{byte(a.args[0])}) 356 }, 357 args: make([]int64, 1), 358 }, 359 { 360 name: "SetTransientState", 361 fn: func(a testAction, s *StateDB) { 362 var key, val common.Hash 363 binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) 364 binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) 365 s.SetTransientState(addr, key, val) 366 }, 367 args: make([]int64, 2), 368 }, 369 } 370 action := actions[r.Intn(len(actions))] 371 var nameargs []string 372 if !action.noAddr { 373 nameargs = append(nameargs, addr.Hex()) 374 } 375 for i := range action.args { 376 action.args[i] = rand.Int63n(100) 377 nameargs = append(nameargs, fmt.Sprint(action.args[i])) 378 } 379 action.name += strings.Join(nameargs, ", ") 380 return action 381 } 382 383 // Generate returns a new snapshot test of the given size. All randomness is 384 // derived from r. 385 func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { 386 // Generate random actions. 387 addrs := make([]common.Address, 50) 388 for i := range addrs { 389 addrs[i][0] = byte(i) 390 } 391 actions := make([]testAction, size) 392 for i := range actions { 393 addr := addrs[r.Intn(len(addrs))] 394 actions[i] = newTestAction(addr, r) 395 } 396 // Generate snapshot indexes. 397 nsnapshots := int(math.Sqrt(float64(size))) 398 if size > 0 && nsnapshots == 0 { 399 nsnapshots = 1 400 } 401 snapshots := make([]int, nsnapshots) 402 snaplen := len(actions) / nsnapshots 403 for i := range snapshots { 404 // Try to place the snapshots some number of actions apart from each other. 405 snapshots[i] = (i * snaplen) + r.Intn(snaplen) 406 } 407 return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) 408 } 409 410 func (test *snapshotTest) String() string { 411 out := new(bytes.Buffer) 412 sindex := 0 413 for i, action := range test.actions { 414 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 415 fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) 416 sindex++ 417 } 418 fmt.Fprintf(out, "%4d: %s\n", i, action.name) 419 } 420 return out.String() 421 } 422 423 func (test *snapshotTest) run() bool { 424 // Run all actions and create snapshots. 425 var ( 426 state, _ = New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) 427 snapshotRevs = make([]int, len(test.snapshots)) 428 sindex = 0 429 ) 430 for i, action := range test.actions { 431 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 432 snapshotRevs[sindex] = state.Snapshot() 433 sindex++ 434 } 435 action.fn(action, state) 436 } 437 // Revert all snapshots in reverse order. Each revert must yield a state 438 // that is equivalent to fresh state with all actions up the snapshot applied. 439 for sindex--; sindex >= 0; sindex-- { 440 checkstate, _ := New(types.EmptyRootHash, state.Database(), nil) 441 for _, action := range test.actions[:test.snapshots[sindex]] { 442 action.fn(action, checkstate) 443 } 444 state.RevertToSnapshot(snapshotRevs[sindex]) 445 if err := test.checkEqual(state, checkstate); err != nil { 446 test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err) 447 return false 448 } 449 } 450 return true 451 } 452 453 func forEachStorage(s *StateDB, addr common.Address, cb func(key, value common.Hash) bool) error { 454 so := s.getStateObject(addr) 455 if so == nil { 456 return nil 457 } 458 tr, err := so.getTrie() 459 if err != nil { 460 return err 461 } 462 trieIt, err := tr.NodeIterator(nil) 463 if err != nil { 464 return err 465 } 466 it := trie.NewIterator(trieIt) 467 468 for it.Next() { 469 key := common.BytesToHash(s.trie.GetKey(it.Key)) 470 if value, dirty := so.dirtyStorage[key]; dirty { 471 if !cb(key, value) { 472 return nil 473 } 474 continue 475 } 476 477 if len(it.Value) > 0 { 478 _, content, _, err := rlp.Split(it.Value) 479 if err != nil { 480 return err 481 } 482 if !cb(key, common.BytesToHash(content)) { 483 return nil 484 } 485 } 486 } 487 return nil 488 } 489 490 // checkEqual checks that methods of state and checkstate return the same values. 491 func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { 492 for _, addr := range test.addrs { 493 var err error 494 checkeq := func(op string, a, b interface{}) bool { 495 if err == nil && !reflect.DeepEqual(a, b) { 496 err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b) 497 return false 498 } 499 return true 500 } 501 // Check basic accessor methods. 502 checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) 503 checkeq("HasSelfdestructed", state.HasSelfDestructed(addr), checkstate.HasSelfDestructed(addr)) 504 checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) 505 checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) 506 checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) 507 checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) 508 checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) 509 // Check storage. 510 if obj := state.getStateObject(addr); obj != nil { 511 forEachStorage(state, addr, func(key, value common.Hash) bool { 512 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 513 }) 514 forEachStorage(checkstate, addr, func(key, value common.Hash) bool { 515 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 516 }) 517 } 518 if err != nil { 519 return err 520 } 521 } 522 523 if state.GetRefund() != checkstate.GetRefund() { 524 return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", 525 state.GetRefund(), checkstate.GetRefund()) 526 } 527 if !reflect.DeepEqual(state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) { 528 return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", 529 state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) 530 } 531 return nil 532 } 533 534 func TestTouchDelete(t *testing.T) { 535 s := newStateEnv() 536 s.state.GetOrNewStateObject(common.Address{}) 537 root, _ := s.state.Commit(0, false) 538 s.state, _ = New(root, s.state.db, s.state.snaps) 539 540 snapshot := s.state.Snapshot() 541 s.state.AddBalance(common.Address{}, new(big.Int)) 542 543 if len(s.state.journal.dirties) != 1 { 544 t.Fatal("expected one dirty state object") 545 } 546 s.state.RevertToSnapshot(snapshot) 547 if len(s.state.journal.dirties) != 0 { 548 t.Fatal("expected no dirty state object") 549 } 550 } 551 552 // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. 553 // See https://github.com/theQRL/go-zond/pull/15225#issuecomment-380191512 554 func TestCopyOfCopy(t *testing.T) { 555 state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) 556 addr := common.HexToAddress("aaaa") 557 state.SetBalance(addr, big.NewInt(42)) 558 559 if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { 560 t.Fatalf("1st copy fail, expected 42, got %v", got) 561 } 562 if got := state.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { 563 t.Fatalf("2nd copy fail, expected 42, got %v", got) 564 } 565 } 566 567 // Tests a regression where committing a copy lost some internal meta information, 568 // leading to corrupted subsequent copies. 569 // 570 // See https://github.com/theQRL/go-zond/issues/20106. 571 func TestCopyCommitCopy(t *testing.T) { 572 tdb := NewDatabase(rawdb.NewMemoryDatabase()) 573 state, _ := New(types.EmptyRootHash, tdb, nil) 574 575 // Create an account and check if the retrieved balance is correct 576 addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") 577 skey := common.HexToHash("aaa") 578 sval := common.HexToHash("bbb") 579 580 state.SetBalance(addr, big.NewInt(42)) // Change the account trie 581 state.SetCode(addr, []byte("hello")) // Change an external metadata 582 state.SetState(addr, skey, sval) // Change the storage trie 583 584 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 585 t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) 586 } 587 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 588 t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) 589 } 590 if val := state.GetState(addr, skey); val != sval { 591 t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) 592 } 593 if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { 594 t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 595 } 596 // Copy the non-committed state database and check pre/post commit balance 597 copyOne := state.Copy() 598 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 599 t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42) 600 } 601 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 602 t.Fatalf("first copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) 603 } 604 if val := copyOne.GetState(addr, skey); val != sval { 605 t.Fatalf("first copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 606 } 607 if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { 608 t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 609 } 610 // Copy the copy and check the balance once more 611 copyTwo := copyOne.Copy() 612 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 613 t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42) 614 } 615 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 616 t.Fatalf("second copy code mismatch: have %x, want %x", code, []byte("hello")) 617 } 618 if val := copyTwo.GetState(addr, skey); val != sval { 619 t.Fatalf("second copy non-committed storage slot mismatch: have %x, want %x", val, sval) 620 } 621 if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { 622 t.Fatalf("second copy committed storage slot mismatch: have %x, want %x", val, sval) 623 } 624 // Commit state, ensure states can be loaded from disk 625 root, _ := state.Commit(0, false) 626 state, _ = New(root, tdb, nil) 627 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 628 t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42) 629 } 630 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 631 t.Fatalf("state post-commit code mismatch: have %x, want %x", code, []byte("hello")) 632 } 633 if val := state.GetState(addr, skey); val != sval { 634 t.Fatalf("state post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 635 } 636 if val := state.GetCommittedState(addr, skey); val != sval { 637 t.Fatalf("state post-commit committed storage slot mismatch: have %x, want %x", val, sval) 638 } 639 } 640 641 // Tests a regression where committing a copy lost some internal meta information, 642 // leading to corrupted subsequent copies. 643 // 644 // See https://github.com/theQRL/go-zond/issues/20106. 645 func TestCopyCopyCommitCopy(t *testing.T) { 646 state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) 647 648 // Create an account and check if the retrieved balance is correct 649 addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") 650 skey := common.HexToHash("aaa") 651 sval := common.HexToHash("bbb") 652 653 state.SetBalance(addr, big.NewInt(42)) // Change the account trie 654 state.SetCode(addr, []byte("hello")) // Change an external metadata 655 state.SetState(addr, skey, sval) // Change the storage trie 656 657 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 658 t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) 659 } 660 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 661 t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) 662 } 663 if val := state.GetState(addr, skey); val != sval { 664 t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) 665 } 666 if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { 667 t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 668 } 669 // Copy the non-committed state database and check pre/post commit balance 670 copyOne := state.Copy() 671 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 672 t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42) 673 } 674 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 675 t.Fatalf("first copy code mismatch: have %x, want %x", code, []byte("hello")) 676 } 677 if val := copyOne.GetState(addr, skey); val != sval { 678 t.Fatalf("first copy non-committed storage slot mismatch: have %x, want %x", val, sval) 679 } 680 if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { 681 t.Fatalf("first copy committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 682 } 683 // Copy the copy and check the balance once more 684 copyTwo := copyOne.Copy() 685 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 686 t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42) 687 } 688 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 689 t.Fatalf("second copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) 690 } 691 if val := copyTwo.GetState(addr, skey); val != sval { 692 t.Fatalf("second copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 693 } 694 if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { 695 t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 696 } 697 // Copy the copy-copy and check the balance once more 698 copyThree := copyTwo.Copy() 699 if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 700 t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42) 701 } 702 if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 703 t.Fatalf("third copy code mismatch: have %x, want %x", code, []byte("hello")) 704 } 705 if val := copyThree.GetState(addr, skey); val != sval { 706 t.Fatalf("third copy non-committed storage slot mismatch: have %x, want %x", val, sval) 707 } 708 if val := copyThree.GetCommittedState(addr, skey); val != (common.Hash{}) { 709 t.Fatalf("third copy committed storage slot mismatch: have %x, want %x", val, sval) 710 } 711 } 712 713 // TestCommitCopy tests the copy from a committed state is not functional. 714 func TestCommitCopy(t *testing.T) { 715 state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) 716 717 // Create an account and check if the retrieved balance is correct 718 addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") 719 skey := common.HexToHash("aaa") 720 sval := common.HexToHash("bbb") 721 722 state.SetBalance(addr, big.NewInt(42)) // Change the account trie 723 state.SetCode(addr, []byte("hello")) // Change an external metadata 724 state.SetState(addr, skey, sval) // Change the storage trie 725 726 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 727 t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) 728 } 729 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 730 t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) 731 } 732 if val := state.GetState(addr, skey); val != sval { 733 t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) 734 } 735 if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { 736 t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 737 } 738 // Copy the committed state database, the copied one is not functional. 739 state.Commit(0, true) 740 copied := state.Copy() 741 if balance := copied.GetBalance(addr); balance.Cmp(big.NewInt(0)) != 0 { 742 t.Fatalf("unexpected balance: have %v", balance) 743 } 744 if code := copied.GetCode(addr); code != nil { 745 t.Fatalf("unexpected code: have %x", code) 746 } 747 if val := copied.GetState(addr, skey); val != (common.Hash{}) { 748 t.Fatalf("unexpected storage slot: have %x", val) 749 } 750 if val := copied.GetCommittedState(addr, skey); val != (common.Hash{}) { 751 t.Fatalf("unexpected storage slot: have %x", val) 752 } 753 if !errors.Is(copied.Error(), trie.ErrCommitted) { 754 t.Fatalf("unexpected state error, %v", copied.Error()) 755 } 756 } 757 758 // TestDeleteCreateRevert tests a weird state transition corner case that we hit 759 // while changing the internals of StateDB. The workflow is that a contract is 760 // self-destructed, then in a follow-up transaction (but same block) it's created 761 // again and the transaction reverted. 762 // 763 // The original StateDB implementation flushed dirty objects to the tries after 764 // each transaction, so this works ok. The rework accumulated writes in memory 765 // first, but the journal wiped the entire state object on create-revert. 766 func TestDeleteCreateRevert(t *testing.T) { 767 // Create an initial state with a single contract 768 state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) 769 770 addr := common.BytesToAddress([]byte("so")) 771 state.SetBalance(addr, big.NewInt(1)) 772 773 root, _ := state.Commit(0, false) 774 state, _ = New(root, state.db, state.snaps) 775 776 // Simulate self-destructing in one transaction, then create-reverting in another 777 state.SelfDestruct(addr) 778 state.Finalise(true) 779 780 id := state.Snapshot() 781 state.SetBalance(addr, big.NewInt(2)) 782 state.RevertToSnapshot(id) 783 784 // Commit the entire state and make sure we don't crash and have the correct state 785 root, _ = state.Commit(0, true) 786 state, _ = New(root, state.db, state.snaps) 787 788 if state.getStateObject(addr) != nil { 789 t.Fatalf("self-destructed contract came alive") 790 } 791 } 792 793 // TestMissingTrieNodes tests that if the StateDB fails to load parts of the trie, 794 // the Commit operation fails with an error 795 // If we are missing trie nodes, we should not continue writing to the trie 796 func TestMissingTrieNodes(t *testing.T) { 797 testMissingTrieNodes(t, rawdb.HashScheme) 798 testMissingTrieNodes(t, rawdb.PathScheme) 799 } 800 801 func testMissingTrieNodes(t *testing.T, scheme string) { 802 // Create an initial state with a few accounts 803 var ( 804 triedb *trie.Database 805 memDb = rawdb.NewMemoryDatabase() 806 ) 807 if scheme == rawdb.PathScheme { 808 triedb = trie.NewDatabase(memDb, &trie.Config{PathDB: &pathdb.Config{ 809 CleanCacheSize: 0, 810 DirtyCacheSize: 0, 811 }}) // disable caching 812 } else { 813 triedb = trie.NewDatabase(memDb, &trie.Config{HashDB: &hashdb.Config{ 814 CleanCacheSize: 0, 815 }}) // disable caching 816 } 817 db := NewDatabaseWithNodeDB(memDb, triedb) 818 819 var root common.Hash 820 state, _ := New(types.EmptyRootHash, db, nil) 821 addr := common.BytesToAddress([]byte("so")) 822 { 823 state.SetBalance(addr, big.NewInt(1)) 824 state.SetCode(addr, []byte{1, 2, 3}) 825 a2 := common.BytesToAddress([]byte("another")) 826 state.SetBalance(a2, big.NewInt(100)) 827 state.SetCode(a2, []byte{1, 2, 4}) 828 root, _ = state.Commit(0, false) 829 t.Logf("root: %x", root) 830 // force-flush 831 triedb.Commit(root, false) 832 } 833 // Create a new state on the old root 834 state, _ = New(root, db, nil) 835 // Now we clear out the memdb 836 it := memDb.NewIterator(nil, nil) 837 for it.Next() { 838 k := it.Key() 839 // Leave the root intact 840 if !bytes.Equal(k, root[:]) { 841 t.Logf("key: %x", k) 842 memDb.Delete(k) 843 } 844 } 845 balance := state.GetBalance(addr) 846 // The removed elem should lead to it returning zero balance 847 if exp, got := uint64(0), balance.Uint64(); got != exp { 848 t.Errorf("expected %d, got %d", exp, got) 849 } 850 // Modify the state 851 state.SetBalance(addr, big.NewInt(2)) 852 root, err := state.Commit(0, false) 853 if err == nil { 854 t.Fatalf("expected error, got root :%x", root) 855 } 856 } 857 858 func TestStateDBAccessList(t *testing.T) { 859 // Some helpers 860 addr := func(a string) common.Address { 861 return common.HexToAddress(a) 862 } 863 slot := func(a string) common.Hash { 864 return common.HexToHash(a) 865 } 866 867 memDb := rawdb.NewMemoryDatabase() 868 db := NewDatabase(memDb) 869 state, _ := New(types.EmptyRootHash, db, nil) 870 state.accessList = newAccessList() 871 872 verifyAddrs := func(astrings ...string) { 873 t.Helper() 874 // convert to common.Address form 875 var addresses []common.Address 876 var addressMap = make(map[common.Address]struct{}) 877 for _, astring := range astrings { 878 address := addr(astring) 879 addresses = append(addresses, address) 880 addressMap[address] = struct{}{} 881 } 882 // Check that the given addresses are in the access list 883 for _, address := range addresses { 884 if !state.AddressInAccessList(address) { 885 t.Fatalf("expected %x to be in access list", address) 886 } 887 } 888 // Check that only the expected addresses are present in the access list 889 for address := range state.accessList.addresses { 890 if _, exist := addressMap[address]; !exist { 891 t.Fatalf("extra address %x in access list", address) 892 } 893 } 894 } 895 verifySlots := func(addrString string, slotStrings ...string) { 896 if !state.AddressInAccessList(addr(addrString)) { 897 t.Fatalf("scope missing address/slots %v", addrString) 898 } 899 var address = addr(addrString) 900 // convert to common.Hash form 901 var slots []common.Hash 902 var slotMap = make(map[common.Hash]struct{}) 903 for _, slotString := range slotStrings { 904 s := slot(slotString) 905 slots = append(slots, s) 906 slotMap[s] = struct{}{} 907 } 908 // Check that the expected items are in the access list 909 for i, s := range slots { 910 if _, slotPresent := state.SlotInAccessList(address, s); !slotPresent { 911 t.Fatalf("input %d: scope missing slot %v (address %v)", i, s, addrString) 912 } 913 } 914 // Check that no extra elements are in the access list 915 index := state.accessList.addresses[address] 916 if index >= 0 { 917 stateSlots := state.accessList.slots[index] 918 for s := range stateSlots { 919 if _, slotPresent := slotMap[s]; !slotPresent { 920 t.Fatalf("scope has extra slot %v (address %v)", s, addrString) 921 } 922 } 923 } 924 } 925 926 state.AddAddressToAccessList(addr("aa")) // 1 927 state.AddSlotToAccessList(addr("bb"), slot("01")) // 2,3 928 state.AddSlotToAccessList(addr("bb"), slot("02")) // 4 929 verifyAddrs("aa", "bb") 930 verifySlots("bb", "01", "02") 931 932 // Make a copy 933 stateCopy1 := state.Copy() 934 if exp, got := 4, state.journal.length(); exp != got { 935 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 936 } 937 938 // same again, should cause no journal entries 939 state.AddSlotToAccessList(addr("bb"), slot("01")) 940 state.AddSlotToAccessList(addr("bb"), slot("02")) 941 state.AddAddressToAccessList(addr("aa")) 942 if exp, got := 4, state.journal.length(); exp != got { 943 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 944 } 945 // some new ones 946 state.AddSlotToAccessList(addr("bb"), slot("03")) // 5 947 state.AddSlotToAccessList(addr("aa"), slot("01")) // 6 948 state.AddSlotToAccessList(addr("cc"), slot("01")) // 7,8 949 state.AddAddressToAccessList(addr("cc")) 950 if exp, got := 8, state.journal.length(); exp != got { 951 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 952 } 953 954 verifyAddrs("aa", "bb", "cc") 955 verifySlots("aa", "01") 956 verifySlots("bb", "01", "02", "03") 957 verifySlots("cc", "01") 958 959 // now start rolling back changes 960 state.journal.revert(state, 7) 961 if _, ok := state.SlotInAccessList(addr("cc"), slot("01")); ok { 962 t.Fatalf("slot present, expected missing") 963 } 964 verifyAddrs("aa", "bb", "cc") 965 verifySlots("aa", "01") 966 verifySlots("bb", "01", "02", "03") 967 968 state.journal.revert(state, 6) 969 if state.AddressInAccessList(addr("cc")) { 970 t.Fatalf("addr present, expected missing") 971 } 972 verifyAddrs("aa", "bb") 973 verifySlots("aa", "01") 974 verifySlots("bb", "01", "02", "03") 975 976 state.journal.revert(state, 5) 977 if _, ok := state.SlotInAccessList(addr("aa"), slot("01")); ok { 978 t.Fatalf("slot present, expected missing") 979 } 980 verifyAddrs("aa", "bb") 981 verifySlots("bb", "01", "02", "03") 982 983 state.journal.revert(state, 4) 984 if _, ok := state.SlotInAccessList(addr("bb"), slot("03")); ok { 985 t.Fatalf("slot present, expected missing") 986 } 987 verifyAddrs("aa", "bb") 988 verifySlots("bb", "01", "02") 989 990 state.journal.revert(state, 3) 991 if _, ok := state.SlotInAccessList(addr("bb"), slot("02")); ok { 992 t.Fatalf("slot present, expected missing") 993 } 994 verifyAddrs("aa", "bb") 995 verifySlots("bb", "01") 996 997 state.journal.revert(state, 2) 998 if _, ok := state.SlotInAccessList(addr("bb"), slot("01")); ok { 999 t.Fatalf("slot present, expected missing") 1000 } 1001 verifyAddrs("aa", "bb") 1002 1003 state.journal.revert(state, 1) 1004 if state.AddressInAccessList(addr("bb")) { 1005 t.Fatalf("addr present, expected missing") 1006 } 1007 verifyAddrs("aa") 1008 1009 state.journal.revert(state, 0) 1010 if state.AddressInAccessList(addr("aa")) { 1011 t.Fatalf("addr present, expected missing") 1012 } 1013 if got, exp := len(state.accessList.addresses), 0; got != exp { 1014 t.Fatalf("expected empty, got %d", got) 1015 } 1016 if got, exp := len(state.accessList.slots), 0; got != exp { 1017 t.Fatalf("expected empty, got %d", got) 1018 } 1019 // Check the copy 1020 // Make a copy 1021 state = stateCopy1 1022 verifyAddrs("aa", "bb") 1023 verifySlots("bb", "01", "02") 1024 if got, exp := len(state.accessList.addresses), 2; got != exp { 1025 t.Fatalf("expected empty, got %d", got) 1026 } 1027 if got, exp := len(state.accessList.slots), 1; got != exp { 1028 t.Fatalf("expected empty, got %d", got) 1029 } 1030 } 1031 1032 // Tests that account and storage tries are flushed in the correct order and that 1033 // no data loss occurs. 1034 func TestFlushOrderDataLoss(t *testing.T) { 1035 // Create a state trie with many accounts and slots 1036 var ( 1037 memdb = rawdb.NewMemoryDatabase() 1038 triedb = trie.NewDatabase(memdb, nil) 1039 statedb = NewDatabaseWithNodeDB(memdb, triedb) 1040 state, _ = New(types.EmptyRootHash, statedb, nil) 1041 ) 1042 for a := byte(0); a < 10; a++ { 1043 state.CreateAccount(common.Address{a}) 1044 for s := byte(0); s < 10; s++ { 1045 state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s}) 1046 } 1047 } 1048 root, err := state.Commit(0, false) 1049 if err != nil { 1050 t.Fatalf("failed to commit state trie: %v", err) 1051 } 1052 triedb.Reference(root, common.Hash{}) 1053 if err := triedb.Cap(1024); err != nil { 1054 t.Fatalf("failed to cap trie dirty cache: %v", err) 1055 } 1056 if err := triedb.Commit(root, false); err != nil { 1057 t.Fatalf("failed to commit state trie: %v", err) 1058 } 1059 // Reopen the state trie from flushed disk and verify it 1060 state, err = New(root, NewDatabase(memdb), nil) 1061 if err != nil { 1062 t.Fatalf("failed to reopen state trie: %v", err) 1063 } 1064 for a := byte(0); a < 10; a++ { 1065 for s := byte(0); s < 10; s++ { 1066 if have := state.GetState(common.Address{a}, common.Hash{a, s}); have != (common.Hash{a, s}) { 1067 t.Errorf("account %d: slot %d: state mismatch: have %x, want %x", a, s, have, common.Hash{a, s}) 1068 } 1069 } 1070 } 1071 } 1072 1073 func TestStateDBTransientStorage(t *testing.T) { 1074 memDb := rawdb.NewMemoryDatabase() 1075 db := NewDatabase(memDb) 1076 state, _ := New(types.EmptyRootHash, db, nil) 1077 1078 key := common.Hash{0x01} 1079 value := common.Hash{0x02} 1080 addr := common.Address{} 1081 1082 state.SetTransientState(addr, key, value) 1083 if exp, got := 1, state.journal.length(); exp != got { 1084 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 1085 } 1086 // the retrieved value should equal what was set 1087 if got := state.GetTransientState(addr, key); got != value { 1088 t.Fatalf("transient storage mismatch: have %x, want %x", got, value) 1089 } 1090 1091 // revert the transient state being set and then check that the 1092 // value is now the empty hash 1093 state.journal.revert(state, 0) 1094 if got, exp := state.GetTransientState(addr, key), (common.Hash{}); exp != got { 1095 t.Fatalf("transient storage mismatch: have %x, want %x", got, exp) 1096 } 1097 1098 // set transient state and then copy the statedb and ensure that 1099 // the transient state is copied 1100 state.SetTransientState(addr, key, value) 1101 cpy := state.Copy() 1102 if got := cpy.GetTransientState(addr, key); got != value { 1103 t.Fatalf("transient storage mismatch: have %x, want %x", got, value) 1104 } 1105 } 1106 1107 func TestResetObject(t *testing.T) { 1108 var ( 1109 disk = rawdb.NewMemoryDatabase() 1110 tdb = trie.NewDatabase(disk, nil) 1111 db = NewDatabaseWithNodeDB(disk, tdb) 1112 snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash) 1113 state, _ = New(types.EmptyRootHash, db, snaps) 1114 addr = common.HexToAddress("0x1") 1115 slotA = common.HexToHash("0x1") 1116 slotB = common.HexToHash("0x2") 1117 ) 1118 // Initialize account with balance and storage in first transaction. 1119 state.SetBalance(addr, big.NewInt(1)) 1120 state.SetState(addr, slotA, common.BytesToHash([]byte{0x1})) 1121 state.IntermediateRoot(true) 1122 1123 // Reset account and mutate balance and storages 1124 state.CreateAccount(addr) 1125 state.SetBalance(addr, big.NewInt(2)) 1126 state.SetState(addr, slotB, common.BytesToHash([]byte{0x2})) 1127 root, _ := state.Commit(0, true) 1128 1129 // Ensure the original account is wiped properly 1130 snap := snaps.Snapshot(root) 1131 slot, _ := snap.Storage(crypto.Keccak256Hash(addr.Bytes()), crypto.Keccak256Hash(slotA.Bytes())) 1132 if len(slot) != 0 { 1133 t.Fatalf("Unexpected storage slot") 1134 } 1135 slot, _ = snap.Storage(crypto.Keccak256Hash(addr.Bytes()), crypto.Keccak256Hash(slotB.Bytes())) 1136 if !bytes.Equal(slot, []byte{0x2}) { 1137 t.Fatalf("Unexpected storage slot value %v", slot) 1138 } 1139 } 1140 1141 func TestDeleteStorage(t *testing.T) { 1142 var ( 1143 disk = rawdb.NewMemoryDatabase() 1144 tdb = trie.NewDatabase(disk, nil) 1145 db = NewDatabaseWithNodeDB(disk, tdb) 1146 snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash) 1147 state, _ = New(types.EmptyRootHash, db, snaps) 1148 addr = common.HexToAddress("0x1") 1149 ) 1150 // Initialize account and populate storage 1151 state.SetBalance(addr, big.NewInt(1)) 1152 state.CreateAccount(addr) 1153 for i := 0; i < 1000; i++ { 1154 slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32()) 1155 value := common.Hash(uint256.NewInt(uint64(10 * i)).Bytes32()) 1156 state.SetState(addr, slot, value) 1157 } 1158 root, _ := state.Commit(0, true) 1159 // Init phase done, create two states, one with snap and one without 1160 fastState, _ := New(root, db, snaps) 1161 slowState, _ := New(root, db, nil) 1162 1163 obj := fastState.GetOrNewStateObject(addr) 1164 storageRoot := obj.data.Root 1165 1166 _, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) 1167 if err != nil { 1168 t.Fatal(err) 1169 } 1170 1171 _, _, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot) 1172 if err != nil { 1173 t.Fatal(err) 1174 } 1175 check := func(set *trienode.NodeSet) string { 1176 var a []string 1177 set.ForEachWithOrder(func(path string, n *trienode.Node) { 1178 if n.Hash != (common.Hash{}) { 1179 t.Fatal("delete should have empty hashes") 1180 } 1181 if len(n.Blob) != 0 { 1182 t.Fatal("delete should have have empty blobs") 1183 } 1184 a = append(a, fmt.Sprintf("%x", path)) 1185 }) 1186 return strings.Join(a, ",") 1187 } 1188 slowRes := check(slowNodes) 1189 fastRes := check(fastNodes) 1190 if slowRes != fastRes { 1191 t.Fatalf("difference found:\nfast: %v\nslow: %v\n", fastRes, slowRes) 1192 } 1193 }