mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-01 12:38:40 +00:00
work around billy slotter interface limitations
This commit is contained in:
parent
4daf354b2c
commit
f8a0b6fa1c
2 changed files with 53 additions and 20 deletions
|
|
@ -346,10 +346,10 @@ type BlobPool struct {
|
||||||
reserver txpool.Reserver // Address reserver to ensure exclusivity across subpools
|
reserver txpool.Reserver // Address reserver to ensure exclusivity across subpools
|
||||||
hasPendingAuth func(common.Address) bool // Determine whether the specified address has a pending 7702-auth
|
hasPendingAuth func(common.Address) bool // Determine whether the specified address has a pending 7702-auth
|
||||||
|
|
||||||
store billy.Database // Persistent data store for the tx metadata and blobs
|
store billy.Database // Persistent data store for the tx metadata and blobs
|
||||||
newSlotter func() billy.SlotSizeFn // Factory to create fresh slotter instances for slot size lookups
|
slotter slotSizer // O(1) slot size calculator matching the active billy shelves
|
||||||
stored uint64 // Useful data size of all transactions on disk
|
stored uint64 // Useful data size of all transactions on disk
|
||||||
limbo *limbo // Persistent data store for the non-finalized blobs
|
limbo *limbo // Persistent data store for the non-finalized blobs
|
||||||
|
|
||||||
gapped map[common.Address][]*types.Transaction // Transactions that are currently gapped (nonce too high)
|
gapped map[common.Address][]*types.Transaction // Transactions that are currently gapped (nonce too high)
|
||||||
gappedSource map[common.Hash]common.Address // Source of gapped transactions to allow rechecking on inclusion
|
gappedSource map[common.Hash]common.Address // Source of gapped transactions to allow rechecking on inclusion
|
||||||
|
|
@ -437,16 +437,19 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserver txpool.Reser
|
||||||
|
|
||||||
// Create new slotter for pre-Osaka blob configuration.
|
// Create new slotter for pre-Osaka blob configuration.
|
||||||
slotter := newSlotter(params.BlobTxMaxBlobs)
|
slotter := newSlotter(params.BlobTxMaxBlobs)
|
||||||
p.newSlotter = func() billy.SlotSizeFn { return newSlotter(params.BlobTxMaxBlobs) }
|
|
||||||
|
|
||||||
// See if we need to migrate the queue blob store after fusaka
|
// See if we need to migrate the queue blob store after fusaka
|
||||||
slotter, err = tryMigrate(p.chain.Config(), slotter, queuedir)
|
slotter, err = tryMigrate(p.chain.Config(), slotter, queuedir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Update the slotter factory if Osaka is active
|
// Build an O(1) slot size calculator from the active slotter configuration.
|
||||||
|
// We need a fresh slotter instance since tryMigrate may have consumed the
|
||||||
|
// previous one, and billy.Open below will consume this one.
|
||||||
if p.chain.Config().OsakaTime != nil {
|
if p.chain.Config().OsakaTime != nil {
|
||||||
p.newSlotter = func() billy.SlotSizeFn { return newSlotterEIP7594(params.BlobTxMaxBlobs) }
|
p.slotter = newSlotSizer(newSlotterEIP7594(params.BlobTxMaxBlobs))
|
||||||
|
} else {
|
||||||
|
p.slotter = newSlotSizer(newSlotter(params.BlobTxMaxBlobs))
|
||||||
}
|
}
|
||||||
// Index all transactions on disk and delete anything unprocessable
|
// Index all transactions on disk and delete anything unprocessable
|
||||||
var fails []uint64
|
var fails []uint64
|
||||||
|
|
@ -1593,7 +1596,7 @@ func (p *BlobPool) addLocked(tx *types.Transaction, checkGapped bool) (err error
|
||||||
|
|
||||||
// Create meta, in preparation of adding to the pool.
|
// Create meta, in preparation of adding to the pool.
|
||||||
// Having the meta simplifies the check below for underpriced transactions.
|
// Having the meta simplifies the check below for underpriced transactions.
|
||||||
// Note: the meta will be finalized with storage information after the transaction is stored
|
// Note: the meta will be finalized with storage information after the transaction is stored.
|
||||||
meta := newBlobTxMeta(tx)
|
meta := newBlobTxMeta(tx)
|
||||||
|
|
||||||
// Calculate the eviction parameters for the transaction
|
// Calculate the eviction parameters for the transaction
|
||||||
|
|
@ -1627,9 +1630,9 @@ func (p *BlobPool) addLocked(tx *types.Transaction, checkGapped bool) (err error
|
||||||
log.Error("Failed to encode transaction for storage", "hash", tx.Hash(), "err", err)
|
log.Error("Failed to encode transaction for storage", "hash", tx.Hash(), "err", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
newStorageSize, err := getSlotSize(p.newSlotter(), uint32(len(blob)))
|
newStorageSize, err := p.slotter.getSlotSize(uint32(len(blob)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// This should also not happen at this stage
|
// This should never happen, but better safe than sorry.
|
||||||
log.Warn("Dropping blob transaction due to size", "tx", tx.Hash(), "size", meta.size, "err", err)
|
log.Warn("Dropping blob transaction due to size", "tx", tx.Hash(), "size", meta.size, "err", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,17 +23,47 @@ import (
|
||||||
"github.com/holiman/billy"
|
"github.com/holiman/billy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getSlotSize return the storage size for a given transaction size based on the current slotter.
|
// slotSizer computes the storage shelf size for a given transaction size using
|
||||||
func getSlotSize(slotter billy.SlotSizeFn, size uint32) (uint32, error) {
|
// O(1) arithmetic. Shelf sizes form an arithmetic sequence:
|
||||||
for {
|
//
|
||||||
slotSize, done := slotter()
|
// base, base+step, base+2*step, ...
|
||||||
if size <= slotSize {
|
//
|
||||||
return slotSize, nil
|
// This mirrors the progression in newSlotter and newSlotterEIP7594, but avoids
|
||||||
}
|
// creating and iterating a stateful closure on every lookup.
|
||||||
if done {
|
type slotSizer struct {
|
||||||
return size, errors.New("size exceeds maximum slot size")
|
base uint32 // Size of the first shelf (txAvgSize)
|
||||||
}
|
step uint32 // Size increment per subsequent shelf
|
||||||
|
max uint32 // Largest valid shelf size
|
||||||
|
}
|
||||||
|
|
||||||
|
// newSlotSizer creates a slotSizer by consuming a slotter closure once to
|
||||||
|
// discover its base size, step size, and maximum shelf size.
|
||||||
|
func newSlotSizer(slotter billy.SlotSizeFn) slotSizer {
|
||||||
|
first, done := slotter()
|
||||||
|
if done {
|
||||||
|
return slotSizer{base: first, step: 0, max: first}
|
||||||
}
|
}
|
||||||
|
second, done := slotter()
|
||||||
|
step := second - first
|
||||||
|
last := second
|
||||||
|
for !done {
|
||||||
|
last, done = slotter()
|
||||||
|
}
|
||||||
|
return slotSizer{base: first, step: step, max: last}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSlotSize returns the shelf size that can store a transaction of the given
|
||||||
|
// byte size, or an error if it exceeds the largest shelf.
|
||||||
|
func (s slotSizer) getSlotSize(size uint32) (uint32, error) {
|
||||||
|
if size <= s.base {
|
||||||
|
return s.base, nil
|
||||||
|
}
|
||||||
|
// Round up to the nearest shelf: base + ⌈(size-base)/step⌉ * step
|
||||||
|
slot := s.base + ((size-s.base+s.step-1)/s.step)*s.step
|
||||||
|
if slot > s.max {
|
||||||
|
return 0, errors.New("size exceeds maximum slot size")
|
||||||
|
}
|
||||||
|
return slot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// tryMigrate checks if the billy needs to be migrated and migrates if needed.
|
// tryMigrate checks if the billy needs to be migrated and migrates if needed.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue