diff --git a/action/protocol/execution/evm/context.go b/action/protocol/execution/evm/context.go new file mode 100644 index 0000000000..82b1686cf5 --- /dev/null +++ b/action/protocol/execution/evm/context.go @@ -0,0 +1,33 @@ +package evm + +import ( + "context" + + "github.com/iotexproject/iotex-core/pkg/log" +) + +type ( + helperContextKey struct{} + + // HelperContext is the context for EVM helper + HelperContext struct { + GetBlockHash GetBlockHash + DepositGasFunc DepositGasWithSGD + // TODO: sgd should be moved into depositGasFunc + Sgd SGDRegistry + } +) + +// WithHelperCtx returns a new context with helper context +func WithHelperCtx(ctx context.Context, hctx HelperContext) context.Context { + return context.WithValue(ctx, helperContextKey{}, hctx) +} + +// mustGetHelperCtx returns the helper context from the context +func mustGetHelperCtx(ctx context.Context) HelperContext { + hc, ok := ctx.Value(helperContextKey{}).(HelperContext) + if !ok { + log.S().Panic("Miss evm helper context") + } + return hc +} diff --git a/action/protocol/execution/evm/evm.go b/action/protocol/execution/evm/evm.go index 9b0433805b..a36a2f0434 100644 --- a/action/protocol/execution/evm/evm.go +++ b/action/protocol/execution/evm/evm.go @@ -97,6 +97,7 @@ type ( genesis genesis.Blockchain featureCtx protocol.FeatureCtx actionCtx protocol.ActionCtx + helperCtx HelperContext } ) @@ -105,15 +106,16 @@ func newParams( ctx context.Context, execution *action.Execution, stateDB *StateDBAdapter, - getBlockHash GetBlockHash, ) (*Params, error) { var ( actionCtx = protocol.MustGetActionCtx(ctx) blkCtx = protocol.MustGetBlockCtx(ctx) featureCtx = protocol.MustGetFeatureCtx(ctx) g = genesis.MustExtractGenesisContext(ctx) + helperCtx = mustGetHelperCtx(ctx) evmNetworkID = protocol.MustGetBlockchainCtx(ctx).EvmNetworkID executorAddr = common.BytesToAddress(actionCtx.Caller.Bytes()) + getBlockHash = helperCtx.GetBlockHash vmConfig vm.Config contractAddrPointer *common.Address @@ -198,6 +200,7 @@ func newParams( g.Blockchain, featureCtx, actionCtx, + helperCtx, }, nil } @@ -224,9 +227,6 @@ func ExecuteContract( ctx context.Context, sm protocol.StateManager, execution *action.Execution, - getBlockHash GetBlockHash, - depositGasFunc DepositGasWithSGD, - sgd SGDRegistry, ) ([]byte, *action.Receipt, error) { ctx, span := tracer.NewSpan(ctx, "evm.ExecuteContract") defer span.End() @@ -235,10 +235,11 @@ func ExecuteContract( if err != nil { return nil, nil, err } - ps, err := newParams(ctx, execution, stateDB, getBlockHash) + ps, err := newParams(ctx, execution, stateDB) if err != nil { return nil, nil, err } + sgd := ps.helperCtx.Sgd retval, depositGas, remainingGas, contractAddress, statusCode, err := executeInEVM(ps, stateDB) if err != nil { return nil, nil, err @@ -279,6 +280,7 @@ func ExecuteContract( sharedGasFee, totalGasFee *big.Int ) if ps.featureCtx.SharedGasWithDapp && sgd != nil { + // TODO: sgd is whether nil should be checked in processSGD receiver, sharedGas, err = processSGD(ctx, sm, execution, consumedGas, sgd) if err != nil { return nil, nil, errors.Wrap(err, "failed to process Sharing of Gas-fee with DApps") @@ -289,7 +291,7 @@ func ExecuteContract( sharedGasFee.Mul(sharedGasFee, ps.txCtx.GasPrice) } totalGasFee = new(big.Int).Mul(new(big.Int).SetUint64(consumedGas), ps.txCtx.GasPrice) - depositLog, err = depositGasFunc(ctx, sm, receiver, totalGasFee, sharedGasFee) + depositLog, err = ps.helperCtx.DepositGasFunc(ctx, sm, receiver, totalGasFee, sharedGasFee) if err != nil { return nil, nil, err } @@ -610,7 +612,6 @@ func SimulateExecution( sm protocol.StateManager, caller address.Address, ex *action.Execution, - getBlockHash GetBlockHash, ) ([]byte, *action.Receipt, error) { ctx, span := tracer.NewSpan(ctx, "evm.SimulateExecution") defer span.End() @@ -638,14 +639,18 @@ func SimulateExecution( ) ctx = protocol.WithFeatureCtx(ctx) + // TODO: move the logic out of SimulateExecution + helperCtx := mustGetHelperCtx(ctx) + ctx = WithHelperCtx(ctx, HelperContext{ + GetBlockHash: helperCtx.GetBlockHash, + DepositGasFunc: func(context.Context, protocol.StateManager, address.Address, *big.Int, *big.Int) (*action.TransactionLog, error) { + return nil, nil + }, + Sgd: nil, + }) return ExecuteContract( ctx, sm, ex, - getBlockHash, - func(context.Context, protocol.StateManager, address.Address, *big.Int, *big.Int) (*action.TransactionLog, error) { - return nil, nil - }, - nil, ) } diff --git a/action/protocol/execution/evm/evm_test.go b/action/protocol/execution/evm/evm_test.go index 1108dd1505..e8781b7ab2 100644 --- a/action/protocol/execution/evm/evm_test.go +++ b/action/protocol/execution/evm/evm_test.go @@ -60,13 +60,16 @@ func TestExecuteContractFailure(t *testing.T) { ChainID: 1, EvmNetworkID: 100, }) - retval, receipt, err := ExecuteContract(ctx, sm, e, - func(uint64) (hash.Hash256, error) { + ctx = WithHelperCtx(ctx, HelperContext{ + GetBlockHash: func(uint64) (hash.Hash256, error) { return hash.ZeroHash256, nil }, - func(context.Context, protocol.StateManager, address.Address, *big.Int, *big.Int) (*action.TransactionLog, error) { + DepositGasFunc: func(context.Context, protocol.StateManager, address.Address, *big.Int, *big.Int) (*action.TransactionLog, error) { return nil, nil - }, nil) + }, + Sgd: nil, + }) + retval, receipt, err := ExecuteContract(ctx, sm, e) require.Nil(t, retval) require.Nil(t, receipt) require.Error(t, err) @@ -255,11 +258,14 @@ func TestConstantinople(t *testing.T) { GasLimit: testutil.TestGasLimit, BlockHeight: e.height, })) + fCtx = WithHelperCtx(fCtx, HelperContext{ + GetBlockHash: func(uint64) (hash.Hash256, error) { + return hash.ZeroHash256, nil + }, + }) stateDB, err := prepareStateDB(fCtx, sm) require.NoError(err) - ps, err := newParams(fCtx, ex, stateDB, func(uint64) (hash.Hash256, error) { - return hash.ZeroHash256, nil - }) + ps, err := newParams(fCtx, ex, stateDB) require.NoError(err) var evmConfig vm.Config diff --git a/action/protocol/execution/protocol.go b/action/protocol/execution/protocol.go index 108aa262c7..6fc23fa13a 100644 --- a/action/protocol/execution/protocol.go +++ b/action/protocol/execution/protocol.go @@ -8,11 +8,11 @@ package execution import ( "context" + "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-address/address" "github.com/pkg/errors" "go.uber.org/zap" - "github.com/iotexproject/go-pkgs/hash" - "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-core/action" "github.com/iotexproject/iotex-core/action/protocol" "github.com/iotexproject/iotex-core/action/protocol/execution/evm" @@ -66,7 +66,12 @@ func (p *Protocol) Handle(ctx context.Context, act action.Action, sm protocol.St if !ok { return nil, nil } - _, receipt, err := evm.ExecuteContract(ctx, sm, exec, p.getBlockHash, p.depositGas, p.sgdRegistry) + ctx = evm.WithHelperCtx(ctx, evm.HelperContext{ + GetBlockHash: p.getBlockHash, + DepositGasFunc: p.depositGas, + Sgd: p.sgdRegistry, + }) + _, receipt, err := evm.ExecuteContract(ctx, sm, exec) if err != nil { return nil, errors.Wrap(err, "failed to execute contract") diff --git a/action/protocol/execution/protocol_test.go b/action/protocol/execution/protocol_test.go index fe5664d89a..d33fb28aa5 100644 --- a/action/protocol/execution/protocol_test.go +++ b/action/protocol/execution/protocol_test.go @@ -283,8 +283,10 @@ func readExecution( if err != nil { return nil, nil, err } - - return sf.SimulateExecution(ctx, addr, exec, dao.GetBlockHash) + ctx = evm.WithHelperCtx(ctx, evm.HelperContext{ + GetBlockHash: dao.GetBlockHash, + }) + return sf.SimulateExecution(ctx, addr, exec) } func runExecutions( diff --git a/action/protocol/poll/consortium.go b/action/protocol/poll/consortium.go index 021ff74d58..460de19c20 100644 --- a/action/protocol/poll/consortium.go +++ b/action/protocol/poll/consortium.go @@ -11,6 +11,10 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/iotexproject/go-pkgs/hash" "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/pkg/errors" + "go.uber.org/zap" + "github.com/iotexproject/iotex-core/action" "github.com/iotexproject/iotex-core/action/protocol" "github.com/iotexproject/iotex-core/action/protocol/execution/evm" @@ -18,9 +22,6 @@ import ( "github.com/iotexproject/iotex-core/blockchain/genesis" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-core/state" - "github.com/iotexproject/iotex-proto/golang/iotextypes" - "github.com/pkg/errors" - "go.uber.org/zap" ) var ( @@ -124,19 +125,21 @@ func (cc *consortiumCommittee) CreateGenesisStates(ctx context.Context, sm proto } ctx = protocol.WithActionCtx(ctx, actionCtx) ctx = protocol.WithBlockCtx(ctx, blkCtx) + ctx = evm.WithHelperCtx(ctx, evm.HelperContext{ + GetBlockHash: func(height uint64) (hash.Hash256, error) { + return hash.ZeroHash256, nil + }, + DepositGasFunc: func(context.Context, protocol.StateManager, address.Address, *big.Int, *big.Int) (*action.TransactionLog, error) { + return nil, nil + }, + Sgd: nil, + }) // deploy consortiumCommittee contract _, receipt, err := evm.ExecuteContract( ctx, sm, execution, - func(height uint64) (hash.Hash256, error) { - return hash.ZeroHash256, nil - }, - func(context.Context, protocol.StateManager, address.Address, *big.Int, *big.Int) (*action.TransactionLog, error) { - return nil, nil - }, - nil, ) if err != nil { return err @@ -291,7 +294,11 @@ func getContractReaderForGenesisStates(ctx context.Context, sm protocol.StateMan return nil, err } - res, _, err := evm.SimulateExecution(ctx, sm, addr, ex, getBlockHash) + // TODO: move to the caller, then getBlockHash param can be removed + ctx = evm.WithHelperCtx(ctx, evm.HelperContext{ + GetBlockHash: getBlockHash, + }) + res, _, err := evm.SimulateExecution(ctx, sm, addr, ex) return res, err } diff --git a/action/protocol/poll/staking_committee.go b/action/protocol/poll/staking_committee.go index d6d4d115dc..3277bfee19 100644 --- a/action/protocol/poll/staking_committee.go +++ b/action/protocol/poll/staking_committee.go @@ -135,18 +135,20 @@ func (sc *stakingCommittee) CreateGenesisStates(ctx context.Context, sm protocol } ctx = protocol.WithActionCtx(ctx, actionCtx) ctx = protocol.WithBlockCtx(ctx, blkCtx) + ctx = evm.WithHelperCtx(ctx, evm.HelperContext{ + GetBlockHash: func(height uint64) (hash.Hash256, error) { + return hash.ZeroHash256, nil + }, + DepositGasFunc: func(context.Context, protocol.StateManager, address.Address, *big.Int, *big.Int) (*action.TransactionLog, error) { + return nil, nil + }, + Sgd: nil, + }) // deploy native staking contract _, receipt, err := evm.ExecuteContract( ctx, sm, execution, - func(height uint64) (hash.Hash256, error) { - return hash.ZeroHash256, nil - }, - func(context.Context, protocol.StateManager, address.Address, *big.Int, *big.Int) (*action.TransactionLog, error) { - return nil, nil - }, - nil, ) if err != nil { return err diff --git a/api/coreservice.go b/api/coreservice.go index 32951b9d42..36d1ce6668 100644 --- a/api/coreservice.go +++ b/api/coreservice.go @@ -517,7 +517,7 @@ func (core *coreService) ReadContract(ctx context.Context, callerAddr address.Ad } sc.SetGasPrice(big.NewInt(0)) // ReadContract() is read-only, use 0 to prevent insufficient gas - retval, receipt, err := core.sf.SimulateExecution(ctx, callerAddr, sc, core.dao.GetBlockHash) + retval, receipt, err := core.simulateExecution(ctx, callerAddr, sc, core.dao.GetBlockHash) if err != nil { return "", nil, status.Error(codes.Internal, err.Error()) } @@ -1479,7 +1479,8 @@ func (core *coreService) isGasLimitEnough( if err != nil { return false, nil, err } - _, receipt, err := core.sf.SimulateExecution(ctx, caller, sc, core.dao.GetBlockHash) + + _, receipt, err := core.simulateExecution(ctx, caller, sc, core.dao.GetBlockHash) if err != nil { return false, nil, err } @@ -1628,7 +1629,7 @@ func (core *coreService) SimulateExecution(ctx context.Context, addr address.Add return nil, nil, err } exec.SetGasLimit(core.bc.Genesis().BlockGasLimit) - return core.sf.SimulateExecution(ctx, addr, exec, core.dao.GetBlockHash) + return core.simulateExecution(ctx, addr, exec, core.dao.GetBlockHash) } // SyncingProgress returns the syncing status of node @@ -1715,7 +1716,7 @@ func (core *coreService) TraceCall(ctx context.Context, getblockHash := func(height uint64) (hash.Hash256, error) { return blkHash, nil } - retval, receipt, err := core.sf.SimulateExecution(ctx, callerAddr, exec, getblockHash) + retval, receipt, err := core.simulateExecution(ctx, callerAddr, exec, getblockHash) return retval, receipt, traces, err } @@ -1731,3 +1732,11 @@ func (core *coreService) Track(ctx context.Context, start time.Time, method stri Success: success, }, size) } + +func (core *coreService) simulateExecution(ctx context.Context, addr address.Address, exec *action.Execution, getBlockHash evm.GetBlockHash) ([]byte, *action.Receipt, error) { + // TODO: add depositGas + ctx = evm.WithHelperCtx(ctx, evm.HelperContext{ + GetBlockHash: getBlockHash, + }) + return core.sf.SimulateExecution(ctx, addr, exec) +} diff --git a/chainservice/builder.go b/chainservice/builder.go index 9ccca8adc8..2fe1e894dc 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -21,6 +21,7 @@ import ( "github.com/iotexproject/iotex-core/action/protocol/account" accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util" "github.com/iotexproject/iotex-core/action/protocol/execution" + "github.com/iotexproject/iotex-core/action/protocol/execution/evm" "github.com/iotexproject/iotex-core/action/protocol/poll" "github.com/iotexproject/iotex-core/action/protocol/rewarding" "github.com/iotexproject/iotex-core/action/protocol/rolldpos" @@ -617,7 +618,11 @@ func (builder *Builder) registerRollDPoSProtocol() error { return nil, err } - data, _, err := factory.SimulateExecution(ctx, addr, ex, dao.GetBlockHash) + // TODO: add depositGas + ctx = evm.WithHelperCtx(ctx, evm.HelperContext{ + GetBlockHash: dao.GetBlockHash, + }) + data, _, err := factory.SimulateExecution(ctx, addr, ex) return data, err }, diff --git a/e2etest/staking_test.go b/e2etest/staking_test.go index 316aeeac8a..1c1a1b58bc 100644 --- a/e2etest/staking_test.go +++ b/e2etest/staking_test.go @@ -22,6 +22,7 @@ import ( "github.com/iotexproject/iotex-core/action" "github.com/iotexproject/iotex-core/action/protocol" + "github.com/iotexproject/iotex-core/action/protocol/execution/evm" "github.com/iotexproject/iotex-core/action/protocol/poll" "github.com/iotexproject/iotex-core/blockchain/genesis" "github.com/iotexproject/iotex-core/config" @@ -121,7 +122,10 @@ func TestStakingContract(t *testing.T) { return nil, err } - data, _, err := sf.SimulateExecution(ctx, addr, ex, dao.GetBlockHash) + ctx = evm.WithHelperCtx(ctx, evm.HelperContext{ + GetBlockHash: dao.GetBlockHash, + }) + data, _, err := sf.SimulateExecution(ctx, addr, ex) return data, err }) diff --git a/state/factory/factory.go b/state/factory/factory.go index 982cf4cd5f..2d1f336309 100644 --- a/state/factory/factory.go +++ b/state/factory/factory.go @@ -86,7 +86,7 @@ type ( Validate(context.Context, *block.Block) error // NewBlockBuilder creates block builder NewBlockBuilder(context.Context, actpool.ActPool, func(action.Envelope) (action.SealedEnvelope, error)) (*block.Builder, error) - SimulateExecution(context.Context, address.Address, *action.Execution, evm.GetBlockHash) ([]byte, *action.Receipt, error) + SimulateExecution(context.Context, address.Address, *action.Execution) ([]byte, *action.Receipt, error) ReadContractStorage(context.Context, address.Address, []byte) ([]byte, error) PutBlock(context.Context, *block.Block) error DeleteTipBlock(context.Context, *block.Block) error @@ -387,7 +387,6 @@ func (sf *factory) SimulateExecution( ctx context.Context, caller address.Address, ex *action.Execution, - getBlockHash evm.GetBlockHash, ) ([]byte, *action.Receipt, error) { ctx, span := tracer.NewSpan(ctx, "factory.SimulateExecution") defer span.End() @@ -399,7 +398,7 @@ func (sf *factory) SimulateExecution( return nil, nil, errors.Wrap(err, "failed to obtain working set from state factory") } - return evm.SimulateExecution(ctx, ws, caller, ex, getBlockHash) + return evm.SimulateExecution(ctx, ws, caller, ex) } // ReadContractStorage reads contract's storage diff --git a/state/factory/factory_test.go b/state/factory/factory_test.go index 8b229e422b..9f15e4f7b3 100644 --- a/state/factory/factory_test.go +++ b/state/factory/factory_test.go @@ -30,6 +30,7 @@ import ( "github.com/iotexproject/iotex-core/action/protocol" "github.com/iotexproject/iotex-core/action/protocol/account" accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util" + "github.com/iotexproject/iotex-core/action/protocol/execution/evm" "github.com/iotexproject/iotex-core/action/protocol/poll" "github.com/iotexproject/iotex-core/action/protocol/rewarding" "github.com/iotexproject/iotex-core/action/protocol/rolldpos" @@ -1223,9 +1224,12 @@ func testSimulateExecution(ctx context.Context, sf Factory, t *testing.T) { addr, err := address.FromString(address.ZeroAddress) require.NoError(err) - _, _, err = sf.SimulateExecution(ctx, addr, ex, func(uint64) (hash.Hash256, error) { - return hash.ZeroHash256, nil + ctx = evm.WithHelperCtx(ctx, evm.HelperContext{ + GetBlockHash: func(uint64) (hash.Hash256, error) { + return hash.ZeroHash256, nil + }, }) + _, _, err = sf.SimulateExecution(ctx, addr, ex) require.NoError(err) } diff --git a/state/factory/statedb.go b/state/factory/statedb.go index 46dea6893d..47f0a79537 100644 --- a/state/factory/statedb.go +++ b/state/factory/statedb.go @@ -267,7 +267,6 @@ func (sdb *stateDB) SimulateExecution( ctx context.Context, caller address.Address, ex *action.Execution, - getBlockHash evm.GetBlockHash, ) ([]byte, *action.Receipt, error) { ctx, span := tracer.NewSpan(ctx, "stateDB.SimulateExecution") defer span.End() @@ -280,7 +279,7 @@ func (sdb *stateDB) SimulateExecution( return nil, nil, err } - return evm.SimulateExecution(ctx, ws, caller, ex, getBlockHash) + return evm.SimulateExecution(ctx, ws, caller, ex) } // ReadContractStorage reads contract's storage diff --git a/test/mock/mock_factory/mock_factory.go b/test/mock/mock_factory/mock_factory.go index 65ed2dac26..2aed6bd37d 100644 --- a/test/mock/mock_factory/mock_factory.go +++ b/test/mock/mock_factory/mock_factory.go @@ -12,7 +12,6 @@ import ( address "github.com/iotexproject/iotex-address/address" action "github.com/iotexproject/iotex-core/action" protocol "github.com/iotexproject/iotex-core/action/protocol" - evm "github.com/iotexproject/iotex-core/action/protocol/execution/evm" actpool "github.com/iotexproject/iotex-core/actpool" block "github.com/iotexproject/iotex-core/blockchain/block" state "github.com/iotexproject/iotex-core/state" @@ -144,9 +143,9 @@ func (mr *MockFactoryMockRecorder) Register(arg0 interface{}) *gomock.Call { } // SimulateExecution mocks base method. -func (m *MockFactory) SimulateExecution(arg0 context.Context, arg1 address.Address, arg2 *action.Execution, arg3 evm.GetBlockHash) ([]byte, *action.Receipt, error) { +func (m *MockFactory) SimulateExecution(arg0 context.Context, arg1 address.Address, arg2 *action.Execution) ([]byte, *action.Receipt, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SimulateExecution", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "SimulateExecution", arg0, arg1, arg2) ret0, _ := ret[0].([]byte) ret1, _ := ret[1].(*action.Receipt) ret2, _ := ret[2].(error) @@ -154,9 +153,9 @@ func (m *MockFactory) SimulateExecution(arg0 context.Context, arg1 address.Addre } // SimulateExecution indicates an expected call of SimulateExecution. -func (mr *MockFactoryMockRecorder) SimulateExecution(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockFactoryMockRecorder) SimulateExecution(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SimulateExecution", reflect.TypeOf((*MockFactory)(nil).SimulateExecution), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SimulateExecution", reflect.TypeOf((*MockFactory)(nil).SimulateExecution), arg0, arg1, arg2) } // Start mocks base method.