gitlab.com/flarenetwork/coreth@v0.1.1/core/state/statedb_test.go (about)

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