Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[action] add EvmTransaction to represent actions that run in EVM #4227

Merged
merged 2 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions action/evm_transaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) 2024 IoTeX Foundation
// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
// This source code is governed by Apache License 2.0 that can be found in the LICENSE file.

package action

import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)

type (
// EvmTransaction represents an action to be executed by EVM protocol
// as of now 3 types of transactions are supported:
// 1. Legacy transaction
// 2. EIP-2930 access list transaction
// 3. EIP-4844 shard blob transaction
EvmTransaction struct {
inner TxData
}

TxData interface {
Nonce() uint64
GasLimit() uint64
GasPrice() *big.Int
Amount() *big.Int
To() *common.Address
Data() []byte
AccessList() types.AccessList
}
)

func NewEvmTx(a Action) *EvmTransaction {
tx := new(EvmTransaction)
switch act := a.(type) {
case *Execution:
tx.inner = act
default:
panic("unsupported action type")
}
return tx
}

func (tx *EvmTransaction) Nonce() uint64 {
return tx.inner.Nonce()
}

func (tx *EvmTransaction) Gas() uint64 {
return tx.inner.GasLimit()
}

func (tx *EvmTransaction) GasPrice() *big.Int {
return tx.inner.GasPrice()
}

func (tx *EvmTransaction) Value() *big.Int {
return tx.inner.Amount()
}

func (tx *EvmTransaction) To() *common.Address {
return tx.inner.To()
}

func (tx *EvmTransaction) Data() []byte {
return tx.inner.Data()
}

func (tx *EvmTransaction) AccessList() types.AccessList {
return tx.inner.AccessList()
}
17 changes: 16 additions & 1 deletion action/execution.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2019 IoTeX Foundation
// Copyright (c) 2024 IoTeX Foundation
// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
// This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
Expand Down Expand Up @@ -33,6 +33,7 @@ const (
var (
_ hasDestination = (*Execution)(nil)
_ EthCompatibleAction = (*Execution)(nil)
_ TxData = (*Execution)(nil)
)

// Execution defines the struct of account-based contract execution
Expand Down Expand Up @@ -91,6 +92,20 @@ func NewExecutionWithAccessList(
}, nil
}

// To returns the contract address pointer
// nil indicates a contract-creation transaction
func (ex *Execution) To() *common.Address {
if ex.contract == EmptyAddress {
return nil
}
addr, err := address.FromString(ex.contract)
if err != nil {
panic(err)
}
evmAddr := common.BytesToAddress(addr.Bytes())
return &evmAddr
}

// Contract returns a contract address
func (ex *Execution) Contract() string { return ex.contract }

Expand Down
17 changes: 17 additions & 0 deletions action/execution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/pkg/errors"
"github.com/stretchr/testify/require"

"github.com/iotexproject/iotex-address/address"
"github.com/iotexproject/iotex-core/test/identityset"
)

Expand Down Expand Up @@ -75,6 +76,22 @@ func TestExecutionSanityCheck(t *testing.T) {
require.Contains(ex.SanityCheck().Error(), "error when validating contract's address")
})

t.Run("Empty contract address", func(t *testing.T) {
ex, err := NewExecution(
EmptyAddress,
uint64(1),
big.NewInt(0),
uint64(0),
big.NewInt(0),
[]byte{},
)
require.NoError(err)
require.Nil(ex.To())
addr, _ := address.FromBytes(_c1.Bytes())
ex.contract = addr.String()
require.Equal(_c1, *ex.To())
})

