github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/execution/evm/contract_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  	"math/big"
    10  	"testing"
    11  
    12  	"github.com/ethereum/go-ethereum/common"
    13  	"github.com/golang/mock/gomock"
    14  	"github.com/pkg/errors"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/iotexproject/go-pkgs/hash"
    18  
    19  	"github.com/iotexproject/iotex-core/action/protocol"
    20  	accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util"
    21  	"github.com/iotexproject/iotex-core/db/batch"
    22  	"github.com/iotexproject/iotex-core/state"
    23  	"github.com/iotexproject/iotex-core/test/identityset"
    24  	"github.com/iotexproject/iotex-core/test/mock/mock_chainmanager"
    25  	"github.com/iotexproject/iotex-core/testutil"
    26  )
    27  
    28  func TestCreateContract(t *testing.T) {
    29  	require := require.New(t)
    30  	ctrl := gomock.NewController(t)
    31  	testTriePath, err := testutil.PathOfTempFile("trie")
    32  	require.NoError(err)
    33  	defer testutil.CleanupPath(testTriePath)
    34  
    35  	sm := mock_chainmanager.NewMockStateManager(ctrl)
    36  	cb := batch.NewCachedBatch()
    37  	sm.EXPECT().State(gomock.Any(), gomock.Any()).DoAndReturn(
    38  		func(account interface{}, opts ...protocol.StateOption) (uint64, error) {
    39  			cfg, err := protocol.CreateStateConfig(opts...)
    40  			if err != nil {
    41  				return 0, err
    42  			}
    43  			val, err := cb.Get("state", cfg.Key)
    44  			if err != nil {
    45  				return 0, state.ErrStateNotExist
    46  			}
    47  			return 0, state.Deserialize(account, val)
    48  		}).AnyTimes()
    49  	sm.EXPECT().PutState(gomock.Any(), gomock.Any()).DoAndReturn(
    50  		func(account interface{}, opts ...protocol.StateOption) (uint64, error) {
    51  			cfg, err := protocol.CreateStateConfig(opts...)
    52  			if err != nil {
    53  				return 0, err
    54  			}
    55  			ss, err := state.Serialize(account)
    56  			if err != nil {
    57  				return 0, err
    58  			}
    59  			cb.Put("state", cfg.Key, ss, "failed to put state")
    60  			return 0, nil
    61  		}).AnyTimes()
    62  
    63  	addr := identityset.Address(28)
    64  	_, err = accountutil.LoadOrCreateAccount(sm, addr)
    65  	require.NoError(err)
    66  	stateDB, err := NewStateDBAdapter(sm, 0, hash.ZeroHash256, NotFixTopicCopyBugOption())
    67  	require.NoError(err)
    68  
    69  	contract := addr.Bytes()
    70  	var evmContract common.Address
    71  	copy(evmContract[:], contract[:])
    72  	stateDB.SetCode(evmContract, _bytecode)
    73  	// contract exist
    74  	codeHash := stateDB.GetCodeHash(evmContract)
    75  	var emptyEVMHash common.Hash
    76  	require.NotEqual(emptyEVMHash, codeHash)
    77  	v := stateDB.GetCode(evmContract)
    78  	require.Equal(_bytecode, v)
    79  	// non-existing contract
    80  	addr1 := hash.Hash160b([]byte("random"))
    81  	var evmAddr1 common.Address
    82  	copy(evmAddr1[:], addr1[:])
    83  	h := stateDB.GetCodeHash(evmAddr1)
    84  	require.Equal(emptyEVMHash, h)
    85  	require.Nil(stateDB.GetCode(evmAddr1))
    86  	require.NoError(stateDB.CommitContracts())
    87  	stateDB.clear()
    88  	// reload same contract
    89  	contract1, err := accountutil.LoadOrCreateAccount(sm, addr)
    90  	require.NoError(err)
    91  	require.Equal(codeHash[:], contract1.CodeHash)
    92  }
    93  
    94  func TestLoadStoreCommit(t *testing.T) {
    95  	require := require.New(t)
    96  
    97  	testLoadStoreCommit := func(t *testing.T, enableAsync bool) {
    98  		ctrl := gomock.NewController(t)
    99  		sm, err := initMockStateManager(ctrl)
   100  		require.NoError(err)
   101  		acct := &state.Account{}
   102  		cntr1, err := newContract(hash.BytesToHash160(_c1[:]), acct, sm, enableAsync)
   103  		require.NoError(err)
   104  
   105  		tests := []cntrTest{
   106  			{
   107  				cntr1,
   108  				[]code{
   109  					{_c1, []byte("2nd contract creation")},
   110  				},
   111  				[]set{
   112  					{_k1b, _v1b[:], nil},
   113  					{_k2b, _v2b[:], nil},
   114  				},
   115  			},
   116  			{
   117  				cntr1,
   118  				[]code{
   119  					{_c2, _bytecode},
   120  				},
   121  				[]set{
   122  					{_k1b, _v4b[:], nil},
   123  					{_k2b, _v3b[:], nil},
   124  					{_k3b, _v2b[:], nil},
   125  					{_k4b, _v1b[:], nil},
   126  				},
   127  			},
   128  			{
   129  				cntr1,
   130  				nil,
   131  				[]set{
   132  					{_k1b, _v2b[:], nil},
   133  					{_k2b, _v1b[:], nil},
   134  					{_k3b, _v4b[:], nil},
   135  					{_k4b, nil, nil},
   136  				},
   137  			},
   138  		}
   139  
   140  		for i, test := range tests {
   141  			c := test.contract
   142  			// set code
   143  			for _, e := range test.codes {
   144  				c.SetCode(hash.Hash256b(e.v), e.v)
   145  			}
   146  			// set states
   147  			for _, e := range test.states {
   148  				require.NoError(c.SetState(e.k, e.v))
   149  				if i > 0 {
   150  					// committed state == value of previous test's SetState()
   151  					committed := tests[i-1].states
   152  					for _, e := range committed {
   153  						v, err := c.GetCommittedState(e.k)
   154  						require.NoError(err)
   155  						require.Equal(e.v, v)
   156  					}
   157  				}
   158  				v, err := c.GetState(e.k)
   159  				require.NoError(err)
   160  				require.Equal(e.v, v)
   161  			}
   162  			require.NoError(c.Commit())
   163  		}
   164  
   165  		checks := []cntrTest{
   166  			{
   167  				cntr1,
   168  				[]code{
   169  					{_c1, _bytecode},
   170  				},
   171  				[]set{
   172  					{_k1b, _v2b[:], nil},
   173  					{_k2b, _v1b[:], nil},
   174  					{_k3b, _v4b[:], nil},
   175  					{_k4b, nil, nil},
   176  				},
   177  			},
   178  		}
   179  
   180  		for _, test := range checks {
   181  			c := test.contract
   182  			// check code
   183  			for _, e := range test.codes {
   184  				v, err := c.GetCode()
   185  				require.NoError(err)
   186  				require.Equal(e.v, v)
   187  				chash := hash.Hash256b(e.v)
   188  				require.Equal(chash[:], c.SelfState().CodeHash)
   189  				require.NotEqual(hash.ZeroHash256, hash.BytesToHash256(chash[:]))
   190  			}
   191  			// check states
   192  			for _, e := range test.states {
   193  				v, err := c.GetState(e.k)
   194  				require.Equal(e.v, v)
   195  				if err != nil {
   196  					require.Equal(e.cause, errors.Cause(err))
   197  				}
   198  			}
   199  		}
   200  	}
   201  
   202  	t.Run("contract load/store with stateDB, sync mode", func(t *testing.T) {
   203  		testLoadStoreCommit(t, false)
   204  	})
   205  	t.Run("contract load/store with stateDB, async mode", func(t *testing.T) {
   206  		testLoadStoreCommit(t, true)
   207  	})
   208  
   209  }
   210  
   211  func TestSnapshot(t *testing.T) {
   212  	require := require.New(t)
   213  	ctrl := gomock.NewController(t)
   214  	testfunc := func(enableAsync bool) {
   215  		sm, err := initMockStateManager(ctrl)
   216  		require.NoError(err)
   217  		s, err := state.NewAccount()
   218  		require.NoError(err)
   219  		require.NoError(s.AddBalance(big.NewInt(5)))
   220  		_c1, err := newContract(
   221  			hash.BytesToHash160(identityset.Address(28).Bytes()),
   222  			s,
   223  			sm,
   224  			enableAsync,
   225  		)
   226  		require.NoError(err)
   227  		require.NoError(_c1.SetState(_k2b, _v2[:]))
   228  		_c2 := _c1.Snapshot()
   229  		require.NoError(_c1.SelfState().AddBalance(big.NewInt(7)))
   230  		require.NoError(_c1.SetState(_k1b, _v1[:]))
   231  		require.Equal(big.NewInt(12), _c1.SelfState().Balance)
   232  		require.Equal(big.NewInt(5), _c2.SelfState().Balance)
   233  	}
   234  	t.Run("sync mode", func(t *testing.T) {
   235  		testfunc(false)
   236  	})
   237  	t.Run("async mode", func(t *testing.T) {
   238  		testfunc(true)
   239  	})
   240  }