Skip to content

[evm] enable cancun at Vanuatu #4369

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

Merged
merged 14 commits into from
Sep 26, 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
2 changes: 2 additions & 0 deletions action/protocol/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ type (
AccumulatedTips big.Int
// BaseFee is the base fee of the block
BaseFee *big.Int
// ExcessBlobGas is the excess blob gas of the block
ExcessBlobGas uint64
}

// ActionCtx provides action auxiliary information.
Expand Down
16 changes: 7 additions & 9 deletions blockchain/block/eip1559.go → action/protocol/eip1559.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// 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 block
package protocol

import (
"math/big"
Expand All @@ -13,11 +13,10 @@ import (
"github.com/pkg/errors"

"github.com/iotexproject/iotex-core/action"
"github.com/iotexproject/iotex-core/action/protocol"
"github.com/iotexproject/iotex-core/blockchain/genesis"
)

func VerifyEIP1559Header(g genesis.Blockchain, parent *protocol.TipInfo, header *Header) error {
func VerifyEIP1559Header(g genesis.Blockchain, parent *TipInfo, header blockHeader) error {
if header.BaseFee() == nil {
return errors.New("header is missing baseFee")
}
Expand All @@ -31,14 +30,13 @@ func VerifyEIP1559Header(g genesis.Blockchain, parent *protocol.TipInfo, header
}

// CalcBaseFee calculates the basefee of the header.
func CalcBaseFee(g genesis.Blockchain, parent *protocol.TipInfo) *big.Int {
if parent.Height < g.VanuatuBlockHeight-1 {
// return nil for no base fee block
return nil
}
if parent.Height < g.VanuatuBlockHeight {
func CalcBaseFee(g genesis.Blockchain, parent *TipInfo) *big.Int {
if parent.Height == g.VanuatuBlockHeight-1 {
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
return new(big.Int).SetUint64(action.InitialBaseFee)
} else if parent.Height < g.VanuatuBlockHeight-1 {
// return nil for no base fee block
return nil
}

parentGasTarget := g.BlockGasLimitByHeight(parent.Height) / action.DefaultElasticityMultiplier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
// 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 block
package protocol

import (
"math/big"
"testing"

"github.com/stretchr/testify/require"

"github.com/iotexproject/iotex-core/action"
"github.com/iotexproject/iotex-core/action/protocol"
"github.com/iotexproject/iotex-core/blockchain/genesis"
"github.com/stretchr/testify/require"
)

func TestCalcBaseFee(t *testing.T) {
Expand All @@ -29,7 +29,7 @@ func TestCalcBaseFee(t *testing.T) {
}
g := genesis.Default.Blockchain
for _, test := range tests {
parent := &protocol.TipInfo{
parent := &TipInfo{
Height: g.VanuatuBlockHeight,
GasUsed: test.parentGasUsed,
BaseFee: big.NewInt(test.parentBaseFee),
Expand Down
12 changes: 9 additions & 3 deletions blockchain/block/eip4844.go → action/protocol/eip4844.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package block
package protocol

import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/params"
)

"github.com/iotexproject/iotex-core/action/protocol"
type (
blockHeader interface {
BaseFee() *big.Int
BlobGasUsed() uint64
ExcessBlobGas() uint64
}
)

var (
Expand All @@ -17,7 +23,7 @@ var (
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
// if the current block contains no transactions, the excessBlobGas is updated
// accordingly.
func VerifyEIP4844Header(parent *protocol.TipInfo, header *Header) error {
func VerifyEIP4844Header(parent *TipInfo, header blockHeader) error {
// Verify that the blob gas used remains within reasonable limits.
if header.BlobGasUsed() > params.MaxBlobGasPerBlock {
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", header.BlobGasUsed(), params.MaxBlobGasPerBlock)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package block
package protocol

import (
"fmt"
Expand Down
32 changes: 27 additions & 5 deletions action/protocol/execution/evm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ func newParams(
// Random opcode (EIP-4399) is not supported
context.Random = &common.Hash{}
}
if g.IsVanuatu(blkCtx.BlockHeight) {
// enable BLOBBASEFEE opcode
context.BlobBaseFee = protocol.CalcBlobFee(blkCtx.ExcessBlobGas)
// enable BASEFEE opcode
if blkCtx.BaseFee != nil {
context.BaseFee = new(big.Int).Set(blkCtx.BaseFee)
}
}

if vmCfg, ok := protocol.GetVMConfigCtx(ctx); ok {
vmConfig = vmCfg
Expand All @@ -174,13 +182,18 @@ func newParams(
if err != nil {
return nil, err
}

vmTxCtx := vm.TxContext{
Origin: executorAddr,
GasPrice: execution.GasPrice(),
}
if g.IsVanuatu(blkCtx.BlockHeight) {
// enable BLOBHASH opcode
vmTxCtx.BlobHashes = execution.BlobHashes()
vmTxCtx.BlobFeeCap = execution.BlobGasFeeCap()
}
return &Params{
context,
vm.TxContext{
Origin: executorAddr,
GasPrice: execution.GasPrice(),
},
vmTxCtx,
execution.Nonce(),
execution.Value(),
execution.To(),
Expand Down Expand Up @@ -396,6 +409,13 @@ func getChainConfig(g genesis.Blockchain, height uint64, id uint32, getBlockTime
}
sumatraTimestamp := (uint64)(sumatraTime.Unix())
chainConfig.ShanghaiTime = &sumatraTimestamp
// enable Cancun at Vanuatu
cancunTime, err := getBlockTime(g.VanuatuBlockHeight)
if err != nil {
return nil, err
}
cancunTimestamp := (uint64)(cancunTime.Unix())
chainConfig.CancunTime = &cancunTimestamp
return &chainConfig, nil
}

Expand Down Expand Up @@ -616,6 +636,8 @@ func SimulateExecution(
BlockTimeStamp: bcCtx.Tip.Timestamp.Add(g.BlockInterval),
GasLimit: g.BlockGasLimitByHeight(bcCtx.Tip.Height + 1),
Producer: zeroAddr,
BaseFee: protocol.CalcBaseFee(g.Blockchain, &bcCtx.Tip),
ExcessBlobGas: protocol.CalcExcessBlobGas(bcCtx.Tip.ExcessBlobGas, bcCtx.Tip.BlobGasUsed),
},
)

Expand Down
22 changes: 18 additions & 4 deletions action/protocol/execution/evm/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,20 @@ func TestConstantinople(t *testing.T) {
"io1pcg2ja9krrhujpazswgz77ss46xgt88afqlk6y",
31174200,
},
// after Upernavik
// after Upernavik - Vanuatu
{
action.EmptyAddress,
31174201,
},
{
"io1pcg2ja9krrhujpazswgz77ss46xgt88afqlk6y",
41174200,
},
// after Vanuatu
{
action.EmptyAddress,
41174201,
},
{
"io1pcg2ja9krrhujpazswgz77ss46xgt88afqlk6y",
1261440000, // = 200*365*24*3600/5, around 200 years later
Expand Down Expand Up @@ -350,11 +359,16 @@ func TestConstantinople(t *testing.T) {
require.Equal(isSumatra, chainRules.IsMerge)
require.Equal(isSumatra, chainRules.IsShanghai)

// Cancun and Prague not yet enabled
require.False(chainRules.IsCancun)
require.False(evmChainConfig.IsCancun(big.NewInt(int64(e.height)), evm.Context.Time))
// Vanuatu = enable Cancun
isVanuatu := g.IsVanuatu(e.height)
require.Equal(isVanuatu, chainRules.IsCancun)
require.Equal(isVanuatu, evmChainConfig.IsCancun(big.NewInt(int64(e.height)), evm.Context.Time))

// Prague and Verkle not yet enabled
require.False(chainRules.IsPrague)
require.False(evmChainConfig.IsPrague(big.NewInt(int64(e.height)), evm.Context.Time))
require.False(chainRules.IsVerkle)
require.False(evmChainConfig.IsVerkle(big.NewInt(int64(e.height)), evm.Context.Time))

// test basefee
require.Equal(new(big.Int), evm.Context.BaseFee)
Expand Down
30 changes: 25 additions & 5 deletions action/protocol/execution/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,11 @@ func (sct *SmartContractTest) runExecutions(
}
hashes = append(hashes, selpHash)
}
blk, err := bc.MintNewBlock(fixedTime)
t, err := getBlockTimeForTest(bc.TipHeight() + 1)
if err != nil {
return nil, nil, err
}
blk, err := bc.MintNewBlock(t)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -429,7 +433,7 @@ func (sct *SmartContractTest) prepareBlockchain(
cfg.Genesis.ActionGasLimit = 10000000
}
if sct.InitGenesis.IsCancun {
cfg.Genesis.Blockchain.UpernavikBlockHeight = 0
cfg.Genesis.Blockchain.VanuatuBlockHeight = 1
}
for _, expectedBalance := range sct.InitBalances {
cfg.Genesis.InitBalanceMap[expectedBalance.Account] = expectedBalance.Balance().String()
Expand Down Expand Up @@ -582,7 +586,7 @@ func (sct *SmartContractTest) run(r *require.Assertions) {

if sct.InitGenesis.IsBering {
// if it is post bering, it compares the status with expected status
r.Equal(exec.ExpectedStatus, receipt.Status)
r.Equal(exec.ExpectedStatus, receipt.Status, receipt.ExecutionRevertMsg())
} else {
if exec.Failed {
r.Equal(uint64(iotextypes.ReceiptStatus_Failure), receipt.Status)
Expand Down Expand Up @@ -1305,10 +1309,26 @@ func TestShanghaiEVM(t *testing.T) {

func TestCancunEVM(t *testing.T) {
t.Run("eip1153-transientstorage", func(t *testing.T) {
// TODO: re-enable this test when enable Cancun
t.Skip()
NewSmartContractTest(t, "testdata-cancun/transientstorage.json")
})
t.Run("eip5656-mcopy", func(t *testing.T) {
NewSmartContractTest(t, "testdata-cancun/mcopy.json")
})
t.Run("eip4844-point_evaluation_precompile", func(t *testing.T) {
NewSmartContractTest(t, "testdata-cancun/point_evaluation.json")
})
t.Run("eip4844-blobhash", func(t *testing.T) {
NewSmartContractTest(t, "testdata-cancun/blobhash.json")
})
t.Run("eip7516-blobbasefee", func(t *testing.T) {
NewSmartContractTest(t, "testdata-cancun/blobbasefee.json")
})
t.Run("eip1559-basefee", func(t *testing.T) {
NewSmartContractTest(t, "testdata-cancun/basefee.json")
})
t.Run("eip6780-selfdestruct", func(t *testing.T) {
t.Skip("TODO: test it ")
})
}

func benchmarkHotContractWithFactory(b *testing.B, async bool) {
Expand Down
37 changes: 37 additions & 0 deletions action/protocol/execution/testdata-cancun/basefee.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"initGenesis": {
"isBering" : true,
"isIceland" : true,
"isLondon" : true,
"isShanghai" : true,
"isCancun": true
},
"initBalances": [{
"account": "io1mflp9m6hcgm2qcghchsdqj3z3eccrnekx9p0ms",
"rawBalance": "1000000000000000000000000000"
}],
"deployments": [{
"rawByteCode": "6080604052348015600e575f80fd5b5060b380601a5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c806315e812ad14602a575b5f80fd5b60306044565b604051603b91906066565b60405180910390f35b5f804890508091505090565b5f819050919050565b6060816050565b82525050565b5f60208201905060775f8301846059565b9291505056fea26469706673582212201b31cd7b56119dab3cf44a07710a282a1ab4d8abf891b955606d684278f0b45364736f6c634300081a0033",
"rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
"rawAmount": "0",
"rawGasLimit": 5000000,
"rawGasPrice": "2000000000000",
"rawExpectedGasConsumed": 66385,
"expectedStatus": 1,
"expectedBalances": [],
"comment": "deploy basefee contract"
}],
"executions": [{
"rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
"rawByteCode": "15e812ad",
"rawAmount": "0",
"rawGasLimit": 1000000,
"rawGasPrice": "2000000000000",
"rawAccessList": [],
"rawExpectedGasConsumed": 10722,
"expectedStatus": 1,
"readOnly": true,
"rawReturnValue": "000000000000000000000000000000000000000000000000000000e8d4a51000",
"comment": "call getBaseFee"
}]
}
12 changes: 12 additions & 0 deletions action/protocol/execution/testdata-cancun/basefee.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract BaseFeeTest {
function getBaseFee() public view returns (uint256) {
uint256 baseFee;
assembly {
baseFee := basefee()
}
return baseFee;
}
}
37 changes: 37 additions & 0 deletions action/protocol/execution/testdata-cancun/blobbasefee.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"initGenesis": {
"isBering" : true,
"isIceland" : true,
"isLondon" : true,
"isShanghai" : true,
"isCancun": true
},
"initBalances": [{
"account": "io1mflp9m6hcgm2qcghchsdqj3z3eccrnekx9p0ms",
"rawBalance": "1000000000000000000000000000"
}],
"deployments": [{
"rawByteCode": "6080604052348015600e575f80fd5b5060b380601a5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c80631f6d6ef714602a575b5f80fd5b60306044565b604051603b91906066565b60405180910390f35b5f804a90508091505090565b5f819050919050565b6060816050565b82525050565b5f60208201905060775f8301846059565b9291505056fea264697066735822122079dd036ad97e2152acf9763c0d02695bcda866427a06241bc2440730d30a058c64736f6c634300081a0033",
"rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
"rawAmount": "0",
"rawGasLimit": 5000000,
"rawGasPrice": "2000000000000",
"rawExpectedGasConsumed": 66385,
"expectedStatus": 1,
"expectedBalances": [],
"comment": "deploy blobbasefee contract"
}],
"executions": [{
"rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1",
"rawByteCode": "1f6d6ef7",
"rawAmount": "0",
"rawGasLimit": 1000000,
"rawGasPrice": "2000000000000",
"rawAccessList": [],
"rawExpectedGasConsumed": 10722,
"expectedStatus": 1,
"readOnly": true,
"rawReturnValue": "0000000000000000000000000000000000000000000000000000000000000001",
"comment": "call getBlobBaseFee"
}]
}
12 changes: 12 additions & 0 deletions action/protocol/execution/testdata-cancun/blobbasefee.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract BlobBaseFeeTest {
function getBlobBaseFee() public view returns (uint256) {
uint256 blobBaseFee;
assembly {
blobBaseFee := blobbasefee()
}
return blobBaseFee;
}
}
Loading
Loading