Skip to content

Commit 7f582c3

Browse files
Merge pull request #4113 from OffchainLabs/post-fusaka-blob-ports
v3.9.x post fusaka blob backports
2 parents 88edd3a + 5f14aab commit 7f582c3

File tree

7 files changed

+508
-395
lines changed

7 files changed

+508
-395
lines changed

arbnode/dataposter/data_poster.go

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -775,29 +775,7 @@ func (p *DataPoster) PostTransaction(ctx context.Context, dataCreatedAt time.Tim
775775
return p.postTransactionWithMutex(ctx, dataCreatedAt, nonce, meta, to, calldata, gasLimit, value, kzgBlobs, accessList)
776776
}
777777

778-
// shouldEnableCellProofs determines whether to use cell proofs based on the config and L1 state.
779-
// Returns true if cell proofs should be used, false otherwise.
780-
func (p *DataPoster) shouldEnableCellProofs(ctx context.Context) (bool, error) {
781-
config := p.config().EnableCellProofs
782-
783-
switch config {
784-
case "force-enable":
785-
return true, nil
786-
case "force-disable":
787-
return false, nil
788-
case "", "auto":
789-
// Auto-detect based on L1 Osaka fork activation
790-
if p.parentChain == nil {
791-
return false, fmt.Errorf("cannot auto-detect cell proof support: parent chain not configured")
792-
}
793-
return p.parentChain.SupportsCellProofs(ctx, nil)
794-
default:
795-
return false, fmt.Errorf("invalid enable-cell-proofs config value: %q (valid values: \"\", \"auto\", \"force-enable\", \"force-disable\")", config)
796-
}
797-
}
798-
799778
func (p *DataPoster) postTransactionWithMutex(ctx context.Context, dataCreatedAt time.Time, nonce uint64, meta []byte, to common.Address, calldata []byte, gasLimit uint64, value *big.Int, kzgBlobs []kzg4844.Blob, accessList types.AccessList) (*types.Transaction, error) {
800-
801779
if p.config().DisableNewTx {
802780
return nil, fmt.Errorf("posting new transaction is disabled")
803781
}
@@ -845,11 +823,7 @@ func (p *DataPoster) postTransactionWithMutex(ctx context.Context, dataCreatedAt
845823
if err != nil {
846824
return nil, fmt.Errorf("failed to compute KZG commitments: %w", err)
847825
}
848-
enableCellProofs, err := p.shouldEnableCellProofs(ctx)
849-
if err != nil {
850-
return nil, fmt.Errorf("failed to determine cell proof support: %w", err)
851-
}
852-
proofs, version, err := blobs.ComputeProofs(kzgBlobs, commitments, enableCellProofs)
826+
proofs, version, err := blobs.ComputeProofs(kzgBlobs, commitments)
853827
if err != nil {
854828
return nil, fmt.Errorf("failed to compute KZG proofs: %w", err)
855829
}
@@ -1354,7 +1328,6 @@ type DataPosterConfig struct {
13541328
MaxFeeBidMultipleBips arbmath.UBips `koanf:"max-fee-bid-multiple-bips" reload:"hot"`
13551329
NonceRbfSoftConfs uint64 `koanf:"nonce-rbf-soft-confs" reload:"hot"`
13561330
Post4844Blobs bool `koanf:"post-4844-blobs" reload:"hot"`
1357-
EnableCellProofs string `koanf:"enable-cell-proofs" reload:"hot"`
13581331
AllocateMempoolBalance bool `koanf:"allocate-mempool-balance" reload:"hot"`
13591332
UseDBStorage bool `koanf:"use-db-storage"`
13601333
UseNoOpStorage bool `koanf:"use-noop-storage"`
@@ -1413,12 +1386,6 @@ type DangerousConfig struct {
14131386

14141387
// Validate checks that the DataPosterConfig is valid.
14151388
func (c *DataPosterConfig) Validate() error {
1416-
switch c.EnableCellProofs {
1417-
case "", "auto", "force-enable", "force-disable":
1418-
// Valid values
1419-
default:
1420-
return fmt.Errorf("invalid enable-cell-proofs value %q (valid: \"\", \"auto\", \"force-enable\", \"force-disable\")", c.EnableCellProofs)
1421-
}
14221389
if len(c.ReplacementTimes) == 0 {
14231390
return fmt.Errorf("replacement-times must have at least one value")
14241391
}
@@ -1479,7 +1446,6 @@ func DataPosterConfigAddOptions(prefix string, f *pflag.FlagSet, defaultDataPost
14791446
f.DurationSlice(prefix+".blob-tx-replacement-times", defaultDataPosterConfig.BlobTxReplacementTimes, "comma-separated list of durations since first posting a blob transaction to attempt a replace-by-fee")
14801447
f.Float64(prefix+".min-blob-tx-tip-cap-gwei", defaultDataPosterConfig.MinBlobTxTipCapGwei, "the minimum tip cap to post EIP-4844 blob carrying transactions at")
14811448
f.Float64(prefix+".max-blob-tx-tip-cap-gwei", defaultDataPosterConfig.MaxBlobTxTipCapGwei, "the maximum tip cap to post EIP-4844 blob carrying transactions at")
1482-
f.String(prefix+".enable-cell-proofs", defaultDataPosterConfig.EnableCellProofs, "enable cell proofs in blob transactions for Fusaka compatibility. Valid values: \"\" or \"auto\" (auto-detect based on L1 Osaka fork), \"force-enable\", \"force-disable\"")
14831449
}
14841450

14851451
// We intentionally don't expose an option to configure Post4844Blobs.
@@ -1515,7 +1481,6 @@ var DefaultDataPosterConfig = DataPosterConfig{
15151481
MaxFeeBidMultipleBips: arbmath.OneInUBips * 10,
15161482
NonceRbfSoftConfs: 1,
15171483
Post4844Blobs: false,
1518-
EnableCellProofs: "", // empty string = auto-detect based on L1 Osaka fork
15191484
AllocateMempoolBalance: true,
15201485
UseDBStorage: true,
15211486
UseNoOpStorage: false,
@@ -1537,7 +1502,6 @@ var DefaultDataPosterConfigForValidator = func() DataPosterConfig {
15371502
config.BlobTxReplacementTimes = nil
15381503
config.MinBlobTxTipCapGwei = 0
15391504
config.MaxBlobTxTipCapGwei = 0
1540-
config.EnableCellProofs = ""
15411505
return config
15421506
}()
15431507

@@ -1557,7 +1521,6 @@ var TestDataPosterConfig = DataPosterConfig{
15571521
MaxFeeBidMultipleBips: arbmath.OneInUBips * 10,
15581522
NonceRbfSoftConfs: 1,
15591523
Post4844Blobs: false,
1560-
EnableCellProofs: "", // empty string = auto-detect based on L1 Osaka fork
15611524
AllocateMempoolBalance: true,
15621525
UseDBStorage: false,
15631526
UseNoOpStorage: false,

arbnode/parent/parent.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -110,27 +110,3 @@ func (p *ParentChain) BlobFeePerByte(ctx context.Context, h *types.Header) (*big
110110
}
111111
return eip4844.CalcBlobFee(pCfg, header), nil
112112
}
113-
114-
// SupportsCellProofs returns whether the parent chain has activated the Osaka fork
115-
// (Fusaka), which introduced cell proofs for blobs.
116-
// Passing in a nil header will use the time from the latest header.
117-
func (p *ParentChain) SupportsCellProofs(ctx context.Context, h *types.Header) (bool, error) {
118-
header := h
119-
if h == nil {
120-
lh, err := p.L1Reader.LastHeader(ctx)
121-
if err != nil {
122-
return false, err
123-
}
124-
header = lh
125-
}
126-
pCfg, err := p.chainConfig()
127-
if err != nil {
128-
return false, err
129-
}
130-
if pCfg.IsArbitrum() {
131-
// Arbitrum does not support blob transactions, so this should not have been called.
132-
return false, nil
133-
}
134-
// arbosVersion 0 because we're checking L1 (not L2 Arbitrum)
135-
return pCfg.IsOsaka(pCfg.LondonBlock, header.Time, 0), nil
136-
}

cmd/blobtool/blobtool.go

Lines changed: 7 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2025, Offchain Labs, Inc.
22
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE.md
33

4-
// This is a command line tool for testing beacon/blobs and blob_sidecars endpoints.
4+
// This is a command line tool for testing beacon/blobs endpoint.
55
package main
66

77
import (
@@ -42,20 +42,16 @@ func main() {
4242
}
4343

4444
type FetchConfig struct {
45-
BeaconURL string `koanf:"beacon-url"`
46-
Slot uint64 `koanf:"slot"`
47-
VersionedHashes []string `koanf:"versioned-hashes"`
48-
UseLegacyEndpoint bool `koanf:"use-legacy-endpoint"`
49-
CompareEndpoints bool `koanf:"compare-endpoints"`
45+
BeaconURL string `koanf:"beacon-url"`
46+
Slot uint64 `koanf:"slot"`
47+
VersionedHashes []string `koanf:"versioned-hashes"`
5048
}
5149

5250
func parseFetchConfig(args []string) (*FetchConfig, error) {
5351
f := flag.NewFlagSet("blobtool fetch", flag.ContinueOnError)
5452
f.String("beacon-url", "", "Beacon Chain RPC URL. For example with --beacon-url=http://localhost, an RPC call will be made to http://localhost/eth/v1/beacon/blobs")
5553
f.Uint64("slot", 0, "Beacon chain slot number to fetch blobs from")
5654
f.StringSlice("versioned-hashes", []string{}, "Comma-separated list of versioned hashes to fetch (optional - fetches all if not provided)")
57-
f.Bool("use-legacy-endpoint", false, "Use the legacy blob_sidecars endpoint")
58-
f.Bool("compare-endpoints", false, "Fetch using both endpoints and compare results")
5955

6056
k, err := confighelpers.BeginCommonParse(f, args)
6157
if err != nil {
@@ -94,20 +90,8 @@ func fetchBlobs(args []string) error {
9490
versionedHashes[i] = common.HexToHash(hashStr)
9591
}
9692

97-
if config.UseLegacyEndpoint && len(versionedHashes) == 0 {
98-
return fmt.Errorf("--versioned-hashes is required when using --use-legacy-endpoint")
99-
}
100-
101-
if config.CompareEndpoints {
102-
if len(versionedHashes) == 0 {
103-
return fmt.Errorf("--versioned-hashes is required when using --compare-endpoints")
104-
}
105-
return compareEndpoints(ctx, config, versionedHashes)
106-
}
107-
10893
blobClientConfig := headerreader.BlobClientConfig{
109-
BeaconUrl: config.BeaconURL,
110-
UseLegacyEndpoint: config.UseLegacyEndpoint,
94+
BeaconUrl: config.BeaconURL,
11195
}
11296

11397
blobClient, err := headerreader.NewBlobClient(blobClientConfig, nil)
@@ -119,15 +103,10 @@ func fetchBlobs(args []string) error {
119103
return fmt.Errorf("failed to initialize blob client: %w", err)
120104
}
121105

122-
endpointType := "new blobs"
123-
if config.UseLegacyEndpoint {
124-
endpointType = "legacy blob_sidecars"
125-
}
126-
127106
if len(versionedHashes) > 0 {
128-
fmt.Printf("Fetching %d blobs for slot %d using %s endpoint...\n", len(versionedHashes), config.Slot, endpointType)
107+
fmt.Printf("Fetching %d blobs for slot %d...\n", len(versionedHashes), config.Slot)
129108
} else {
130-
fmt.Printf("Fetching all blobs for slot %d using %s endpoint...\n", config.Slot, endpointType)
109+
fmt.Printf("Fetching all blobs for slot %d...\n", config.Slot)
131110
}
132111

133112
startTime := time.Now()
@@ -153,82 +132,3 @@ func fetchBlobs(args []string) error {
153132

154133
return nil
155134
}
156-
157-
func compareEndpoints(ctx context.Context, config *FetchConfig, versionedHashes []common.Hash) error {
158-
fmt.Println("Comparing legacy blob_sidecars and new blobs endpoints...")
159-
fmt.Println()
160-
161-
legacyConfig := headerreader.BlobClientConfig{
162-
BeaconUrl: config.BeaconURL,
163-
UseLegacyEndpoint: true,
164-
}
165-
legacyClient, err := headerreader.NewBlobClient(legacyConfig, nil)
166-
if err != nil {
167-
return fmt.Errorf("failed to create legacy blob client: %w", err)
168-
}
169-
if err := legacyClient.Initialize(ctx); err != nil {
170-
return fmt.Errorf("failed to initialize legacy blob client: %w", err)
171-
}
172-
173-
fmt.Println("Fetching with legacy blob_sidecars endpoint...")
174-
legacyStart := time.Now()
175-
legacyBlobs, err := legacyClient.GetBlobsBySlot(ctx, config.Slot, versionedHashes)
176-
legacyDuration := time.Since(legacyStart)
177-
if err != nil {
178-
return fmt.Errorf("failed to fetch blobs with legacy endpoint: %w", err)
179-
}
180-
fmt.Printf("✓ Legacy endpoint: fetched %d blobs in %v\n", len(legacyBlobs), legacyDuration)
181-
fmt.Println()
182-
183-
newConfig := headerreader.BlobClientConfig{
184-
BeaconUrl: config.BeaconURL,
185-
UseLegacyEndpoint: false,
186-
}
187-
newClient, err := headerreader.NewBlobClient(newConfig, nil)
188-
if err != nil {
189-
return fmt.Errorf("failed to create new blob client: %w", err)
190-
}
191-
if err := newClient.Initialize(ctx); err != nil {
192-
return fmt.Errorf("failed to initialize new blob client: %w", err)
193-
}
194-
195-
fmt.Println("Fetching with new blobs endpoint...")
196-
newStart := time.Now()
197-
newBlobs, err := newClient.GetBlobsBySlot(ctx, config.Slot, versionedHashes)
198-
newDuration := time.Since(newStart)
199-
if err != nil {
200-
return fmt.Errorf("failed to fetch blobs with new endpoint: %w", err)
201-
}
202-
fmt.Printf("✓ New endpoint: fetched %d blobs in %v\n", len(newBlobs), newDuration)
203-
fmt.Println()
204-
205-
if len(legacyBlobs) != len(newBlobs) {
206-
return fmt.Errorf("blob count mismatch: legacy=%d, new=%d", len(legacyBlobs), len(newBlobs))
207-
}
208-
209-
fmt.Println("Comparing blob data...")
210-
for i := range legacyBlobs {
211-
if legacyBlobs[i] != newBlobs[i] {
212-
return fmt.Errorf("blob %d data mismatch", i)
213-
}
214-
_, hashes, err := blobs.ComputeCommitmentsAndHashes([]kzg4844.Blob{legacyBlobs[i]})
215-
if err != nil {
216-
return fmt.Errorf("failed to compute hash for blob %d: %w", i, err)
217-
}
218-
fmt.Printf(" Blob %d: ✓ identical (%s)\n", i, hashes[0].Hex())
219-
}
220-
221-
fmt.Println()
222-
fmt.Printf("Performance comparison:\n")
223-
fmt.Printf(" Legacy endpoint: %v\n", legacyDuration)
224-
fmt.Printf(" New endpoint: %v\n", newDuration)
225-
if newDuration < legacyDuration {
226-
improvement := float64(legacyDuration-newDuration) / float64(legacyDuration) * 100
227-
fmt.Printf(" New endpoint is %.1f%% faster\n", improvement)
228-
} else {
229-
slower := float64(newDuration-legacyDuration) / float64(legacyDuration) * 100
230-
fmt.Printf(" New endpoint is %.1f%% slower\n", slower)
231-
}
232-
233-
return nil
234-
}

util/blobs/blobs.go

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -128,36 +128,21 @@ func ComputeCommitmentsAndHashes(blobs []kzg4844.Blob) ([]kzg4844.Commitment, []
128128
return commitments, versionedHashes, nil
129129
}
130130

131-
// ComputeProofs computes either legacy blob proofs (Version0) or cell proofs (Version1)
132-
// based on the enableCellProofs flag. Returns proofs, version byte, and error.
133-
func ComputeProofs(blobs []kzg4844.Blob, commitments []kzg4844.Commitment, enableCellProofs bool) ([]kzg4844.Proof, byte, error) {
131+
// ComputeProofs computes cell proofs for the given blobs.
132+
// Each blob generates CellProofsPerBlob (128) proofs.
133+
// Returns proofs, version byte (always 1), and error.
134+
func ComputeProofs(blobs []kzg4844.Blob, commitments []kzg4844.Commitment) ([]kzg4844.Proof, byte, error) {
134135
if len(blobs) != len(commitments) {
135136
return nil, 0, fmt.Errorf("ComputeProofs got %v blobs but %v commitments", len(blobs), len(commitments))
136137
}
137138

138-
if enableCellProofs {
139-
// Version1: Use cell proofs for Fusaka compatibility
140-
// Each blob generates CellProofsPerBlob (128) proofs
141-
proofs := make([]kzg4844.Proof, 0, len(blobs)*kzg4844.CellProofsPerBlob)
142-
for i := range blobs {
143-
cellProofs, err := kzg4844.ComputeCellProofs(&blobs[i])
144-
if err != nil {
145-
return nil, 0, fmt.Errorf("failed to compute cell proofs for blob %d: %w", i, err)
146-
}
147-
proofs = append(proofs, cellProofs...)
148-
}
149-
return proofs, 1, nil // BlobSidecarVersion1
150-
}
151-
152-
// Version0: Use legacy blob proofs (pre-Fusaka)
153-
// Each blob generates 1 proof
154-
proofs := make([]kzg4844.Proof, len(blobs))
139+
proofs := make([]kzg4844.Proof, 0, len(blobs)*kzg4844.CellProofsPerBlob)
155140
for i := range blobs {
156-
var err error
157-
proofs[i], err = kzg4844.ComputeBlobProof(&blobs[i], commitments[i])
141+
cellProofs, err := kzg4844.ComputeCellProofs(&blobs[i])
158142
if err != nil {
159-
return nil, 0, fmt.Errorf("failed to compute blob proof for blob %d: %w", i, err)
143+
return nil, 0, fmt.Errorf("failed to compute cell proofs for blob %d: %w", i, err)
160144
}
145+
proofs = append(proofs, cellProofs...)
161146
}
162-
return proofs, 0, nil // BlobSidecarVersion0
147+
return proofs, 1, nil
163148
}

0 commit comments

Comments
 (0)