github.com/fff-chain/go-fff@v0.0.0-20220726032732-1c84420b8a99/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  	"math"
    24  	"math/big"
    25  	"math/rand"
    26  	"reflect"
    27  	"strings"
    28  	"sync"
    29  	"testing"
    30  	"testing/quick"
    31  
    32  	"github.com/fff-chain/go-fff/common"
    33  	"github.com/fff-chain/go-fff/core/rawdb"
    34  	"github.com/fff-chain/go-fff/core/types"
    35  )
    36  
    37  // Tests that updating a state trie does not leak any database writes prior to
    38  // actually committing the state.
    39  func TestUpdateLeaks(t *testing.T) {
    40  	// Create an empty state database
    41  	db := rawdb.NewMemoryDatabase()
    42  	state, _ := New(common.Hash{}, NewDatabase(db), nil)
    43  
    44  	// Update it with some accounts
    45  	for i := byte(0); i < 255; i++ {
    46  		addr := common.BytesToAddress([]byte{i})
    47  		state.AddBalance(addr, big.NewInt(int64(11*i)))
    48  		state.SetNonce(addr, uint64(42*i))
    49  		if i%2 == 0 {
    50  			state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i}))
    51  		}
    52  		if i%3 == 0 {
    53  			state.SetCode(addr, []byte{i, i, i, i, i})
    54  		}
    55  	}
    56  
    57  	root := state.IntermediateRoot(false)
    58  	if err := state.Database().TrieDB().Commit(root, false, nil); err != nil {
    59  		t.Errorf("can not commit trie %v to persistent database", root.Hex())
    60  	}
    61  
    62  	// Ensure that no data was leaked into the database
    63  	it := db.NewIterator(nil, nil)
    64  	for it.Next() {
    65  		t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value())
    66  	}
    67  	it.Release()
    68  }
    69  
    70  // Tests that no intermediate state of an object is stored into the database,
    71  // only the one right before the commit.
    72  func TestIntermediateLeaks(t *testing.T) {
    73  	// Create two state databases, one transitioning to the final state, the other final from the beginning
    74  	transDb := rawdb.NewMemoryDatabase()
    75  	finalDb := rawdb.NewMemoryDatabase()
    76  	transState, _ := New(common.Hash{}, NewDatabase(transDb), nil)
    77  	finalState, _ := New(common.Hash{}, NewDatabase(finalDb), nil)
    78  
    79  	modify := func(state *StateDB, addr common.Address, i, tweak byte) {
    80  		state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
    81  		state.SetNonce(addr, uint64(42*i+tweak))
    82  		if i%2 == 0 {
    83  			state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
    84  			state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak})
    85  		}
    86  		if i%3 == 0 {
    87  			state.SetCode(addr, []byte{i, i, i, i, i, tweak})
    88  		}
    89  	}
    90  
    91  	// Modify the transient state.
    92  	for i := byte(0); i < 255; i++ {
    93  		modify(transState, common.Address{i}, i, 0)
    94  	}
    95  	// Write modifications to trie.
    96  	transState.IntermediateRoot(false)
    97  
    98  	// Overwrite all the data with new values in the transient database.
    99  	for i := byte(0); i < 255; i++ {
   100  		modify(transState, common.Address{i}, i, 99)
   101  		modify(finalState, common.Address{i}, i, 99)
   102  	}
   103  
   104  	// Commit and cross check the databases.
   105  	transState.Finalise(false)
   106  	transState.AccountsIntermediateRoot()
   107  	transRoot, _, err := transState.Commit(nil)
   108  	if err != nil {
   109  		t.Fatalf("failed to commit transition state: %v", err)
   110  	}
   111  	if err = transState.Database().TrieDB().Commit(transRoot, false, nil); err != nil {
   112  		t.Errorf("can not commit trie %v to persistent database", transRoot.Hex())
   113  	}
   114  
   115  	finalState.Finalise(false)
   116  	finalState.AccountsIntermediateRoot()
   117  	finalRoot, _, err := finalState.Commit(nil)
   118  	if err != nil {
   119  		t.Fatalf("failed to commit final state: %v", err)
   120  	}
   121  	if err = finalState.Database().TrieDB().Commit(finalRoot, false, nil); err != nil {
   122  		t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex())
   123  	}
   124  
   125  	it := finalDb.NewIterator(nil, nil)
   126  	for it.Next() {
   127  		key, fvalue := it.Key(), it.Value()
   128  		tvalue, err := transDb.Get(key)
   129  		if err != nil {
   130  			t.Errorf("entry missing from the transition database: %x -> %x", key, fvalue)
   131  		}
   132  		if !bytes.Equal(fvalue, tvalue) {
   133  			t.Errorf("the value associate key %x is mismatch,: %x in transition database ,%x in final database", key, tvalue, fvalue)
   134  		}
   135  	}
   136  	it.Release()
   137  
   138  	it = transDb.NewIterator(nil, nil)
   139  	for it.Next() {
   140  		key, tvalue := it.Key(), it.Value()
   141  		fvalue, err := finalDb.Get(key)
   142  		if err != nil {
   143  			t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value())
   144  		}
   145  		if !bytes.Equal(fvalue, tvalue) {
   146  			t.Errorf("the value associate key %x is mismatch,: %x in transition database ,%x in final database", key, tvalue, fvalue)
   147  		}
   148  	}
   149  }
   150  
   151  // TestCopy tests that copying a StateDB object indeed makes the original and
   152  // the copy independent of each other. This test is a regression test against
   153  // https://github.com/fff-chain/go-fff/pull/15549.
   154  func TestCopy(t *testing.T) {
   155  	// Create a random state test to copy and modify "independently"
   156  	orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
   157  
   158  	for i := byte(0); i < 255; i++ {
   159  		obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   160  		obj.AddBalance(big.NewInt(int64(i)))
   161  		orig.updateStateObject(obj)
   162  	}
   163  	orig.Finalise(false)
   164  
   165  	// Copy the state
   166  	copy := orig.Copy()
   167  
   168  	// Copy the copy state
   169  	ccopy := copy.Copy()
   170  
   171  	// modify all in memory
   172  	for i := byte(0); i < 255; i++ {
   173  		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   174  		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   175  		ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   176  
   177  		origObj.AddBalance(big.NewInt(2 * int64(i)))
   178  		copyObj.AddBalance(big.NewInt(3 * int64(i)))
   179  		ccopyObj.AddBalance(big.NewInt(4 * int64(i)))
   180  
   181  		orig.updateStateObject(origObj)
   182  		copy.updateStateObject(copyObj)
   183  		ccopy.updateStateObject(copyObj)
   184  	}
   185  
   186  	// Finalise the changes on all concurrently
   187  	finalise := func(wg *sync.WaitGroup, db *StateDB) {
   188  		defer wg.Done()
   189  		db.Finalise(true)
   190  	}
   191  
   192  	var wg sync.WaitGroup
   193  	wg.Add(3)
   194  	go finalise(&wg, orig)
   195  	go finalise(&wg, copy)
   196  	go finalise(&wg, ccopy)
   197  	wg.Wait()
   198  
   199  	// Verify that the three states have been updated independently
   200  	for i := byte(0); i < 255; i++ {
   201  		origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   202  		copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   203  		ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
   204  
   205  		if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 {
   206  			t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want)
   207  		}
   208  		if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 {
   209  			t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want)
   210  		}
   211  		if want := big.NewInt(5 * int64(i)); ccopyObj.Balance().Cmp(want) != 0 {
   212  			t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, ccopyObj.Balance(), want)
   213  		}
   214  	}
   215  }
   216  
   217  func TestSnapshotRandom(t *testing.T) {
   218  	config := &quick.Config{MaxCount: 1000}
   219  	err := quick.Check((*snapshotTest).run, config)
   220  	if cerr, ok := err.(*quick.CheckError); ok {
   221  		test := cerr.In[0].(*snapshotTest)
   222  		t.Errorf("%v:\n%s", test.err, test)
   223  	} else if err != nil {
   224  		t.Error(err)
   225  	}
   226  }
   227  
   228  // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes
   229  // captured by the snapshot. Instances of this test with pseudorandom content are created
   230  // by Generate.
   231  //
   232  // The test works as follows:
   233  //
   234  // A new state is created and all actions are applied to it. Several snapshots are taken
   235  // in between actions. The test then reverts each snapshot. For each snapshot the actions
   236  // leading up to it are replayed on a fresh, empty state. The behaviour of all public
   237  // accessor methods on the reverted state must match the return value of the equivalent
   238  // methods on the replayed state.
   239  type snapshotTest struct {
   240  	addrs     []common.Address // all account addresses
   241  	actions   []testAction     // modifications to the state
   242  	snapshots []int            // actions indexes at which snapshot is taken
   243  	err       error            // failure details are reported through this field
   244  }
   245  
   246  type testAction struct {
   247  	name   string
   248  	fn     func(testAction, *StateDB)
   249  	args   []int64
   250  	noAddr bool
   251  }
   252  
   253  // newTestAction creates a random action that changes state.
   254  func newTestAction(addr common.Address, r *rand.Rand) testAction {
   255  	actions := []testAction{
   256  		{
   257  			name: "SetBalance",
   258  			fn: func(a testAction, s *StateDB) {
   259  				s.SetBalance(addr, big.NewInt(a.args[0]))
   260  			},
   261  			args: make([]int64, 1),
   262  		},
   263  		{
   264  			name: "AddBalance",
   265  			fn: func(a testAction, s *StateDB) {
   266  				s.AddBalance(addr, big.NewInt(a.args[0]))
   267  			},
   268  			args: make([]int64, 1),
   269  		},
   270  		{
   271  			name: "SetNonce",
   272  			fn: func(a testAction, s *StateDB) {
   273  				s.SetNonce(addr, uint64(a.args[0]))
   274  			},
   275  			args: make([]int64, 1),
   276  		},
   277  		{
   278  			name: "SetState",
   279  			fn: func(a testAction, s *StateDB) {
   280  				var key, val common.Hash
   281  				binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
   282  				binary.BigEndian.PutUint16(val[:], uint16(a.args[1]))
   283  				s.SetState(addr, key, val)
   284  			},
   285  			args: make([]int64, 2),
   286  		},
   287  		{
   288  			name: "SetCode",
   289  			fn: func(a testAction, s *StateDB) {
   290  				code := make([]byte, 16)
   291  				binary.BigEndian.PutUint64(code, uint64(a.args[0]))
   292  				binary.BigEndian.PutUint64(code[8:], uint64(a.args[1]))
   293  				s.SetCode(addr, code)
   294  			},
   295  			args: make([]int64, 2),
   296  		},
   297  		{
   298  			name: "CreateAccount",
   299  			fn: func(a testAction, s *StateDB) {
   300  				s.CreateAccount(addr)
   301  			},
   302  		},
   303  		{
   304  			name: "Suicide",
   305  			fn: func(a testAction, s *StateDB) {
   306  				s.Suicide(addr)
   307  			},
   308  		},
   309  		{
   310  			name: "AddRefund",
   311  			fn: func(a testAction, s *StateDB) {
   312  				s.AddRefund(uint64(a.args[0]))
   313  			},
   314  			args:   make([]int64, 1),
   315  			noAddr: true,
   316  		},
   317  		{
   318  			name: "AddLog",
   319  			fn: func(a testAction, s *StateDB) {
   320  				data := make([]byte, 2)
   321  				binary.BigEndian.PutUint16(data, uint16(a.args[0]))
   322  				s.AddLog(&types.Log{Address: addr, Data: data})
   323  			},
   324  			args: make([]int64, 1),
   325  		},
   326  		{
   327  			name: "AddPreimage",
   328  			fn: func(a testAction, s *StateDB) {
   329  				preimage := []byte{1}
   330  				hash := common.BytesToHash(preimage)
   331  				s.AddPreimage(hash, preimage)
   332  			},
   333  			args: make([]int64, 1),
   334  		},
   335  		{
   336  			name: "AddAddressToAccessList",
   337  			fn: func(a testAction, s *StateDB) {
   338  				s.AddAddressToAccessList(addr)
   339  			},
   340  		},
   341  		{
   342  			name: "AddSlotToAccessList",
   343  			fn: func(a testAction, s *StateDB) {
   344  				s.AddSlotToAccessList(addr,
   345  					common.Hash{byte(a.args[0])})
   346  			},
   347  			args: make([]int64, 1),
   348  		},
   349  	}
   350  	action := actions[r.Intn(len(actions))]
   351  	var nameargs []string
   352  	if !action.noAddr {
   353  		nameargs = append(nameargs, addr.Hex())
   354  	}
   355  	for i := range action.args {
   356  		action.args[i] = rand.Int63n(100)
   357  		nameargs = append(nameargs, fmt.Sprint(action.args[i]))
   358  	}
   359  	action.name += strings.Join(nameargs, ", ")
   360  	return action
   361  }
   362  
   363  // Generate returns a new snapshot test of the given size. All randomness is
   364  // derived from r.
   365  func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value {
   366  	// Generate random actions.
   367  	addrs := make([]common.Address, 50)
   368  	for i := range addrs {
   369  		addrs[i][0] = byte(i)
   370  	}
   371  	actions := make([]testAction, size)
   372  	for i := range actions {
   373  		addr := addrs[r.Intn(len(addrs))]
   374  		actions[i] = newTestAction(addr, r)
   375  	}
   376  	// Generate snapshot indexes.
   377  	nsnapshots := int(math.Sqrt(float64(size)))
   378  	if size > 0 && nsnapshots == 0 {
   379  		nsnapshots = 1
   380  	}
   381  	snapshots := make([]int, nsnapshots)
   382  	snaplen := len(actions) / nsnapshots
   383  	for i := range snapshots {
   384  		// Try to place the snapshots some number of actions apart from each other.
   385  		snapshots[i] = (i * snaplen) + r.Intn(snaplen)
   386  	}
   387  	return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil})
   388  }
   389  
   390  func (test *snapshotTest) String() string {
   391  	out := new(bytes.Buffer)
   392  	sindex := 0
   393  	for i, action := range test.actions {
   394  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   395  			fmt.Fprintf(out, "---- snapshot %d ----\n", sindex)
   396  			sindex++
   397  		}
   398  		fmt.Fprintf(out, "%4d: %s\n", i, action.name)
   399  	}
   400  	return out.String()
   401  }
   402  
   403  func (test *snapshotTest) run() bool {
   404  	// Run all actions and create snapshots.
   405  	var (
   406  		state, _     = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
   407  		snapshotRevs = make([]int, len(test.snapshots))
   408  		sindex       = 0
   409  	)
   410  	for i, action := range test.actions {
   411  		if len(test.snapshots) > sindex && i == test.snapshots[sindex] {
   412  			snapshotRevs[sindex] = state.Snapshot()
   413  			sindex++
   414  		}
   415  		action.fn(action, state)
   416  	}
   417  	// Revert all snapshots in reverse order. Each revert must yield a state
   418  	// that is equivalent to fresh state with all actions up the snapshot applied.
   419  	for sindex--; sindex >= 0; sindex-- {
   420  		checkstate, _ := New(common.Hash{}, state.Database(), nil)
   421  		for _, action := range test.actions[:test.snapshots[sindex]] {
   422  			action.fn(action, checkstate)
   423  		}
   424  		state.RevertToSnapshot(snapshotRevs[sindex])
   425  		if err := test.checkEqual(state, checkstate); err != nil {
   426  			test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err)
   427  			return false
   428  		}
   429  	}
   430  	return true
   431  }
   432  
   433  // checkEqual checks that methods of state and checkstate return the same values.
   434  func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
   435  	for _, addr := range test.addrs {
   436  		var err error
   437  		checkeq := func(op string, a, b interface{}) bool {
   438  			if err == nil && !reflect.DeepEqual(a, b) {
   439  				err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b)
   440  				return false
   441  			}
   442  			return true
   443  		}
   444  		// Check basic accessor methods.
   445  		checkeq("Exist", state.Exist(addr), checkstate.Exist(addr))
   446  		checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr))
   447  		checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr))
   448  		checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr))
   449  		checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr))
   450  		checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
   451  		checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
   452  		// Check storage.
   453  		if obj := state.getStateObject(addr); obj != nil {
   454  			state.ForEachStorage(addr, func(key, value common.Hash) bool {
   455  				return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value)
   456  			})
   457  			checkstate.ForEachStorage(addr, func(key, value common.Hash) bool {
   458  				return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value)
   459  			})
   460  		}
   461  		if err != nil {
   462  			return err
   463  		}
   464  	}
   465  
   466  	if state.GetRefund() != checkstate.GetRefund() {
   467  		return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d",
   468  			state.GetRefund(), checkstate.GetRefund())
   469  	}
   470  	if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) {
   471  		return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v",
   472  			state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{}))
   473  	}
   474  	return nil
   475  }
   476  
   477  func TestTouchDelete(t *testing.T) {
   478  	s := newStateTest()
   479  	s.state.GetOrNewStateObject(common.Address{})
   480  	root, _, _ := s.state.Commit(nil)
   481  	s.state, _ = New(root, s.state.db, s.state.snaps)
   482  
   483  	snapshot := s.state.Snapshot()
   484  	s.state.AddBalance(common.Address{}, new(big.Int))
   485  
   486  	if len(s.state.journal.dirties) != 1 {
   487  		t.Fatal("expected one dirty state object")
   488  	}
   489  	s.state.RevertToSnapshot(snapshot)
   490  	if len(s.state.journal.dirties) != 0 {
   491  		t.Fatal("expected no dirty state object")
   492  	}
   493  }
   494  
   495  // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy.
   496  // See https://github.com/fff-chain/go-fff/pull/15225#issuecomment-380191512
   497  func TestCopyOfCopy(t *testing.T) {
   498  	state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
   499  	addr := common.HexToAddress("aaaa")
   500  	state.SetBalance(addr, big.NewInt(42))
   501  
   502  	if got := state.Copy().GetBalance(addr).Uint64(); got != 42 {
   503  		t.Fatalf("1st copy fail, expected 42, got %v", got)
   504  	}
   505  	if got := state.Copy().Copy().GetBalance(addr).Uint64(); got != 42 {
   506  		t.Fatalf("2nd copy fail, expected 42, got %v", got)
   507  	}
   508  }
   509  
   510  // Tests a regression where committing a copy lost some internal meta information,
   511  // leading to corrupted subsequent copies.
   512  //
   513  // See https://github.com/fff-chain/go-fff/issues/20106.
   514  func TestCopyCommitCopy(t *testing.T) {
   515  	state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
   516  
   517  	// Create an account and check if the retrieved balance is correct
   518  	addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
   519  	skey := common.HexToHash("aaa")
   520  	sval := common.HexToHash("bbb")
   521  
   522  	state.SetBalance(addr, big.NewInt(42)) // Change the account trie
   523  	state.SetCode(addr, []byte("hello"))   // Change an external metadata
   524  	state.SetState(addr, skey, sval)       // Change the storage trie
   525  
   526  	if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   527  		t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
   528  	}
   529  	if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   530  		t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello"))
   531  	}
   532  	if val := state.GetState(addr, skey); val != sval {
   533  		t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval)
   534  	}
   535  	if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) {
   536  		t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   537  	}
   538  	// Copy the non-committed state database and check pre/post commit balance
   539  	copyOne := state.Copy()
   540  	if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   541  		t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42)
   542  	}
   543  	if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   544  		t.Fatalf("first copy pre-commit code mismatch: have %x, want %x", code, []byte("hello"))
   545  	}
   546  	if val := copyOne.GetState(addr, skey); val != sval {
   547  		t.Fatalf("first copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
   548  	}
   549  	if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) {
   550  		t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   551  	}
   552  
   553  	copyOne.Finalise(false)
   554  	copyOne.AccountsIntermediateRoot()
   555  	copyOne.Commit(nil)
   556  	if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   557  		t.Fatalf("first copy post-commit balance mismatch: have %v, want %v", balance, 42)
   558  	}
   559  	if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   560  		t.Fatalf("first copy post-commit code mismatch: have %x, want %x", code, []byte("hello"))
   561  	}
   562  	if val := copyOne.GetState(addr, skey); val != sval {
   563  		t.Fatalf("first copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
   564  	}
   565  	if val := copyOne.GetCommittedState(addr, skey); val != sval {
   566  		t.Fatalf("first copy post-commit committed storage slot mismatch: have %x, want %x", val, sval)
   567  	}
   568  	// Copy the copy and check the balance once more
   569  	copyTwo := copyOne.Copy()
   570  	if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   571  		t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42)
   572  	}
   573  	if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   574  		t.Fatalf("second copy code mismatch: have %x, want %x", code, []byte("hello"))
   575  	}
   576  	if val := copyTwo.GetState(addr, skey); val != sval {
   577  		t.Fatalf("second copy non-committed storage slot mismatch: have %x, want %x", val, sval)
   578  	}
   579  	if val := copyTwo.GetCommittedState(addr, skey); val != sval {
   580  		t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval)
   581  	}
   582  }
   583  
   584  // Tests a regression where committing a copy lost some internal meta information,
   585  // leading to corrupted subsequent copies.
   586  //
   587  // See https://github.com/fff-chain/go-fff/issues/20106.
   588  func TestCopyCopyCommitCopy(t *testing.T) {
   589  	state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
   590  
   591  	// Create an account and check if the retrieved balance is correct
   592  	addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe")
   593  	skey := common.HexToHash("aaa")
   594  	sval := common.HexToHash("bbb")
   595  
   596  	state.SetBalance(addr, big.NewInt(42)) // Change the account trie
   597  	state.SetCode(addr, []byte("hello"))   // Change an external metadata
   598  	state.SetState(addr, skey, sval)       // Change the storage trie
   599  
   600  	if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   601  		t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
   602  	}
   603  	if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   604  		t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello"))
   605  	}
   606  	if val := state.GetState(addr, skey); val != sval {
   607  		t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval)
   608  	}
   609  	if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) {
   610  		t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   611  	}
   612  	// Copy the non-committed state database and check pre/post commit balance
   613  	copyOne := state.Copy()
   614  	if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   615  		t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42)
   616  	}
   617  	if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   618  		t.Fatalf("first copy code mismatch: have %x, want %x", code, []byte("hello"))
   619  	}
   620  	if val := copyOne.GetState(addr, skey); val != sval {
   621  		t.Fatalf("first copy non-committed storage slot mismatch: have %x, want %x", val, sval)
   622  	}
   623  	if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) {
   624  		t.Fatalf("first copy committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   625  	}
   626  	// Copy the copy and check the balance once more
   627  	copyTwo := copyOne.Copy()
   628  	if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   629  		t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42)
   630  	}
   631  	if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   632  		t.Fatalf("second copy pre-commit code mismatch: have %x, want %x", code, []byte("hello"))
   633  	}
   634  	if val := copyTwo.GetState(addr, skey); val != sval {
   635  		t.Fatalf("second copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
   636  	}
   637  	if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) {
   638  		t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{})
   639  	}
   640  
   641  	copyTwo.Finalise(false)
   642  	copyTwo.AccountsIntermediateRoot()
   643  	copyTwo.Commit(nil)
   644  	if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   645  		t.Fatalf("second copy post-commit balance mismatch: have %v, want %v", balance, 42)
   646  	}
   647  	if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   648  		t.Fatalf("second copy post-commit code mismatch: have %x, want %x", code, []byte("hello"))
   649  	}
   650  	if val := copyTwo.GetState(addr, skey); val != sval {
   651  		t.Fatalf("second copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval)
   652  	}
   653  	if val := copyTwo.GetCommittedState(addr, skey); val != sval {
   654  		t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval)
   655  	}
   656  	// Copy the copy-copy and check the balance once more
   657  	copyThree := copyTwo.Copy()
   658  	if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
   659  		t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42)
   660  	}
   661  	if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) {
   662  		t.Fatalf("third copy code mismatch: have %x, want %x", code, []byte("hello"))
   663  	}
   664  	if val := copyThree.GetState(addr, skey); val != sval {
   665  		t.Fatalf("third copy non-committed storage slot mismatch: have %x, want %x", val, sval)
   666  	}
   667  	if val := copyThree.GetCommittedState(addr, skey); val != sval {
   668  		t.Fatalf("third copy committed storage slot mismatch: have %x, want %x", val, sval)
   669  	}
   670  }
   671  
   672  // TestDeleteCreateRevert tests a weird state transition corner case that we hit
   673  // while changing the internals of StateDB. The workflow is that a contract is
   674  // self-destructed, then in a follow-up transaction (but same block) it's created
   675  // again and the transaction reverted.
   676  //
   677  // The original StateDB implementation flushed dirty objects to the tries after
   678  // each transaction, so this works ok. The rework accumulated writes in memory
   679  // first, but the journal wiped the entire state object on create-revert.
   680  func TestDeleteCreateRevert(t *testing.T) {
   681  	// Create an initial state with a single contract
   682  	state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
   683  
   684  	addr := common.BytesToAddress([]byte("so"))
   685  	state.SetBalance(addr, big.NewInt(1))
   686  
   687  	state.Finalise(false)
   688  	state.AccountsIntermediateRoot()
   689  	root, _, _ := state.Commit(nil)
   690  	state, _ = New(root, state.db, state.snaps)
   691  
   692  	// Simulate self-destructing in one transaction, then create-reverting in another
   693  	state.Suicide(addr)
   694  	state.Finalise(true)
   695  
   696  	id := state.Snapshot()
   697  	state.SetBalance(addr, big.NewInt(2))
   698  	state.RevertToSnapshot(id)
   699  
   700  	state.Finalise(true)
   701  	state.AccountsIntermediateRoot()
   702  	// Commit the entire state and make sure we don't crash and have the correct state
   703  	root, _, _ = state.Commit(nil)
   704  	state, _ = New(root, state.db, state.snaps)
   705  
   706  	if state.getStateObject(addr) != nil {
   707  		t.Fatalf("self-destructed contract came alive")
   708  	}
   709  }
   710  
   711  // TestMissingTrieNodes tests that if the StateDB fails to load parts of the trie,
   712  // the Commit operation fails with an error
   713  // If we are missing trie nodes, we should not continue writing to the trie
   714  func TestMissingTrieNodes(t *testing.T) {
   715  
   716  	// Create an initial state with a few accounts
   717  	memDb := rawdb.NewMemoryDatabase()
   718  	db := NewDatabase(memDb)
   719  	var root common.Hash
   720  	state, _ := New(common.Hash{}, db, nil)
   721  	addr := common.BytesToAddress([]byte("so"))
   722  	{
   723  		state.SetBalance(addr, big.NewInt(1))
   724  		state.SetCode(addr, []byte{1, 2, 3})
   725  		a2 := common.BytesToAddress([]byte("another"))
   726  		state.SetBalance(a2, big.NewInt(100))
   727  		state.SetCode(a2, []byte{1, 2, 4})
   728  		state.Finalise(false)
   729  		state.AccountsIntermediateRoot()
   730  		root, _, _ = state.Commit(nil)
   731  		t.Logf("root: %x", root)
   732  		// force-flush
   733  		state.Database().TrieDB().Cap(0)
   734  	}
   735  	// Create a new state on the old root
   736  	state, _ = New(root, db, nil)
   737  	// Now we clear out the memdb
   738  	it := memDb.NewIterator(nil, nil)
   739  	for it.Next() {
   740  		k := it.Key()
   741  		// Leave the root intact
   742  		if !bytes.Equal(k, root[:]) {
   743  			t.Logf("key: %x", k)
   744  			memDb.Delete(k)
   745  		}
   746  	}
   747  	balance := state.GetBalance(addr)
   748  	// The removed elem should lead to it returning zero balance
   749  	if exp, got := uint64(0), balance.Uint64(); got != exp {
   750  		t.Errorf("expected %d, got %d", exp, got)
   751  	}
   752  	// Modify the state
   753  	state.SetBalance(addr, big.NewInt(2))
   754  	state.Finalise(false)
   755  	state.AccountsIntermediateRoot()
   756  	root, _, err := state.Commit(nil)
   757  	if err == nil {
   758  		t.Fatalf("expected error, got root :%x", root)
   759  	}
   760  }
   761  
   762  func TestStateDBAccessList(t *testing.T) {
   763  	// Some helpers
   764  	addr := func(a string) common.Address {
   765  		return common.HexToAddress(a)
   766  	}
   767  	slot := func(a string) common.Hash {
   768  		return common.HexToHash(a)
   769  	}
   770  
   771  	memDb := rawdb.NewMemoryDatabase()
   772  	db := NewDatabase(memDb)
   773  	state, _ := New(common.Hash{}, db, nil)
   774  	state.accessList = newAccessList()
   775  
   776  	verifyAddrs := func(astrings ...string) {
   777  		t.Helper()
   778  		// convert to common.Address form
   779  		var addresses []common.Address
   780  		var addressMap = make(map[common.Address]struct{})
   781  		for _, astring := range astrings {
   782  			address := addr(astring)
   783  			addresses = append(addresses, address)
   784  			addressMap[address] = struct{}{}
   785  		}
   786  		// Check that the given addresses are in the access list
   787  		for _, address := range addresses {
   788  			if !state.AddressInAccessList(address) {
   789  				t.Fatalf("expected %x to be in access list", address)
   790  			}
   791  		}
   792  		// Check that only the expected addresses are present in the acesslist
   793  		for address := range state.accessList.addresses {
   794  			if _, exist := addressMap[address]; !exist {
   795  				t.Fatalf("extra address %x in access list", address)
   796  			}
   797  		}
   798  	}
   799  	verifySlots := func(addrString string, slotStrings ...string) {
   800  		if !state.AddressInAccessList(addr(addrString)) {
   801  			t.Fatalf("scope missing address/slots %v", addrString)
   802  		}
   803  		var address = addr(addrString)
   804  		// convert to common.Hash form
   805  		var slots []common.Hash
   806  		var slotMap = make(map[common.Hash]struct{})
   807  		for _, slotString := range slotStrings {
   808  			s := slot(slotString)
   809  			slots = append(slots, s)
   810  			slotMap[s] = struct{}{}
   811  		}
   812  		// Check that the expected items are in the access list
   813  		for i, s := range slots {
   814  			if _, slotPresent := state.SlotInAccessList(address, s); !slotPresent {
   815  				t.Fatalf("input %d: scope missing slot %v (address %v)", i, s, addrString)
   816  			}
   817  		}
   818  		// Check that no extra elements are in the access list
   819  		index := state.accessList.addresses[address]
   820  		if index >= 0 {
   821  			stateSlots := state.accessList.slots[index]
   822  			for s := range stateSlots {
   823  				if _, slotPresent := slotMap[s]; !slotPresent {
   824  					t.Fatalf("scope has extra slot %v (address %v)", s, addrString)
   825  				}
   826  			}
   827  		}
   828  	}
   829  
   830  	state.AddAddressToAccessList(addr("aa"))          // 1
   831  	state.AddSlotToAccessList(addr("bb"), slot("01")) // 2,3
   832  	state.AddSlotToAccessList(addr("bb"), slot("02")) // 4
   833  	verifyAddrs("aa", "bb")
   834  	verifySlots("bb", "01", "02")
   835  
   836  	// Make a copy
   837  	stateCopy1 := state.Copy()
   838  	if exp, got := 4, state.journal.length(); exp != got {
   839  		t.Fatalf("journal length mismatch: have %d, want %d", got, exp)
   840  	}
   841  
   842  	// same again, should cause no journal entries
   843  	state.AddSlotToAccessList(addr("bb"), slot("01"))
   844  	state.AddSlotToAccessList(addr("bb"), slot("02"))
   845  	state.AddAddressToAccessList(addr("aa"))
   846  	if exp, got := 4, state.journal.length(); exp != got {
   847  		t.Fatalf("journal length mismatch: have %d, want %d", got, exp)
   848  	}
   849  	// some new ones
   850  	state.AddSlotToAccessList(addr("bb"), slot("03")) // 5
   851  	state.AddSlotToAccessList(addr("aa"), slot("01")) // 6
   852  	state.AddSlotToAccessList(addr("cc"), slot("01")) // 7,8
   853  	state.AddAddressToAccessList(addr("cc"))
   854  	if exp, got := 8, state.journal.length(); exp != got {
   855  		t.Fatalf("journal length mismatch: have %d, want %d", got, exp)
   856  	}
   857  
   858  	verifyAddrs("aa", "bb", "cc")
   859  	verifySlots("aa", "01")
   860  	verifySlots("bb", "01", "02", "03")
   861  	verifySlots("cc", "01")
   862  
   863  	// now start rolling back changes
   864  	state.journal.revert(state, 7)
   865  	if _, ok := state.SlotInAccessList(addr("cc"), slot("01")); ok {
   866  		t.Fatalf("slot present, expected missing")
   867  	}
   868  	verifyAddrs("aa", "bb", "cc")
   869  	verifySlots("aa", "01")
   870  	verifySlots("bb", "01", "02", "03")
   871  
   872  	state.journal.revert(state, 6)
   873  	if state.AddressInAccessList(addr("cc")) {
   874  		t.Fatalf("addr present, expected missing")
   875  	}
   876  	verifyAddrs("aa", "bb")
   877  	verifySlots("aa", "01")
   878  	verifySlots("bb", "01", "02", "03")
   879  
   880  	state.journal.revert(state, 5)
   881  	if _, ok := state.SlotInAccessList(addr("aa"), slot("01")); ok {
   882  		t.Fatalf("slot present, expected missing")
   883  	}
   884  	verifyAddrs("aa", "bb")
   885  	verifySlots("bb", "01", "02", "03")
   886  
   887  	state.journal.revert(state, 4)
   888  	if _, ok := state.SlotInAccessList(addr("bb"), slot("03")); ok {
   889  		t.Fatalf("slot present, expected missing")
   890  	}
   891  	verifyAddrs("aa", "bb")
   892  	verifySlots("bb", "01", "02")
   893  
   894  	state.journal.revert(state, 3)
   895  	if _, ok := state.SlotInAccessList(addr("bb"), slot("02")); ok {
   896  		t.Fatalf("slot present, expected missing")
   897  	}
   898  	verifyAddrs("aa", "bb")
   899  	verifySlots("bb", "01")
   900  
   901  	state.journal.revert(state, 2)
   902  	if _, ok := state.SlotInAccessList(addr("bb"), slot("01")); ok {
   903  		t.Fatalf("slot present, expected missing")
   904  	}
   905  	verifyAddrs("aa", "bb")
   906  
   907  	state.journal.revert(state, 1)
   908  	if state.AddressInAccessList(addr("bb")) {
   909  		t.Fatalf("addr present, expected missing")
   910  	}
   911  	verifyAddrs("aa")
   912  
   913  	state.journal.revert(state, 0)
   914  	if state.AddressInAccessList(addr("aa")) {
   915  		t.Fatalf("addr present, expected missing")
   916  	}
   917  	if got, exp := len(state.accessList.addresses), 0; got != exp {
   918  		t.Fatalf("expected empty, got %d", got)
   919  	}
   920  	if got, exp := len(state.accessList.slots), 0; got != exp {
   921  		t.Fatalf("expected empty, got %d", got)
   922  	}
   923  	// Check the copy
   924  	// Make a copy
   925  	state = stateCopy1
   926  	verifyAddrs("aa", "bb")
   927  	verifySlots("bb", "01", "02")
   928  	if got, exp := len(state.accessList.addresses), 2; got != exp {
   929  		t.Fatalf("expected empty, got %d", got)
   930  	}
   931  	if got, exp := len(state.accessList.slots), 1; got != exp {
   932  		t.Fatalf("expected empty, got %d", got)
   933  	}
   934  }