github.com/dim4egster/coreth@v0.10.2/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/dim4egster/coreth/core/rawdb"
    43  	"github.com/dim4egster/coreth/core/state/snapshot"
    44  	"github.com/dim4egster/coreth/core/types"
    45  	"github.com/ethereum/go-ethereum/common"
    46  	"github.com/ethereum/go-ethereum/crypto"
    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, 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, 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, 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, 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, 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, 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, false)
   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  	// Create an initial state with a few accounts
   715  	memDb := rawdb.NewMemoryDatabase()
   716  	db := NewDatabase(memDb)
   717  	var root common.Hash
   718  	state, _ := New(common.Hash{}, db, nil)
   719  	addr := common.BytesToAddress([]byte("so"))
   720  	{
   721  		state.SetBalance(addr, big.NewInt(1))
   722  		state.SetCode(addr, []byte{1, 2, 3})
   723  		a2 := common.BytesToAddress([]byte("another"))
   724  		state.SetBalance(a2, big.NewInt(100))
   725  		state.SetCode(a2, []byte{1, 2, 4})
   726  		root, _ = state.Commit(false, false)
   727  		t.Logf("root: %x", root)
   728  		// force-flush
   729  		state.Database().TrieDB().Cap(0)
   730  	}
   731  	// Create a new state on the old root
   732  	state, _ = New(root, db, nil)
   733  	// Now we clear out the memdb
   734  	it := memDb.NewIterator(nil, nil)
   735  	for it.Next() {
   736  		k := it.Key()
   737  		// Leave the root intact
   738  		if !bytes.Equal(k, root[:]) {
   739  			t.Logf("key: %x", k)
   740  			memDb.Delete(k)
   741  		}
   742  	}
   743  	balance := state.GetBalance(addr)
   744  	// The removed elem should lead to it returning zero balance
   745  	if exp, got := uint64(0), balance.Uint64(); got != exp {
   746  		t.Errorf("expected %d, got %d", exp, got)
   747  	}
   748  	// Modify the state
   749  	state.SetBalance(addr, big.NewInt(2))
   750  	root, err := state.Commit(false, false)
   751  	if err == nil {
   752  		t.Fatalf("expected error, got root :%x", root)
   753  	}
   754  }
   755  
   756  func TestStateDBAccessList(t *testing.T) {
   757  	// Some helpers
   758  	addr := func(a string) common.Address {
   759  		return common.HexToAddress(a)
   760  	}
   761  	slot := func(a string) common.Hash {
   762  		return common.HexToHash(a)
   763  	}
   764  
   765  	memDb := rawdb.NewMemoryDatabase()
   766  	db := NewDatabase(memDb)
   767  	state, _ := New(common.Hash{}, db, nil)
   768  	state.accessList = newAccessList()
   769  
   770  	verifyAddrs := func(astrings ...string) {
   771  		t.Helper()
   772  		// convert to common.Address form
   773  		var addresses []common.Address
   774  		var addressMap = make(map[common.Address]struct{})
   775  		for _, astring := range astrings {
   776  			address := addr(astring)
   777  			addresses = append(addresses, address)
   778  			addressMap[address] = struct{}{}
   779  		}
   780  		// Check that the given addresses are in the access list
   781  		for _, address := range addresses {
   782  			if !state.AddressInAccessList(address) {
   783  				t.Fatalf("expected %x to be in access list", address)
   784  			}
   785  		}
   786  		// Check that only the expected addresses are present in the access list
   787  		for address := range state.accessList.addresses {
   788  			if _, exist := addressMap[address]; !exist {
   789  				t.Fatalf("extra address %x in access list", address)
   790  			}
   791  		}
   792  	}
   793  	verifySlots := func(addrString string, slotStrings ...string) {
   794  		if !state.AddressInAccessList(addr(addrString)) {
   795  			t.Fatalf("scope missing address/slots %v", addrString)
   796  		}
   797  		var address = addr(addrString)
   798  		// convert to common.Hash form
   799  		var slots []common.Hash
   800  		var slotMap = make(map[common.Hash]struct{})
   801  		for _, slotString := range slotStrings {
   802  			s := slot(slotString)
   803  			slots = append(slots, s)
   804  			slotMap[s] = struct{}{}
   805  		}
   806  		// Check that the expected items are in the access list
   807  		for i, s := range slots {
   808  			if _, slotPresent := state.SlotInAccessList(address, s); !slotPresent {
   809  				t.Fatalf("input %d: scope missing slot %v (address %v)", i, s, addrString)
   810  			}
   811  		}
   812  		// Check that no extra elements are in the access list
   813  		index := state.accessList.addresses[address]
   814  		if index >= 0 {
   815  			stateSlots := state.accessList.slots[index]
   816  			for s := range stateSlots {
   817  				if _, slotPresent := slotMap[s]; !slotPresent {
   818  					t.Fatalf("scope has extra slot %v (address %v)", s, addrString)
   819  				}
   820  			}
   821  		}
   822  	}
   823  
   824  	state.AddAddressToAccessList(addr("aa"))          // 1
   825  	state.AddSlotToAccessList(addr("bb"), slot("01")) // 2,3
   826  	state.AddSlotToAccessList(addr("bb"), slot("02")) // 4
   827  	verifyAddrs("aa", "bb")
   828  	verifySlots("bb", "01", "02")
   829  
   830  	// Make a copy
   831  	stateCopy1 := state.Copy()
   832  	if exp, got := 4, state.journal.length(); exp != got {
   833  		t.Fatalf("journal length mismatch: have %d, want %d", got, exp)
   834  	}
   835  
   836  	// same again, should cause no journal entries
   837  	state.AddSlotToAccessList(addr("bb"), slot("01"))
   838  	state.AddSlotToAccessList(addr("bb"), slot("02"))
   839  	state.AddAddressToAccessList(addr("aa"))
   840  	if exp, got := 4, state.journal.length(); exp != got {
   841  		t.Fatalf("journal length mismatch: have %d, want %d", got, exp)
   842  	}
   843  	// some new ones
   844  	state.AddSlotToAccessList(addr("bb"), slot("03")) // 5
   845  	state.AddSlotToAccessList(addr("aa"), slot("01")) // 6
   846  	state.AddSlotToAccessList(addr("cc"), slot("01")) // 7,8
   847  	state.AddAddressToAccessList(addr("cc"))
   848  	if exp, got := 8, state.journal.length(); exp != got {
   849  		t.Fatalf("journal length mismatch: have %d, want %d", got, exp)
   850  	}
   851  
   852  	verifyAddrs("aa", "bb", "cc")
   853  	verifySlots("aa", "01")
   854  	verifySlots("bb", "01", "02", "03")
   855  	verifySlots("cc", "01")
   856  
   857  	// now start rolling back changes
   858  	state.journal.revert(state, 7)
   859  	if _, ok := state.SlotInAccessList(addr("cc"), slot("01")); ok {
   860  		t.Fatalf("slot present, expected missing")
   861  	}
   862  	verifyAddrs("aa", "bb", "cc")
   863  	verifySlots("aa", "01")
   864  	verifySlots("bb", "01", "02", "03")
   865  
   866  	state.journal.revert(state, 6)
   867  	if state.AddressInAccessList(addr("cc")) {
   868  		t.Fatalf("addr present, expected missing")
   869  	}
   870  	verifyAddrs("aa", "bb")
   871  	verifySlots("aa", "01")
   872  	verifySlots("bb", "01", "02", "03")
   873  
   874  	state.journal.revert(state, 5)
   875  	if _, ok := state.SlotInAccessList(addr("aa"), slot("01")); ok {
   876  		t.Fatalf("slot present, expected missing")
   877  	}
   878  	verifyAddrs("aa", "bb")
   879  	verifySlots("bb", "01", "02", "03")
   880  
   881  	state.journal.revert(state, 4)
   882  	if _, ok := state.SlotInAccessList(addr("bb"), slot("03")); ok {
   883  		t.Fatalf("slot present, expected missing")
   884  	}
   885  	verifyAddrs("aa", "bb")
   886  	verifySlots("bb", "01", "02")
   887  
   888  	state.journal.revert(state, 3)
   889  	if _, ok := state.SlotInAccessList(addr("bb"), slot("02")); ok {
   890  		t.Fatalf("slot present, expected missing")
   891  	}
   892  	verifyAddrs("aa", "bb")
   893  	verifySlots("bb", "01")
   894  
   895  	state.journal.revert(state, 2)
   896  	if _, ok := state.SlotInAccessList(addr("bb"), slot("01")); ok {
   897  		t.Fatalf("slot present, expected missing")
   898  	}
   899  	verifyAddrs("aa", "bb")
   900  
   901  	state.journal.revert(state, 1)
   902  	if state.AddressInAccessList(addr("bb")) {
   903  		t.Fatalf("addr present, expected missing")
   904  	}
   905  	verifyAddrs("aa")
   906  
   907  	state.journal.revert(state, 0)
   908  	if state.AddressInAccessList(addr("aa")) {
   909  		t.Fatalf("addr present, expected missing")
   910  	}
   911  	if got, exp := len(state.accessList.addresses), 0; got != exp {
   912  		t.Fatalf("expected empty, got %d", got)
   913  	}
   914  	if got, exp := len(state.accessList.slots), 0; got != exp {
   915  		t.Fatalf("expected empty, got %d", got)
   916  	}
   917  	// Check the copy
   918  	// Make a copy
   919  	state = stateCopy1
   920  	verifyAddrs("aa", "bb")
   921  	verifySlots("bb", "01", "02")
   922  	if got, exp := len(state.accessList.addresses), 2; got != exp {
   923  		t.Fatalf("expected empty, got %d", got)
   924  	}
   925  	if got, exp := len(state.accessList.slots), 1; got != exp {
   926  		t.Fatalf("expected empty, got %d", got)
   927  	}
   928  }
   929  
   930  func TestMultiCoinOperations(t *testing.T) {
   931  	s := newStateTest()
   932  	addr := common.Address{1}
   933  	assetID := common.Hash{2}
   934  
   935  	s.state.GetOrNewStateObject(addr)
   936  	root, _ := s.state.Commit(false, false)
   937  	s.state, _ = NewWithSnapshot(root, s.state.db, s.state.snap)
   938  
   939  	s.state.AddBalance(addr, new(big.Int))
   940  
   941  	balance := s.state.GetBalanceMultiCoin(addr, assetID)
   942  	if balance.Cmp(big.NewInt(0)) != 0 {
   943  		t.Fatal("expected zero multicoin balance")
   944  	}
   945  
   946  	s.state.SetBalanceMultiCoin(addr, assetID, big.NewInt(10))
   947  	s.state.SubBalanceMultiCoin(addr, assetID, big.NewInt(5))
   948  	s.state.AddBalanceMultiCoin(addr, assetID, big.NewInt(3))
   949  
   950  	balance = s.state.GetBalanceMultiCoin(addr, assetID)
   951  	if balance.Cmp(big.NewInt(8)) != 0 {
   952  		t.Fatal("expected multicoin balance to be 8")
   953  	}
   954  }
   955  
   956  func TestMultiCoinSnapshot(t *testing.T) {
   957  	db := rawdb.NewMemoryDatabase()
   958  	sdb := NewDatabase(db)
   959  
   960  	// Create empty snapshot.Tree and StateDB
   961  	root := common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
   962  	// Use the root as both the stateRoot and blockHash for this test.
   963  	snapTree := snapshot.NewTestTree(db, root, root)
   964  
   965  	addr := common.Address{1}
   966  	assetID1 := common.Hash{1}
   967  	assetID2 := common.Hash{2}
   968  
   969  	var stateDB *StateDB
   970  	assertBalances := func(regular, multicoin1, multicoin2 int64) {
   971  		balance := stateDB.GetBalance(addr)
   972  		if balance.Cmp(big.NewInt(regular)) != 0 {
   973  			t.Fatal("incorrect non-multicoin balance")
   974  		}
   975  		balance = stateDB.GetBalanceMultiCoin(addr, assetID1)
   976  		if balance.Cmp(big.NewInt(multicoin1)) != 0 {
   977  			t.Fatal("incorrect multicoin1 balance")
   978  		}
   979  		balance = stateDB.GetBalanceMultiCoin(addr, assetID2)
   980  		if balance.Cmp(big.NewInt(multicoin2)) != 0 {
   981  			t.Fatal("incorrect multicoin2 balance")
   982  		}
   983  	}
   984  
   985  	// Create new state
   986  	stateDB, _ = New(root, sdb, snapTree)
   987  	assertBalances(0, 0, 0)
   988  
   989  	stateDB.AddBalance(addr, big.NewInt(10))
   990  	assertBalances(10, 0, 0)
   991  
   992  	// Commit and get the new root
   993  	root, _ = stateDB.Commit(false, false)
   994  	assertBalances(10, 0, 0)
   995  
   996  	// Create a new state from the latest root, add a multicoin balance, and
   997  	// commit it to the tree.
   998  	stateDB, _ = New(root, sdb, snapTree)
   999  	stateDB.AddBalanceMultiCoin(addr, assetID1, big.NewInt(10))
  1000  	root, _ = stateDB.Commit(false, false)
  1001  	assertBalances(10, 10, 0)
  1002  
  1003  	// Add more layers than the cap and ensure the balances and layers are correct
  1004  	for i := 0; i < 256; i++ {
  1005  		stateDB, _ = New(root, sdb, snapTree)
  1006  		stateDB.AddBalanceMultiCoin(addr, assetID1, big.NewInt(1))
  1007  		stateDB.AddBalanceMultiCoin(addr, assetID2, big.NewInt(2))
  1008  		root, _ = stateDB.Commit(false, false)
  1009  	}
  1010  	assertBalances(10, 266, 512)
  1011  
  1012  	// Do one more add, including the regular balance which is now in the
  1013  	// collapsed snapshot
  1014  	stateDB, _ = New(root, sdb, snapTree)
  1015  	stateDB.AddBalance(addr, big.NewInt(1))
  1016  	stateDB.AddBalanceMultiCoin(addr, assetID1, big.NewInt(1))
  1017  	_, _ = stateDB.Commit(false, false)
  1018  	assertBalances(11, 267, 512)
  1019  }
  1020  
  1021  func TestGenerateMultiCoinAccounts(t *testing.T) {
  1022  	var (
  1023  		diskdb   = rawdb.NewMemoryDatabase()
  1024  		database = NewDatabase(diskdb)
  1025  
  1026  		addr     = common.BytesToAddress([]byte("addr1"))
  1027  		addrHash = crypto.Keccak256Hash(addr[:])
  1028  
  1029  		assetID      = common.BytesToHash([]byte("coin1"))
  1030  		assetBalance = big.NewInt(10)
  1031  	)
  1032  
  1033  	stateDB, err := New(common.Hash{}, database, nil)
  1034  	if err != nil {
  1035  		t.Fatal(err)
  1036  	}
  1037  	stateDB.SetBalanceMultiCoin(addr, assetID, assetBalance)
  1038  	root, err := stateDB.Commit(false, false)
  1039  	if err != nil {
  1040  		t.Fatal(err)
  1041  	}
  1042  
  1043  	triedb := database.TrieDB()
  1044  	if err := triedb.Commit(root, true, nil); err != nil {
  1045  		t.Fatal(err)
  1046  	}
  1047  	// Build snapshot from scratch
  1048  	snaps, err := snapshot.New(diskdb, triedb, 16, common.Hash{}, root, false, true, false)
  1049  	if err != nil {
  1050  		t.Error("Unexpected error while rebuilding snapshot:", err)
  1051  	}
  1052  
  1053  	// Get latest snapshot and make sure it has the correct account and storage
  1054  	snap := snaps.Snapshot(root)
  1055  	snapAccount, err := snap.Account(addrHash)
  1056  	if err != nil {
  1057  		t.Fatal(err)
  1058  	}
  1059  	if !snapAccount.IsMultiCoin {
  1060  		t.Fatalf("Expected SnapAccount to return IsMultiCoin: true, found: %v", snapAccount.IsMultiCoin)
  1061  	}
  1062  
  1063  	NormalizeCoinID(&assetID)
  1064  	assetHash := crypto.Keccak256Hash(assetID.Bytes())
  1065  	storageBytes, err := snap.Storage(addrHash, assetHash)
  1066  	if err != nil {
  1067  		t.Fatal(err)
  1068  	}
  1069  
  1070  	actualAssetBalance := new(big.Int).SetBytes(storageBytes)
  1071  	if actualAssetBalance.Cmp(assetBalance) != 0 {
  1072  		t.Fatalf("Expected asset balance: %v, found %v", assetBalance, actualAssetBalance)
  1073  	}
  1074  }
  1075  
  1076  // Tests that account and storage tries are flushed in the correct order and that
  1077  // no data loss occurs.
  1078  func TestFlushOrderDataLoss(t *testing.T) {
  1079  	// Create a state trie with many accounts and slots
  1080  	var (
  1081  		memdb    = rawdb.NewMemoryDatabase()
  1082  		statedb  = NewDatabase(memdb)
  1083  		state, _ = New(common.Hash{}, statedb, nil)
  1084  	)
  1085  	for a := byte(0); a < 10; a++ {
  1086  		state.CreateAccount(common.Address{a})
  1087  		for s := byte(0); s < 10; s++ {
  1088  			state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s})
  1089  		}
  1090  	}
  1091  	root, err := state.Commit(false, false)
  1092  	if err != nil {
  1093  		t.Fatalf("failed to commit state trie: %v", err)
  1094  	}
  1095  	statedb.TrieDB().Reference(root, common.Hash{})
  1096  	if err := statedb.TrieDB().Cap(1024); err != nil {
  1097  		t.Fatalf("failed to cap trie dirty cache: %v", err)
  1098  	}
  1099  	if err := statedb.TrieDB().Commit(root, false, nil); err != nil {
  1100  		t.Fatalf("failed to commit state trie: %v", err)
  1101  	}
  1102  	// Reopen the state trie from flushed disk and verify it
  1103  	state, err = New(root, NewDatabase(memdb), nil)
  1104  	if err != nil {
  1105  		t.Fatalf("failed to reopen state trie: %v", err)
  1106  	}
  1107  	for a := byte(0); a < 10; a++ {
  1108  		for s := byte(0); s < 10; s++ {
  1109  			if have := state.GetState(common.Address{a}, common.Hash{a, s}); have != (common.Hash{a, s}) {
  1110  				t.Errorf("account %d: slot %d: state mismatch: have %x, want %x", a, s, have, common.Hash{a, s})
  1111  			}
  1112  		}
  1113  	}
  1114  }