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

core: implement EIP-7623 increase calldata cost #30946

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
13 changes: 13 additions & 0 deletions cmd/evm/internal/t8ntool/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ func Transaction(ctx *cli.Context) error {
results = append(results, r)
continue
}
if chainConfig.IsPrague(new(big.Int), 0) {
if floorDataGas, err := core.FloorDataGas(tx.Data()); err != nil {
r.Error = err
results = append(results, r)
continue
} else {
if tx.Gas() < floorDataGas {
r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrDataFloorGas, tx.Gas(), floorDataGas)
results = append(results, r)
continue
}
}
}
}
// Validate <256bit fields
switch {
Expand Down
4 changes: 4 additions & 0 deletions core/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ var (
// than required to start the invocation.
ErrIntrinsicGas = errors.New("intrinsic gas too low")

// ErrDataFloorGas is returned if the transaction is specified to use less gas
// than required for the data floor cost.
ErrDataFloorGas = errors.New("insufficient gas for data floor cost")
s1na marked this conversation as resolved.
Show resolved Hide resolved

// ErrTxTypeNotSupported is returned if a transaction is not supported in the
// current network configuration.
ErrTxTypeNotSupported = types.ErrTxTypeNotSupported
Expand Down
4 changes: 2 additions & 2 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ func TestStateProcessorErrors(t *testing.T) {
},
{ // ErrMaxInitCodeSizeExceeded
txs: []*types.Transaction{
mkDynamicCreationTx(0, 500000, common.Big0, big.NewInt(params.InitialBaseFee), tooBigInitCode[:]),
mkDynamicCreationTx(0, 520000, common.Big0, big.NewInt(params.InitialBaseFee), tooBigInitCode[:]),
},
want: "could not apply tx 0 [0xd491405f06c92d118dd3208376fcee18a57c54bc52063ee4a26b1cf296857c25]: max initcode size exceeded: code size 49153 limit 49152",
want: "could not apply tx 0 [0x3a30404d42d6ccc843d7c391fd0c87b9b9795a0c174261b46d2ac95ca17b81cd]: max initcode size exceeded: code size 49153 limit 49152",
},
{ // ErrIntrinsicGas: Not enough gas to cover init code
txs: []*types.Transaction{
Expand Down
74 changes: 55 additions & 19 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package core

import (
"bytes"
"fmt"
"math"
"math/big"
Expand Down Expand Up @@ -66,7 +67,8 @@ func (result *ExecutionResult) Revert() []byte {
return common.CopyBytes(result.ReturnData)
}

// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
// IntrinsicGas computes the 'intrinsic gas' and the number of tokens for EIP-7623
// for a message with the given data.
s1na marked this conversation as resolved.
Show resolved Hide resolved
func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) {
// Set the starting gas for the raw transaction
var gas uint64
Expand All @@ -79,12 +81,9 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
// Bump the required gas by the amount of transactional data
if dataLen > 0 {
// Zero and non-zero bytes are priced differently
var nz uint64
for _, byt := range data {
if byt != 0 {
nz++
}
}
z := uint64(bytes.Count(data, []byte{0}))
rjl493456442 marked this conversation as resolved.
Show resolved Hide resolved
nz := uint64(dataLen - z)

// Make sure we don't exceed uint64 for all data combinations
nonZeroGas := params.TxDataNonZeroGasFrontier
if isEIP2028 {
Expand All @@ -95,7 +94,6 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
}
gas += nz * nonZeroGas

z := dataLen - nz
if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
return 0, ErrGasUintOverflow
}
Expand All @@ -119,6 +117,21 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
return gas, nil
}

// FloorDataGas computes the minimum gas required for a transaction based on its data tokens (EIP-7623).
func FloorDataGas(data []byte) (uint64, error) {
var (
z = uint64(bytes.Count(data, []byte{0}))
nz = uint64(len(data)) - z
tokens = nz*params.TokenPerNonZeroByte7623 + z
)
// Check for overflow
if (math.MaxUint64-params.TxGas)/params.CostFloorPerToken7623 < tokens {
return 0, ErrGasUintOverflow
}
// Minimum gas required for a transaction based on its data tokens (EIP-7623).
return params.TxGas + tokens*params.CostFloorPerToken7623, nil
}

// toWordSize returns the ceiled word size required for init code payment calculation.
func toWordSize(size uint64) uint64 {
if size > math.MaxUint64-31 {
Expand Down Expand Up @@ -414,6 +427,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
sender = vm.AccountRef(msg.From)
rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time)
contractCreation = msg.To == nil
floorDataGas uint64
)

// Check clauses 4-5, subtract intrinsic gas if everything is correct
Expand All @@ -424,6 +438,16 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
if st.gasRemaining < gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
}
// Gas limit suffices for the floor data cost (EIP-7623)
if rules.IsPrague {
floorDataGas, err = FloorDataGas(msg.Data)
if err != nil {
return nil, err
}
if st.gasRemaining < floorDataGas {
Copy link
Member

Choose a reason for hiding this comment

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

nitpick, it's probably better to use msg.GasLimit rather than the gasRemaining

return nil, fmt.Errorf("%w: have %d, want %d", ErrDataFloorGas, st.gasRemaining, floorDataGas)
}
}
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas)
}
Expand Down Expand Up @@ -490,11 +514,28 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
var gasRefund uint64
if !rules.IsLondon {
// Before EIP-3529: refunds were capped to gasUsed / 2
gasRefund = st.refundGas(params.RefundQuotient)
gasRefund = st.refundAmount(params.RefundQuotient)
} else {
// After EIP-3529: refunds are capped to gasUsed / 5
gasRefund = st.refundGas(params.RefundQuotientEIP3529)
gasRefund = st.refundAmount(params.RefundQuotientEIP3529)
}

if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && gasRefund > 0 {
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+gasRefund, tracing.GasChangeTxRefunds)
}
st.gasRemaining += gasRefund
if rules.IsPrague {
// After EIP-7623: Data-heavy transactions pay the floor gas.
if st.gasUsed() < floorDataGas {
prev := st.gasRemaining
st.gasRemaining = st.initialGas - floorDataGas
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
t.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor)
}
}
}
st.returnGas()

