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