eth, cmd: add flag for fetch probability (blobpool.fetchprobability)

This commit is contained in:
healthykim 2026-06-22 14:21:18 +02:00
parent 5e737101e6
commit cfcd8aa797
7 changed files with 84 additions and 51 deletions

View file

@ -75,6 +75,7 @@ var (
utils.BlobPoolDataDirFlag,
utils.BlobPoolDataCapFlag,
utils.BlobPoolPriceBumpFlag,
utils.BlobPoolFetchProbabilityFlag,
utils.SyncModeFlag,
utils.SyncTargetFlag,
utils.ExitWhenSyncedFlag,

View file

@ -48,6 +48,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/eth/fetcher"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/eth/syncer"
@ -497,6 +498,12 @@ var (
Value: ethconfig.Defaults.BlobPool.PriceBump,
Category: flags.BlobPoolCategory,
}
BlobPoolFetchProbabilityFlag = &cli.Uint64Flag{
Name: "blobpool.fetchprobability",
Usage: "Probability of fetching the full blob payload for sparse blobpool",
Value: fetcher.DefaultFetchProbability,
Category: flags.BlobPoolCategory,
}
// Performance tuning settings
CacheFlag = &cli.IntFlag{
Name: "cache",
@ -1669,6 +1676,10 @@ func setBlobPool(ctx *cli.Context, cfg *blobpool.Config) {
if ctx.IsSet(BlobPoolPriceBumpFlag.Name) {
cfg.PriceBump = ctx.Uint64(BlobPoolPriceBumpFlag.Name)
}
if ctx.IsSet(BlobPoolFetchProbabilityFlag.Name) {
v := ctx.Uint64(BlobPoolFetchProbabilityFlag.Name)
cfg.FetchProbability = &v
}
}
func setMiner(ctx *cli.Context, cfg *miner.Config) {

View file

@ -25,6 +25,8 @@ type Config struct {
Datadir string // Data directory containing the currently executable blobs
Datacap uint64 // Soft-cap of database storage (hard cap is larger due to overhead)
PriceBump uint64 // Minimum price bump percentage to replace an already existing nonce
FetchProbability *uint64 // EIP-8070: full blob fetch probability for sparse blobpool
}
// DefaultConfig contains the default configurations for the transaction pool.

View file

@ -344,20 +344,27 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
stack.RegisterLifecycle(eth.localTxTracker)
}
var fetchProb uint64
if config.BlobPool.FetchProbability != nil {
fetchProb = *config.BlobPool.FetchProbability
} else {
fetchProb = fetcher.DefaultFetchProbability
}
// Permit the downloader to use the trie cache allowance during fast sync
cacheLimit := options.TrieCleanLimit + options.TrieDirtyLimit + options.SnapshotLimit
if eth.handler, err = newHandler(&handlerConfig{
NodeID: eth.p2pServer.Self().ID(),
Database: chainDb,
Chain: eth.blockchain,
TxPool: eth.txPool,
BlobPool: eth.blobTxPool,
Network: networkID,
Sync: config.SyncMode,
BloomCache: uint64(cacheLimit),
RequiredBlocks: config.RequiredBlocks,
Custody: types.CustodyBitmapAll,
SnapV2: config.SnapV2,
NodeID: eth.p2pServer.Self().ID(),
Database: chainDb,
Chain: eth.blockchain,
TxPool: eth.txPool,
BlobPool: eth.blobTxPool,
Network: networkID,
Sync: config.SyncMode,
BloomCache: uint64(cacheLimit),
RequiredBlocks: config.RequiredBlocks,
SnapV2: config.SnapV2,
FetchProbability: fetchProb,
}); err != nil {
return nil, err
}

View file

@ -41,12 +41,14 @@ type random interface {
var blobFetchTimeout = 5 * time.Second
var blobAvailabilityTimeout = 2 * time.Second
// DefaultFetchProbability is the default probability of fetching the full blob
// payload for the sparse blobpool.
const DefaultFetchProbability = 15
const (
availabilityThreshold = 2
maxPayloadRetrievals = 128
maxPayloadAnnounces = 4096
fetchProbability = 15
MAX_CELLS_PER_PARTIAL_REQUEST = 8
availabilityThreshold = 2
maxPayloadRetrievals = 128
maxPayloadAnnounces = 4096
// maxCellRequests caps the burst of cell requests we can issue at once
// to a single peer. Worst case 256 * 6 = 1536 cells (~3 MB)
@ -140,7 +142,8 @@ type BlobFetcher struct {
requests map[string][]*cellRequest // In-flight transaction retrievals
alternates map[common.Hash]map[string]types.CustodyBitmap // In-flight transaction alternate origins (in case the peer is dropped)
fn BlobFetcherFunctions // callbacks
fn BlobFetcherFunctions // callbacks
fetchProbability uint64
// peerTokens tracks each peer's remaining cell request token.
peerTokens map[string]*token
@ -157,28 +160,29 @@ type token struct {
last mclock.AbsTime
}
func NewBlobFetcher(fn BlobFetcherFunctions, custody types.CustodyBitmap, rand random) *BlobFetcher {
func NewBlobFetcher(fn BlobFetcherFunctions, custody types.CustodyBitmap, rand random, fetchProbability uint64) *BlobFetcher {
return &BlobFetcher{
notify: make(chan *blobTxAnnounce),
cleanup: make(chan *payloadDelivery),
drop: make(chan *txDrop),
custodyCh: make(chan types.CustodyBitmap),
quit: make(chan struct{}),
full: make(map[common.Hash]struct{}),
partial: make(map[common.Hash]struct{}),
waitlist: make(map[common.Hash]map[string]struct{}),
waittime: make(map[common.Hash]mclock.AbsTime),
waitslots: make(map[string]map[common.Hash]struct{}),
announces: make(map[string]map[common.Hash]*cellWithSeq),
fetches: make(map[common.Hash]*fetchStatus),
requests: make(map[string][]*cellRequest),
alternates: make(map[common.Hash]map[string]types.CustodyBitmap),
peerTokens: make(map[string]*token),
fn: fn,
custody: custody,
clock: mclock.System{},
realTime: time.Now,
rand: rand,
notify: make(chan *blobTxAnnounce),
cleanup: make(chan *payloadDelivery),
drop: make(chan *txDrop),
custodyCh: make(chan types.CustodyBitmap),
quit: make(chan struct{}),
full: make(map[common.Hash]struct{}),
partial: make(map[common.Hash]struct{}),
waitlist: make(map[common.Hash]map[string]struct{}),
waittime: make(map[common.Hash]mclock.AbsTime),
waitslots: make(map[string]map[common.Hash]struct{}),
announces: make(map[string]map[common.Hash]*cellWithSeq),
fetches: make(map[common.Hash]*fetchStatus),
requests: make(map[string][]*cellRequest),
alternates: make(map[common.Hash]map[string]types.CustodyBitmap),
peerTokens: make(map[string]*token),
fn: fn,
fetchProbability: fetchProbability,
custody: custody,
clock: mclock.System{},
realTime: time.Now,
rand: rand,
}
}
@ -295,7 +299,7 @@ func (f *BlobFetcher) loop() {
randomValue = f.rand.Intn(100)
}
// For eager mode, always fetch immediately
if randomValue < fetchProbability || f.custody.OneCount() >= kzg4844.DataPerBlob {
if uint64(randomValue) < f.fetchProbability || f.custody.OneCount() >= kzg4844.DataPerBlob {
f.full[hash] = struct{}{}
} else {
f.partial[hash] = struct{}{}

View file

@ -162,6 +162,7 @@ func TestBlobFetcherFullFetch(t *testing.T) {
},
custody,
&mockRand{value: 5}, // Force full requests (5 < fetchProbability)
15,
)
},
steps: []interface{}{
@ -253,6 +254,7 @@ func TestBlobFetcherPartialFetch(t *testing.T) {
},
custody,
&mockRand{value: 60}, // Force partial requests (20 >= 15)
15,
)
},
steps: []interface{}{
@ -345,6 +347,7 @@ func TestBlobFetcherFullDelivery(t *testing.T) {
},
custody,
&mockRand{value: 5}, // Force full requests for simplicity
15,
)
},
steps: []interface{}{
@ -393,6 +396,7 @@ func TestBlobFetcherPartialDelivery(t *testing.T) {
},
custody,
&mockRand{value: 60},
15,
)
},
steps: []interface{}{
@ -529,6 +533,7 @@ func TestBlobFetcherAvailabilityTimeout(t *testing.T) {
},
custody,
&mockRand{value: 60},
15,
)
},
steps: []interface{}{
@ -571,6 +576,7 @@ func TestBlobFetcherPeerDrop(t *testing.T) {
},
custody,
&mockRand{value: 5},
15,
)
},
steps: []interface{}{
@ -648,6 +654,7 @@ func TestBlobFetcherFetchTimeout(t *testing.T) {
},
custody,
&mockRand{value: 5},
15,
)
},
steps: []interface{}{
@ -1044,6 +1051,7 @@ func TestMultiBlobDeliveryVerification(t *testing.T) {
},
custody,
&mockRand{value: 60}, // Force partial requests (60 >= fetchProbability)
15,
)
},
steps: []interface{}{

View file

@ -113,17 +113,17 @@ type blobPool interface {
// handlerConfig is the collection of initialization parameters to create a full
// node network handler.
type handlerConfig struct {
NodeID enode.ID // P2P node ID used for tx propagation topology
Database ethdb.Database // Database for direct sync insertions
Chain *core.BlockChain // Blockchain to serve data from
TxPool txPool // Transaction pool to propagate from
BlobPool blobPool // Blob pool for cell-based blob data availability
Network uint64 // Network identifier to advertise
Sync ethconfig.SyncMode // Whether to snap or full sync
BloomCache uint64 // Megabytes to alloc for snap sync bloom
RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges
Custody types.CustodyBitmap
SnapV2 bool // Whether to advertise and sync via the snap/2 protocol
NodeID enode.ID // P2P node ID used for tx propagation topology
Database ethdb.Database // Database for direct sync insertions
Chain *core.BlockChain // Blockchain to serve data from
TxPool txPool // Transaction pool to propagate from
BlobPool blobPool // Blob pool for cell-based blob data availability
Network uint64 // Network identifier to advertise
Sync ethconfig.SyncMode // Whether to snap or full sync
BloomCache uint64 // Megabytes to alloc for snap sync bloom
RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges
SnapV2 bool // Whether to advertise and sync via the snap/2 protocol
FetchProbability uint64 // Full blob fetch probability for sparse blobpool (blobFetcher)
}
type handler struct {
@ -231,7 +231,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
},
DropPeer: h.removePeer,
}
h.blobFetcher = fetcher.NewBlobFetcher(blobCallbacks, config.Custody, nil)
h.blobFetcher = fetcher.NewBlobFetcher(blobCallbacks, types.CustodyBitmapAll, nil, config.FetchProbability)
return h, nil
}