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