github.com/klaytn/klaytn@v1.10.2/blockchain/state/statedb_test.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2016 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from core/state/statedb_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package state 22 23 import ( 24 "bytes" 25 "encoding/binary" 26 "fmt" 27 "math" 28 "math/big" 29 "math/rand" 30 "reflect" 31 "strings" 32 "testing" 33 "testing/quick" 34 35 "github.com/klaytn/klaytn/blockchain/types" 36 "github.com/klaytn/klaytn/common" 37 "github.com/klaytn/klaytn/params" 38 "github.com/klaytn/klaytn/storage/database" 39 "github.com/klaytn/klaytn/storage/statedb" 40 "github.com/stretchr/testify/assert" 41 "gopkg.in/check.v1" 42 ) 43 44 // Updating a state statedb without commit must not affect persistent DB. 45 func TestUpdateLeaks(t *testing.T) { 46 // Create an empty state database 47 memDBManager := database.NewMemoryDBManager() 48 db := memDBManager.GetMemDB() 49 state, _ := New(common.Hash{}, NewDatabase(memDBManager), nil) 50 51 // Update it with some accounts 52 for i := byte(0); i < 255; i++ { 53 addr := common.BytesToAddress([]byte{i}) 54 if i%2 == 0 { 55 state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) 56 } 57 if i%3 == 0 { 58 state.SetCode(addr, []byte{i, i, i, i, i}) 59 } 60 state.AddBalance(addr, big.NewInt(int64(11*i))) 61 state.SetNonce(addr, uint64(42*i)) 62 state.IntermediateRoot(false) 63 } 64 // Ensure that no data was leaked into the database. 65 // DB should be empty. 66 for _, key := range db.Keys() { 67 value, _ := db.Get(key) 68 t.Errorf("State leaked into database: %x -> %x", key, value) 69 } 70 } 71 72 // Tests that no intermediate state of an object is stored into the database, 73 // only the one right before the commit. 74 func TestIntermediateLeaks(t *testing.T) { 75 // Create two state databases, one transitioning to the final state, the other final from the beginning 76 transDBManager := database.NewMemoryDBManager() 77 finalDBManager := database.NewMemoryDBManager() 78 79 transDb := transDBManager.GetMemDB() 80 finalDb := finalDBManager.GetMemDB() 81 82 transState, _ := New(common.Hash{}, NewDatabase(transDBManager), nil) 83 finalState, _ := New(common.Hash{}, NewDatabase(finalDBManager), nil) 84 85 modify := func(state *StateDB, addr common.Address, i, tweak byte) { 86 if i%2 == 0 { 87 state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) 88 state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) 89 } 90 if i%3 == 0 { 91 state.SetCode(addr, []byte{i, i, i, i, i, tweak}) 92 } 93 state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) 94 state.SetNonce(addr, uint64(42*i+tweak)) 95 } 96 97 // Modify the transient state. 98 for i := byte(0); i < 255; i++ { 99 modify(transState, common.Address{byte(i)}, i, 0) 100 } 101 // Write modifications to trie. 102 transState.IntermediateRoot(false) 103 104 // Overwrite all the data with new values in the transient database. 105 for i := byte(0); i < 255; i++ { 106 modify(transState, common.Address{byte(i)}, i, 99) 107 modify(finalState, common.Address{byte(i)}, i, 99) 108 } 109 110 // Commit and cross check the databases. 111 if _, err := transState.Commit(false); err != nil { 112 t.Fatalf("failed to commit transition state: %v", err) 113 } 114 if _, err := finalState.Commit(false); err != nil { 115 t.Fatalf("failed to commit final state: %v", err) 116 } 117 for _, key := range finalDb.Keys() { 118 if _, err := transDb.Get(key); err != nil { 119 val, _ := finalDb.Get(key) 120 t.Errorf("entry missing from the transition database: %x -> %x", key, val) 121 } 122 } 123 for _, key := range transDb.Keys() { 124 if _, err := finalDb.Get(key); err != nil { 125 val, _ := transDb.Get(key) 126 t.Errorf("extra entry in the transition database: %x -> %x", key, val) 127 } 128 } 129 } 130 131 // TestCopy tests that copying a statedb object indeed makes the original and 132 // the copy independent of each other. This test is a regression test against 133 // https://github.com/ethereum/go-ethereum/pull/15549. 134 func TestCopy(t *testing.T) { 135 // Create a random state test to copy and modify "independently" 136 orig, _ := New(common.Hash{}, NewDatabase(database.NewMemoryDBManager()), nil) 137 138 for i := byte(0); i < 255; i++ { 139 obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 140 obj.AddBalance(big.NewInt(int64(i))) 141 orig.updateStateObject(obj) 142 } 143 orig.Finalise(false, true) 144 145 // Copy the state, modify both in-memory 146 copy := orig.Copy() 147 148 for i := byte(0); i < 255; i++ { 149 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 150 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 151 152 origObj.AddBalance(big.NewInt(2 * int64(i))) 153 copyObj.AddBalance(big.NewInt(3 * int64(i))) 154 155 orig.updateStateObject(origObj) 156 copy.updateStateObject(copyObj) 157 } 158 159 // Finalise the changes on both concurrently 160 done := make(chan struct{}) 161 162 go func() { 163 orig.Finalise(true, true) 164 close(done) 165 }() 166 167 copy.Finalise(true, true) 168 <-done 169 170 // Verify that the two states have been updated independently 171 for i := byte(0); i < 255; i++ { 172 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 173 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 174 175 if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { 176 t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) 177 } 178 if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 { 179 t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want) 180 } 181 } 182 } 183 184 func TestSnapshotRandom(t *testing.T) { 185 config := &quick.Config{MaxCount: 1000} 186 err := quick.Check((*snapshotTest).run, config) 187 if cerr, ok := err.(*quick.CheckError); ok { 188 test := cerr.In[0].(*snapshotTest) 189 t.Errorf("%v:\n%s", test.err, test) 190 } else if err != nil { 191 t.Error(err) 192 } 193 } 194 195 // TestStateObjects tests basic functional operations of StateObjects. 196 // It will be updated by StateDB.Commit() with state objects in StateDB.stateObjects. 197 func TestStateObjects(t *testing.T) { 198 stateDB, _ := New(common.Hash{}, NewDatabase(database.NewMemoryDBManager()), nil) 199 200 // Update each account, it will update StateDB.stateObjects. 201 for i := byte(0); i < 128; i++ { 202 addr := common.BytesToAddress([]byte{i}) 203 stateObj := stateDB.GetOrNewStateObject(addr) 204 205 stateObj.AddBalance(big.NewInt(int64(i))) 206 stateDB.updateStateObject(stateObj) 207 } 208 209 assert.Equal(t, 128, len(stateDB.stateObjects)) 210 } 211 212 // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes 213 // captured by the snapshot. Instances of this test with pseudorandom content are created 214 // by Generate. 215 // 216 // The test works as follows: 217 // 218 // A new state is created and all actions are applied to it. Several snapshots are taken 219 // in between actions. The test then reverts each snapshot. For each snapshot the actions 220 // leading up to it are replayed on a fresh, empty state. The behaviour of all public 221 // accessor methods on the reverted state must match the return value of the equivalent 222 // methods on the replayed state. 223 type snapshotTest struct { 224 addrs []common.Address // all account addresses 225 actions []testAction // modifications to the state 226 snapshots []int // actions indexes at which snapshot is taken 227 err error // failure details are reported through this field 228 } 229 230 type testAction struct { 231 name string 232 fn func(testAction, *StateDB) 233 args []int64 234 noAddr bool 235 } 236 237 // newTestAction creates a random action that changes state. 238 func newTestAction(addr common.Address, r *rand.Rand) testAction { 239 actions := []testAction{ 240 { 241 name: "SetBalance", 242 fn: func(a testAction, s *StateDB) { 243 s.SetBalance(addr, big.NewInt(a.args[0])) 244 }, 245 args: make([]int64, 1), 246 }, 247 { 248 name: "AddBalance", 249 fn: func(a testAction, s *StateDB) { 250 s.AddBalance(addr, big.NewInt(a.args[0])) 251 }, 252 args: make([]int64, 1), 253 }, 254 { 255 name: "SetNonce", 256 fn: func(a testAction, s *StateDB) { 257 s.SetNonce(addr, uint64(a.args[0])) 258 }, 259 args: make([]int64, 1), 260 }, 261 { 262 name: "SetState", 263 fn: func(a testAction, s *StateDB) { 264 var key, val common.Hash 265 binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) 266 binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) 267 s.SetState(addr, key, val) 268 }, 269 args: make([]int64, 2), 270 }, 271 { 272 name: "SetCode", 273 fn: func(a testAction, s *StateDB) { 274 code := make([]byte, 16) 275 binary.BigEndian.PutUint64(code, uint64(a.args[0])) 276 binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) 277 s.SetCode(addr, code) 278 }, 279 args: make([]int64, 2), 280 }, 281 { 282 name: "CreateAccount", 283 fn: func(a testAction, s *StateDB) { 284 s.CreateSmartContractAccount(addr, params.CodeFormatEVM, params.Rules{IsIstanbul: true}) 285 }, 286 }, 287 { 288 name: "Suicide", 289 fn: func(a testAction, s *StateDB) { 290 s.Suicide(addr) 291 }, 292 }, 293 { 294 name: "AddRefund", 295 fn: func(a testAction, s *StateDB) { 296 s.AddRefund(uint64(a.args[0])) 297 }, 298 args: make([]int64, 1), 299 noAddr: true, 300 }, 301 { 302 name: "AddLog", 303 fn: func(a testAction, s *StateDB) { 304 data := make([]byte, 2) 305 binary.BigEndian.PutUint16(data, uint16(a.args[0])) 306 s.AddLog(&types.Log{Address: addr, Data: data}) 307 }, 308 args: make([]int64, 1), 309 }, 310 { 311 name: "AddPreimage", 312 fn: func(a testAction, s *StateDB) { 313 preimage := []byte{1} 314 hash := common.BytesToHash(preimage) 315 s.AddPreimage(hash, preimage) 316 }, 317 args: make([]int64, 1), 318 }, 319 { 320 name: "AddAddressToAccessList", 321 fn: func(a testAction, s *StateDB) { 322 s.AddAddressToAccessList(addr) 323 }, 324 }, 325 { 326 name: "AddSlotToAccessList", 327 fn: func(a testAction, s *StateDB) { 328 s.AddSlotToAccessList(addr, 329 common.Hash{byte(a.args[0])}) 330 }, 331 args: make([]int64, 1), 332 }, 333 } 334 action := actions[r.Intn(len(actions))] 335 var nameargs []string 336 if !action.noAddr { 337 nameargs = append(nameargs, addr.Hex()) 338 } 339 for _, i := range action.args { 340 action.args[i] = rand.Int63n(100) 341 nameargs = append(nameargs, fmt.Sprint(action.args[i])) 342 } 343 action.name += strings.Join(nameargs, ", ") 344 return action 345 } 346 347 // Generate returns a new snapshot test of the given size. All randomness is 348 // derived from r. 349 func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { 350 // Generate random actions. 351 addrs := make([]common.Address, 50) 352 for i := range addrs { 353 addrs[i][0] = byte(i) 354 } 355 actions := make([]testAction, size) 356 for i := range actions { 357 addr := addrs[r.Intn(len(addrs))] 358 actions[i] = newTestAction(addr, r) 359 } 360 // Generate snapshot indexes. 361 nsnapshots := int(math.Sqrt(float64(size))) 362 if size > 0 && nsnapshots == 0 { 363 nsnapshots = 1 364 } 365 snapshots := make([]int, nsnapshots) 366 snaplen := len(actions) / nsnapshots 367 for i := range snapshots { 368 // Try to place the snapshots some number of actions apart from each other. 369 snapshots[i] = (i * snaplen) + r.Intn(snaplen) 370 } 371 return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) 372 } 373 374 func (test *snapshotTest) String() string { 375 out := new(bytes.Buffer) 376 sindex := 0 377 for i, action := range test.actions { 378 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 379 fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) 380 sindex++ 381 } 382 fmt.Fprintf(out, "%4d: %s\n", i, action.name) 383 } 384 return out.String() 385 } 386 387 func (test *snapshotTest) run() bool { 388 // Run all actions and create snapshots. 389 var ( 390 state, _ = New(common.Hash{}, NewDatabase(database.NewMemoryDBManager()), nil) 391 snapshotRevs = make([]int, len(test.snapshots)) 392 sindex = 0 393 ) 394 for i, action := range test.actions { 395 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 396 snapshotRevs[sindex] = state.Snapshot() 397 sindex++ 398 } 399 action.fn(action, state) 400 } 401 // Revert all snapshots in reverse order. Each revert must yield a state 402 // that is equivalent to fresh state with all actions up the snapshot applied. 403 for sindex--; sindex >= 0; sindex-- { 404 checkstate, _ := New(common.Hash{}, state.Database(), nil) 405 for _, action := range test.actions[:test.snapshots[sindex]] { 406 action.fn(action, checkstate) 407 } 408 state.RevertToSnapshot(snapshotRevs[sindex]) 409 if err := test.checkEqual(state, checkstate); err != nil { 410 test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err) 411 return false 412 } 413 } 414 return true 415 } 416 417 // checkEqual checks that methods of state and checkstate return the same values. 418 func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { 419 for _, addr := range test.addrs { 420 var err error 421 checkeq := func(op string, a, b interface{}) bool { 422 if err == nil && !reflect.DeepEqual(a, b) { 423 err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b) 424 return false 425 } 426 return true 427 } 428 // Check basic accessor methods. 429 checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) 430 checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) 431 checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) 432 checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) 433 checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) 434 checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) 435 checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) 436 // Check storage. 437 if obj := state.getStateObject(addr); obj != nil { 438 state.ForEachStorage(addr, func(key, value common.Hash) bool { 439 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 440 }) 441 checkstate.ForEachStorage(addr, func(key, value common.Hash) bool { 442 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 443 }) 444 } 445 if err != nil { 446 return err 447 } 448 } 449 450 if state.GetRefund() != checkstate.GetRefund() { 451 return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", 452 state.GetRefund(), checkstate.GetRefund()) 453 } 454 if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) { 455 return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", 456 state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) 457 } 458 return nil 459 } 460 461 // This test is to check the functionality of restoring with dirties of journal. 462 // Snapshot must remember the exact number of dirties. 463 func (s *StateSuite) TestSnapshotWithJournalDirties(c *check.C) { 464 s.state.GetOrNewStateObject(common.Address{}) 465 root, _ := s.state.Commit(false) 466 s.state.Reset(root) 467 468 snapshot := s.state.Snapshot() 469 s.state.AddBalance(common.Address{}, new(big.Int)) 470 471 if len(s.state.journal.dirties) != 1 { 472 c.Fatal("expected one dirty state object") 473 } 474 s.state.RevertToSnapshot(snapshot) 475 if len(s.state.journal.dirties) != 0 { 476 c.Fatal("expected no dirty state object") 477 } 478 } 479 480 // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. 481 // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 482 func TestCopyOfCopy(t *testing.T) { 483 sdb, _ := New(common.Hash{}, NewDatabase(database.NewMemoryDBManager()), nil) 484 addr := common.HexToAddress("aaaa") 485 sdb.SetBalance(addr, big.NewInt(42)) 486 487 if got := sdb.Copy().GetBalance(addr).Uint64(); got != 42 { 488 t.Fatalf("1st copy fail, expected 42, got %v", got) 489 } 490 if got := sdb.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { 491 t.Fatalf("2nd copy fail, expected 42, got %v", got) 492 } 493 } 494 495 // TestZeroHashNode checks returning values of `(db *Database) Node` function. 496 // The function should return (nil, ErrZeroHashNode) for default common.Hash{} value. 497 func TestZeroHashNode(t *testing.T) { 498 zeroHash := common.Hash{} 499 500 db := database.NewMemoryDBManager() 501 sdb := NewDatabase(db) 502 node, err := sdb.TrieDB().Node(zeroHash) 503 if err != nil { 504 assert.Equal(t, statedb.ErrZeroHashNode, err) 505 } 506 if node != nil { 507 t.Fatalf("node should return nil value for zero hash") 508 } 509 } 510 511 // TestMissingTrieNodes tests that if the statedb fails to load parts of the trie, 512 // the Commit operation fails with an error 513 // If we are missing trie nodes, we should not continue writing to the trie 514 func TestMissingTrieNodes(t *testing.T) { 515 // Create an initial state with a few accounts 516 memDb := database.NewMemoryDBManager() 517 db := NewDatabase(memDb) 518 var root common.Hash 519 state, _ := New(common.Hash{}, db, nil) 520 addr := toAddr([]byte("so")) 521 { 522 state.SetBalance(addr, big.NewInt(1)) 523 state.SetCode(addr, []byte{1, 2, 3}) 524 a2 := toAddr([]byte("another")) 525 state.SetBalance(a2, big.NewInt(100)) 526 state.SetCode(a2, []byte{1, 2, 4}) 527 root, _ = state.Commit(false) 528 t.Logf("root: %x", root) 529 // force-flush 530 state.Database().TrieDB().Cap(0) 531 } 532 // Create a new state on the old root 533 state, _ = New(root, db, nil) 534 // Now we clear out the memdb 535 it := memDb.GetMemDB().NewIterator(nil, nil) 536 for it.Next() { 537 k := it.Key() 538 // Leave the root intact 539 if !bytes.Equal(k, root[:]) { 540 t.Logf("key: %x", k) 541 memDb.GetMemDB().Delete(k) 542 } 543 } 544 balance := state.GetBalance(addr) 545 // The removed elem should lead to it returning zero balance 546 if exp, got := uint64(0), balance.Uint64(); got != exp { 547 t.Errorf("expected %d, got %d", exp, got) 548 } 549 // Modify the state 550 state.SetBalance(addr, big.NewInt(2)) 551 root, err := state.Commit(false) 552 if err == nil { 553 t.Fatalf("expected error, got root :%x", root) 554 } 555 } 556 557 func TestStateDBAccessList(t *testing.T) { 558 // Some helpers 559 addr := func(a string) common.Address { 560 return common.HexToAddress(a) 561 } 562 slot := func(a string) common.Hash { 563 return common.HexToHash(a) 564 } 565 566 memDb := database.NewMemoryDBManager() 567 db := NewDatabase(memDb) 568 state, _ := New(common.Hash{}, db, nil) 569 state.accessList = newAccessList() 570 571 verifyAddrs := func(astrings ...string) { 572 t.Helper() 573 // convert to common.Address form 574 var addresses []common.Address 575 addressMap := make(map[common.Address]struct{}) 576 for _, astring := range astrings { 577 address := addr(astring) 578 addresses = append(addresses, address) 579 addressMap[address] = struct{}{} 580 } 581 // Check that the given addresses are in the access list 582 for _, address := range addresses { 583 if !state.AddressInAccessList(address) { 584 t.Fatalf("expected %x to be in access list", address) 585 } 586 } 587 // Check that only the expected addresses are present in the acesslist 588 for address := range state.accessList.addresses { 589 if _, exist := addressMap[address]; !exist { 590 t.Fatalf("extra address %x in access list", address) 591 } 592 } 593 } 594 verifySlots := func(addrString string, slotStrings ...string) { 595 if !state.AddressInAccessList(addr(addrString)) { 596 t.Fatalf("scope missing address/slots %v", addrString) 597 } 598 address := addr(addrString) 599 // convert to common.Hash form 600 var slots []common.Hash 601 slotMap := make(map[common.Hash]struct{}) 602 for _, slotString := range slotStrings { 603 s := slot(slotString) 604 slots = append(slots, s) 605 slotMap[s] = struct{}{} 606 } 607 // Check that the expected items are in the access list 608 for i, s := range slots { 609 if _, slotPresent := state.SlotInAccessList(address, s); !slotPresent { 610 t.Fatalf("input %d: scope missing slot %v (address %v)", i, s, addrString) 611 } 612 } 613 // Check that no extra elements are in the access list 614 index := state.accessList.addresses[address] 615 if index >= 0 { 616 stateSlots := state.accessList.slots[index] 617 for s := range stateSlots { 618 if _, slotPresent := slotMap[s]; !slotPresent { 619 t.Fatalf("scope has extra slot %v (address %v)", s, addrString) 620 } 621 } 622 } 623 } 624 625 state.AddAddressToAccessList(addr("aa")) // 1 626 state.AddSlotToAccessList(addr("bb"), slot("01")) // 2,3 627 state.AddSlotToAccessList(addr("bb"), slot("02")) // 4 628 verifyAddrs("aa", "bb") 629 verifySlots("bb", "01", "02") 630 631 // Make a copy 632 stateCopy1 := state.Copy() 633 if exp, got := 4, state.journal.length(); exp != got { 634 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 635 } 636 637 // same again, should cause no journal entries 638 state.AddSlotToAccessList(addr("bb"), slot("01")) 639 state.AddSlotToAccessList(addr("bb"), slot("02")) 640 state.AddAddressToAccessList(addr("aa")) 641 if exp, got := 4, state.journal.length(); exp != got { 642 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 643 } 644 // some new ones 645 state.AddSlotToAccessList(addr("bb"), slot("03")) // 5 646 state.AddSlotToAccessList(addr("aa"), slot("01")) // 6 647 state.AddSlotToAccessList(addr("cc"), slot("01")) // 7,8 648 state.AddAddressToAccessList(addr("cc")) 649 if exp, got := 8, state.journal.length(); exp != got { 650 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 651 } 652 653 verifyAddrs("aa", "bb", "cc") 654 verifySlots("aa", "01") 655 verifySlots("bb", "01", "02", "03") 656 verifySlots("cc", "01") 657 658 // now start rolling back changes 659 state.journal.revert(state, 7) 660 if _, ok := state.SlotInAccessList(addr("cc"), slot("01")); ok { 661 t.Fatalf("slot present, expected missing") 662 } 663 verifyAddrs("aa", "bb", "cc") 664 verifySlots("aa", "01") 665 verifySlots("bb", "01", "02", "03") 666 667 state.journal.revert(state, 6) 668 if state.AddressInAccessList(addr("cc")) { 669 t.Fatalf("addr present, expected missing") 670 } 671 verifyAddrs("aa", "bb") 672 verifySlots("aa", "01") 673 verifySlots("bb", "01", "02", "03") 674 675 state.journal.revert(state, 5) 676 if _, ok := state.SlotInAccessList(addr("aa"), slot("01")); ok { 677 t.Fatalf("slot present, expected missing") 678 } 679 verifyAddrs("aa", "bb") 680 verifySlots("bb", "01", "02", "03") 681 682 state.journal.revert(state, 4) 683 if _, ok := state.SlotInAccessList(addr("bb"), slot("03")); ok { 684 t.Fatalf("slot present, expected missing") 685 } 686 verifyAddrs("aa", "bb") 687 verifySlots("bb", "01", "02") 688 689 state.journal.revert(state, 3) 690 if _, ok := state.SlotInAccessList(addr("bb"), slot("02")); ok { 691 t.Fatalf("slot present, expected missing") 692 } 693 verifyAddrs("aa", "bb") 694 verifySlots("bb", "01") 695 696 state.journal.revert(state, 2) 697 if _, ok := state.SlotInAccessList(addr("bb"), slot("01")); ok { 698 t.Fatalf("slot present, expected missing") 699 } 700 verifyAddrs("aa", "bb") 701 702 state.journal.revert(state, 1) 703 if state.AddressInAccessList(addr("bb")) { 704 t.Fatalf("addr present, expected missing") 705 } 706 verifyAddrs("aa") 707 708 state.journal.revert(state, 0) 709 if state.AddressInAccessList(addr("aa")) { 710 t.Fatalf("addr present, expected missing") 711 } 712 if got, exp := len(state.accessList.addresses), 0; got != exp { 713 t.Fatalf("expected empty, got %d", got) 714 } 715 if got, exp := len(state.accessList.slots), 0; got != exp { 716 t.Fatalf("expected empty, got %d", got) 717 } 718 // Check the copy 719 // Make a copy 720 state = stateCopy1 721 verifyAddrs("aa", "bb") 722 verifySlots("bb", "01", "02") 723 if got, exp := len(state.accessList.addresses), 2; got != exp { 724 t.Fatalf("expected empty, got %d", got) 725 } 726 if got, exp := len(state.accessList.slots), 1; got != exp { 727 t.Fatalf("expected empty, got %d", got) 728 } 729 }