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

tests: update for cancun #27721

Merged
merged 15 commits into from Jul 15, 2023
1 change: 1 addition & 0 deletions cmd/evm/staterunner.go
Expand Up @@ -117,6 +117,7 @@ func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error {
// Test failed, mark as so and dump any state to aid debugging
result.Pass, result.Error = false, err.Error()
if dump && s != nil {
s, _ = state.New(*result.Root, s.Database(), nil)
dump := s.RawDump(nil)
result.State = &dump
}
Expand Down
14 changes: 2 additions & 12 deletions core/block_validator.go
Expand Up @@ -86,18 +86,8 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
for _, tx := range block.Transactions() {
// Count the number of blobs to validate against the header's dataGasUsed
blobs += len(tx.BlobHashes())

// Validate the data blobs individually too
if tx.Type() == types.BlobTxType {
if len(tx.BlobHashes()) == 0 {
return errors.New("no-blob blob transaction present in block body")
}
for _, hash := range tx.BlobHashes() {
if hash[0] != params.BlobTxHashVersion {
return fmt.Errorf("blob hash version mismatch (have %d, supported %d)", hash[0], params.BlobTxHashVersion)
}
}
}
// The individual checks for blob validity (version-check + not empty)
// happens in the state_transition check.
}
if header.DataGasUsed != nil {
if want := *header.DataGasUsed / params.BlobTxDataGasPerBlob; uint64(blobs) != want { // div because the header is surely good vs the body might be bloated
Expand Down
4 changes: 4 additions & 0 deletions core/error.go
Expand Up @@ -100,4 +100,8 @@ var (

// ErrSenderNoEOA is returned if the sender of a transaction is a contract.
ErrSenderNoEOA = errors.New("sender not an eoa")

// ErrBlobFeeCapTooLow is returned if the transaction fee cap is less than the
// data gas fee of the block.
ErrBlobFeeCapTooLow = errors.New("max fee per data gas less than block data gas fee")
)
21 changes: 11 additions & 10 deletions core/evm.go
Expand Up @@ -56,16 +56,17 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
random = &header.MixDigest
}
return vm.BlockContext{
CanTransfer: CanTransfer,
Transfer: Transfer,
GetHash: GetHashFn(header, chain),
Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number),
Time: header.Time,
Difficulty: new(big.Int).Set(header.Difficulty),
BaseFee: baseFee,
GasLimit: header.GasLimit,
Random: random,
CanTransfer: CanTransfer,
Transfer: Transfer,
GetHash: GetHashFn(header, chain),
Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number),
Time: header.Time,
Difficulty: new(big.Int).Set(header.Difficulty),
BaseFee: baseFee,
GasLimit: header.GasLimit,
Random: random,
ExcessDataGas: header.ExcessDataGas,
}
}

Expand Down
58 changes: 32 additions & 26 deletions core/gen_genesis.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 17 additions & 7 deletions core/genesis.go
Expand Up @@ -59,10 +59,11 @@ type Genesis struct {

// These fields are used for consensus tests. Please don't use them
// in actual genesis blocks.
Number uint64 `json:"number"`
GasUsed uint64 `json:"gasUsed"`
ParentHash common.Hash `json:"parentHash"`
BaseFee *big.Int `json:"baseFeePerGas"`
Number uint64 `json:"number"`
GasUsed uint64 `json:"gasUsed"`
ParentHash common.Hash `json:"parentHash"`
BaseFee *big.Int `json:"baseFeePerGas"`
ExcessDataGas *uint64 `json:"excessDataGas"`
}

func ReadGenesis(db ethdb.Database) (*Genesis, error) {
Expand Down Expand Up @@ -463,9 +464,18 @@ func (g *Genesis) ToBlock() *types.Block {
}
}
var withdrawals []*types.Withdrawal
if g.Config != nil && g.Config.IsShanghai(big.NewInt(int64(g.Number)), g.Timestamp) {
head.WithdrawalsHash = &types.EmptyWithdrawalsHash
withdrawals = make([]*types.Withdrawal, 0)
if conf := g.Config; conf != nil {
num := big.NewInt(int64(g.Number))
if conf.IsShanghai(num, g.Timestamp) {
head.WithdrawalsHash = &types.EmptyWithdrawalsHash
withdrawals = make([]*types.Withdrawal, 0)
}
if conf.IsCancun(num, g.Timestamp) {
head.ExcessDataGas = g.ExcessDataGas
if head.ExcessDataGas == nil {
head.ExcessDataGas = new(uint64)
}
}
}
return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)).WithWithdrawals(withdrawals)
}
Expand Down
2 changes: 1 addition & 1 deletion core/state_processor.go
Expand Up @@ -157,6 +157,6 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
}
// Create a new context to be used in the EVM environment
blockContext := NewEVMBlockContext(header, bc, author)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
vmenv := vm.NewEVM(blockContext, vm.TxContext{BlobHashes: tx.BlobHashes()}, statedb, config, cfg)
return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
}
73 changes: 60 additions & 13 deletions core/state_transition.go
Expand Up @@ -17,12 +17,14 @@
package core

