mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 00:39:26 +00:00
core: make sure the floorDataGas fits within MaxTxGas
This commit is contained in:
parent
e4a6a5ab75
commit
931955cdcc
2 changed files with 121 additions and 11 deletions
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -432,3 +433,105 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
|
||||||
}
|
}
|
||||||
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestEIP8037MaxRegularGasValidation tests that transactions with floor data gas
|
||||||
|
// exceeding MaxTxGas are rejected in Amsterdam.
|
||||||
|
func TestEIP8037MaxRegularGasValidation(t *testing.T) {
|
||||||
|
var (
|
||||||
|
// Create an Amsterdam-enabled chain config
|
||||||
|
config = ¶ms.ChainConfig{
|
||||||
|
ChainID: big.NewInt(1),
|
||||||
|
HomesteadBlock: big.NewInt(0),
|
||||||
|
EIP150Block: big.NewInt(0),
|
||||||
|
EIP155Block: big.NewInt(0),
|
||||||
|
EIP158Block: big.NewInt(0),
|
||||||
|
ByzantiumBlock: big.NewInt(0),
|
||||||
|
ConstantinopleBlock: big.NewInt(0),
|
||||||
|
PetersburgBlock: big.NewInt(0),
|
||||||
|
IstanbulBlock: big.NewInt(0),
|
||||||
|
MuirGlacierBlock: big.NewInt(0),
|
||||||
|
BerlinBlock: big.NewInt(0),
|
||||||
|
LondonBlock: big.NewInt(0),
|
||||||
|
ArrowGlacierBlock: big.NewInt(0),
|
||||||
|
GrayGlacierBlock: big.NewInt(0),
|
||||||
|
MergeNetsplitBlock: big.NewInt(0),
|
||||||
|
ShanghaiTime: u64(0),
|
||||||
|
CancunTime: u64(0),
|
||||||
|
PragueTime: u64(0),
|
||||||
|
OsakaTime: u64(0),
|
||||||
|
AmsterdamTime: u64(0),
|
||||||
|
TerminalTotalDifficulty: big.NewInt(0),
|
||||||
|
Ethash: new(params.EthashConfig),
|
||||||
|
BlobScheduleConfig: ¶ms.BlobScheduleConfig{
|
||||||
|
Cancun: params.DefaultCancunBlobConfig,
|
||||||
|
Prague: params.DefaultPragueBlobConfig,
|
||||||
|
Osaka: params.DefaultOsakaBlobConfig,
|
||||||
|
Amsterdam: params.DefaultOsakaBlobConfig,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
signer = types.LatestSigner(config)
|
||||||
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Calculate how much data is needed to exceed MaxTxGas with floor data gas.
|
||||||
|
// FloorDataGas = TxGas + tokens * TxCostFloorPerToken
|
||||||
|
// For non-zero bytes: tokens = 4 per byte, so cost = 40 gas per byte
|
||||||
|
// MaxTxGas = 16,777,216
|
||||||
|
// To exceed: tokens * 10 > MaxTxGas - TxGas = 16,756,216
|
||||||
|
// For non-zero bytes: bytes * 4 * 10 > 16,756,216 → bytes > 418,905
|
||||||
|
dataSize := 420000 // This should exceed MaxTxGas
|
||||||
|
largeData := make([]byte, dataSize)
|
||||||
|
for i := range largeData {
|
||||||
|
largeData[i] = 0xFF // Non-zero bytes have higher token cost
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that floor data gas exceeds MaxTxGas
|
||||||
|
floorGas, err := FloorDataGas(largeData)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to calculate floor data gas: %v", err)
|
||||||
|
}
|
||||||
|
if floorGas <= params.MaxTxGas {
|
||||||
|
t.Fatalf("Test setup error: floor data gas %d should exceed MaxTxGas %d", floorGas, params.MaxTxGas)
|
||||||
|
}
|
||||||
|
t.Logf("Floor data gas: %d, MaxTxGas: %d", floorGas, params.MaxTxGas)
|
||||||
|
|
||||||
|
// Create a transaction with large calldata. The gas limit is set high enough
|
||||||
|
// to cover the floor data gas, but since floor data gas > MaxTxGas,
|
||||||
|
// this should be rejected in Amsterdam.
|
||||||
|
tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{
|
||||||
|
Nonce: 0,
|
||||||
|
GasTipCap: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasFeeCap: big.NewInt(params.InitialBaseFee),
|
||||||
|
Gas: floorGas + 1000000, // Enough gas to cover floor + state gas
|
||||||
|
To: &common.Address{},
|
||||||
|
Value: big.NewInt(0),
|
||||||
|
Data: largeData,
|
||||||
|
}), signer, key1)
|
||||||
|
|
||||||
|
var (
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
gspec = &Genesis{
|
||||||
|
Config: config,
|
||||||
|
GasLimit: 100_000_000, // High block gas limit to not interfere with the test
|
||||||
|
Alloc: types.GenesisAlloc{
|
||||||
|
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): types.Account{
|
||||||
|
Balance: new(big.Int).Mul(big.NewInt(1000000), big.NewInt(params.Ether)), // Lots of ether
|
||||||
|
Nonce: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
blockchain, _ = NewBlockChain(db, gspec, beacon.New(ethash.NewFaker()), nil)
|
||||||
|
)
|
||||||
|
defer blockchain.Stop()
|
||||||
|
|
||||||
|
block := GenerateBadBlock(gspec.ToBlock(), beacon.New(ethash.NewFaker()), types.Transactions{tx}, config, false)
|
||||||
|
_, err = blockchain.InsertChain(types.Blocks{block})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("block with floor data gas > MaxTxGas should have been rejected")
|
||||||
|
}
|
||||||
|
// The error should indicate that max regular gas exceeds the limit
|
||||||
|
if !strings.Contains(err.Error(), "max regular gas") || !strings.Contains(err.Error(), "exceeds limit") {
|
||||||
|
t.Errorf("unexpected error message: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf("Got expected error: %v", err)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -470,11 +470,29 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute the floor data cost (EIP-7623), needed for both Prague and Amsterdam validation.
|
||||||
|
if rules.IsPrague {
|
||||||
|
floorDataGas, err = FloorDataGas(msg.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if msg.GasLimit < floorDataGas {
|
||||||
|
return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, msg.GasLimit, floorDataGas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if rules.IsAmsterdam {
|
if rules.IsAmsterdam {
|
||||||
// EIP-8037: total intrinsic must fit within the transaction gas limit.
|
// EIP-8037: total intrinsic must fit within the transaction gas limit.
|
||||||
if msg.GasLimit < gas.Sum() {
|
if msg.GasLimit < gas.Sum() {
|
||||||
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, msg.GasLimit, gas.Sum())
|
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, msg.GasLimit, gas.Sum())
|
||||||
}
|
}
|
||||||
|
// EIP-8037: the regular gas consumption (intrinsic or floor) must fit within MaxTxGas.
|
||||||
|
// The transaction gas limit is no longer statically capped, but regular gas usage is.
|
||||||
|
maxRegularGas := max(gas.RegularGas, floorDataGas)
|
||||||
|
if maxRegularGas > params.MaxTxGas {
|
||||||
|
return nil, fmt.Errorf("%w: max regular gas %d exceeds limit %d", ErrIntrinsicGas, maxRegularGas, params.MaxTxGas)
|
||||||
|
}
|
||||||
// Split remaining execution gas into regular and state reservoir.
|
// Split remaining execution gas into regular and state reservoir.
|
||||||
executionGas := msg.GasLimit - gas.Sum()
|
executionGas := msg.GasLimit - gas.Sum()
|
||||||
regularGas := min(params.MaxTxGas-gas.RegularGas, executionGas)
|
regularGas := min(params.MaxTxGas-gas.RegularGas, executionGas)
|
||||||
|
|
@ -485,17 +503,6 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
}
|
}
|
||||||
st.gasRemaining.Sub(gas)
|
st.gasRemaining.Sub(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 msg.GasLimit < floorDataGas {
|
|
||||||
return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, msg.GasLimit, floorDataGas)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
|
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
|
||||||
if rules.IsAmsterdam {
|
if rules.IsAmsterdam {
|
||||||
t.OnGasChange(msg.GasLimit, st.gasRemaining.RegularGas+st.gasRemaining.StateGas, tracing.GasChangeTxIntrinsicGas)
|
t.OnGasChange(msg.GasLimit, st.gasRemaining.RegularGas+st.gasRemaining.StateGas, tracing.GasChangeTxIntrinsicGas)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue