diff --git a/driver/txlist_fetcher/blob.go b/driver/txlist_fetcher/blob.go index 3f17da247..4acc4d5d7 100644 --- a/driver/txlist_fetcher/blob.go +++ b/driver/txlist_fetcher/blob.go @@ -3,7 +3,6 @@ package txlistdecoder import ( "context" "crypto/sha256" - "math/big" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/common" @@ -36,12 +35,12 @@ func (d *BlobFetcher) Fetch( } // Fetch the L1 block sidecars. - sidecars, err := d.rpc.L1Beacon.GetBlobs(ctx, new(big.Int).SetUint64(meta.L1Height+1)) + sidecars, err := d.rpc.L1Beacon.GetBlobs(ctx, meta.Timestamp) if err != nil { return nil, err } - log.Info("Fetch sidecars", "slot", meta.L1Height+1, "sidecars", len(sidecars)) + log.Info("Fetch sidecars", "blockNumber", meta.L1Height+1, "sidecars", len(sidecars)) // Compare the blob hash with the sidecar's kzg commitment. for i, sidecar := range sidecars { diff --git a/pkg/rpc/beaconclient.go b/pkg/rpc/beaconclient.go index f69be6833..1359277ba 100644 --- a/pkg/rpc/beaconclient.go +++ b/pkg/rpc/beaconclient.go @@ -2,16 +2,12 @@ package rpc import ( "context" - "crypto/sha256" "encoding/json" - "errors" "fmt" - "math/big" + "strconv" "time" - "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/log" "github.com/prysmaticlabs/prysm/v4/api/client" "github.com/prysmaticlabs/prysm/v4/api/client/beacon" "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/blob" @@ -20,12 +16,25 @@ import ( var ( // Request urls. sidecarsRequestURL = "eth/v1/beacon/blob_sidecars/%d" + genesisRequestURL = "eth/v1/beacon/genesis" ) +type ConfigSpec struct { + SecondsPerSlot string `json:"SECONDS_PER_SLOT"` +} + +type GenesisResponse struct { + Data struct { + GenesisTime string `json:"genesis_time"` + } `json:"data"` +} + type BeaconClient struct { *beacon.Client - timeout time.Duration + timeout time.Duration + genesisTime uint64 + secondsPerSlot uint64 } // NewBeaconClient returns a new beacon client. @@ -34,43 +43,67 @@ func NewBeaconClient(endpoint string, timeout time.Duration) (*BeaconClient, err if err != nil { return nil, err } - return &BeaconClient{cli, timeout}, nil -} -// GetBlobs returns the sidecars for a given slot. -func (c *BeaconClient) GetBlobs(ctx context.Context, slot *big.Int) ([]*blob.Sidecar, error) { - ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) + ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() - var sidecars *blob.SidecarsResponse - resBytes, err := c.Get(ctxWithTimeout, fmt.Sprintf(sidecarsRequestURL, slot)) + // Get the genesis time. + var genesisDetail *GenesisResponse + resBytes, err := cli.Get(ctx, genesisRequestURL) if err != nil { return nil, err } - return sidecars.Data, json.Unmarshal(resBytes, &sidecars) + if err := json.Unmarshal(resBytes, &genesisDetail); err != nil { + return nil, err + } + + genesisTime, err := strconv.Atoi(genesisDetail.Data.GenesisTime) + if err != nil { + return nil, err + } + + log.Info("L1 genesis time", "time", genesisTime) + + // Get the seconds per slot. + spec, err := cli.GetConfigSpec(ctx) + if err != nil { + return nil, err + } + + secondsPerSlot, err := strconv.Atoi(spec.Data.(map[string]interface{})["SECONDS_PER_SLOT"].(string)) + if err != nil { + return nil, err + } + + log.Info("L1 seconds per slot", "seconds", secondsPerSlot) + + return &BeaconClient{cli, timeout, uint64(genesisTime), uint64(secondsPerSlot)}, nil } -// GetBlobByHash returns the sidecars for a given slot. -func (c *BeaconClient) GetBlobByHash(ctx context.Context, slot *big.Int, blobHash common.Hash) ([]byte, error) { +// GetBlobs returns the sidecars for a given slot. +func (c *BeaconClient) GetBlobs(ctx context.Context, time uint64) ([]*blob.Sidecar, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - sidecars, err := c.GetBlobs(ctxWithTimeout, slot) + slot, err := c.timeToSlot(time) if err != nil { return nil, err } - for _, sidecar := range sidecars { - commitment := kzg4844.Commitment(common.FromHex(sidecar.KzgCommitment)) - if kzg4844.CalcBlobHashV1( - sha256.New(), - &commitment, - ) == blobHash { - blob := eth.Blob(common.FromHex(sidecar.Blob)) - return blob.ToData() - } + var sidecars *blob.SidecarsResponse + resBytes, err := c.Get(ctxWithTimeout, fmt.Sprintf(sidecarsRequestURL, slot)) + if err != nil { + return nil, err } - return nil, errors.New("sidecar not found") + return sidecars.Data, json.Unmarshal(resBytes, &sidecars) +} + +// TimeToSlot returns the slots of the given timestamp. +func (c *BeaconClient) timeToSlot(timestamp uint64) (uint64, error) { + if timestamp < c.genesisTime { + return 0, fmt.Errorf("provided timestamp (%v) precedes genesis time (%v)", timestamp, c.genesisTime) + } + return (timestamp - c.genesisTime) / c.secondsPerSlot, nil }