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  }