effectiveTip := msg.GasPrice
if rules.IsLondon {
effectiveTip = new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee)
Expand Down Expand Up @@ -585,19 +626,16 @@ func (st *stateTransition) applyAuthorization(msg *Message, auth *types.SetCodeA
return nil
}

func (st *stateTransition) refundGas(refundQuotient uint64) uint64 {
func (st *stateTransition) refundAmount(refundQuotient uint64) uint64 {
// Apply refund counter, capped to a refund quotient
refund := st.gasUsed() / refundQuotient
if refund > st.state.GetRefund() {
refund = st.state.GetRefund()
}
return refund
}

if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 {
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, tracing.GasChangeTxRefunds)
}

st.gasRemaining += refund

func (st *stateTransition) returnGas() {
// Return ETH for remaining gas, exchanged at the original rate.
remaining := uint256.NewInt(st.gasRemaining)
remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice))
Expand All @@ -610,8 +648,6 @@ func (st *stateTransition) refundGas(refundQuotient uint64) uint64 {
// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
st.gp.AddGas(st.gasRemaining)

return refund
}

// gasUsed returns the amount of gas used up by the state transition.
Expand Down
3 changes: 3 additions & 0 deletions core/tracing/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,9 @@ const (
GasChangeWitnessCodeChunk GasChangeReason = 17
// GasChangeWitnessContractCollisionCheck flags the event of adding to the witness when checking for contract address collision.
GasChangeWitnessContractCollisionCheck GasChangeReason = 18
// GasChangeTxDataFloor is the amount of extra gas the transaction has to pay to reach the minimum gas requirement for the
// transaction data. This change will always be a negative change.
GasChangeTxDataFloor GasChangeReason = 19

// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
// it will be "manually" tracked by a direct emit of the gas change event.
Expand Down
10 changes: 10 additions & 0 deletions core/txpool/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
if tx.Gas() < intrGas {
return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrIntrinsicGas, tx.Gas(), intrGas)
}
// Ensure the transaction can cover floor data gas.
if opts.Config.IsPrague(head.Number, head.Time) {
floorDataGas, err := core.FloorDataGas(tx.Data())
if err != nil {
return err
}
if tx.Gas() < floorDataGas {
return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrDataFloorGas, tx.Gas(), floorDataGas)
}
}
// Ensure the gasprice is high enough to cover the requirement of the calling pool
if tx.GasTipCapIntCmp(opts.MinTip) < 0 {
return fmt.Errorf("%w: gas tip cap %v, minimum needed %v", ErrUnderpriced, tx.GasTipCap(), opts.MinTip)
Expand Down
2 changes: 1 addition & 1 deletion core/verkle_witness_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func TestProcessVerkle(t *testing.T) {
params.WitnessChunkWriteCost + /* SSTORE in constructor */
params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash for tx creation */
15*(params.WitnessChunkReadCost+params.WitnessChunkWriteCost) + /* code chunks #0..#14 */
4844 /* execution costs */
uint64(4844) /* execution costs */
blockGasUsagesExpected := []uint64{
txCost1*2 + txCost2,
txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
{
"blobGasPrice": "0x1",
"blobGasUsed": "0x20000",
"blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49",
"blockHash": "0x5f58514bcb3b216908f0aff6ced44666c3aa250df06093150ac850a7a7850f3c",
"blockNumber": "0x6",
"contractAddress": null,
"cumulativeGasUsed": "0x5208",
"effectiveGasPrice": "0x1b09d63b",
"effectiveGasPrice": "0x1b0a08c4",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5208",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e",
"transactionHash": "0xb51ee3d2a89ba5d5623c73133c8d7a6ba9fb41194c17f4302c21b30994a1180f",
"transactionHash": "0x80348f994fb5f3b05bd2e5f58bbdc73485e449c028612a2c0680f9ac6ff70add",
"transactionIndex": "0x0",
"type": "0x3"
}
]
]
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[
{
"blockHash": "0x102e50de30318ee99a03a09db74387e79cad3165bf6840cc84249806a2a302f3",
"blockHash": "0x47cd44027bb55856a175e36be0396bad221e52172529d9c1bf12bf5424a041ae",
"blockNumber": "0x4",
"contractAddress": null,
"cumulativeGasUsed": "0x538d",
"cumulativeGasUsed": "0x5564",
"effectiveGasPrice": "0x2325c42f",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x538d",
"gasUsed": "0x5564",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x0",
Expand All @@ -15,4 +15,4 @@
"transactionIndex": "0x0",
"type": "0x2"
}
]
]
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
{
"blobGasPrice": "0x1",
"blobGasUsed": "0x20000",
"blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49",
"blockHash": "0x5f58514bcb3b216908f0aff6ced44666c3aa250df06093150ac850a7a7850f3c",
"blockNumber": "0x6",
"contractAddress": null,
"cumulativeGasUsed": "0x5208",
"effectiveGasPrice": "0x1b09d63b",
"effectiveGasPrice": "0x1b0a08c4",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5208",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e",
"transactionHash": "0xb51ee3d2a89ba5d5623c73133c8d7a6ba9fb41194c17f4302c21b30994a1180f",
"transactionHash": "0x80348f994fb5f3b05bd2e5f58bbdc73485e449c028612a2c0680f9ac6ff70add",
"transactionIndex": "0x0",
"type": "0x3"
}
]
]
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"blobGasPrice": "0x1",
"blobGasUsed": "0x20000",
"blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49",
"blockHash": "0x5f58514bcb3b216908f0aff6ced44666c3aa250df06093150ac850a7a7850f3c",
"blockNumber": "0x6",
"contractAddress": null,
"cumulativeGasUsed": "0x5208",
"effectiveGasPrice": "0x1b09d63b",
"effectiveGasPrice": "0x1b0a08c4",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x5208",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": "0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e",
"transactionHash": "0xb51ee3d2a89ba5d5623c73133c8d7a6ba9fb41194c17f4302c21b30994a1180f",
"transactionHash": "0x80348f994fb5f3b05bd2e5f58bbdc73485e449c028612a2c0680f9ac6ff70add",
"transactionIndex": "0x0",
"type": "0x3"
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"blockHash": "0x53bffe54375c0a31fe7bc0db7455db7d48278234c2400efa4d40d1c57cbe868d",
"blockHash": "0x5bff93f8f94ba7ee52bef1a80062b9fed22c6d1eebb2b0e87a4a003365a7bd66",
"blockNumber": "0x5",
"contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18",
"cumulativeGasUsed": "0xe01c",
"effectiveGasPrice": "0x1ecb3fb4",
"effectiveGasPrice": "0x1ecb7942",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0xe01c",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x1",
"to": null,
"transactionHash": "0xb5a1148819cfdfff9bfe70035524fec940eb735d89b76960b97751d01ae2a9f2",
"transactionHash": "0x173dffc76966c72542560c376ce512a871e31b86988f9169bf021da0937640f9",
"transactionIndex": "0x0",
"type": "0x1"
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
"blockHash": "0x102e50de30318ee99a03a09db74387e79cad3165bf6840cc84249806a2a302f3",
"blockHash": "0x47cd44027bb55856a175e36be0396bad221e52172529d9c1bf12bf5424a041ae",
"blockNumber": "0x4",
"contractAddress": null,
"cumulativeGasUsed": "0x538d",
"cumulativeGasUsed": "0x5564",
"effectiveGasPrice": "0x2325c42f",
"from": "0x703c4b2bd70c169f5717101caee543299fc946c7",
"gasUsed": "0x538d",
"gasUsed": "0x5564",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x0",
"to": "0x0000000000000000000000000000000000031ec7",
"transactionHash": "0xdcde2574628c9d7dff22b9afa19f235959a924ceec65a9df903a517ae91f5c84",
"transactionIndex": "0x0",
"type": "0x2"
}
}
Loading