Skip to content

Commit

Permalink
all: add blob schedule eip
Browse files Browse the repository at this point in the history
  • Loading branch information
lightclient committed Jan 10, 2025
1 parent 033de2a commit ed67bc3
Show file tree
Hide file tree
Showing 33 changed files with 421 additions and 153 deletions.
10 changes: 8 additions & 2 deletions cmd/devp2p/internal/ethtest/testdata/genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@
"shanghaiTime": 780,
"cancunTime": 840,
"terminalTotalDifficulty": 9454784,
"ethash": {}
"ethash": {},
"blobSchedule": {
"cancun": {
"target": 3,
"max": 6
}
}
},
"nonce": "0x0",
"timestamp": "0x0",
Expand Down Expand Up @@ -108,4 +114,4 @@
"baseFeePerGas": null,
"excessBlobGas": null,
"blobGasUsed": null
}
}
9 changes: 7 additions & 2 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
parentExcessBlobGas := pre.Env.ParentExcessBlobGas
parentBlobGasUsed := pre.Env.ParentBlobGasUsed
if parentExcessBlobGas != nil && parentBlobGasUsed != nil {
excessBlobGas = eip4844.CalcExcessBlobGas(*parentExcessBlobGas, *parentBlobGasUsed)
parent := &types.Header{
Time: pre.Env.ParentTimestamp,
ExcessBlobGas: pre.Env.ParentExcessBlobGas,
BlobGasUsed: pre.Env.ParentBlobGasUsed,
}
excessBlobGas = eip4844.CalcExcessBlobGas(chainConfig, parent)
vmContext.BlobBaseFee = eip4844.CalcBlobFee(excessBlobGas)
}
}
Expand Down Expand Up @@ -234,7 +239,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
txBlobGas := uint64(0)
if tx.Type() == types.BlobTxType {
txBlobGas = uint64(params.BlobTxBlobGasPerBlob * len(tx.BlobHashes()))
if used, max := blobGasUsed+txBlobGas, uint64(params.MaxBlobGasPerBlock); used > max {
if used, max := blobGasUsed+txBlobGas, chainConfig.MaxBlobsPerBlock(pre.Env.Number)*params.BlobTxBlobGasPerBlob; used > max {
err := fmt.Errorf("blob gas (%d) would exceed maximum allowance %d", used, max)
log.Warn("rejected tx", "index", i, "err", err)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
Expand Down
2 changes: 1 addition & 1 deletion consensus/beacon/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
if header.ParentBeaconRoot == nil {
return errors.New("header is missing beaconRoot")
}
if err := eip4844.VerifyEIP4844Header(parent, header); err != nil {
if err := eip4844.VerifyEIP4844Header(chain.Config(), parent, header); err != nil {
return err
}
}
Expand Down
32 changes: 16 additions & 16 deletions consensus/misc/eip4844/eip4844.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var (
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
// if the current block contains no transactions, the excessBlobGas is updated
// accordingly.
func VerifyEIP4844Header(parent, header *types.Header) error {
func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Header) error {
// Verify the header is not malformed
if header.ExcessBlobGas == nil {
return errors.New("header is missing excessBlobGas")
Expand All @@ -42,37 +42,37 @@ func VerifyEIP4844Header(parent, header *types.Header) error {
return errors.New("header is missing blobGasUsed")
}
// Verify that the blob gas used remains within reasonable limits.
if *header.BlobGasUsed > params.MaxBlobGasPerBlock {
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, params.MaxBlobGasPerBlock)
if max := config.MaxBlobsPerBlock(header.Time) * params.BlobTxBlobGasPerBlob; *header.BlobGasUsed > max {
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, max)
}
if *header.BlobGasUsed%params.BlobTxBlobGasPerBlob != 0 {
return fmt.Errorf("blob gas used %d not a multiple of blob gas per blob %d", header.BlobGasUsed, params.BlobTxBlobGasPerBlob)
}
// Verify the excessBlobGas is correct based on the parent header
expectedExcessBlobGas := CalcExcessBlobGas(config, parent)
if *header.ExcessBlobGas != expectedExcessBlobGas {
return fmt.Errorf("invalid excessBlobGas: have %d, want %d", *header.ExcessBlobGas, expectedExcessBlobGas)
}
return nil
}

// CalcExcessBlobGas calculates the excess blob gas after applying the set of
// blobs on top of the excess blob gas.
func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 {
var (
target = config.TargetBlobsPerBlock(parent.Time) * params.BlobTxBlobGasPerBlob
parentExcessBlobGas uint64
parentBlobGasUsed uint64
)
if parent.ExcessBlobGas != nil {
parentExcessBlobGas = *parent.ExcessBlobGas
parentBlobGasUsed = *parent.BlobGasUsed
}
expectedExcessBlobGas := CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed)
if *header.ExcessBlobGas != expectedExcessBlobGas {
return fmt.Errorf("invalid excessBlobGas: have %d, want %d, parent excessBlobGas %d, parent blobDataUsed %d",
*header.ExcessBlobGas, expectedExcessBlobGas, parentExcessBlobGas, parentBlobGasUsed)
}
return nil
}

// CalcExcessBlobGas calculates the excess blob gas after applying the set of
// blobs on top of the excess blob gas.
func CalcExcessBlobGas(parentExcessBlobGas uint64, parentBlobGasUsed uint64) uint64 {
excessBlobGas := parentExcessBlobGas + parentBlobGasUsed
if excessBlobGas < params.BlobTxTargetBlobGasPerBlock {
if excessBlobGas < target {
return 0
}
return excessBlobGas - params.BlobTxTargetBlobGasPerBlock
return excessBlobGas - target
}

// CalcBlobFee calculates the blobfee from the header's excess blob gas field.
Expand Down
30 changes: 21 additions & 9 deletions consensus/misc/eip4844/eip4844_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@ import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)

func TestCalcExcessBlobGas(t *testing.T) {
var (
config = params.MainnetChainConfig
targetBlobs = config.TargetBlobsPerBlock(*config.CancunTime)
targetBlobGas = targetBlobs * params.BlobTxBlobGasPerBlob
)
var tests = []struct {
excess uint64
blobs uint64
Expand All @@ -34,23 +40,29 @@ func TestCalcExcessBlobGas(t *testing.T) {
// slots are below - or equal - to the target.
{0, 0, 0},
{0, 1, 0},
{0, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, 0},
{0, targetBlobs, 0},

// If the target blob gas is exceeded, the excessBlobGas should increase
// by however much it was overshot
{0, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob},
{1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 1, params.BlobTxBlobGasPerBlob + 1},
{1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) + 2, 2*params.BlobTxBlobGasPerBlob + 1},
{0, targetBlobs + 1, params.BlobTxBlobGasPerBlob},
{1, targetBlobs + 1, params.BlobTxBlobGasPerBlob + 1},
{1, targetBlobs + 2, 2*params.BlobTxBlobGasPerBlob + 1},

// The excess blob gas should decrease by however much the target was
// under-shot, capped at zero.
{params.BlobTxTargetBlobGasPerBlock, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, params.BlobTxTargetBlobGasPerBlock},
{params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, params.BlobTxTargetBlobGasPerBlock - params.BlobTxBlobGasPerBlob},
{params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 2, params.BlobTxTargetBlobGasPerBlock - (2 * params.BlobTxBlobGasPerBlob)},
{params.BlobTxBlobGasPerBlob - 1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, 0},
{targetBlobGas, targetBlobs, targetBlobGas},
{targetBlobGas, targetBlobs - 1, targetBlobGas - params.BlobTxBlobGasPerBlob},
{targetBlobGas, targetBlobs - 2, targetBlobGas - (2 * params.BlobTxBlobGasPerBlob)},
{params.BlobTxBlobGasPerBlob - 1, targetBlobs - 1, 0},
}
for i, tt := range tests {
result := CalcExcessBlobGas(tt.excess, tt.blobs*params.BlobTxBlobGasPerBlob)
blobGasUsed := tt.blobs * params.BlobTxBlobGasPerBlob
parent := &types.Header{
Time: *config.CancunTime,
ExcessBlobGas: &tt.excess,
BlobGasUsed: &blobGasUsed,
}
result := CalcExcessBlobGas(config, parent)
if result != tt.want {
t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want)
}
Expand Down
10 changes: 1 addition & 9 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,15 +595,7 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi
}
}
if cm.config.IsCancun(header.Number, header.Time) {
var (
parentExcessBlobGas uint64
parentBlobGasUsed uint64
)
if parent.ExcessBlobGas() != nil {
parentExcessBlobGas = *parent.ExcessBlobGas()
parentBlobGasUsed = *parent.BlobGasUsed()
}
excessBlobGas := eip4844.CalcExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed)
excessBlobGas := eip4844.CalcExcessBlobGas(cm.config, parent.Header())
header.ExcessBlobGas = &excessBlobGas
header.BlobGasUsed = new(uint64)
header.ParentBeaconRoot = new(common.Hash)
Expand Down
6 changes: 1 addition & 5 deletions core/chain_makers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestGeneratePOSChain(t *testing.T) {
aa = common.Address{0xaa}
bb = common.Address{0xbb}
funds = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether))
config = *params.AllEthashProtocolChanges
config = *params.MergedTestChainConfig
gspec = &Genesis{
Config: &config,
Alloc: types.GenesisAlloc{
Expand All @@ -57,10 +57,6 @@ func TestGeneratePOSChain(t *testing.T) {
db = rawdb.NewMemoryDatabase()
)

config.TerminalTotalDifficulty = common.Big0
config.ShanghaiTime = u64(0)
config.CancunTime = u64(0)

// init 0xaa with some storage elements
storage := make(map[common.Hash]common.Hash)
storage[common.Hash{0x00}] = common.Hash{0x00}
Expand Down
27 changes: 2 additions & 25 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,7 @@ func u64(val uint64) *uint64 { return &val }
// contain invalid transactions
func TestStateProcessorErrors(t *testing.T) {
var (
config = &params.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),
Ethash: new(params.EthashConfig),
TerminalTotalDifficulty: big.NewInt(0),
ShanghaiTime: new(uint64),
CancunTime: new(uint64),
PragueTime: new(uint64),
}
config = params.MergedTestChainConfig
signer = types.LatestSigner(config)
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("0202020202020202020202020202020202020202020202020202002020202020")
Expand Down Expand Up @@ -425,12 +407,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
}
header.Root = common.BytesToHash(hasher.Sum(nil))
if config.IsCancun(header.Number, header.Time) {
var pExcess, pUsed = uint64(0), uint64(0)
if parent.ExcessBlobGas() != nil {
pExcess = *parent.ExcessBlobGas()
pUsed = *parent.BlobGasUsed()
}
excess := eip4844.CalcExcessBlobGas(pExcess, pUsed)
excess := eip4844.CalcExcessBlobGas(config, parent.Header())
used := uint64(nBlobs * params.BlobTxBlobGasPerBlob)
header.ExcessBlobGas = &excess
header.BlobGasUsed = &used
Expand Down
19 changes: 10 additions & 9 deletions core/txpool/blobpool/blobpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,6 @@ const (
// transaction. There can be multiple of these embedded into a single tx.
blobSize = params.BlobTxFieldElementsPerBlob * params.BlobTxBytesPerFieldElement

// maxBlobsPerTransaction is the maximum number of blobs a single transaction
// is allowed to contain. Whilst the spec states it's unlimited, the block
// data slots are protocol bound, which implicitly also limit this.
maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob

// txAvgSize is an approximate byte size of a transaction metadata to avoid
// tiny overflows causing all txs to move a shelf higher, wasting disk space.
txAvgSize = 4 * 1024
Expand Down Expand Up @@ -223,6 +218,11 @@ func newBlobTxMeta(id uint64, size uint32, tx *types.Transaction) *blobTxMeta {
// very relaxed ones can be included even if the fees go up, when the closer
// ones could already be invalid.
//
// - Because the maximum number of blobs allowed in a block can change per
// fork, the pool is designed to handle the maximum number of blobs allowed
// in the chain's latest defined fork -- even if it isn't active. This
// avoids needing to upgrade the database around the fork boundary.
//
// When the pool eventually reaches saturation, some old transactions - that may
// never execute - will need to be evicted in favor of newer ones. The eviction
// strategy is quite complex:
Expand Down Expand Up @@ -387,7 +387,8 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
fails = append(fails, id)
}
}
store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, newSlotter(), index)
slotter := newSlotter(p.chain.Config().LatestMaxBlobsPerBlock())
store, err := billy.Open(billy.Options{Path: queuedir, Repair: true}, slotter, index)
if err != nil {
return err
}
Expand Down Expand Up @@ -420,7 +421,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres

// Pool initialized, attach the blob limbo to it to track blobs included
// recently but not yet finalized
p.limbo, err = newLimbo(limbodir)
p.limbo, err = newLimbo(limbodir, p.chain.Config().LatestMaxBlobsPerBlock())
if err != nil {
p.Close()
return err
Expand Down Expand Up @@ -1598,7 +1599,7 @@ func (p *BlobPool) updateStorageMetrics() {
metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotusedGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.FilledSlots))
metrics.GetOrRegisterGauge(fmt.Sprintf(shelfSlotgapsGaugeName, shelf.SlotSize/blobSize), nil).Update(int64(shelf.GappedSlots))

if shelf.SlotSize/blobSize > maxBlobsPerTransaction {
if shelf.SlotSize/blobSize > uint32(p.chain.Config().LatestMaxBlobsPerBlock()) {
oversizedDataused += slotDataused
oversizedDatagaps += slotDatagaps
oversizedSlotused += shelf.FilledSlots
Expand Down Expand Up @@ -1751,7 +1752,7 @@ func (p *BlobPool) Clear() {
// The transaction addition may attempt to reserve the sender addr which
// can't happen until Clear releases the reservation lock. Clear cannot
// acquire the subpool lock until the transaction addition is completed.
for acct, _ := range p.index {
for acct := range p.index {
p.reserve(acct, false)
}
p.lookup = newLookup()
Expand Down
Loading

0 comments on commit ed67bc3

Please sign in to comment.