From b58f8b3a5f30c480818d9ddaa6a8fb2d83a38cee Mon Sep 17 00:00:00 2001 From: lightclient Date: Mon, 23 Jun 2025 20:09:36 +0200 Subject: [PATCH] consensus: implement EIP-7918 Co-authored-by: Sina Mahmoodi --- consensus/misc/eip4844/eip4844.go | 27 +++++++++++++++-- consensus/misc/eip4844/eip4844_test.go | 40 ++++++++++++++++++++++++++ params/protocol_params.go | 1 + 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/consensus/misc/eip4844/eip4844.go b/consensus/misc/eip4844/eip4844.go index 1c0c651964..65ee9f01d7 100644 --- a/consensus/misc/eip4844/eip4844.go +++ b/consensus/misc/eip4844/eip4844.go @@ -70,11 +70,28 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim parentExcessBlobGas = *parent.ExcessBlobGas parentBlobGasUsed = *parent.BlobGasUsed } - excessBlobGas := parentExcessBlobGas + parentBlobGasUsed - targetGas := uint64(targetBlobsPerBlock(config, headTimestamp)) * params.BlobTxBlobGasPerBlob + var ( + excessBlobGas = parentExcessBlobGas + parentBlobGasUsed + target = targetBlobsPerBlock(config, headTimestamp) + targetGas = uint64(target) * params.BlobTxBlobGasPerBlob + ) if excessBlobGas < targetGas { return 0 } + if !config.IsOsaka(config.LondonBlock, headTimestamp) { + return excessBlobGas - targetGas + } + + // EIP-7918 (post-Osaka). + var ( + reservePrice = new(big.Int).Mul(parent.BaseFee, big.NewInt(params.BlobBaseCost)) + blobPrice = calcBlobPrice(config, parent) + ) + if reservePrice.Cmp(blobPrice) > 0 { + max := MaxBlobsPerBlock(config, headTimestamp) + scaledExcess := parentBlobGasUsed * uint64(max-target) / uint64(max) + return parentExcessBlobGas + scaledExcess + } return excessBlobGas - targetGas } @@ -185,3 +202,9 @@ func fakeExponential(factor, numerator, denominator *big.Int) *big.Int { } return output.Div(output, denominator) } + +// calcBlobPrice calculates the blob price for a block. +func calcBlobPrice(config *params.ChainConfig, header *types.Header) *big.Int { + blobBaseFee := CalcBlobFee(config, header) + return new(big.Int).Mul(blobBaseFee, big.NewInt(params.BlobTxBlobGasPerBlob)) +} diff --git a/consensus/misc/eip4844/eip4844_test.go b/consensus/misc/eip4844/eip4844_test.go index f4e3cb3d9a..555324db65 100644 --- a/consensus/misc/eip4844/eip4844_test.go +++ b/consensus/misc/eip4844/eip4844_test.go @@ -127,3 +127,43 @@ func TestFakeExponential(t *testing.T) { } } } + +func TestCalcExcessBlobGasEIP7918(t *testing.T) { + var ( + cfg = params.MergedTestChainConfig + targetBlobs = targetBlobsPerBlock(cfg, *cfg.CancunTime) + blobGasTarget = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob + ) + makeHeader := func(parentExcess, parentBaseFee uint64, blobsUsed int) *types.Header { + blobGasUsed := uint64(blobsUsed) * params.BlobTxBlobGasPerBlob + return &types.Header{ + BaseFee: big.NewInt(int64(parentBaseFee)), + ExcessBlobGas: &parentExcess, + BlobGasUsed: &blobGasUsed, + } + } + + tests := []struct { + name string + header *types.Header + wantExcessGas uint64 + }{ + { + name: "BelowReservePrice", + header: makeHeader(0, 1_000_000_000, targetBlobs), + wantExcessGas: blobGasTarget * 3 / 9, + }, + { + name: "AboveReservePrice", + header: makeHeader(0, 1, targetBlobs), + wantExcessGas: 0, + }, + } + for _, tc := range tests { + got := CalcExcessBlobGas(cfg, tc.header, *cfg.CancunTime) + if got != tc.wantExcessGas { + t.Fatalf("%s: excess-blob-gas mismatch – have %d, want %d", + tc.name, got, tc.wantExcessGas) + } + } +} diff --git a/params/protocol_params.go b/params/protocol_params.go index e953ba01cb..143f643ef4 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -178,6 +178,7 @@ const ( BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size) BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile. + BlobBaseCost = 1 << 14 // Base execution gas cost for a blob. HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935. )