t.Run("Negative gas price", func(t *testing.T) {
ex, err := NewExecution(identityset.Address(29).String(), uint64(1), big.NewInt(100), uint64(0), big.NewInt(-1), []byte{})
require.NoError(err)
Expand Down
35 changes: 13 additions & 22 deletions action/protocol/execution/evm/evm.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2019 IoTeX Foundation
// Copyright (c) 2024 IoTeX Foundation
// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
// This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
Expand Down Expand Up @@ -108,7 +108,7 @@ type (
// newParams creates a new context for use in the EVM.
func newParams(
ctx context.Context,
execution *action.Execution,
execution *action.EvmTransaction,
stateDB *StateDBAdapter,
) (*Params, error) {
var (
Expand All @@ -121,21 +121,11 @@ func newParams(
executorAddr = common.BytesToAddress(actionCtx.Caller.Bytes())
getBlockHash = helperCtx.GetBlockHash

vmConfig vm.Config
contractAddrPointer *common.Address
getHashFn vm.GetHashFunc
vmConfig vm.Config
getHashFn vm.GetHashFunc
)

if dest := execution.Contract(); dest != action.EmptyAddress {
contract, err := address.FromString(execution.Contract())
if err != nil {
return nil, errors.Wrapf(err, "failed to decode contract address %s", dest)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new code panic instead of return error, no problem?

contractAddr := common.BytesToAddress(contract.Bytes())
contractAddrPointer = &contractAddr
}

gasLimit := execution.GasLimit()
gasLimit := execution.Gas()
// Reset gas limit to the system wide action gas limit cap if it's greater than it
if blkCtx.BlockHeight > 0 && featureCtx.SystemWideActionGasLimit && gasLimit > _preAleutianActionGasLimit {
gasLimit = _preAleutianActionGasLimit
Expand Down Expand Up @@ -200,8 +190,8 @@ func newParams(
GasPrice: execution.GasPrice(),
},
execution.Nonce(),
execution.Amount(),
contractAddrPointer,
envestcc marked this conversation as resolved.
Show resolved Hide resolved
execution.Value(),
execution.To(),
gasLimit,
execution.Data(),
execution.AccessList(),
Expand Down Expand Up @@ -237,7 +227,7 @@ func securityDeposit(ps *Params, stateDB vm.StateDB, gasLimit uint64) error {
func ExecuteContract(
ctx context.Context,
sm protocol.StateManager,
execution *action.Execution,
execution *action.EvmTransaction,
) ([]byte, *action.Receipt, error) {
ctx, span := tracer.NewSpan(ctx, "evm.ExecuteContract")
defer span.End()
Expand Down Expand Up @@ -332,16 +322,17 @@ func ExecuteContract(
return retval, receipt, nil
}

func processSGD(ctx context.Context, sm protocol.StateManager, execution *action.Execution, consumedGas uint64, sgd SGDRegistry,
func processSGD(ctx context.Context, sm protocol.StateManager, execution *action.EvmTransaction, consumedGas uint64, sgd SGDRegistry,
) (address.Address, uint64, error) {
if execution.Contract() == action.EmptyAddress {
if execution.To() == nil {
return nil, 0, nil
}
height, err := sm.Height()
if err != nil {
return nil, 0, err
}
receiver, percentage, ok, err := sgd.CheckContract(ctx, execution.Contract(), height-1)
contract, _ := address.FromBytes((*execution.To())[:])
receiver, percentage, ok, err := sgd.CheckContract(ctx, contract.String(), height-1)
if err != nil || !ok {
return nil, 0, err
}
Expand Down Expand Up @@ -680,6 +671,6 @@ func SimulateExecution(
return ExecuteContract(
ctx,
sm,
ex,
action.NewEvmTx(ex),
)
}
4 changes: 2 additions & 2 deletions action/protocol/execution/evm/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestExecuteContractFailure(t *testing.T) {
},
Sgd: nil,
})
retval, receipt, err := ExecuteContract(ctx, sm, e)
retval, receipt, err := ExecuteContract(ctx, sm, action.NewEvmTx(e))
require.Nil(t, retval)
require.Nil(t, receipt)
require.Error(t, err)
Expand Down Expand Up @@ -302,7 +302,7 @@ func TestConstantinople(t *testing.T) {
})
stateDB, err := prepareStateDB(fCtx, sm)
require.NoError(err)
ps, err := newParams(fCtx, ex, stateDB)
ps, err := newParams(fCtx, action.NewEvmTx(ex), stateDB)
require.NoError(err)

evm := vm.NewEVM(ps.context, ps.txCtx, stateDB, ps.chainConfig, ps.evmConfig)
Expand Down
4 changes: 2 additions & 2 deletions action/protocol/execution/protocol.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2019 IoTeX Foundation
// Copyright (c) 2024 IoTeX Foundation
// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
// This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
Expand Down Expand Up @@ -74,7 +74,7 @@ func (p *Protocol) Handle(ctx context.Context, act action.Action, sm protocol.St
DepositGasFunc: p.depositGas,
Sgd: p.sgdRegistry,
})
_, receipt, err := evm.ExecuteContract(ctx, sm, exec)
_, receipt, err := evm.ExecuteContract(ctx, sm, action.NewEvmTx(exec))

if err != nil {
return nil, errors.Wrap(err, "failed to execute contract")
Expand Down
2 changes: 1 addition & 1 deletion action/protocol/poll/consortium.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (cc *consortiumCommittee) CreateGenesisStates(ctx context.Context, sm proto
_, receipt, err := evm.ExecuteContract(
ctx,
sm,
execution,
action.NewEvmTx(execution),
)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion action/protocol/poll/staking_committee.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func (sc *stakingCommittee) CreateGenesisStates(ctx context.Context, sm protocol
_, receipt, err := evm.ExecuteContract(
ctx,
sm,
execution,
action.NewEvmTx(execution),
)
if err != nil {
return err
Expand Down
Loading