From 954d6dc421239516150cf039c0403638dde4fe19 Mon Sep 17 00:00:00 2001 From: bnoieh <135800952+bnoieh@users.noreply.github.com> Date: Thu, 25 Apr 2024 20:42:36 +0800 Subject: [PATCH] 4844: derivate blobs from bsc rather than beacon chain --- op-node/node/node.go | 5 ++- op-service/eth/blobs_api.go | 22 ++++++++++ op-service/sources/l1_client.go | 72 +++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/op-node/node/node.go b/op-node/node/node.go index 68526469e4a2..3da88cbdad58 100644 --- a/op-node/node/node.go +++ b/op-node/node/node.go @@ -310,6 +310,9 @@ func (n *OpNode) initRuntimeConfig(ctx context.Context, cfg *Config) error { } func (n *OpNode) initL1BeaconAPI(ctx context.Context, cfg *Config) error { + // BSC use L1 client to fetch blobs + return nil + // If Ecotone upgrade is not scheduled yet, then there is no need for a Beacon API. if cfg.Rollup.EcotoneTime == nil { return nil @@ -409,7 +412,7 @@ func (n *OpNode) initL2(ctx context.Context, cfg *Config, snapshotLog log.Logger } else { n.safeDB = safedb.Disabled } - n.l2Driver = driver.NewDriver(&cfg.Driver, &cfg.Rollup, n.l2Source, n.l1Source, n.beacon, n, n, n.log, snapshotLog, n.metrics, cfg.ConfigPersistence, n.safeDB, &cfg.Sync, sequencerConductor, plasmaDA) + n.l2Driver = driver.NewDriver(&cfg.Driver, &cfg.Rollup, n.l2Source, n.l1Source, n.l1Source, n, n, n.log, snapshotLog, n.metrics, cfg.ConfigPersistence, n.safeDB, &cfg.Sync, sequencerConductor, plasmaDA) return nil } diff --git a/op-service/eth/blobs_api.go b/op-service/eth/blobs_api.go index 3dbff1745bc2..2ceb093b4b2c 100644 --- a/op-service/eth/blobs_api.go +++ b/op-service/eth/blobs_api.go @@ -1,5 +1,11 @@ package eth +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" +) + type BlobSidecar struct { Blob Blob `json:"blob"` Index Uint64String `json:"index"` @@ -66,3 +72,19 @@ type APIVersionResponse struct { type VersionInformation struct { Version string `json:"version"` } + +type BSCBlobTxSidecar struct { + Blobs []Blob `json:"blobs"` // Blobs needed by the blob pool + Commitments []Bytes48 `json:"commitments"` // Commitments needed by the blob pool + Proofs []Bytes48 `json:"proofs"` // Proofs needed by the blob pool +} + +type BSCBlobSidecar struct { + BSCBlobTxSidecar + BlockNumber *big.Int `json:"blockNumber"` + BlockHash common.Hash `json:"blockHash"` + TxIndex uint64 `json:"transactionIndex"` + TxHash common.Hash `json:"transactionHash"` +} + +type BSCBlobSidecars []*BSCBlobSidecar diff --git a/op-service/sources/l1_client.go b/op-service/sources/l1_client.go index a347a17272b3..bea3c199d9a2 100644 --- a/op-service/sources/l1_client.go +++ b/op-service/sources/l1_client.go @@ -3,12 +3,14 @@ package sources import ( "context" "fmt" + "math/big" "strings" "sync" "time" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-node/rollup" @@ -255,6 +257,76 @@ func (s *L1Client) ClearReceiptsCacheBefore(blockNumber uint64) { s.recProvider.GetReceiptsCache().RemoveLessThan(blockNumber) } +func (s *L1Client) GetBlobs(ctx context.Context, ref eth.L1BlockRef, hashes []eth.IndexedBlobHash) ([]*eth.Blob, error) { + if len(hashes) == 0 { + return []*eth.Blob{}, nil + } + + blobSidecars, err := s.getBlobSidecars(ctx, ref) + if err != nil { + return nil, fmt.Errorf("failed to get blob sidecars for L1BlockRef %s: %w", ref, err) + } + + validatedBlobs, err := validateBlobSidecars(blobSidecars, ref) + if err != nil { + return nil, fmt.Errorf("failed to validate blob sidecars for L1BlockRef %s: %w", ref, err) + } + + blobs := make([]*eth.Blob, len(hashes)) + for i, indexedBlobHash := range hashes { + blob, ok := validatedBlobs[indexedBlobHash.Hash] + if !ok { + return nil, fmt.Errorf("blob sidecars fetched from rpc mismatched with expected hash %s for L1BlockRef %s", indexedBlobHash.Hash, ref) + } + blobs[i] = blob + } + return blobs, nil +} + +func (s *L1Client) getBlobSidecars(ctx context.Context, ref eth.L1BlockRef) (eth.BSCBlobSidecars, error) { + var blobSidecars eth.BSCBlobSidecars + err := s.client.CallContext(ctx, &blobSidecars, "eth_getBlobSidecars", numberID(ref.Number).Arg()) + if err != nil { + return nil, err + } + if blobSidecars == nil { + return nil, ethereum.NotFound + } + return blobSidecars, nil +} + +func validateBlobSidecars (blobSidecars eth.BSCBlobSidecars, ref eth.L1BlockRef) (map[common.Hash]*eth.Blob, error) { + if len(blobSidecars) == 0 { + return nil, fmt.Errorf("invalidate api response, blob sidecars of block %s are empty", ref.Hash) + } + blobsMap := make(map[common.Hash]*eth.Blob) + for _, blobSidecar := range blobSidecars { + if blobSidecar.BlockNumber.Cmp(big.NewInt(0).SetUint64(ref.Number)) != 0 { + return nil, fmt.Errorf("invalidate api response of tx %s, expect block number %d, got %d", blobSidecar.TxHash, ref.Number, blobSidecar.BlockNumber.Uint64()) + } + if blobSidecar.BlockHash.Cmp(ref.Hash) != 0 { + return nil, fmt.Errorf("invalidate api response of tx %s, expect block hash %s, got %s", blobSidecar.TxHash, ref.Hash, blobSidecar.BlockHash) + } + if len(blobSidecar.Blobs) == 0 || len(blobSidecar.Blobs) != len(blobSidecar.Commitments) || len(blobSidecar.Blobs) != len(blobSidecar.Proofs) { + return nil, fmt.Errorf("invalidate api response of tx %s, len of blobs/commitments/proofs is not equal or is 0", blobSidecar.TxHash) + } + + for i:=0; i