Skip to content

Commit

Permalink
all: add blob schedule where relevant
Browse files Browse the repository at this point in the history
  • Loading branch information
lightclient committed Jan 9, 2025
1 parent 6c35beb commit 0cd89ea
Show file tree
Hide file tree
Showing 26 changed files with 218 additions and 84 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
}
}
11 changes: 9 additions & 2 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,14 @@ 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{
ParentHash: common.Hash{},
Number: new(big.Int).SetUint64(pre.Env.Number - 1),
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 +241,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
4 changes: 2 additions & 2 deletions consensus/misc/eip4844/eip4844.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
return errors.New("header is missing blobGasUsed")
}
// Verify that the blob gas used remains within reasonable limits.
if max := config.LatestMaxBlobsPerBlock(header.Time); *header.BlobGasUsed > max*params.BlobTxBlobGasPerBlob {
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 {
Expand All @@ -61,7 +61,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
// blobs on top of the excess blob gas.
func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header) uint64 {
var (
target = config.LatestTargetBlobsPerBlock(parent.Time) * params.BlobTxBlobGasPerBlob
target = config.TargetBlobsPerBlock(parent.Time) * params.BlobTxBlobGasPerBlob
parentExcessBlobGas uint64
parentBlobGasUsed uint64
)
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
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
20 changes: 1 addition & 19 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
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 uint64(shelf.SlotSize/blobSize) > p.chain.Config().LatestMaxBlobsPerBlock(p.head.Time)*params.BlobTxBlobGasPerBlob {
if shelf.SlotSize/blobSize > uint32(p.chain.Config().LatestMaxBlobsPerBlock()*params.BlobTxBlobGasPerBlob) {
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
12 changes: 7 additions & 5 deletions core/txpool/blobpool/blobpool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ var (
testBlobVHashes [][32]byte
)

const testMaxBlobsPerBlock = 6

func init() {
for i := 0; i < 10; i++ {
testBlob := &kzg4844.Blob{byte(i)}
Expand Down Expand Up @@ -415,7 +417,7 @@ func TestOpenDrops(t *testing.T) {
defer os.RemoveAll(storage)

os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)

// Insert a malformed transaction to verify that decoding errors (or format
// changes) are handled gracefully (case 1)
Expand Down Expand Up @@ -738,7 +740,7 @@ func TestOpenIndex(t *testing.T) {
defer os.RemoveAll(storage)

os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)

// Insert a sequence of transactions with varying price points to check that
// the cumulative minimum will be maintained.
Expand Down Expand Up @@ -827,7 +829,7 @@ func TestOpenHeap(t *testing.T) {
defer os.RemoveAll(storage)

os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)

// Insert a few transactions from a few accounts. To remove randomness from
// the heap initialization, use a deterministic account/tx/priority ordering.
Expand Down Expand Up @@ -914,7 +916,7 @@ func TestOpenCap(t *testing.T) {
defer os.RemoveAll(storage)

os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)

// Insert a few transactions from a few accounts
var (
Expand Down Expand Up @@ -1369,7 +1371,7 @@ func TestAdd(t *testing.T) {
defer os.RemoveAll(storage) // late defer, still ok

os.MkdirAll(filepath.Join(storage, pendingTransactionStore), 0700)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(), nil)
store, _ := billy.Open(billy.Options{Path: filepath.Join(storage, pendingTransactionStore)}, newSlotter(testMaxBlobsPerBlock), nil)

// Insert the seed transactions for the pool startup
var (
Expand Down
4 changes: 2 additions & 2 deletions core/txpool/blobpool/limbo.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type limbo struct {
}

// newLimbo opens and indexes a set of limboed blob transactions.
func newLimbo(datadir string) (*limbo, error) {
func newLimbo(datadir string, maxBlobsPerTransaction uint64) (*limbo, error) {
l := &limbo{
index: make(map[common.Hash]uint64),
groups: make(map[uint64]map[uint64]common.Hash),
Expand All @@ -60,7 +60,7 @@ func newLimbo(datadir string) (*limbo, error) {
fails = append(fails, id)
}
}
store, err := billy.Open(billy.Options{Path: datadir, Repair: true}, newSlotter(), index)
store, err := billy.Open(billy.Options{Path: datadir, Repair: true}, newSlotter(maxBlobsPerTransaction), index)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions core/txpool/blobpool/slotter.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ package blobpool
// The slotter also creates a shelf for 0-blob transactions. Whilst those are not
// allowed in the current protocol, having an empty shelf is not a relevant use
// of resources, but it makes stress testing with junk transactions simpler.
func newSlotter() func() (uint32, bool) {
func newSlotter(maxBlobsPerTransaction uint64) func() (uint32, bool) {
slotsize := uint32(txAvgSize)
slotsize -= uint32(blobSize) // underflows, it's ok, will overflow back in the first return

return func() (size uint32, done bool) {
slotsize += blobSize
finished := slotsize > 9*blobSize+txMaxSize
finished := slotsize > uint32(maxBlobsPerTransaction)*blobSize+txMaxSize

return slotsize, finished
}
Expand Down
2 changes: 1 addition & 1 deletion core/txpool/blobpool/slotter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import "testing"
// Tests that the slotter creates the expected database shelves.
func TestNewSlotter(t *testing.T) {
// Generate the database shelve sizes
slotter := newSlotter()
slotter := newSlotter(6)

var shelves []uint32
for {
Expand Down
3 changes: 3 additions & 0 deletions eth/catalyst/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,7 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
genesis.Config.ShanghaiTime = &time
genesis.Config.CancunTime = &time
genesis.Config.PragueTime = &time
genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule

n, ethservice := startEthService(t, genesis, blocks)

Expand Down Expand Up @@ -1626,6 +1627,7 @@ func TestParentBeaconBlockRoot(t *testing.T) {
time := blocks[len(blocks)-1].Time() + 5
genesis.Config.ShanghaiTime = &time
genesis.Config.CancunTime = &time
genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule

n, ethservice := startEthService(t, genesis, blocks)
defer n.Close()
Expand Down Expand Up @@ -1708,6 +1710,7 @@ func TestWitnessCreationAndConsumption(t *testing.T) {
timestamp := blocks[len(blocks)-2].Time() + 5
genesis.Config.ShanghaiTime = &timestamp
genesis.Config.CancunTime = &timestamp
genesis.Config.BlobScheduleConfig = params.DefaultBlobSchedule

n, ethservice := startEthService(t, genesis, blocks[:9])
defer n.Close()
Expand Down
6 changes: 3 additions & 3 deletions eth/fetcher/tx_fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,7 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) {
doTxNotify{peer: "C",
hashes: []common.Hash{{0x07}, {0x08}},
types: []byte{types.BlobTxType, types.BlobTxType},
sizes: []uint32{params.MaxBlobGasPerBlock, params.MaxBlobGasPerBlock},
sizes: []uint32{params.BlobTxBlobGasPerBlob * 10, params.BlobTxBlobGasPerBlob * 10},
},
doWait{time: txArriveTimeout, step: true},
isWaiting(nil),
Expand All @@ -1125,8 +1125,8 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) {
{common.Hash{0x06}, types.LegacyTxType, maxTxRetrievalSize},
},
"C": {
{common.Hash{0x07}, types.BlobTxType, params.MaxBlobGasPerBlock},
{common.Hash{0x08}, types.BlobTxType, params.MaxBlobGasPerBlock},
{common.Hash{0x07}, types.BlobTxType, params.BlobTxBlobGasPerBlob * 10},
{common.Hash{0x08}, types.BlobTxType, params.BlobTxBlobGasPerBlob * 10},
},
},
fetching: map[string][]common.Hash{
Expand Down
2 changes: 1 addition & 1 deletion eth/gasprice/feehistory.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
// Compute gas used ratio for normal and blob gas.
bf.results.gasUsedRatio = float64(bf.header.GasUsed) / float64(bf.header.GasLimit)
if blobGasUsed := bf.header.BlobGasUsed; blobGasUsed != nil {
bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(config.LatestMaxBlobsPerBlock(bf.header.Time))
bf.results.blobGasUsedRatio = float64(*blobGasUsed) / float64(config.MaxBlobsPerBlock(bf.header.Time))
}

if len(percentiles) == 0 {
Expand Down
6 changes: 6 additions & 0 deletions eth/gasprice/gasprice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe
ts := gspec.Timestamp + cancunBlock.Uint64()*10 // fixed 10 sec block time in blockgen
config.ShanghaiTime = &ts
config.CancunTime = &ts
config.BlobScheduleConfig = &params.BlobScheduleConfig{
Cancun: &params.BlobConfig{
Target: 3,
Max: 6,
},
}
signer = types.LatestSigner(gspec.Config)
}

Expand Down
1 change: 1 addition & 0 deletions eth/tracers/internal/tracetest/supply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ func TestSupplySelfdestruct(t *testing.T) {
cancunTime := uint64(0)
gspec.Config.ShanghaiTime = &cancunTime
gspec.Config.CancunTime = &cancunTime
gspec.Config.BlobScheduleConfig = params.DefaultBlobSchedule

postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc)
if err != nil {
Expand Down
Loading

0 comments on commit 0cd89ea

Please sign in to comment.