github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/execution/evm/evmstatedbadapter_test.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package evm
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"math/big"
    12  	"testing"
    13  
    14  	"github.com/ethereum/go-ethereum/common"
    15  	"github.com/ethereum/go-ethereum/core/types"
    16  	"github.com/golang/mock/gomock"
    17  	"github.com/iotexproject/go-pkgs/hash"
    18  	"github.com/iotexproject/iotex-address/address"
    19  	"github.com/pkg/errors"
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  
    23  	"github.com/iotexproject/iotex-core/action/protocol"
    24  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    25  	"github.com/iotexproject/iotex-core/db/batch"
    26  	"github.com/iotexproject/iotex-core/state"
    27  	"github.com/iotexproject/iotex-core/test/identityset"
    28  	"github.com/iotexproject/iotex-core/test/mock/mock_chainmanager"
    29  )
    30  
    31  func initMockStateManager(ctrl *gomock.Controller) (*mock_chainmanager.MockStateManager, error) {
    32  	sm := mock_chainmanager.NewMockStateManager(ctrl)
    33  	cb := batch.NewCachedBatch()
    34  	sm.EXPECT().State(gomock.Any(), gomock.Any()).DoAndReturn(
    35  		func(account interface{}, opts ...protocol.StateOption) (uint64, error) {
    36  			cfg, err := protocol.CreateStateConfig(opts...)
    37  			if err != nil {
    38  				return 0, err
    39  			}
    40  			ns := "state"
    41  			if cfg.Namespace != "" {
    42  				ns = cfg.Namespace
    43  			}
    44  			val, err := cb.Get(ns, cfg.Key)
    45  			if err != nil {
    46  				return 0, state.ErrStateNotExist
    47  			}
    48  			return 0, state.Deserialize(account, val)
    49  		}).AnyTimes()
    50  	sm.EXPECT().PutState(gomock.Any(), gomock.Any()).DoAndReturn(
    51  		func(account interface{}, opts ...protocol.StateOption) (uint64, error) {
    52  			cfg, err := protocol.CreateStateConfig(opts...)
    53  			if err != nil {
    54  				return 0, err
    55  			}
    56  			ss, err := state.Serialize(account)
    57  			if err != nil {
    58  				return 0, err
    59  			}
    60  			ns := "state"
    61  			if cfg.Namespace != "" {
    62  				ns = cfg.Namespace
    63  			}
    64  			cb.Put(ns, cfg.Key, ss, "failed to put state")
    65  			return 0, nil
    66  		}).AnyTimes()
    67  	sm.EXPECT().DelState(gomock.Any()).DoAndReturn(
    68  		func(opts ...protocol.StateOption) (uint64, error) {
    69  			cfg, err := protocol.CreateStateConfig(opts...)
    70  			if err != nil {
    71  				return 0, err
    72  			}
    73  			ns := "state"
    74  			if cfg.Namespace != "" {
    75  				ns = cfg.Namespace
    76  			}
    77  			cb.Delete(ns, cfg.Key, "failed to delete state")
    78  			return 0, nil
    79  		}).AnyTimes()
    80  	sm.EXPECT().Snapshot().DoAndReturn(cb.Snapshot).AnyTimes()
    81  	sm.EXPECT().Revert(gomock.Any()).DoAndReturn(cb.RevertSnapshot).AnyTimes()
    82  	return sm, nil
    83  }
    84  
    85  func TestAddBalance(t *testing.T) {
    86  	require := require.New(t)
    87  	ctrl := gomock.NewController(t)
    88  
    89  	sm, err := initMockStateManager(ctrl)
    90  	require.NoError(err)
    91  	addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec")
    92  	stateDB, err := NewStateDBAdapter(
    93  		sm,
    94  		1,
    95  		hash.ZeroHash256,
    96  		NotFixTopicCopyBugOption(),
    97  		FixSnapshotOrderOption(),
    98  	)
    99  	require.NoError(err)
   100  	addAmount := big.NewInt(40000)
   101  	stateDB.AddBalance(addr, addAmount)
   102  	require.Equal(addAmount, stateDB.lastAddBalanceAmount)
   103  	beneficiary, _ := address.FromBytes(addr[:])
   104  	require.Equal(beneficiary.String(), stateDB.lastAddBalanceAddr)
   105  	amount := stateDB.GetBalance(addr)
   106  	require.Equal(amount, addAmount)
   107  	stateDB.AddBalance(addr, addAmount)
   108  	amount = stateDB.GetBalance(addr)
   109  	require.Equal(amount, big.NewInt(80000))
   110  	stateDB.AddBalance(addr, new(big.Int))
   111  	require.Zero(len(stateDB.lastAddBalanceAmount.Bytes()))
   112  }
   113  
   114  func TestRefundAPIs(t *testing.T) {
   115  	require := require.New(t)
   116  	ctrl := gomock.NewController(t)
   117  
   118  	sm, err := initMockStateManager(ctrl)
   119  	require.NoError(err)
   120  	stateDB, err := NewStateDBAdapter(
   121  		sm,
   122  		1,
   123  		hash.ZeroHash256,
   124  		NotFixTopicCopyBugOption(),
   125  		FixSnapshotOrderOption(),
   126  	)
   127  	require.NoError(err)
   128  	require.Zero(stateDB.GetRefund())
   129  	refund := uint64(1024)
   130  	stateDB.AddRefund(refund)
   131  	require.Equal(refund, stateDB.GetRefund())
   132  }
   133  
   134  func TestEmptyAndCode(t *testing.T) {
   135  	require := require.New(t)
   136  	ctrl := gomock.NewController(t)
   137  
   138  	sm, err := initMockStateManager(ctrl)
   139  	require.NoError(err)
   140  	addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec")
   141  	stateDB, err := NewStateDBAdapter(
   142  		sm,
   143  		1,
   144  		hash.ZeroHash256,
   145  		NotFixTopicCopyBugOption(),
   146  		FixSnapshotOrderOption(),
   147  	)
   148  	require.NoError(err)
   149  	require.True(stateDB.Empty(addr))
   150  	stateDB.CreateAccount(addr)
   151  	require.True(stateDB.Empty(addr))
   152  	stateDB.SetCode(addr, []byte("0123456789"))
   153  	require.True(bytes.Equal(stateDB.GetCode(addr), []byte("0123456789")))
   154  	require.False(stateDB.Empty(addr))
   155  }
   156  
   157  var kvs = map[common.Hash]common.Hash{
   158  	common.HexToHash("0123456701234567012345670123456701234567012345670123456701234560"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234560"),
   159  	common.HexToHash("0123456701234567012345670123456701234567012345670123456701234561"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234561"),
   160  	common.HexToHash("0123456701234567012345670123456701234567012345670123456701234562"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234562"),
   161  	common.HexToHash("0123456701234567012345670123456701234567012345670123456701234563"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234563"),
   162  	common.HexToHash("2345670123456701234567012345670123456701234567012345670123456301"): common.HexToHash("2345670123456701234567012345670123456701234567012345670123456301"),
   163  	common.HexToHash("4567012345670123456701234567012345670123456701234567012345630123"): common.HexToHash("4567012345670123456701234567012345670123456701234567012345630123"),
   164  	common.HexToHash("6701234567012345670123456701234567012345670123456701234563012345"): common.HexToHash("6701234567012345670123456701234567012345670123456701234563012345"),
   165  	common.HexToHash("0123456701234567012345670123456701234567012345670123456301234567"): common.HexToHash("0123456701234567012345670123456701234567012345670123456301234567"),
   166  	common.HexToHash("ab45670123456701234567012345670123456701234567012345630123456701"): common.HexToHash("ab45670123456701234567012345670123456701234567012345630123456701"),
   167  	common.HexToHash("cd67012345670123456701234567012345670123456701234563012345670123"): common.HexToHash("cd67012345670123456701234567012345670123456701234563012345670123"),
   168  	common.HexToHash("ef01234567012345670123456701234567012345670123456301234567012345"): common.HexToHash("ef01234567012345670123456701234567012345670123456301234567012345"),
   169  }
   170  
   171  func TestForEachStorage(t *testing.T) {
   172  	require := require.New(t)
   173  	ctrl := gomock.NewController(t)
   174  
   175  	sm, err := initMockStateManager(ctrl)
   176  	require.NoError(err)
   177  	addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec")
   178  	stateDB, err := NewStateDBAdapter(
   179  		sm,
   180  		1,
   181  		hash.ZeroHash256,
   182  		NotFixTopicCopyBugOption(),
   183  		FixSnapshotOrderOption(),
   184  	)
   185  	require.NoError(err)
   186  	stateDB.CreateAccount(addr)
   187  	for k, v := range kvs {
   188  		stateDB.SetState(addr, k, v)
   189  	}
   190  	require.NoError(
   191  		stateDB.ForEachStorage(addr, func(k common.Hash, v common.Hash) bool {
   192  			require.Equal(k, v)
   193  			delete(kvs, k)
   194  			return true
   195  		}),
   196  	)
   197  	require.Equal(0, len(kvs))
   198  }
   199  
   200  func TestReadContractStorage(t *testing.T) {
   201  	require := require.New(t)
   202  	ctrl := gomock.NewController(t)
   203  
   204  	sm, err := initMockStateManager(ctrl)
   205  	require.NoError(err)
   206  	addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec")
   207  	stateDB, err := NewStateDBAdapter(
   208  		sm,
   209  		1,
   210  		hash.ZeroHash256,
   211  		AsyncContractTrieOption(),
   212  		FixSnapshotOrderOption(),
   213  	)
   214  	require.NoError(err)
   215  	stateDB.CreateAccount(addr)
   216  	kvs := map[common.Hash]common.Hash{
   217  		common.HexToHash("0123456701234567012345670123456701234567012345670123456701234560"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234560"),
   218  		common.HexToHash("0123456701234567012345670123456701234567012345670123456701234561"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234561"),
   219  		common.HexToHash("0123456701234567012345670123456701234567012345670123456701234562"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234562"),
   220  		common.HexToHash("0123456701234567012345670123456701234567012345670123456701234563"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234563"),
   221  		common.HexToHash("2345670123456701234567012345670123456701234567012345670123456301"): common.HexToHash("2345670123456701234567012345670123456701234567012345670123456301"),
   222  		common.HexToHash("4567012345670123456701234567012345670123456701234567012345630123"): common.HexToHash("4567012345670123456701234567012345670123456701234567012345630123"),
   223  		common.HexToHash("6701234567012345670123456701234567012345670123456701234563012345"): common.HexToHash("6701234567012345670123456701234567012345670123456701234563012345"),
   224  		common.HexToHash("0123456701234567012345670123456701234567012345670123456301234567"): common.HexToHash("0123456701234567012345670123456701234567012345670123456301234567"),
   225  		common.HexToHash("ab45670123456701234567012345670123456701234567012345630123456701"): common.HexToHash("ab45670123456701234567012345670123456701234567012345630123456701"),
   226  		common.HexToHash("cd67012345670123456701234567012345670123456701234563012345670123"): common.HexToHash("cd67012345670123456701234567012345670123456701234563012345670123"),
   227  		common.HexToHash("ef01234567012345670123456701234567012345670123456301234567012345"): common.HexToHash("ef01234567012345670123456701234567012345670123456301234567012345"),
   228  	}
   229  	for k, v := range kvs {
   230  		stateDB.SetState(addr, k, v)
   231  	}
   232  	stateDB.CommitContracts()
   233  
   234  	ctx := protocol.WithBlockchainCtx(protocol.WithFeatureCtx(protocol.WithBlockCtx(
   235  		genesis.WithGenesisContext(context.Background(), genesis.Default),
   236  		protocol.BlockCtx{BlockHeight: genesis.Default.MidwayBlockHeight})),
   237  		protocol.BlockchainCtx{})
   238  	for k, v := range kvs {
   239  		b, err := ReadContractStorage(ctx, sm, addr, k[:])
   240  		require.NoError(err)
   241  		require.Equal(v[:], b)
   242  	}
   243  }
   244  
   245  func TestNonce(t *testing.T) {
   246  	require := require.New(t)
   247  	ctrl := gomock.NewController(t)
   248  
   249  	addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec")
   250  	t.Run("legacy nonce account with confirmed nonce", func(t *testing.T) {
   251  		sm, err := initMockStateManager(ctrl)
   252  		require.NoError(err)
   253  		opt := []StateDBAdapterOption{
   254  			NotFixTopicCopyBugOption(),
   255  			FixSnapshotOrderOption(),
   256  			LegacyNonceAccountOption(),
   257  			UseConfirmedNonceOption(),
   258  		}
   259  		stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...)
   260  		require.NoError(err)
   261  		require.Equal(uint64(0), stateDB.GetNonce(addr))
   262  		stateDB.SetNonce(addr, 1)
   263  		require.Equal(uint64(1), stateDB.GetNonce(addr))
   264  	})
   265  	t.Run("legacy nonce account with pending nonce", func(t *testing.T) {
   266  		sm, err := initMockStateManager(ctrl)
   267  		require.NoError(err)
   268  		opt := []StateDBAdapterOption{
   269  			NotFixTopicCopyBugOption(),
   270  			FixSnapshotOrderOption(),
   271  			LegacyNonceAccountOption(),
   272  		}
   273  		stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...)
   274  		require.NoError(err)
   275  		require.Equal(uint64(1), stateDB.GetNonce(addr))
   276  		stateDB.SetNonce(addr, 2)
   277  		require.Equal(uint64(2), stateDB.GetNonce(addr))
   278  	})
   279  	t.Run("zero nonce account with confirmed nonce", func(t *testing.T) {
   280  		sm, err := initMockStateManager(ctrl)
   281  		require.NoError(err)
   282  		opt := []StateDBAdapterOption{
   283  			NotFixTopicCopyBugOption(),
   284  			FixSnapshotOrderOption(),
   285  			UseConfirmedNonceOption(),
   286  		}
   287  		_, err = NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...)
   288  		require.Error(err)
   289  	})
   290  	t.Run("zero nonce account with pending nonce", func(t *testing.T) {
   291  		sm, err := initMockStateManager(ctrl)
   292  		require.NoError(err)
   293  		opt := []StateDBAdapterOption{
   294  			NotFixTopicCopyBugOption(),
   295  			FixSnapshotOrderOption(),
   296  		}
   297  		stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...)
   298  		require.NoError(err)
   299  		require.Equal(uint64(0), stateDB.GetNonce(addr))
   300  		stateDB.SetNonce(addr, 1)
   301  		require.Equal(uint64(1), stateDB.GetNonce(addr))
   302  	})
   303  	t.Run("legacy fresh nonce account with pending nonce", func(t *testing.T) {
   304  		sm, err := initMockStateManager(ctrl)
   305  		require.NoError(err)
   306  		opt := []StateDBAdapterOption{
   307  			NotFixTopicCopyBugOption(),
   308  			FixSnapshotOrderOption(),
   309  			ZeroNonceForFreshAccountOption(),
   310  		}
   311  		stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...)
   312  		require.NoError(err)
   313  		require.Equal(uint64(0), stateDB.GetNonce(addr))
   314  		stateDB.SetNonce(addr, 1)
   315  		require.Equal(uint64(1), stateDB.GetNonce(addr))
   316  	})
   317  }
   318  
   319  var tests = []stateDBTest{
   320  	{
   321  		[]bal{
   322  			{_addr1, big.NewInt(40000)},
   323  		},
   324  		[]code{
   325  			{_c1, _bytecode},
   326  		},
   327  		[]evmSet{
   328  			{_c1, _k1, _v1},
   329  			{_c1, _k2, _v2},
   330  			{_c3, _k3, _v4},
   331  		},
   332  		15000,
   333  		[]sui{
   334  			{nil, _c4, _c2, false, false},
   335  			{nil, _c2, _c4, false, false},
   336  		},
   337  		[]image{
   338  			{common.BytesToHash(_v1[:]), []byte("cat")},
   339  			{common.BytesToHash(_v2[:]), []byte("dog")},
   340  		},
   341  		[]access{
   342  			{_c1, []common.Hash{_k1, _k2}, []common.Hash{_k3, _k4}, false},
   343  		},
   344  		[]*types.Log{
   345  			newTestLog(_c3), newTestLog(_c2), newTestLog(_c1),
   346  		},
   347  		3, 0,
   348  		"io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", "io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", "",
   349  	},
   350  	{
   351  		[]bal{
   352  			{_addr1, big.NewInt(40000)},
   353  		},
   354  		[]code{
   355  			{_c2, _bytecode},
   356  		},
   357  		[]evmSet{
   358  			{_c1, _k1, _v3},
   359  			{_c1, _k2, _v4},
   360  			{_c2, _k3, _v3},
   361  			{_c2, _k4, _v4},
   362  		},
   363  		2000,
   364  		[]sui{
   365  			{nil, _c4, _c1, true, true},
   366  			{big.NewInt(1000), _c2, _c3, true, true},
   367  		},
   368  		[]image{
   369  			{common.BytesToHash(_v3[:]), []byte("hen")},
   370  		},
   371  		[]access{
   372  			{_c1, []common.Hash{_k3, _k4}, nil, true},
   373  			{_c2, []common.Hash{_k1, _k3}, []common.Hash{_k2, _k4}, false},
   374  		},
   375  		[]*types.Log{
   376  			newTestLog(_c4),
   377  		},
   378  		4, 1,
   379  		"io1zg0qrlpyvc68pnmz4c4f2mfc6jqu8f57jjy09q",
   380  		"io1j4kjr6x5s8p6dyqlcfrxxdrsea32u2hpvpl5us",
   381  		"io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe",
   382  	},
   383  	{
   384  		nil,
   385  		nil,
   386  		[]evmSet{
   387  			{_c2, _k3, _v1},
   388  			{_c2, _k4, _v2},
   389  		},
   390  		15000,
   391  		[]sui{
   392  			{big.NewInt(0), _c1, _addr1, true, true},
   393  		},
   394  		[]image{
   395  			{common.BytesToHash(_v4[:]), []byte("fox")},
   396  		},
   397  		[]access{
   398  			{_c2, []common.Hash{_k2, _k4}, nil, true},
   399  		},
   400  		[]*types.Log{
   401  			newTestLog(_c1), newTestLog(_c2),
   402  		},
   403  		6, 2,
   404  		"io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe",
   405  		"io1q2hz49tdy85dfqwr560pge3ngux0vf0vmhanad",
   406  		"io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r",
   407  	},
   408  }
   409  
   410  func TestSnapshotRevertAndCommit(t *testing.T) {
   411  	testSnapshotAndRevert := func(t *testing.T, async, fixSnapshot, revertLog bool) {
   412  		require := require.New(t)
   413  		ctrl := gomock.NewController(t)
   414  
   415  		sm, err := initMockStateManager(ctrl)
   416  		require.NoError(err)
   417  		opt := []StateDBAdapterOption{
   418  			NotFixTopicCopyBugOption(),
   419  			SuicideTxLogMismatchPanicOption(),
   420  		}
   421  		if async {
   422  			opt = append(opt, AsyncContractTrieOption())
   423  		}
   424  		if fixSnapshot {
   425  			opt = append(opt, FixSnapshotOrderOption())
   426  		}
   427  		if revertLog {
   428  			opt = append(opt, RevertLogOption())
   429  		}
   430  		stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...)
   431  		require.NoError(err)
   432  
   433  		for i, test := range tests {
   434  			// add balance
   435  			for _, e := range test.balance {
   436  				stateDB.AddBalance(e.addr, e.v)
   437  			}
   438  			// set code
   439  			for _, e := range test.codes {
   440  				stateDB.SetCode(e.addr, e.v)
   441  				v := stateDB.GetCode(e.addr)
   442  				require.Equal(e.v, v)
   443  			}
   444  			// set states
   445  			for _, e := range test.states {
   446  				stateDB.SetState(e.addr, e.k, e.v)
   447  			}
   448  			// set refund
   449  			stateDB.refund = test.refund
   450  			// set suicide
   451  			for _, e := range test.suicide {
   452  				if e.amount != nil {
   453  					stateDB.AddBalance(e.addr, e.amount)
   454  				}
   455  				stateDB.AddBalance(e.beneficiary, stateDB.GetBalance(e.addr)) // simulate transfer to beneficiary inside Suicide()
   456  				require.Equal(e.suicide, stateDB.Suicide(e.addr))
   457  				require.Equal(e.exist, stateDB.Exist(e.addr))
   458  				require.Zero(new(big.Int).Cmp(stateDB.GetBalance(e.addr)))
   459  			}
   460  			// set preimage
   461  			for _, e := range test.preimage {
   462  				stateDB.AddPreimage(e.hash, e.v)
   463  			}
   464  			// set access list
   465  			for _, e := range test.accessList {
   466  				require.Equal(e.exist, stateDB.AddressInAccessList(e.addr))
   467  				for _, slot := range e.slots {
   468  					aOk, sOk := stateDB.SlotInAccessList(e.addr, slot)
   469  					require.Equal(e.exist, aOk)
   470  					require.False(sOk)
   471  					stateDB.AddSlotToAccessList(e.addr, slot)
   472  					e.exist = true
   473  					aOk, sOk = stateDB.SlotInAccessList(e.addr, slot)
   474  					require.True(aOk)
   475  					require.True(sOk)
   476  				}
   477  				for _, slot := range e.nx {
   478  					aOk, sOk := stateDB.SlotInAccessList(e.addr, slot)
   479  					require.True(aOk)
   480  					require.False(sOk)
   481  				}
   482  			}
   483  			// set logs and txLogs
   484  			for _, l := range test.logs {
   485  				stateDB.AddLog(l)
   486  			}
   487  
   488  			require.Equal(test.logSize, len(stateDB.logs))
   489  			require.Equal(test.txLogSize, len(stateDB.transactionLogs))
   490  			require.Equal(test.logAddr, stateDB.logs[test.logSize-1].Address)
   491  			if test.txLogSize > 0 {
   492  				require.Equal(test.txSender, stateDB.transactionLogs[test.txLogSize-1].Sender)
   493  				require.Equal(test.txReceiver, stateDB.transactionLogs[test.txLogSize-1].Recipient)
   494  			}
   495  			require.Equal(i, stateDB.Snapshot())
   496  		}
   497  
   498  		reverts := []stateDBTest{
   499  			{
   500  				[]bal{
   501  					{_addr1, big.NewInt(0)},
   502  				},
   503  				[]code{},
   504  				[]evmSet{
   505  					{_c1, _k1, _v3},
   506  					{_c1, _k2, _v4},
   507  					{_c2, _k3, _v1},
   508  					{_c2, _k4, _v2},
   509  				},
   510  				tests[2].refund,
   511  				[]sui{
   512  					{nil, common.Address{}, _c1, true, true},
   513  					{nil, common.Address{}, _c3, true, true},
   514  					{nil, common.Address{}, _c2, false, true},
   515  					{nil, common.Address{}, _c4, false, false},
   516  					{nil, common.Address{}, _addr1, true, true},
   517  				},
   518  				[]image{
   519  					{common.BytesToHash(_v1[:]), []byte("cat")},
   520  					{common.BytesToHash(_v2[:]), []byte("dog")},
   521  					{common.BytesToHash(_v3[:]), []byte("hen")},
   522  					{common.BytesToHash(_v4[:]), []byte("fox")},
   523  				},
   524  				[]access{
   525  					{_c1, []common.Hash{_k1, _k2, _k3, _k4}, nil, true},
   526  					{_c2, []common.Hash{_k1, _k2, _k3, _k4}, nil, true},
   527  				},
   528  				nil,
   529  				6, 2,
   530  				"io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe",
   531  				"io1q2hz49tdy85dfqwr560pge3ngux0vf0vmhanad",
   532  				"io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r",
   533  			},
   534  			{
   535  				[]bal{
   536  					{_addr1, big.NewInt(80000)},
   537  				},
   538  				[]code{},
   539  				tests[1].states,
   540  				tests[1].refund,
   541  				[]sui{
   542  					{nil, common.Address{}, _c1, true, true},
   543  					{nil, common.Address{}, _c3, true, true},
   544  					{nil, common.Address{}, _c2, false, true},
   545  					{nil, common.Address{}, _c4, false, false},
   546  					{nil, common.Address{}, _addr1, false, true},
   547  				},
   548  				[]image{
   549  					{common.BytesToHash(_v1[:]), []byte("cat")},
   550  					{common.BytesToHash(_v2[:]), []byte("dog")},
   551  					{common.BytesToHash(_v3[:]), []byte("hen")},
   552  					{common.BytesToHash(_v4[:]), []byte(nil)},
   553  				},
   554  				[]access{
   555  					{_c1, []common.Hash{_k1, _k2, _k3, _k4}, nil, true},
   556  					{_c2, []common.Hash{_k1, _k3}, []common.Hash{_k2, _k4}, true},
   557  				},
   558  				nil,
   559  				4, 1,
   560  				"io1zg0qrlpyvc68pnmz4c4f2mfc6jqu8f57jjy09q",
   561  				"io1j4kjr6x5s8p6dyqlcfrxxdrsea32u2hpvpl5us",
   562  				"io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe",
   563  			},
   564  			{
   565  				[]bal{
   566  					{_addr1, big.NewInt(40000)},
   567  				},
   568  				[]code{},
   569  				[]evmSet{
   570  					{_c1, _k1, _v1},
   571  					{_c1, _k2, _v2},
   572  					{_c3, _k3, _v4},
   573  				},
   574  				tests[0].refund,
   575  				[]sui{
   576  					{nil, common.Address{}, _c1, false, true},
   577  					{nil, common.Address{}, _c3, false, true},
   578  					{nil, common.Address{}, _c2, false, false},
   579  					{nil, common.Address{}, _c4, false, false},
   580  					{nil, common.Address{}, _addr1, false, true},
   581  				},
   582  				[]image{
   583  					{common.BytesToHash(_v1[:]), []byte("cat")},
   584  					{common.BytesToHash(_v2[:]), []byte("dog")},
   585  					{common.BytesToHash(_v3[:]), []byte(nil)},
   586  					{common.BytesToHash(_v4[:]), []byte(nil)},
   587  				},
   588  				[]access{
   589  					{_c1, []common.Hash{_k1, _k2}, []common.Hash{_k3, _k4}, true},
   590  					{_c2, nil, []common.Hash{_k1, _k2, _k3, _k4}, false},
   591  				},
   592  				nil,
   593  				3, 0,
   594  				"io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r",
   595  				"io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r",
   596  				"",
   597  			},
   598  		}
   599  
   600  		// test revert
   601  		for i, test := range reverts {
   602  			stateDB.RevertToSnapshot(len(reverts) - 1 - i)
   603  			// test balance
   604  			for _, e := range test.balance {
   605  				amount := stateDB.GetBalance(e.addr)
   606  				require.Equal(e.v, amount)
   607  			}
   608  			if async && !fixSnapshot {
   609  				// test preimage
   610  				for _, e := range reverts[0].preimage {
   611  					v := stateDB.preimages[e.hash]
   612  					require.Equal(e.v, []byte(v))
   613  				}
   614  			} else {
   615  				// test states
   616  				for _, e := range test.states {
   617  					require.Equal(e.v, stateDB.GetState(e.addr, e.k))
   618  				}
   619  				// test refund
   620  				require.Equal(test.refund, stateDB.refund)
   621  				// test preimage
   622  				for _, e := range test.preimage {
   623  					v := stateDB.preimages[e.hash]
   624  					require.Equal(e.v, []byte(v))
   625  				}
   626  				// test access list
   627  				for _, e := range test.accessList {
   628  					require.Equal(e.exist, stateDB.AddressInAccessList(e.addr))
   629  					for _, slot := range e.slots {
   630  						aOk, sOk := stateDB.SlotInAccessList(e.addr, slot)
   631  						require.Equal(e.exist, aOk)
   632  						require.True(sOk)
   633  					}
   634  					for _, slot := range e.nx {
   635  						aOk, sOk := stateDB.SlotInAccessList(e.addr, slot)
   636  						require.Equal(e.exist, aOk)
   637  						require.False(sOk)
   638  					}
   639  				}
   640  			}
   641  			// test suicide/exist
   642  			for _, e := range test.suicide {
   643  				require.Equal(e.suicide, stateDB.HasSuicided(e.addr))
   644  				require.Equal(e.exist, stateDB.Exist(e.addr))
   645  			}
   646  			// test logs
   647  			if revertLog {
   648  				require.Equal(test.logSize, len(stateDB.logs))
   649  				require.Equal(test.txLogSize, len(stateDB.transactionLogs))
   650  				require.Equal(test.logAddr, stateDB.logs[test.logSize-1].Address)
   651  				if test.txLogSize > 0 {
   652  					require.Equal(test.txSender, stateDB.transactionLogs[test.txLogSize-1].Sender)
   653  					require.Equal(test.txReceiver, stateDB.transactionLogs[test.txLogSize-1].Recipient)
   654  				}
   655  			} else {
   656  				require.Equal(6, len(stateDB.logs))
   657  				require.Equal(2, len(stateDB.transactionLogs))
   658  				require.Equal("io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe", stateDB.logs[5].Address)
   659  				require.Equal("io1q2hz49tdy85dfqwr560pge3ngux0vf0vmhanad", stateDB.transactionLogs[1].Sender)
   660  				require.Equal("io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", stateDB.transactionLogs[1].Recipient)
   661  			}
   662  		}
   663  
   664  		// snapshot after revert
   665  		require.Equal(1, stateDB.Snapshot())
   666  		if fixSnapshot {
   667  			require.Equal(1, len(stateDB.contractSnapshot))
   668  			require.Equal(1, len(stateDB.suicideSnapshot))
   669  			require.Equal(1, len(stateDB.preimageSnapshot))
   670  			require.Equal(1, len(stateDB.accessListSnapshot))
   671  			require.Equal(1, len(stateDB.refundSnapshot))
   672  		} else {
   673  			require.Equal(3, len(stateDB.contractSnapshot))
   674  			require.Equal(3, len(stateDB.suicideSnapshot))
   675  			require.Equal(3, len(stateDB.preimageSnapshot))
   676  			// refund fix and accessList are introduced after fixSnapshot
   677  			// so their snapshot are always properly cleared
   678  			require.Zero(len(stateDB.accessListSnapshot))
   679  			require.Zero(len(stateDB.refundSnapshot))
   680  		}
   681  		// commit snapshot 0's state
   682  		require.NoError(stateDB.CommitContracts())
   683  		stateDB.clear()
   684  		//[TODO] need e2etest to verify state factory commit/re-open (whether result from state/balance/suicide/exist is same)
   685  	}
   686  
   687  	t.Run("contract snapshot/revert/commit", func(t *testing.T) {
   688  		testSnapshotAndRevert(t, false, true, false)
   689  	})
   690  	t.Run("contract snapshot/revert/commit w/o bug fix and revert log", func(t *testing.T) {
   691  		testSnapshotAndRevert(t, false, false, true)
   692  	})
   693  	t.Run("contract snapshot/revert/commit with async trie and revert log", func(t *testing.T) {
   694  		testSnapshotAndRevert(t, true, true, true)
   695  	})
   696  	t.Run("contract snapshot/revert/commit with async trie and w/o bug fix", func(t *testing.T) {
   697  		testSnapshotAndRevert(t, true, false, false)
   698  	})
   699  }
   700  
   701  func TestClearSnapshots(t *testing.T) {
   702  	testClearSnapshots := func(t *testing.T, async, fixSnapshotOrder bool) {
   703  		require := require.New(t)
   704  		ctrl := gomock.NewController(t)
   705  
   706  		sm, err := initMockStateManager(ctrl)
   707  		require.NoError(err)
   708  		opts := []StateDBAdapterOption{
   709  			NotFixTopicCopyBugOption(),
   710  			RevertLogOption(),
   711  		}
   712  		if async {
   713  			opts = append(opts, AsyncContractTrieOption())
   714  		}
   715  		if fixSnapshotOrder {
   716  			opts = append(opts, FixSnapshotOrderOption())
   717  		}
   718  		stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opts...)
   719  		require.NoError(err)
   720  
   721  		for i, test := range tests {
   722  			// add balance
   723  			for _, e := range test.balance {
   724  				stateDB.AddBalance(e.addr, e.v)
   725  			}
   726  			// set code
   727  			for _, e := range test.codes {
   728  				stateDB.SetCode(e.addr, e.v)
   729  				v := stateDB.GetCode(e.addr)
   730  				require.Equal(e.v, v)
   731  			}
   732  			// set states
   733  			for _, e := range test.states {
   734  				stateDB.SetState(e.addr, e.k, e.v)
   735  			}
   736  			// set suicide
   737  			for _, e := range test.suicide {
   738  				require.Equal(e.suicide, stateDB.Suicide(e.addr))
   739  				require.Equal(e.exist, stateDB.Exist(e.addr))
   740  			}
   741  			// set preimage
   742  			for _, e := range test.preimage {
   743  				stateDB.AddPreimage(e.hash, e.v)
   744  			}
   745  			require.Equal(i, stateDB.Snapshot())
   746  		}
   747  
   748  		// revert to snapshot 1
   749  		stateDB.RevertToSnapshot(1)
   750  		require.Equal(1, len(stateDB.logsSnapshot))
   751  
   752  		if stateDB.fixSnapshotOrder {
   753  			// snapshot 1, 2 cleared, only 0 left in map
   754  			require.Equal(1, len(stateDB.suicideSnapshot))
   755  			require.Equal(1, len(stateDB.contractSnapshot))
   756  			require.Equal(1, len(stateDB.preimageSnapshot))
   757  			require.Equal(2, stateDB.Snapshot())
   758  			// now there are 2 snapshots: 0 and the newly added one
   759  			require.Equal(2, len(stateDB.suicideSnapshot))
   760  			require.Equal(2, len(stateDB.contractSnapshot))
   761  			require.Equal(2, len(stateDB.preimageSnapshot))
   762  			require.Equal(2, len(stateDB.logsSnapshot))
   763  		} else {
   764  			// snapshot not cleared
   765  			require.Equal(3, len(stateDB.suicideSnapshot))
   766  			require.Equal(3, len(stateDB.contractSnapshot))
   767  			require.Equal(3, len(stateDB.preimageSnapshot))
   768  			require.Equal(2, stateDB.Snapshot())
   769  			// still 3 old snapshots
   770  			require.Equal(3, len(stateDB.suicideSnapshot))
   771  			require.Equal(3, len(stateDB.contractSnapshot))
   772  			require.Equal(3, len(stateDB.preimageSnapshot))
   773  			// log snapshot added after fixSnapshotOrder, so it is cleared and 1 remains
   774  			require.Equal(1, len(stateDB.logsSnapshot))
   775  		}
   776  
   777  	}
   778  	t.Run("contract w/o clear snapshots", func(t *testing.T) {
   779  		testClearSnapshots(t, false, false)
   780  	})
   781  	t.Run("contract with clear snapshots", func(t *testing.T) {
   782  		testClearSnapshots(t, false, true)
   783  	})
   784  }
   785  
   786  func TestGetCommittedState(t *testing.T) {
   787  	t.Run("committed state with in mem DB", func(t *testing.T) {
   788  		require := require.New(t)
   789  		ctrl := gomock.NewController(t)
   790  
   791  		sm, err := initMockStateManager(ctrl)
   792  		require.NoError(err)
   793  		stateDB, err := NewStateDBAdapter(
   794  			sm,
   795  			1,
   796  			hash.ZeroHash256,
   797  			NotFixTopicCopyBugOption(),
   798  			FixSnapshotOrderOption(),
   799  		)
   800  		require.NoError(err)
   801  
   802  		stateDB.SetState(_c1, _k1, _v1)
   803  		// _k2 does not exist
   804  		require.Equal(common.Hash{}, stateDB.GetCommittedState(_c1, common.BytesToHash(_k2[:])))
   805  		require.Equal(_v1, stateDB.GetState(_c1, _k1))
   806  		require.Equal(common.Hash{}, stateDB.GetCommittedState(_c1, common.BytesToHash(_k2[:])))
   807  
   808  		// commit (_k1, _v1)
   809  		require.NoError(stateDB.CommitContracts())
   810  		stateDB.clear()
   811  
   812  		require.Equal(_v1, stateDB.GetState(_c1, _k1))
   813  		require.Equal(common.BytesToHash(_v1[:]), stateDB.GetCommittedState(_c1, common.BytesToHash(_k1[:])))
   814  		stateDB.SetState(_c1, _k1, _v2)
   815  		require.Equal(common.BytesToHash(_v1[:]), stateDB.GetCommittedState(_c1, common.BytesToHash(_k1[:])))
   816  		require.Equal(_v2, stateDB.GetState(_c1, _k1))
   817  		require.Equal(common.BytesToHash(_v1[:]), stateDB.GetCommittedState(_c1, common.BytesToHash(_k1[:])))
   818  	})
   819  }
   820  
   821  func TestGetBalanceOnError(t *testing.T) {
   822  	ctrl := gomock.NewController(t)
   823  
   824  	sm := mock_chainmanager.NewMockStateManager(ctrl)
   825  	errs := []error{
   826  		state.ErrStateNotExist,
   827  		errors.New("other error"),
   828  	}
   829  	for _, err := range errs {
   830  		sm.EXPECT().State(gomock.Any(), gomock.Any()).Return(uint64(0), err).Times(1)
   831  		addr := common.HexToAddress("test address")
   832  		stateDB, err := NewStateDBAdapter(
   833  			sm,
   834  			1,
   835  			hash.ZeroHash256,
   836  			NotFixTopicCopyBugOption(),
   837  			FixSnapshotOrderOption(),
   838  		)
   839  		assert.NoError(t, err)
   840  		amount := stateDB.GetBalance(addr)
   841  		assert.Equal(t, big.NewInt(0), amount)
   842  	}
   843  }
   844  
   845  func TestPreimage(t *testing.T) {
   846  	require := require.New(t)
   847  	ctrl := gomock.NewController(t)
   848  
   849  	sm, err := initMockStateManager(ctrl)
   850  	require.NoError(err)
   851  	stateDB, err := NewStateDBAdapter(
   852  		sm,
   853  		1,
   854  		hash.ZeroHash256,
   855  		NotFixTopicCopyBugOption(),
   856  		FixSnapshotOrderOption(),
   857  	)
   858  	require.NoError(err)
   859  
   860  	stateDB.AddPreimage(common.BytesToHash(_v1[:]), []byte("cat"))
   861  	stateDB.AddPreimage(common.BytesToHash(_v2[:]), []byte("dog"))
   862  	stateDB.AddPreimage(common.BytesToHash(_v3[:]), []byte("hen"))
   863  	// this won't overwrite preimage of _v1
   864  	stateDB.AddPreimage(common.BytesToHash(_v1[:]), []byte("fox"))
   865  	require.NoError(stateDB.CommitContracts())
   866  	stateDB.clear()
   867  	var k protocol.SerializableBytes
   868  	_, err = stateDB.sm.State(&k, protocol.NamespaceOption(PreimageKVNameSpace), protocol.KeyOption(_v1[:]))
   869  	require.NoError(err)
   870  	require.Equal([]byte("cat"), []byte(k))
   871  	_, err = stateDB.sm.State(&k, protocol.NamespaceOption(PreimageKVNameSpace), protocol.KeyOption(_v2[:]))
   872  	require.NoError(err)
   873  	require.Equal([]byte("dog"), []byte(k))
   874  	_, err = stateDB.sm.State(&k, protocol.NamespaceOption(PreimageKVNameSpace), protocol.KeyOption(_v3[:]))
   875  	require.NoError(err)
   876  	require.Equal([]byte("hen"), []byte(k))
   877  }
   878  
   879  func TestSortMap(t *testing.T) {
   880  	require := require.New(t)
   881  	uniqueSlice := func(slice []string) bool {
   882  		for _, v := range slice[1:] {
   883  			if v != slice[0] {
   884  				return false
   885  			}
   886  		}
   887  		return true
   888  	}
   889  
   890  	testFunc := func(t *testing.T, sm *mock_chainmanager.MockStateManager, opts ...StateDBAdapterOption) bool {
   891  		opts = append(opts,
   892  			NotFixTopicCopyBugOption(),
   893  			FixSnapshotOrderOption(),
   894  		)
   895  		stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opts...)
   896  		require.NoError(err)
   897  		size := 10
   898  
   899  		for i := 0; i < size; i++ {
   900  			addr := common.HexToAddress(identityset.Address(i).Hex())
   901  			stateDB.SetCode(addr, []byte("0123456789"))
   902  			stateDB.SetState(addr, _k1, _k2)
   903  		}
   904  		sn := stateDB.Snapshot()
   905  		caches := []string{}
   906  		for i := 0; i < size; i++ {
   907  			stateDB.RevertToSnapshot(sn)
   908  			s := ""
   909  			if stateDB.disableSortCachedContracts {
   910  				for _, c := range stateDB.cachedContract {
   911  					s += string(c.SelfState().Root[:])
   912  				}
   913  			} else {
   914  				for _, addr := range stateDB.cachedContractAddrs() {
   915  					c := stateDB.cachedContract[addr]
   916  					s += string(c.SelfState().Root[:])
   917  				}
   918  			}
   919  
   920  			caches = append(caches, s)
   921  		}
   922  		return uniqueSlice(caches)
   923  	}
   924  
   925  	ctrl := gomock.NewController(t)
   926  	sm, err := initMockStateManager(ctrl)
   927  	require.NoError(err)
   928  	t.Run("before fix sort map", func(t *testing.T) {
   929  		require.False(testFunc(t, sm, DisableSortCachedContractsOption()))
   930  	})
   931  
   932  	t.Run("after fix sort map", func(t *testing.T) {
   933  		require.True(testFunc(t, sm))
   934  	})
   935  }