-
Notifications
You must be signed in to change notification settings - Fork 644
Add support for new beacon chain /blobs endpoint #3826
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for new beacon chain /blobs endpoint #3826
Conversation
This change adds support for the new beacon chain endpoint `/eth/v1/beacon/blobs/{block_id}` introduced in Fusaka while maintaining backward compatibility with the legacy endpoint `/eth/v1/beacon/blob_sidecars/{slot}`. block_id can be a slot so Nitro just uses slot. The new endpoint supports server-side filtering by versioned hash via query parameters. Since the Arbitrum sequencer inbox message contains the versioned hashes of the blobs that were posted, we can include those in the query. Key changes: - Added `UseLegacyEndpoint` flag to BlobClientConfig to control which endpoint to use - Created new `GetBlobsBySlot()` public method for direct slot-based blob fetching - Implemented `getBlobs()` method for the new endpoint with versioned hash verification - Updated `beaconRequest()` to support query parameters for filtering - Added KZG commitment verification when versioned hashes are provided Created `blobtool` CLI utility for testing both endpoints: ``` # Fetch specific blob using new endpoint (default) blobtool fetch --beacon-url=<url> --slot=<slot> --versioned-hashes=<hash> # Fetch using legacy endpoint (requires versioned hashes) blobtool fetch --beacon-url=<url> --slot=<slot> --versioned-hashes=<hash> --use-legacy-endpoint # Compare both endpoints side-by-side blobtool fetch --beacon-url=<url> --slot=<slot> --versioned-hashes=<hash> --compare-endpoints ``` The new endpoint is used by default, with automatic fallback behavior maintained through the existing secondary beacon URL mechanism. Spec reference: https://github.com/ethereum/beacon-APIs/blob/master/apis/beacon/blobs/blobs.yaml
queryParams.Add("versioned_hashes", hash.Hex()) | ||
} | ||
|
||
response, err := beaconRequest[[]hexutil.Bytes](b, ctx, fmt.Sprintf("/eth/v1/beacon/blobs/%d", slot), queryParams) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for others looking at this pr,
confirmed this was intentional, if versioned hashes are not provided all will be returned, this was intentional to add the query params
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, when posting 4844 enabled batches the sequencer inbox message contains the versioned hashes as calldata. So the new API is actually really nice because we can only fetch what we need, in the order we want it, and also we can verify the blobs retrieved against the versioned hash.
func beaconRequest[T interface{}](b *BlobClient, ctx context.Context, beaconPath string) (T, error) { | ||
// Unfortunately, methods on a struct can't be generic. | ||
|
||
func beaconRequest[T interface{}](b *BlobClient, ctx context.Context, beaconPath string, queryParams url.Values) (T, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prysm should learn from this request setup ( we could also use some generics here)
var blobs []kzg4844.Blob | ||
var err error | ||
if b.useLegacyEndpoint { | ||
blobs, err = b.blobSidecars(ctx, slot, versionedHashes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use versionedHashes on the legacy endpoint, it's blob indicies
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a quirk of how our blob fetching works for Nitro for the legacy endpoint since does client side filtering to filter out non related blobs.
|
||
func (b *BlobClient) blobSidecars(ctx context.Context, slot uint64, versionedHashes []common.Hash) ([]kzg4844.Blob, error) { | ||
rawData, err := beaconRequest[json.RawMessage](b, ctx, fmt.Sprintf("/eth/v1/beacon/blob_sidecars/%d", slot)) | ||
rawData, err := beaconRequest[json.RawMessage](b, ctx, fmt.Sprintf("/eth/v1/beacon/blob_sidecars/%d", slot), nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh good, it's nil here, right we don't use versioned hashes here do we need to provide that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, the versioned hashes are just used for client side filtering for the old endpoint, since we don't know what index a particular blob is at we had to do it entirely client side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Why even pass in versionedHashes
if they aren't going to be used in the body of the function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please see my reponse to James
if queryParams != nil { | ||
beaconUrl.RawQuery = queryParams.Encode() | ||
} | ||
req, err := http.NewRequestWithContext(ctx, "GET", beaconUrl.String(), http.NoBody) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
response might be faster with ssz type instead of json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works now so we can leave this for later.
} | ||
|
||
if config.UseLegacyEndpoint && len(versionedHashes) == 0 { | ||
return fmt.Errorf("--versioned-hashes is required when using --use-legacy-endpoint") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is correct? ( or are you using versioned hashes for something else outside of the endpoint query)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be required when not using the new endpoint (based on implementation?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a quirk of how our blob fetching works for Nitro for the legacy endpoint since does client side filtering to filter out non related blobs.
cmd/blobtool/blobtool.go
Outdated
|
||
func parseFetchConfig(args []string) (*FetchConfig, error) { | ||
f := flag.NewFlagSet("blobtool fetch", flag.ContinueOnError) | ||
f.String("beacon-url", "", "Beacon Chain RPC URL") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you document how much of the URL is expected? Or, maybe provide a default, or an example?
I take it that we don't include the "/blobs" part of the URL, but do we stop at v1
or just before eth
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just the base url, so none of the /eth/v1/beacon
stuff. I don't know what to include as a default.
|
||
func (b *BlobClient) blobSidecars(ctx context.Context, slot uint64, versionedHashes []common.Hash) ([]kzg4844.Blob, error) { | ||
rawData, err := beaconRequest[json.RawMessage](b, ctx, fmt.Sprintf("/eth/v1/beacon/blob_sidecars/%d", slot)) | ||
rawData, err := beaconRequest[json.RawMessage](b, ctx, fmt.Sprintf("/eth/v1/beacon/blob_sidecars/%d", slot), nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Why even pass in versionedHashes
if they aren't going to be used in the body of the function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## v3.7.0-backports #3826 +/- ##
====================================================
+ Coverage 22.68% 22.73% +0.04%
====================================================
Files 383 383
Lines 58209 58253 +44
====================================================
+ Hits 13206 13241 +35
- Misses 42963 42981 +18
+ Partials 2040 2031 -9 |
This change adds support for the new beacon chain endpoint
/eth/v1/beacon/blobs/{block_id}
introduced in Fusaka while maintaining backward compatibility with the legacy endpoint/eth/v1/beacon/blob_sidecars/{slot}
. block_id can be a slot so Nitro just uses slot.The new endpoint supports server-side filtering by versioned hash via query parameters. Since the Arbitrum sequencer inbox message contains the versioned hashes of the blobs that were posted, we can include those in the query.
Key changes:
UseLegacyEndpoint
flag to BlobClientConfig to control which endpoint to useGetBlobsBySlot()
public method for direct slot-based blob fetchinggetBlobs()
method for the new endpoint with versioned hash verificationbeaconRequest()
to support query parameters for filteringCreated
blobtool
CLI utility for testing both endpoints:The new endpoint is used by default, with automatic fallback behavior maintained through the existing secondary beacon URL mechanism.
Spec reference: https://github.com/ethereum/beacon-APIs/blob/master/apis/beacon/blobs/blobs.yaml
Testing
To test the new fetching method I added a new tool called
blobtool
. It's intended to be used for testing beacon endpoints, and it can use either the new or old method for fetching blobs. This is even more important after Fusaka where it is even more difficult to configure beacon nodes to have and keep all blobs. In future we may want to add some features like looking up blobs by block number, which is something operators often want to do.