From 81baa03c43ee5f785daa37d502683f306bf7e89a Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 20 Feb 2024 23:22:43 +0100 Subject: [PATCH 1/6] core: implement eip-7623 Co-authored-by: Marius van der Wijden Co-authored-by: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> return floor gas instead of tokens apply floor after refunds fix tests fix gas return amount fix tests --- cmd/evm/internal/t8ntool/transaction.go | 2 +- core/bench_test.go | 2 +- core/error.go | 4 ++ core/state_processor_test.go | 4 +- core/state_transition.go | 72 +++++++++++++------ core/tracing/hooks.go | 3 + core/txpool/validation.go | 8 ++- core/verkle_witness_test.go | 20 +++--- internal/ethapi/override/override_test.go | 3 +- ...h_getBlockReceipts-block-with-blob-tx.json | 8 +-- ...ockReceipts-block-with-dynamic-fee-tx.json | 8 +-- .../eth_getBlockReceipts-tag-latest.json | 8 +-- .../eth_getTransactionReceipt-blob-tx.json | 8 +-- ...eipt-create-contract-with-access-list.json | 8 +-- ...ansactionReceipt-dynamic-tx-with-logs.json | 8 +-- params/protocol_params.go | 24 ++++--- tests/transaction_test_util.go | 2 +- 17 files changed, 119 insertions(+), 73 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 6dac4301dda3..0e75cba38aa6 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -133,7 +133,7 @@ func Transaction(ctx *cli.Context) error { r.Address = sender } // Check intrinsic gas - if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, + if gas, _, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int), 0)); err != nil { r.Error = err results = append(results, r) diff --git a/core/bench_test.go b/core/bench_test.go index d37683031814..229662f000e5 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -90,7 +90,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { data := make([]byte, nbytes) return func(i int, gen *BlockGen) { toaddr := common.Address{} - gas, _ := IntrinsicGas(data, nil, nil, false, false, false, false) + gas, _, _ := IntrinsicGas(data, nil, nil, false, false, false, false) signer := gen.Signer() gasPrice := big.NewInt(0) if gen.header.BaseFee != nil { diff --git a/core/error.go b/core/error.go index 82f7ddcf5d04..f234fa315b77 100644 --- a/core/error.go +++ b/core/error.go @@ -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") + // ErrTxTypeNotSupported is returned if a transaction is not supported in the // current network configuration. ErrTxTypeNotSupported = types.ErrTxTypeNotSupported diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 2f841eb64aed..750f3708dce5 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -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{ diff --git a/core/state_transition.go b/core/state_transition.go index 93d72d16b715..c5651f63c7b5 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -66,10 +66,14 @@ func (result *ExecutionResult) Revert() []byte { return common.CopyBytes(result.ReturnData) } -// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { +// IntrinsicGas computes the 'intrinsic gas' and the number of tokens for EIP-7623 +// for a message with the given data. +func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, uint64, error) { // Set the starting gas for the raw transaction - var gas uint64 + var ( + gas uint64 + floorDataGas uint64 + ) if isContractCreation && isHomestead { gas = params.TxGasContractCreation } else { @@ -85,26 +89,36 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set nz++ } } + var ( + z = dataLen - nz + tokens = nz*params.TokenPerNonZeroByte7623 + z + ) + // Check for overflow + if (math.MaxUint64-params.TxGas)/params.CostFloorPerToken7623 < tokens { + return 0, 0, ErrGasUintOverflow + } + // Minimum gas required for a transaction based on its data tokens (EIP-7623). + floorDataGas = params.TxGas + tokens*params.CostFloorPerToken7623 + // Make sure we don't exceed uint64 for all data combinations nonZeroGas := params.TxDataNonZeroGasFrontier if isEIP2028 { nonZeroGas = params.TxDataNonZeroGasEIP2028 } if (math.MaxUint64-gas)/nonZeroGas < nz { - return 0, ErrGasUintOverflow + return 0, 0, ErrGasUintOverflow } gas += nz * nonZeroGas - z := dataLen - nz if (math.MaxUint64-gas)/params.TxDataZeroGas < z { - return 0, ErrGasUintOverflow + return 0, 0, ErrGasUintOverflow } gas += z * params.TxDataZeroGas if isContractCreation && isEIP3860 { lenWords := toWordSize(dataLen) if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords { - return 0, ErrGasUintOverflow + return 0, 0, ErrGasUintOverflow } gas += lenWords * params.InitCodeWordGas } @@ -116,7 +130,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set if authList != nil { gas += uint64(len(authList)) * params.CallNewAccountGas } - return gas, nil + return gas, floorDataGas, nil } // toWordSize returns the ceiled word size required for init code payment calculation. @@ -417,13 +431,19 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.SetCodeAuthorizations, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) + gas, floorDataGas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.SetCodeAuthorizations, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) if err != nil { return nil, err } 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 { + if st.gasRemaining < floorDataGas { + 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) } @@ -490,11 +510,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) @@ -585,19 +622,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)) @@ -610,8 +644,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. diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 728f15069b75..06d66143dc34 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -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. diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 412418dcc936..01a698f6312c 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -108,13 +108,19 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // Ensure the transaction has more gas than the bare minimum needed to cover // the transaction metadata - intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) + intrGas, floorDataGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) if err != nil { return err } 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) { + 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) diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index 508823120749..395a3aacad62 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -82,18 +82,18 @@ var ( func TestProcessVerkle(t *testing.T) { var ( - code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`) - intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, nil, true, true, true, true) + code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`) + intrinsicContractCreationGas, _, _ = IntrinsicGas(code, nil, nil, true, true, true, true) // A contract creation that calls EXTCODECOPY in the constructor. Used to ensure that the witness // will not contain that copied data. // Source: https://gist.github.com/gballet/a23db1e1cb4ed105616b5920feb75985 - codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`) - intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, true, true, true) - signer = types.LatestSigner(testVerkleChainConfig) - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain - coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") - gspec = &Genesis{ + codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`) + intrinsicCodeWithExtCodeCopyGas, _, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, true, true, true) + signer = types.LatestSigner(testVerkleChainConfig) + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain + coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") + gspec = &Genesis{ Config: testVerkleChainConfig, Alloc: GenesisAlloc{ coinbase: { @@ -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, diff --git a/internal/ethapi/override/override_test.go b/internal/ethapi/override/override_test.go index 02a17c133170..07ed6442b2d6 100644 --- a/internal/ethapi/override/override_test.go +++ b/internal/ethapi/override/override_test.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/triedb" ) @@ -37,7 +36,7 @@ func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil func TestStateOverrideMovePrecompile(t *testing.T) { db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) - statedb, err := state.New(types.EmptyRootHash, db) + statedb, err := state.New(common.Hash{}, db) if err != nil { t.Fatalf("failed to create statedb: %v", err) } diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json index df2d9349fb0a..5853724cd6fe 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-blob-tx.json @@ -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" } -] \ No newline at end of file +] diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json index b01400e60546..602b25e21fea 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-block-with-dynamic-fee-tx.json @@ -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", @@ -15,4 +15,4 @@ "transactionIndex": "0x0", "type": "0x2" } -] \ No newline at end of file +] diff --git a/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json b/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json index df2d9349fb0a..5853724cd6fe 100644 --- a/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json +++ b/internal/ethapi/testdata/eth_getBlockReceipts-tag-latest.json @@ -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" } -] \ No newline at end of file +] diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json b/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json index 8e0669d10a55..386f1225e6ac 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-blob-tx.json @@ -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" -} \ No newline at end of file +} diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json b/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json index 49c06aad62fb..0519ae1da4b7 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-create-contract-with-access-list.json @@ -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" -} \ No newline at end of file +} diff --git a/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json b/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json index 13bd7bd12c12..4601273a5159 100644 --- a/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json +++ b/internal/ethapi/testdata/eth_getTransactionReceipt-dynamic-tx-with-logs.json @@ -1,11 +1,11 @@ { - "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", @@ -13,4 +13,4 @@ "transactionHash": "0xdcde2574628c9d7dff22b9afa19f235959a924ceec65a9df903a517ae91f5c84", "transactionIndex": "0x0", "type": "0x2" -} \ No newline at end of file +} diff --git a/params/protocol_params.go b/params/protocol_params.go index b46e8d66b255..1c281faac7cc 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -28,17 +28,19 @@ const ( MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1). GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block. - MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis. - ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction. - SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. - CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero. - CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior. - TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions. - TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions. - TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. - QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation. - LogDataGas uint64 = 8 // Per byte in a LOG* operation's data. - CallStipend uint64 = 2300 // Free gas given at beginning of call. + MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis. + ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction. + SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. + CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero. + CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior. + TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions. + TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions. + TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. + TokenPerNonZeroByte7623 uint64 = 4 // Token cost per non-zero byte as specified by EIP-7623. + CostFloorPerToken7623 uint64 = 10 // Cost floor per byte of data as specified by EIP-7623. + QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation. + LogDataGas uint64 = 8 // Per byte in a LOG* operation's data. + CallStipend uint64 = 2300 // Free gas given at beginning of call. Keccak256Gas uint64 = 30 // Once per KECCAK256 operation. Keccak256WordGas uint64 = 6 // Once per word of the KECCAK256 operation's data. diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 55b76df89c54..d0de76aa175c 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -59,7 +59,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { return nil, nil, err } // Intrinsic gas - requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, isHomestead, isIstanbul, false) + requiredGas, _, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, isHomestead, isIstanbul, false) if err != nil { return nil, nil, err } From 55b48679a5603a3abdd8fbc35b8f091e27235839 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 20 Jan 2025 16:59:49 +0100 Subject: [PATCH 2/6] minor --- internal/ethapi/override/override_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/ethapi/override/override_test.go b/internal/ethapi/override/override_test.go index 07ed6442b2d6..02a17c133170 100644 --- a/internal/ethapi/override/override_test.go +++ b/internal/ethapi/override/override_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/triedb" ) @@ -36,7 +37,7 @@ func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil func TestStateOverrideMovePrecompile(t *testing.T) { db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) - statedb, err := state.New(common.Hash{}, db) + statedb, err := state.New(types.EmptyRootHash, db) if err != nil { t.Fatalf("failed to create statedb: %v", err) } From ee4f83063c538267d816b14f8172341b610f38c1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 22 Jan 2025 16:08:50 +0100 Subject: [PATCH 3/6] Move floor gas out of intrinsicGas --- cmd/evm/internal/t8ntool/transaction.go | 15 ++++++- core/bench_test.go | 2 +- core/state_transition.go | 56 +++++++++++++------------ core/txpool/validation.go | 6 ++- core/verkle_witness_test.go | 18 ++++---- tests/transaction_test_util.go | 2 +- 6 files changed, 60 insertions(+), 39 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 0e75cba38aa6..974e14685b49 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -133,7 +133,7 @@ func Transaction(ctx *cli.Context) error { r.Address = sender } // Check intrinsic gas - if gas, _, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, + if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int), 0)); err != nil { r.Error = err results = append(results, r) @@ -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 { diff --git a/core/bench_test.go b/core/bench_test.go index 229662f000e5..d37683031814 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -90,7 +90,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { data := make([]byte, nbytes) return func(i int, gen *BlockGen) { toaddr := common.Address{} - gas, _, _ := IntrinsicGas(data, nil, nil, false, false, false, false) + gas, _ := IntrinsicGas(data, nil, nil, false, false, false, false) signer := gen.Signer() gasPrice := big.NewInt(0) if gen.header.BaseFee != nil { diff --git a/core/state_transition.go b/core/state_transition.go index c5651f63c7b5..f3a451b7e1c5 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -17,6 +17,7 @@ package core import ( + "bytes" "fmt" "math" "math/big" @@ -68,12 +69,9 @@ func (result *ExecutionResult) Revert() []byte { // IntrinsicGas computes the 'intrinsic gas' and the number of tokens for EIP-7623 // for a message with the given data. -func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, uint64, error) { +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 - floorDataGas uint64 - ) + var gas uint64 if isContractCreation && isHomestead { gas = params.TxGasContractCreation } else { @@ -83,22 +81,8 @@ 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++ - } - } - var ( - z = dataLen - nz - tokens = nz*params.TokenPerNonZeroByte7623 + z - ) - // Check for overflow - if (math.MaxUint64-params.TxGas)/params.CostFloorPerToken7623 < tokens { - return 0, 0, ErrGasUintOverflow - } - // Minimum gas required for a transaction based on its data tokens (EIP-7623). - floorDataGas = params.TxGas + tokens*params.CostFloorPerToken7623 + z := uint64(bytes.Count(data, []byte{0})) + nz := uint64(dataLen - z) // Make sure we don't exceed uint64 for all data combinations nonZeroGas := params.TxDataNonZeroGasFrontier @@ -106,19 +90,19 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set nonZeroGas = params.TxDataNonZeroGasEIP2028 } if (math.MaxUint64-gas)/nonZeroGas < nz { - return 0, 0, ErrGasUintOverflow + return 0, ErrGasUintOverflow } gas += nz * nonZeroGas if (math.MaxUint64-gas)/params.TxDataZeroGas < z { - return 0, 0, ErrGasUintOverflow + return 0, ErrGasUintOverflow } gas += z * params.TxDataZeroGas if isContractCreation && isEIP3860 { lenWords := toWordSize(dataLen) if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords { - return 0, 0, ErrGasUintOverflow + return 0, ErrGasUintOverflow } gas += lenWords * params.InitCodeWordGas } @@ -130,7 +114,22 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set if authList != nil { gas += uint64(len(authList)) * params.CallNewAccountGas } - return gas, floorDataGas, nil + 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. @@ -428,10 +427,11 @@ 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 - gas, floorDataGas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.SetCodeAuthorizations, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) + gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.SetCodeAuthorizations, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) if err != nil { return nil, err } @@ -440,6 +440,10 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { } // 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 { return nil, fmt.Errorf("%w: have %d, want %d", ErrDataFloorGas, st.gasRemaining, floorDataGas) } diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 01a698f6312c..7389ab91afc9 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -108,7 +108,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // Ensure the transaction has more gas than the bare minimum needed to cover // the transaction metadata - intrGas, floorDataGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, true, opts.Config.IsIstanbul(head.Number), opts.Config.IsShanghai(head.Number, head.Time)) if err != nil { return err } @@ -117,6 +117,10 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // 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) } diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index 395a3aacad62..f102686c7ca8 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -82,18 +82,18 @@ var ( func TestProcessVerkle(t *testing.T) { var ( - code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`) - intrinsicContractCreationGas, _, _ = IntrinsicGas(code, nil, nil, true, true, true, true) + code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`) + intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, nil, true, true, true, true) // A contract creation that calls EXTCODECOPY in the constructor. Used to ensure that the witness // will not contain that copied data. // Source: https://gist.github.com/gballet/a23db1e1cb4ed105616b5920feb75985 - codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`) - intrinsicCodeWithExtCodeCopyGas, _, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, true, true, true) - signer = types.LatestSigner(testVerkleChainConfig) - testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain - coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") - gspec = &Genesis{ + codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`) + intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, true, true, true) + signer = types.LatestSigner(testVerkleChainConfig) + testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain + coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") + gspec = &Genesis{ Config: testVerkleChainConfig, Alloc: GenesisAlloc{ coinbase: { diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index d0de76aa175c..55b76df89c54 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -59,7 +59,7 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { return nil, nil, err } // Intrinsic gas - requiredGas, _, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, isHomestead, isIstanbul, false) + requiredGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, isHomestead, isIstanbul, false) if err != nil { return nil, nil, err } From 4429474f13e268c77bba3ac64a73f305d097829a Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 23 Jan 2025 13:41:18 +0100 Subject: [PATCH 4/6] comment fix --- core/state_transition.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index f3a451b7e1c5..3b0a483359df 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -67,8 +67,7 @@ func (result *ExecutionResult) Revert() []byte { return common.CopyBytes(result.ReturnData) } -// IntrinsicGas computes the 'intrinsic gas' and the number of tokens for EIP-7623 -// for a message with the given data. +// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. 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 @@ -82,7 +81,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set if dataLen > 0 { // Zero and non-zero bytes are priced differently z := uint64(bytes.Count(data, []byte{0})) - nz := uint64(dataLen - z) + nz := dataLen - z // Make sure we don't exceed uint64 for all data combinations nonZeroGas := params.TxDataNonZeroGasFrontier From 71260cc3826f17a0fd3cd16b141211583067735d Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 23 Jan 2025 19:33:30 +0100 Subject: [PATCH 5/6] Update core/error.go Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- core/error.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/error.go b/core/error.go index f234fa315b77..819c42a9a7a7 100644 --- a/core/error.go +++ b/core/error.go @@ -82,7 +82,7 @@ var ( // 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") + ErrFloorDataGas = errors.New("insufficient gas for floor data gas cost") // ErrTxTypeNotSupported is returned if a transaction is not supported in the // current network configuration. From 269002b784c9544725c0818f4985e6a91419c00a Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 23 Jan 2025 19:34:31 +0100 Subject: [PATCH 6/6] apply review comment --- cmd/evm/internal/t8ntool/transaction.go | 2 +- core/error.go | 2 +- core/state_transition.go | 2 +- core/txpool/validation.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 974e14685b49..acfe0fca9f59 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -152,7 +152,7 @@ func Transaction(ctx *cli.Context) error { continue } else { if tx.Gas() < floorDataGas { - r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrDataFloorGas, tx.Gas(), floorDataGas) + r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrFloorDataGas, tx.Gas(), floorDataGas) results = append(results, r) continue } diff --git a/core/error.go b/core/error.go index 819c42a9a7a7..ce3bbb788886 100644 --- a/core/error.go +++ b/core/error.go @@ -80,7 +80,7 @@ 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 + // ErrFloorDataGas is returned if the transaction is specified to use less gas // than required for the data floor cost. ErrFloorDataGas = errors.New("insufficient gas for floor data gas cost") diff --git a/core/state_transition.go b/core/state_transition.go index 3b0a483359df..a1ac91c4a5a6 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -444,7 +444,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { return nil, err } if st.gasRemaining < floorDataGas { - return nil, fmt.Errorf("%w: have %d, want %d", ErrDataFloorGas, st.gasRemaining, floorDataGas) + return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, st.gasRemaining, floorDataGas) } } if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 7389ab91afc9..dec711b17302 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -122,7 +122,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types return err } if tx.Gas() < floorDataGas { - return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrDataFloorGas, tx.Gas(), floorDataGas) + return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrFloorDataGas, tx.Gas(), floorDataGas) } } // Ensure the gasprice is high enough to cover the requirement of the calling pool