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,6 +344,13 @@ 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{
@ -356,8 +363,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
Sync: config.SyncMode,
BloomCache: uint64(cacheLimit),
RequiredBlocks: config.RequiredBlocks,
Custody: types.CustodyBitmapAll,
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
// maxCellRequests caps the burst of cell requests we can issue at once
// to a single peer. Worst case 256 * 6 = 1536 cells (~3 MB)
@ -141,6 +143,7 @@ type BlobFetcher struct {
alternates map[common.Hash]map[string]types.CustodyBitmap // In-flight transaction alternate origins (in case the peer is dropped)
fn BlobFetcherFunctions // callbacks
fetchProbability uint64
// peerTokens tracks each peer's remaining cell request token.
peerTokens map[string]*token
@ -157,7 +160,7 @@ 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),
@ -175,6 +178,7 @@ func NewBlobFetcher(fn BlobFetcherFunctions, custody types.CustodyBitmap, rand r
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,
@ -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

@ -122,8 +122,8 @@ type handlerConfig struct {
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
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
}