Skip to content

Commit

Permalink
[evm] EVM upgrade to cancun (#4210)
Browse files Browse the repository at this point in the history
  • Loading branch information
millken authored Mar 28, 2024
1 parent 14f8243 commit 85559fb
Show file tree
Hide file tree
Showing 16 changed files with 364 additions and 455 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.19.12
go-version: 1.21.4
cache: false

- name: Build Go
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.19.12
go-version: 1.21.4

- name: make iotex-server/ioctl
if: startsWith(matrix.os, 'windows-latest') != true
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.19.12-alpine as build
FROM golang:1.21.4-alpine as build

WORKDIR apps/iotex-core

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GOVET=$(GOCMD) vet
GOBUILD=$(GOCMD) build
GOINSTALL=$(GOCMD) install
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
GOTEST=GOARCH=amd64 CGO_ENABLED=1 $(GOCMD) test
GOGET=$(GOCMD) get
GOPATH=$(shell go env GOPATH)
BUILD_TARGET_SERVER=server
Expand Down
6 changes: 3 additions & 3 deletions action/protocol/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,14 @@ func TestMustGetActionCtx(t *testing.T) {

func TestWithVMConfigCtx(t *testing.T) {
require := require.New(t)
require.NotNil(WithVMConfigCtx(context.Background(), vm.Config{Debug: true}))
require.NotNil(WithVMConfigCtx(context.Background(), vm.Config{}))
}

func TestGetVMConfigCtx(t *testing.T) {
require := require.New(t)
ctx := WithVMConfigCtx(context.Background(), vm.Config{Debug: true})
ctx := WithVMConfigCtx(context.Background(), vm.Config{NoBaseFee: true})
require.NotNil(ctx)
ret, ok := GetVMConfigCtx(ctx)
require.True(ok)
require.True(ret.Debug)
require.True(ret.NoBaseFee)
}
16 changes: 9 additions & 7 deletions action/protocol/execution/evm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
"github.com/pkg/errors"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
Expand Down Expand Up @@ -64,12 +65,12 @@ type (
)

// CanTransfer checks whether the from account has enough balance
func CanTransfer(db vm.StateDB, fromHash common.Address, balance *big.Int) bool {
func CanTransfer(db vm.StateDB, fromHash common.Address, balance *uint256.Int) bool {
return db.GetBalance(fromHash).Cmp(balance) >= 0
}

// MakeTransfer transfers account
func MakeTransfer(db vm.StateDB, fromHash, toHash common.Address, amount *big.Int) {
func MakeTransfer(db vm.StateDB, fromHash, toHash common.Address, amount *uint256.Int) {
db.SubBalance(fromHash, amount)
db.AddBalance(toHash, amount)

Expand Down Expand Up @@ -224,7 +225,7 @@ func securityDeposit(ps *Params, stateDB vm.StateDB, gasLimit uint64) error {
if gasLimit < ps.gas {
return action.ErrGasLimit
}
gasConsumed := new(big.Int).Mul(new(big.Int).SetUint64(ps.gas), ps.txCtx.GasPrice)
gasConsumed := uint256.MustFromBig(new(big.Int).Mul(new(big.Int).SetUint64(ps.gas), ps.txCtx.GasPrice))
if stateDB.GetBalance(ps.txCtx.Origin).Cmp(gasConsumed) < 0 {
return action.ErrInsufficientFunds
}
Expand Down Expand Up @@ -268,11 +269,11 @@ func ExecuteContract(
)
if ps.featureCtx.FixDoubleChargeGas {
// Refund all deposit and, actual gas fee will be subtracted when depositing gas fee to the rewarding protocol
stateDB.AddBalance(ps.txCtx.Origin, big.NewInt(0).Mul(big.NewInt(0).SetUint64(depositGas), ps.txCtx.GasPrice))
stateDB.AddBalance(ps.txCtx.Origin, uint256.MustFromBig(big.NewInt(0).Mul(big.NewInt(0).SetUint64(depositGas), ps.txCtx.GasPrice)))
} else {
if remainingGas > 0 {
remainingValue := new(big.Int).Mul(new(big.Int).SetUint64(remainingGas), ps.txCtx.GasPrice)
stateDB.AddBalance(ps.txCtx.Origin, remainingValue)
stateDB.AddBalance(ps.txCtx.Origin, uint256.MustFromBig(remainingValue))
}
if consumedGas > 0 {
burnLog = &action.TransactionLog{
Expand Down Expand Up @@ -489,11 +490,12 @@ func executeInEVM(evmParams *Params, stateDB *StateDBAdapter) ([]byte, uint64, u
ret []byte
evmErr error
refund uint64
amount = uint256.MustFromBig(evmParams.amount)
)
if evmParams.contract == nil {
// create contract
var evmContractAddress common.Address
_, evmContractAddress, remainingGas, evmErr = evm.Create(executor, evmParams.data, remainingGas, evmParams.amount)
_, evmContractAddress, remainingGas, evmErr = evm.Create(executor, evmParams.data, remainingGas, amount)
log.L().Debug("evm Create.", log.Hex("addrHash", evmContractAddress[:]))
if evmErr == nil {
if contractAddress, err := address.FromBytes(evmContractAddress.Bytes()); err == nil {
Expand All @@ -503,7 +505,7 @@ func executeInEVM(evmParams *Params, stateDB *StateDBAdapter) ([]byte, uint64, u
} else {
stateDB.SetNonce(evmParams.txCtx.Origin, stateDB.GetNonce(evmParams.txCtx.Origin)+1)
// process contract
ret, remainingGas, evmErr = evm.Call(executor, *evmParams.contract, evmParams.data, remainingGas, evmParams.amount)
ret, remainingGas, evmErr = evm.Call(executor, *evmParams.contract, evmParams.data, remainingGas, amount)
}
if evmErr != nil {
log.L().Debug("evm error", zap.Error(evmErr))
Expand Down
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 @@ -356,8 +356,8 @@ func TestConstantinople(t *testing.T) {
require.Equal(isSumatra, chainRules.IsShanghai)

// Cancun, Prague not yet enabled
require.False(evmChainConfig.IsCancun(evm.Context.Time))
require.False(evmChainConfig.IsPrague(evm.Context.Time))
require.False(evmChainConfig.IsCancun(big.NewInt(int64(e.height)), evm.Context.Time))
require.False(evmChainConfig.IsPrague(big.NewInt(int64(e.height)), evm.Context.Time))

// test basefee
require.Equal(new(big.Int), evm.Context.BaseFee)
Expand Down
36 changes: 22 additions & 14 deletions action/protocol/execution/evm/evmstatedbadapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
"github.com/pkg/errors"
"go.uber.org/zap"

Expand Down Expand Up @@ -234,7 +235,8 @@ func (stateDB *StateDBAdapter) CreateAccount(evmAddr common.Address) {
}

// SubBalance subtracts balance from account
func (stateDB *StateDBAdapter) SubBalance(evmAddr common.Address, amount *big.Int) {
func (stateDB *StateDBAdapter) SubBalance(evmAddr common.Address, a256 *uint256.Int) {
amount := a256.ToBig()
if amount.Cmp(big.NewInt(int64(0))) == 0 {
return
}
Expand Down Expand Up @@ -263,7 +265,8 @@ func (stateDB *StateDBAdapter) SubBalance(evmAddr common.Address, amount *big.In
}

// AddBalance adds balance to account
func (stateDB *StateDBAdapter) AddBalance(evmAddr common.Address, amount *big.Int) {
func (stateDB *StateDBAdapter) AddBalance(evmAddr common.Address, a256 *uint256.Int) {
amount := a256.ToBig()
stateDB.lastAddBalanceAmount.SetUint64(0)
if amount.Cmp(big.NewInt(int64(0))) == 0 {
return
Expand Down Expand Up @@ -306,15 +309,15 @@ func (stateDB *StateDBAdapter) AddBalance(evmAddr common.Address, amount *big.In
}

// GetBalance gets the balance of account
func (stateDB *StateDBAdapter) GetBalance(evmAddr common.Address) *big.Int {
func (stateDB *StateDBAdapter) GetBalance(evmAddr common.Address) *uint256.Int {
state, err := stateDB.accountState(evmAddr)
if err != nil {
log.L().Error("Failed to get balance.", zap.Error(err))
return big.NewInt(0)
return common.U2560
}
log.L().Debug(fmt.Sprintf("Balance of %s is %v", evmAddr.Hex(), state.Balance))

return state.Balance
return uint256.MustFromBig(state.Balance)
}

// IsNewAccount returns true if this is a new account
Expand Down Expand Up @@ -417,28 +420,28 @@ func (stateDB *StateDBAdapter) GetRefund() uint64 {
return stateDB.refund
}

// Suicide kills the contract
func (stateDB *StateDBAdapter) Suicide(evmAddr common.Address) bool {
// SelfDestruct kills the contract
func (stateDB *StateDBAdapter) SelfDestruct(evmAddr common.Address) {
if !stateDB.Exist(evmAddr) {
log.L().Debug("Account does not exist.", zap.String("address", evmAddr.Hex()))
return false
return
}
s, err := stateDB.accountState(evmAddr)
if err != nil {
log.L().Debug("Failed to get account.", zap.String("address", evmAddr.Hex()))
return false
return
}
// clears the account balance
actBalance := new(big.Int).Set(s.Balance)
if err := s.SubBalance(s.Balance); err != nil {
log.L().Debug("failed to clear balance", zap.Error(err), zap.String("address", evmAddr.Hex()))
return false
return
}
addrHash := hash.BytesToHash160(evmAddr.Bytes())
if _, err := stateDB.sm.PutState(s, protocol.LegacyKeyOption(addrHash)); err != nil {
log.L().Error("Failed to kill contract.", zap.Error(err))
stateDB.logError(err)
return false
return
}
// To ensure data consistency, generate this log after the hard-fork
// a separate patch file will be created later to provide missing logs before the hard-fork
Expand All @@ -464,11 +467,10 @@ func (stateDB *StateDBAdapter) Suicide(evmAddr common.Address) bool {
}
// mark it as deleted
stateDB.suicided[addrHash] = struct{}{}
return true
}

// HasSuicided returns whether the contract has been killed
func (stateDB *StateDBAdapter) HasSuicided(evmAddr common.Address) bool {
// HasSelfDestructed returns whether the contract has been killed
func (stateDB *StateDBAdapter) HasSelfDestructed(evmAddr common.Address) bool {
addrHash := hash.BytesToHash160(evmAddr.Bytes())
_, ok := stateDB.suicided[addrHash]
return ok
Expand All @@ -485,6 +487,12 @@ func (stateDB *StateDBAdapter) GetTransientState(addr common.Address, key common
return common.Hash{}
}

// Selfdestruct6780 implements EIP-6780
func (stateDB *StateDBAdapter) Selfdestruct6780(evmAddr common.Address) {
//Todo: implement EIP-6780
log.S().Panic("Selfdestruct6780 not implemented")
}

// Exist checks the existence of an address
func (stateDB *StateDBAdapter) Exist(evmAddr common.Address) bool {
addr, err := address.FromBytes(evmAddr.Bytes())
Expand Down
29 changes: 15 additions & 14 deletions action/protocol/execution/evm/evmstatedbadapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/golang/mock/gomock"
"github.com/holiman/uint256"
"github.com/iotexproject/go-pkgs/hash"
"github.com/iotexproject/iotex-address/address"
"github.com/pkg/errors"
Expand Down Expand Up @@ -98,16 +99,16 @@ func TestAddBalance(t *testing.T) {
)
require.NoError(err)
addAmount := big.NewInt(40000)
stateDB.AddBalance(addr, addAmount)
stateDB.AddBalance(addr, uint256.MustFromBig(addAmount))
require.Equal(addAmount, stateDB.lastAddBalanceAmount)
beneficiary, _ := address.FromBytes(addr[:])
require.Equal(beneficiary.String(), stateDB.lastAddBalanceAddr)
amount := stateDB.GetBalance(addr)
require.Equal(amount, addAmount)
stateDB.AddBalance(addr, addAmount)
require.Equal(amount.ToBig(), addAmount)
stateDB.AddBalance(addr, uint256.MustFromBig(addAmount))
amount = stateDB.GetBalance(addr)
require.Equal(amount, big.NewInt(80000))
stateDB.AddBalance(addr, new(big.Int))
require.Equal(amount, uint256.NewInt(80000))
stateDB.AddBalance(addr, common.U2560)
require.Zero(len(stateDB.lastAddBalanceAmount.Bytes()))
}

Expand Down Expand Up @@ -433,7 +434,7 @@ func TestSnapshotRevertAndCommit(t *testing.T) {
for i, test := range tests {
// add balance
for _, e := range test.balance {
stateDB.AddBalance(e.addr, e.v)
stateDB.AddBalance(e.addr, uint256.MustFromBig(e.v))
}
// set code
for _, e := range test.codes {
Expand All @@ -450,12 +451,12 @@ func TestSnapshotRevertAndCommit(t *testing.T) {
// set suicide
for _, e := range test.suicide {
if e.amount != nil {
stateDB.AddBalance(e.addr, e.amount)
stateDB.AddBalance(e.addr, uint256.MustFromBig(e.amount))
}
stateDB.AddBalance(e.beneficiary, stateDB.GetBalance(e.addr)) // simulate transfer to beneficiary inside Suicide()
require.Equal(e.suicide, stateDB.Suicide(e.addr))
stateDB.SelfDestruct(e.addr)
require.Equal(e.exist, stateDB.Exist(e.addr))
require.Zero(new(big.Int).Cmp(stateDB.GetBalance(e.addr)))
require.Zero(new(uint256.Int).Cmp(stateDB.GetBalance(e.addr)))
}
// set preimage
for _, e := range test.preimage {
Expand Down Expand Up @@ -603,7 +604,7 @@ func TestSnapshotRevertAndCommit(t *testing.T) {
// test balance
for _, e := range test.balance {
amount := stateDB.GetBalance(e.addr)
require.Equal(e.v, amount)
require.Equal(uint256.MustFromBig(e.v), amount)
}
if async && !fixSnapshot {
// test preimage
Expand Down Expand Up @@ -640,7 +641,7 @@ func TestSnapshotRevertAndCommit(t *testing.T) {
}
// test suicide/exist
for _, e := range test.suicide {
require.Equal(e.suicide, stateDB.HasSuicided(e.addr))
require.Equal(e.suicide, stateDB.HasSelfDestructed(e.addr))
require.Equal(e.exist, stateDB.Exist(e.addr))
}
// test logs
Expand Down Expand Up @@ -721,7 +722,7 @@ func TestClearSnapshots(t *testing.T) {
for i, test := range tests {
// add balance
for _, e := range test.balance {
stateDB.AddBalance(e.addr, e.v)
stateDB.AddBalance(e.addr, uint256.MustFromBig(e.v))
}
// set code
for _, e := range test.codes {
Expand All @@ -735,7 +736,7 @@ func TestClearSnapshots(t *testing.T) {
}
// set suicide
for _, e := range test.suicide {
require.Equal(e.suicide, stateDB.Suicide(e.addr))
stateDB.SelfDestruct(e.addr)
require.Equal(e.exist, stateDB.Exist(e.addr))
}
// set preimage
Expand Down Expand Up @@ -838,7 +839,7 @@ func TestGetBalanceOnError(t *testing.T) {
)
assert.NoError(t, err)
amount := stateDB.GetBalance(addr)
assert.Equal(t, big.NewInt(0), amount)
assert.Equal(t, common.U2560, amount)
}
}

Expand Down
2 changes: 1 addition & 1 deletion action/protocol/poll/nativestaking.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (ns *NativeStaking) readBuckets(ctx context.Context, prevIndx, limit *big.I
// decode the contract read result
res, err := ns.abi.Unpack("getActivePyggs", data)
if err != nil {
if err.Error() == "abi: attempting to unmarshall an empty string while arguments are expected" {
if err.Error() == "abi: attempting to unmarshal an empty string while arguments are expected" {
// no data in contract (one possible reason is that contract does not exist yet)
return nil, nil, ErrNoData
}
Expand Down
2 changes: 1 addition & 1 deletion action/protocol/poll/nativestaking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,5 @@ func TestStaking(t *testing.T) {

// test no _data from contract
_, err = ns.abi.Unpack("getActivePyggs", []byte{})
require.Equal(err.Error(), "abi: attempting to unmarshall an empty string while arguments are expected")
require.Equal(err.Error(), "abi: attempting to unmarshal an empty string while arguments are expected")
}
1 change: 0 additions & 1 deletion api/coreservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -1860,7 +1860,6 @@ func (core *coreService) traceTx(ctx context.Context, txctx *tracers.Context, co
tracer = logger.NewStructLogger(config.Config)
}
ctx = protocol.WithVMConfigCtx(ctx, vm.Config{
Debug: true,
Tracer: tracer,
NoBaseFee: true,
})
Expand Down
Loading

0 comments on commit 85559fb

Please sign in to comment.