import (
"errors"
"fmt"
"math"
"math/big"

"github.com/ethereum/go-ethereum/common"
cmath "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
Expand Down Expand Up @@ -125,17 +127,18 @@ func toWordSize(size uint64) uint64 {
// A Message contains the data derived from a single transaction that is relevant to state
// processing.
type Message struct {
To *common.Address
From common.Address
Nonce uint64
Value *big.Int
GasLimit uint64
GasPrice *big.Int
GasFeeCap *big.Int
GasTipCap *big.Int
Data []byte
AccessList types.AccessList
BlobHashes []common.Hash
To *common.Address
From common.Address
Nonce uint64
Value *big.Int
GasLimit uint64
GasPrice *big.Int
GasFeeCap *big.Int
GasTipCap *big.Int
Data []byte
AccessList types.AccessList
BlobGasFeeCap *big.Int
BlobHashes []common.Hash

// When SkipAccountChecks is true, the message nonce is not checked against the
// account nonce in state. It also disables checking that the sender is an EOA.
Expand All @@ -157,6 +160,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
AccessList: tx.AccessList(),
SkipAccountChecks: false,
BlobHashes: tx.BlobHashes(),
BlobGasFeeCap: tx.BlobGasFeeCap(),
}
// If baseFee provided, set gasPrice to effectiveGasPrice.
if baseFee != nil {
Expand Down Expand Up @@ -230,12 +234,28 @@ func (st *StateTransition) to() common.Address {
func (st *StateTransition) buyGas() error {
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
mgval = mgval.Mul(mgval, st.msg.GasPrice)
balanceCheck := mgval
balanceCheck := new(big.Int).Set(mgval)
if st.msg.GasFeeCap != nil {
balanceCheck = new(big.Int).SetUint64(st.msg.GasLimit)
balanceCheck.SetUint64(st.msg.GasLimit)
balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap)
balanceCheck.Add(balanceCheck, st.msg.Value)
}
if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) {
if dataGas := st.dataGasUsed(); dataGas > 0 {
if st.evm.Context.ExcessDataGas == nil {
// programming error
panic("missing field excess data gas")
}
// Check that the user has enough funds to cover dataGasUsed * tx.BlobGasFeeCap
blobBalanceCheck := new(big.Int).SetUint64(dataGas)
blobBalanceCheck.Mul(blobBalanceCheck, st.msg.BlobGasFeeCap)
balanceCheck.Add(balanceCheck, blobBalanceCheck)
// Pay for dataGasUsed * actual blob fee
blobFee := new(big.Int).SetUint64(dataGas)
blobFee.Mul(blobFee, misc.CalcBlobFee(*st.evm.Context.ExcessDataGas))
mgval.Add(mgval, blobFee)
}
}
if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
}
Expand Down Expand Up @@ -297,6 +317,28 @@ func (st *StateTransition) preCheck() error {
}
}
}
// Check the blob version validity
if msg.BlobHashes != nil {
if len(msg.BlobHashes) == 0 {
return errors.New("blob transaction missing blob hashes")
}
for i, hash := range msg.BlobHashes {
if hash[0] != params.BlobTxHashVersion {
return fmt.Errorf("blob %d hash version mismatch (have %d, supported %d)",
i, hash[0], params.BlobTxHashVersion)
}
}
}

if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber, st.evm.Context.Time) {
if st.dataGasUsed() > 0 {
// Check that the user is paying at least the current blob fee
if have, want := st.msg.BlobGasFeeCap, misc.CalcBlobFee(*st.evm.Context.ExcessDataGas); have.Cmp(want) < 0 {
return fmt.Errorf("%w: address %v have %v want %v", ErrBlobFeeCapTooLow, st.msg.From.Hex(), have, want)
}
}
}

return st.buyGas()
}

Expand Down Expand Up @@ -427,3 +469,8 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
func (st *StateTransition) gasUsed() uint64 {
return st.initialGas - st.gasRemaining
}

// dataGasUsed returns the amount of data gas used by the message.
func (st *StateTransition) dataGasUsed() uint64 {
return uint64(len(st.msg.BlobHashes) * params.BlobTxDataGasPerBlob)
}
15 changes: 8 additions & 7 deletions core/vm/evm.go
Expand Up @@ -70,13 +70,14 @@ type BlockContext struct {
GetHash GetHashFunc

// Block information
Coinbase common.Address // Provides information for COINBASE
GasLimit uint64 // Provides information for GASLIMIT
BlockNumber *big.Int // Provides information for NUMBER
Time uint64 // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY
BaseFee *big.Int // Provides information for BASEFEE
Random *common.Hash // Provides information for PREVRANDAO
Coinbase common.Address // Provides information for COINBASE
GasLimit uint64 // Provides information for GASLIMIT
BlockNumber *big.Int // Provides information for NUMBER
Time uint64 // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY
BaseFee *big.Int // Provides information for BASEFEE
Random *common.Hash // Provides information for PREVRANDAO
ExcessDataGas *uint64 // ExcessDataGas field in the header, needed to compute the data
}

// TxContext provides the EVM with information about a transaction.
Expand Down
13 changes: 13 additions & 0 deletions tests/gen_sttransaction.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.