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 }