From 312c24a40b9f2c6338a23afc08c63d421665fc10 Mon Sep 17 00:00:00 2001 From: Alexxxxxx <118710506+alexgao001@users.noreply.github.com> Date: Mon, 24 Jun 2024 20:41:51 +0800 Subject: [PATCH] feat: support bsc (#6) * enhancement and grpc server * feat: support BSC * feat: bump go to 1.22 * fix pipeline * clean code * adapt BSC RPC and add blob extra field grant allowance --- .github/workflows/build.yml | 2 +- .github/workflows/gosec.yml | 2 +- .github/workflows/lint.yml | 2 +- README.md | 2 +- client/blob_server.go | 94 ++++ config/config.go | 47 +- config/const.go | 2 +- db/blob.go | 1 + db/dao.go | 17 +- external/client.go | 165 ++++++ external/{ => cmn}/bundle_client.go | 2 +- external/{ => cmn}/sp_client.go | 2 +- external/{ => cmn}/types.go | 2 +- external/{ => eth}/beacon_client.go | 8 +- external/eth_client.go | 31 -- go.mod | 16 +- go.sum | 60 ++ google/api/BUILD.bazel | 27 + google/api/annotations.proto | 31 ++ google/api/http.proto | 375 +++++++++++++ metrics/metric.go | 8 +- models/b_s_c_blob_sidecar.go | 56 ++ models/b_s_c_blob_tx_sidecar.go | 116 ++++ models/rpc_error.go | 55 ++ models/rpc_request.go | 63 +++ models/rpc_response.go | 170 ++++++ models/sidecar.go | 8 +- proto/blob.pb.go | 527 ++++++++++++++++++ proto/blob.pb.gw.go | 207 +++++++ proto/blob.proto | 47 ++ proto/blob_grpc.pb.go | 101 ++++ restapi/configure_blob_hub.go | 58 +- restapi/doc.go | 2 +- restapi/embedded_spec.go | 320 ++++++++++- restapi/handlers/blob.go | 86 ++- .../get_b_s_c_blob_sidecars_by_block_num.go | 56 ++ ...c_blob_sidecars_by_block_num_parameters.go | 84 +++ ..._c_blob_sidecars_by_block_num_responses.go | 104 ++++ ...c_blob_sidecars_by_block_num_urlbuilder.go | 84 +++ .../blob/get_blob_sidecars_by_block_num.go | 2 +- ...t_blob_sidecars_by_block_num_urlbuilder.go | 5 +- restapi/operations/blob_hub_api.go | 14 +- scripts/.env | 8 +- server-distroless.dockerfile | 2 +- service/blob.go | 53 +- swagger.yaml | 115 +++- syncer-distroless.dockerfile | 2 +- syncer/syncer.go | 414 ++++++++------ syncer/verifier.go | 119 ++-- types/key.go | 2 + types/types.go | 12 + util/util.go | 14 + 52 files changed, 3462 insertions(+), 340 deletions(-) create mode 100644 client/blob_server.go create mode 100644 external/client.go rename external/{ => cmn}/bundle_client.go (99%) rename external/{ => cmn}/sp_client.go (98%) rename external/{ => cmn}/types.go (98%) rename external/{ => eth}/beacon_client.go (90%) delete mode 100644 external/eth_client.go create mode 100644 google/api/BUILD.bazel create mode 100644 google/api/annotations.proto create mode 100644 google/api/http.proto create mode 100644 models/b_s_c_blob_sidecar.go create mode 100644 models/b_s_c_blob_tx_sidecar.go create mode 100644 models/rpc_error.go create mode 100644 models/rpc_request.go create mode 100644 models/rpc_response.go create mode 100644 proto/blob.pb.go create mode 100644 proto/blob.pb.gw.go create mode 100644 proto/blob.proto create mode 100644 proto/blob_grpc.pb.go create mode 100644 restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num.go create mode 100644 restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_parameters.go create mode 100644 restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_responses.go create mode 100644 restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_urlbuilder.go create mode 100644 types/types.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c8bea1..5774b7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: build-test: strategy: matrix: - go-version: [1.20.x] + go-version: [1.22.x] os: [ubuntu-latest] runs-on: ${{ matrix.os }} env: diff --git a/.github/workflows/gosec.yml b/.github/workflows/gosec.yml index 8b82c0b..d4d39d2 100644 --- a/.github/workflows/gosec.yml +++ b/.github/workflows/gosec.yml @@ -14,7 +14,7 @@ jobs: name: gosec strategy: matrix: - go-version: [1.20.x] + go-version: [1.22.x] os: [ubuntu-latest] runs-on: ${{ matrix.os }} env: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f3a64f8..6ba7d44 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,7 +14,7 @@ jobs: name: golangci-lint strategy: matrix: - go-version: [1.20.x] + go-version: [1.22.x] os: [ubuntu-latest] runs-on: ${{ matrix.os }} env: diff --git a/README.md b/README.md index 449a982..48d1c0f 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ Once the bundle is downloaded and extracted, all original blob files can be foun ### Requirement -Go version above 1.20 +Go version above 1.22 ### Create a bucket on Greenfield diff --git a/client/blob_server.go b/client/blob_server.go new file mode 100644 index 0000000..54170b5 --- /dev/null +++ b/client/blob_server.go @@ -0,0 +1,94 @@ +package client + +import ( + "context" + "encoding/hex" + "fmt" + + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/bnb-chain/blob-hub/models" + blobproto "github.com/bnb-chain/blob-hub/proto" + "github.com/bnb-chain/blob-hub/service" + "github.com/bnb-chain/blob-hub/types" + "github.com/bnb-chain/blob-hub/util" +) + +type BlobServer struct { + blobproto.UnimplementedBlobServiceServer + service.Blob +} + +func (s *BlobServer) GetBlobSidecars(ctx context.Context, req *blobproto.GetBlobSidecarsRequest) (*blobproto.GetBlobSidecarsResponse, error) { + if req == nil { + return nil, fmt.Errorf("invalid request") + } + blockID := req.GetBlockId() + indices := req.GetIndices() + + var root []byte + switch blockID { + case "genesis", "finalized": + return nil, fmt.Errorf("block identifier not supported, only and ") + default: + var ( + err error + sidecars []*models.Sidecar + ) + + indicesInx := make([]int64, 0) + for _, idx := range indices { + i, err := util.StringToInt64(idx) + if err != nil { + return nil, err + } + indicesInx = append(indicesInx, i) + } + root, err = hexutil.Decode(blockID) + if err == nil { + if len(root) != types.RootLength { + return nil, fmt.Errorf("invalid block root of length %d", len(root)) + } + sidecars, err = service.BlobSvc.GetBlobSidecarsByRoot(hex.EncodeToString(root), indicesInx) + if err != nil { + return nil, err + } + } else { + blockNumOrSlot, err := util.StringToUint64(blockID) + if err != nil { + return nil, err + } + sidecars, err = service.BlobSvc.GetBlobSidecarsByBlockNumOrSlot(blockNumOrSlot, indicesInx) + if err != nil { + return nil, err + } + } + data := make([]*blobproto.SideCar, 0) + for _, sc := range sidecars { + data = append( + data, + &blobproto.SideCar{ + Blob: sc.Blob, + Index: sc.Index, + KzgCommitment: sc.KzgCommitment, + KzgCommitmentInclusionProof: sc.KzgCommitmentInclusionProof, + KzgProof: sc.KzgProof, + SignedBlockHeader: &blobproto.SignedBeaconBlockHeader{ + Message: &blobproto.BeaconBlockHeader{ + BodyRoot: sc.SignedBlockHeader.Message.BodyRoot, + ParentRoot: sc.SignedBlockHeader.Message.ParentRoot, + StateRoot: sc.SignedBlockHeader.Message.StateRoot, + Slot: sc.SignedBlockHeader.Message.Slot, + ProposerIndex: sc.SignedBlockHeader.Message.ProposerIndex, + }, + Signature: sc.SignedBlockHeader.Signature, + }, + }, + ) + } + return &blobproto.GetBlobSidecarsResponse{ + Data: data, + }, nil + } + +} diff --git a/config/config.go b/config/config.go index 90b031b..612dfa6 100644 --- a/config/config.go +++ b/config/config.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "os" + "strings" "time" "gorm.io/driver/mysql" @@ -15,13 +16,19 @@ import ( syncerdb "github.com/bnb-chain/blob-hub/db" ) +const ( + ETH = "ETH" + BSC = "BSC" +) + type SyncerConfig struct { - BucketName string `json:"bucket_name"` // BucketName is the identifier of bucket on Greenfield that store blob - StartSlot uint64 `json:"start_slot"` // StartSlot is used to init the syncer which slot of beacon chain to synced from, only need to provide once. - CreateBundleSlotInterval uint64 `json:"create_bundle_slot_interval"` // CreateBundleSlotInterval defines the number of slot that syncer would assemble blobs and upload to bundle service - BundleServiceEndpoints []string `json:"bundle_service_endpoints"` // BundleServiceEndpoints is a list of bundle service address - BeaconRPCAddrs []string `json:"beacon_rpc_addrs"` // BeaconRPCAddrs is a list of beacon chain RPC address - ETHRPCAddrs []string `json:"eth_rpc_addrs"` + Chain string `json:"chain"` // support ETH and BSC + BucketName string `json:"bucket_name"` // BucketName is the identifier of bucket on Greenfield that store blob + StartSlotOrBlock uint64 `json:"start_slot_or_block"` // StartSlotOrBlock is used to init the syncer which slot of beacon chain to synced from, only need to provide once. + CreateBundleSlotOrBlockInterval uint64 `json:"create_bundle_slot_or_block_interval"` // CreateBundleSlotOrBlockInterval defines the number of slot that syncer would assemble blobs and upload to bundle service + BundleServiceEndpoints []string `json:"bundle_service_endpoints"` // BundleServiceEndpoints is a list of bundle service address + BeaconRPCAddrs []string `json:"beacon_rpc_addrs"` // BeaconRPCAddrs is a list of beacon chain RPC address + RPCAddrs []string `json:"rpc_addrs"` // RPCAddrs ETH or BSC RPC addr TempDir string `json:"temp_dir"` // TempDir is used to store blobs and created bundle PrivateKey string `json:"private_key"` // PrivateKey is the key of bucket owner, request to bundle service will be signed by it as well. BundleNotSealedReuploadThreshold int64 `json:"bundle_not_sealed_reupload_threshold"` // BundleNotSealedReuploadThreshold for re-uploading a bundle if it cant be sealed within the time threshold. @@ -31,19 +38,22 @@ type SyncerConfig struct { } func (s *SyncerConfig) Validate() { + if !strings.EqualFold(s.Chain, ETH) && !strings.EqualFold(s.Chain, BSC) { + panic("chain not support") + } if len(s.BucketName) == 0 { panic("the Greenfield bucket name is not is not provided") } - if s.StartSlot == 0 { + if s.StartSlotOrBlock == 0 { panic("the start slot to sync slot is not provided") } if len(s.BundleServiceEndpoints) == 0 { panic("BundleService endpoints should not be empty") } - if len(s.BeaconRPCAddrs) == 0 { + if s.Chain == ETH && len(s.BeaconRPCAddrs) == 0 { panic("beacon rpc address should not be empty") } - if len(s.ETHRPCAddrs) == 0 { + if len(s.RPCAddrs) == 0 { panic("eth rpc address should not be empty") } if len(s.TempDir) == 0 { @@ -52,21 +62,24 @@ func (s *SyncerConfig) Validate() { if len(s.PrivateKey) == 0 { panic("private key is not provided") } - if s.CreateBundleSlotInterval > 30 { - panic("create_bundle_slot_interval is supposed less than 20") + if s.Chain == BSC && s.CreateBundleSlotOrBlockInterval > 200 { + panic("create_bundle_slot_interval is supposed to be less than 100") + } + if s.Chain == ETH && s.CreateBundleSlotOrBlockInterval > 30 { + panic("create_bundle_slot_interval is supposed to be less than 30") } if s.BundleNotSealedReuploadThreshold <= 60 { - panic("Bundle_not_sealed_reupload_threshold is supposed larger than 60") + panic("Bundle_not_sealed_reupload_threshold is supposed larger than 60 (s)") } s.DBConfig.Validate() } -func (s *SyncerConfig) GetCreateBundleSlotInterval() uint64 { - if s.CreateBundleSlotInterval == 0 { +func (s *SyncerConfig) GetCreateBundleInterval() uint64 { + if s.CreateBundleSlotOrBlockInterval == 0 { return DefaultCreateBundleSlotInterval } - return s.CreateBundleSlotInterval + return s.CreateBundleSlotOrBlockInterval } func (s *SyncerConfig) GetReUploadBundleThresh() int64 { @@ -77,6 +90,7 @@ func (s *SyncerConfig) GetReUploadBundleThresh() int64 { } type ServerConfig struct { + Chain string `json:"chain"` BucketName string `json:"bucket_name"` BundleServiceEndpoints []string `json:"bundle_service_endpoints"` // BundleServiceEndpoints is a list of bundle service address CacheConfig CacheConfig `json:"cache_config"` @@ -84,6 +98,9 @@ type ServerConfig struct { } func (s *ServerConfig) Validate() { + if !strings.EqualFold(s.Chain, ETH) && !strings.EqualFold(s.Chain, BSC) { + panic("chain not support") + } if len(s.BucketName) == 0 { panic("the Greenfield bucket name is not is not provided") } diff --git a/config/const.go b/config/const.go index 8242c6f..a729427 100644 --- a/config/const.go +++ b/config/const.go @@ -10,7 +10,7 @@ const ( EnvVarDBUserPass = "DB_PASSWORD" EnvVarPrivateKey = "PRIVATE_KEY" - DefaultCreateBundleSlotInterval = 20 + DefaultCreateBundleSlotInterval = 30 DefaultReUploadBundleThreshold = 3600 // in second diff --git a/db/blob.go b/db/blob.go index 4a81586..a588e50 100644 --- a/db/blob.go +++ b/db/blob.go @@ -8,6 +8,7 @@ type Blob struct { VersionedHash string `gorm:"NOT NULL"` Slot uint64 `gorm:"NOT NULL;index:idx_blob_slot_index"` Idx int `gorm:"NOT NULL;index:idx_blob_slot_idx"` + TxIndex int KzgCommitment string `gorm:"NOT NULL"` KzgProof string `gorm:"NOT NULL"` CommitmentInclusionProof string `gorm:"NOT NULL"` diff --git a/db/dao.go b/db/dao.go index bc1c525..225cd04 100644 --- a/db/dao.go +++ b/db/dao.go @@ -81,11 +81,12 @@ func (d *BlobSvcDB) UpdateBlocksStatus(startSlot, endSlot uint64, status Status) } type BlobDB interface { - GetBlobBySlot(slot uint64) ([]*Blob, error) - GetBlobBySlotAndIndices(slot uint64, indices []int64) ([]*Blob, error) + GetBlobByBlockID(slot uint64) ([]*Blob, error) + GetBlobByBlockIDAndIndices(slot uint64, indices []int64) ([]*Blob, error) + GetBlobBetweenBlocks(startSlot, endSlot uint64) ([]*Blob, error) } -func (d *BlobSvcDB) GetBlobBySlot(slot uint64) ([]*Blob, error) { +func (d *BlobSvcDB) GetBlobByBlockID(slot uint64) ([]*Blob, error) { blobs := make([]*Blob, 0) if err := d.db.Where("slot = ?", slot).Order("idx asc").Find(&blobs).Error; err != nil { return blobs, err @@ -93,7 +94,7 @@ func (d *BlobSvcDB) GetBlobBySlot(slot uint64) ([]*Blob, error) { return blobs, nil } -func (d *BlobSvcDB) GetBlobBySlotAndIndices(slot uint64, indices []int64) ([]*Blob, error) { +func (d *BlobSvcDB) GetBlobByBlockIDAndIndices(slot uint64, indices []int64) ([]*Blob, error) { blobs := make([]*Blob, 0) if err := d.db.Where("slot = ? and idx in (?)", slot, indices).Order("idx asc").Find(&blobs).Error; err != nil { return blobs, err @@ -101,6 +102,14 @@ func (d *BlobSvcDB) GetBlobBySlotAndIndices(slot uint64, indices []int64) ([]*Bl return blobs, nil } +func (d *BlobSvcDB) GetBlobBetweenBlocks(startSlot, endSlot uint64) ([]*Blob, error) { + blobs := make([]*Blob, 0) + if err := d.db.Where("slot >= ? and slot <= ?", startSlot, endSlot).Order("idx asc").Find(&blobs).Error; err != nil { + return blobs, err + } + return blobs, nil +} + type BundleDB interface { GetBundle(name string) (*Bundle, error) GetLatestFinalizingBundle() (*Bundle, error) diff --git a/external/client.go b/external/client.go new file mode 100644 index 0000000..32141da --- /dev/null +++ b/external/client.go @@ -0,0 +1,165 @@ +package external + +import ( + "context" + "math/big" + "strconv" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" + "github.com/prysmaticlabs/prysm/v5/api/server/structs" + + "github.com/bnb-chain/blob-hub/config" + "github.com/bnb-chain/blob-hub/external/eth" + types2 "github.com/bnb-chain/blob-hub/types" + "github.com/bnb-chain/blob-hub/util" +) + +const BSCBlockConfirmNum = 3 + +type IClient interface { + GetBlob(ctx context.Context, blockID uint64) ([]*types2.GeneralSideCar, error) + GetBlockHeader(ctx context.Context, height uint64) (*types.Header, error) + GetFinalizedBlockNum(ctx context.Context) (uint64, error) + BlockByNumber(ctx context.Context, int2 *big.Int) (*types.Block, error) + + // for eth beacon chain + GetLatestBeaconBlock(ctx context.Context) (*structs.GetBlockV2Response, error) + GetBeaconHeader(ctx context.Context, slotNumber uint64) (*structs.GetBlockHeaderResponse, error) + GetBeaconBlock(ctx context.Context, slotNumber uint64) (*structs.GetBlockV2Response, error) +} + +type Client struct { + ethClient *ethclient.Client + rpcClient *rpc.Client + beaconClient *eth.BeaconClient + cfg *config.SyncerConfig +} + +func NewClient(cfg *config.SyncerConfig) IClient { + ethClient, err := ethclient.Dial(cfg.RPCAddrs[0]) + if err != nil { + panic("new eth client error") + } + cli := &Client{ + cfg: cfg, + ethClient: ethClient, + } + if cfg.Chain == config.BSC { + rpcClient, err := rpc.DialContext(context.Background(), cfg.RPCAddrs[0]) + if err != nil { + panic("new rpc client error") + } + cli.rpcClient = rpcClient + } else { + beaconClient, err := eth.NewBeaconClient(cfg.BeaconRPCAddrs[0]) + if err != nil { + panic("new eth client error") + } + cli.beaconClient = beaconClient + } + return cli +} + +func (c *Client) GetBlob(ctx context.Context, blockID uint64) ([]*types2.GeneralSideCar, error) { + sidecars := make([]*types2.GeneralSideCar, 0) + if c.cfg.Chain == config.BSC { + var txSidecars []*BSCBlobTxSidecar + number := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(blockID)) + err := c.rpcClient.CallContext(ctx, &txSidecars, "eth_getBlobSidecars", number.String()) + if err != nil { + return nil, err + } + if txSidecars == nil { + return nil, ethereum.NotFound + } + idx := 0 + for _, txSidecar := range txSidecars { + txIndex, err := util.HexToUint64(txSidecar.TxIndex) + if err != nil { + return nil, err + } + for j := range txSidecar.BlobSidecar.Blobs { + sidecars = append(sidecars, + &types2.GeneralSideCar{ + Sidecar: structs.Sidecar{ + Index: strconv.Itoa(idx), + Blob: txSidecar.BlobSidecar.Blobs[j], + KzgCommitment: txSidecar.BlobSidecar.Commitments[j], + KzgProof: txSidecar.BlobSidecar.Proofs[j], + }, + TxIndex: int64(txIndex), + TxHash: txSidecar.TxHash, + }, + ) + idx++ + } + } + return sidecars, err + } + ethSidecars, err := c.beaconClient.GetBlob(ctx, blockID) + if err != nil { + return nil, err + } + for _, sidecar := range ethSidecars { + sidecars = append(sidecars, + &types2.GeneralSideCar{ + Sidecar: *sidecar, + }, + ) + } + return sidecars, nil +} + +func (c *Client) GetBlockHeader(ctx context.Context, height uint64) (*types.Header, error) { + header, err := c.ethClient.HeaderByNumber(ctx, big.NewInt(int64(height))) + if err != nil { + return nil, err + } + return header, nil +} + +func (c *Client) GetFinalizedBlockNum(ctx context.Context) (uint64, error) { + var head *types.Header + if err := c.rpcClient.CallContext(ctx, &head, "eth_getFinalizedHeader", BSCBlockConfirmNum); err != nil { + return 0, err + } + if head == nil || head.Number == nil { + return 0, ethereum.NotFound + } + return head.Number.Uint64(), nil +} + +func (c *Client) BlockByNumber(ctx context.Context, int2 *big.Int) (*types.Block, error) { + return c.ethClient.BlockByNumber(ctx, int2) +} + +func (c *Client) GetLatestBeaconBlock(ctx context.Context) (*structs.GetBlockV2Response, error) { + return c.beaconClient.GetLatestBeaconBlock(ctx) +} + +func (c *Client) GetBeaconHeader(ctx context.Context, slotNumber uint64) (*structs.GetBlockHeaderResponse, error) { + return c.beaconClient.GetBeaconHeader(ctx, slotNumber) +} + +func (c *Client) GetBeaconBlock(ctx context.Context, slotNumber uint64) (*structs.GetBlockV2Response, error) { + return c.beaconClient.GetBeaconBlock(ctx, slotNumber) +} + +// BSCBlobSidecar is a sidecar struct for BSC +type BSCBlobSidecar struct { + Blobs []string `json:"blobs"` + Commitments []string `json:"commitments"` + Proofs []string `json:"proofs"` +} + +// BSCBlobTxSidecar is a sidecar struct for BSC blob tx +type BSCBlobTxSidecar struct { + BlobSidecar BSCBlobSidecar `json:"blobSidecar"` + BlockNumber string `json:"blockNumber"` + BlockHash string `json:"blockHash"` + TxIndex string `json:"txIndex"` + TxHash string `json:"txHash"` +} diff --git a/external/bundle_client.go b/external/cmn/bundle_client.go similarity index 99% rename from external/bundle_client.go rename to external/cmn/bundle_client.go index 4c34157..0b903b2 100644 --- a/external/bundle_client.go +++ b/external/cmn/bundle_client.go @@ -1,4 +1,4 @@ -package external +package cmn import ( "bytes" diff --git a/external/sp_client.go b/external/cmn/sp_client.go similarity index 98% rename from external/sp_client.go rename to external/cmn/sp_client.go index 58ef0ef..f9eb203 100644 --- a/external/sp_client.go +++ b/external/cmn/sp_client.go @@ -1,4 +1,4 @@ -package external +package cmn import ( "context" diff --git a/external/types.go b/external/cmn/types.go similarity index 98% rename from external/types.go rename to external/cmn/types.go index 0b90d1a..ceea879 100644 --- a/external/types.go +++ b/external/cmn/types.go @@ -1,4 +1,4 @@ -package external +package cmn import ( "encoding/xml" diff --git a/external/beacon_client.go b/external/eth/beacon_client.go similarity index 90% rename from external/beacon_client.go rename to external/eth/beacon_client.go index a60bbfa..103b031 100644 --- a/external/beacon_client.go +++ b/external/eth/beacon_client.go @@ -1,4 +1,4 @@ -package external +package eth import ( "context" @@ -67,7 +67,7 @@ func (c *BeaconClient) GetBlob(ctx context.Context, slotNumber uint64) ([]*struc return sidecars.Data, nil } -func (c *BeaconClient) GetBlock(ctx context.Context, slotNumber uint64) (*structs.GetBlockV2Response, error) { +func (c *BeaconClient) GetBeaconBlock(ctx context.Context, slotNumber uint64) (*structs.GetBlockV2Response, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.host+fmt.Sprintf(pathGetBlock, strconv.FormatUint(slotNumber, 10)), nil) if err != nil { return nil, err @@ -95,7 +95,7 @@ func (c *BeaconClient) GetBlock(ctx context.Context, slotNumber uint64) (*struct } -func (c *BeaconClient) GetLatestBlock(ctx context.Context) (*structs.GetBlockV2Response, error) { +func (c *BeaconClient) GetLatestBeaconBlock(ctx context.Context) (*structs.GetBlockV2Response, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.host+fmt.Sprintf(pathGetBlock, "head"), nil) if err != nil { return nil, err @@ -116,7 +116,7 @@ func (c *BeaconClient) GetLatestBlock(ctx context.Context) (*structs.GetBlockV2R } -func (c *BeaconClient) GetHeader(ctx context.Context, slotNumber uint64) (*structs.GetBlockHeaderResponse, error) { +func (c *BeaconClient) GetBeaconHeader(ctx context.Context, slotNumber uint64) (*structs.GetBlockHeaderResponse, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.host+fmt.Sprintf(pathGetHeader, strconv.FormatUint(slotNumber, 10)), nil) if err != nil { return nil, err diff --git a/external/eth_client.go b/external/eth_client.go deleted file mode 100644 index 125a86d..0000000 --- a/external/eth_client.go +++ /dev/null @@ -1,31 +0,0 @@ -package external - -import ( - "time" - - "github.com/ethereum/go-ethereum/ethclient" -) - -type ETHClient struct { - Eth1Client *ethclient.Client - BeaconClient *BeaconClient - endpoint string - updatedAt time.Time -} - -func NewETHClient(rpcAddrs, beaconRPCAddrs string) *ETHClient { - ethClient, err := ethclient.Dial(rpcAddrs) - if err != nil { - panic("new eth client error") - } - beaconClient, err := NewBeaconClient(beaconRPCAddrs) - if err != nil { - panic("new eth client error") - } - return ÐClient{ - Eth1Client: ethClient, - BeaconClient: beaconClient, - endpoint: rpcAddrs, - updatedAt: time.Now(), - } -} diff --git a/go.mod b/go.mod index 3d0943b..4e447f7 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/bnb-chain/blob-hub -go 1.20 +go 1.22 + +toolchain go1.22.4 require ( github.com/bnb-chain/greenfield-bundle-sdk v1.1.0 @@ -13,7 +15,9 @@ require ( github.com/go-openapi/swag v0.22.4 github.com/go-openapi/validate v0.22.1 github.com/go-sql-driver/mysql v1.7.0 + github.com/golang/protobuf v1.5.3 github.com/gorilla/mux v1.8.0 + github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/jessevdk/go-flags v1.5.0 github.com/node-real/greenfield-bundle-service v0.0.1-beta @@ -22,8 +26,10 @@ require ( github.com/prysmaticlabs/prysm/v5 v5.0.2 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.15.0 - github.com/stretchr/testify v1.8.4 golang.org/x/net v0.21.0 + google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a + google.golang.org/grpc v1.59.0 + google.golang.org/protobuf v1.31.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gorm.io/driver/mysql v1.5.1 gorm.io/gorm v1.25.5 @@ -41,7 +47,6 @@ require ( github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.5.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -52,7 +57,6 @@ require ( github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/uuid v1.5.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect @@ -74,7 +78,6 @@ require ( github.com/oklog/ulid v1.3.1 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect @@ -102,10 +105,7 @@ require ( golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.16.0 // indirect google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 28f10fb..d6808e6 100644 --- a/go.sum +++ b/go.sum @@ -38,13 +38,17 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= +github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -60,6 +64,7 @@ github.com/btcsuite/btcd v0.23.3 h1:4KH/JKy9WiCd+iUS9Mu0Zp7Dnj17TGdKrg9xc/FGj24= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -71,26 +76,35 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= +github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= +github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.5.0 h1:hn6cEZtQ0h3J8kFrHR/NrzyOoTnjgW1+FmNJzQ7y/sA= github.com/deckarep/golang-set/v2 v2.5.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -106,12 +120,18 @@ github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1 github.com/ethereum/go-ethereum v1.13.10 h1:Ppdil79nN+Vc+mXfge0AuUgmKWuVv4eMqzoIVSdqZek= github.com/ethereum/go-ethereum v1.13.10/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= +github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI= +github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -183,10 +203,14 @@ github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGt github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -216,6 +240,7 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -256,9 +281,12 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 h1:gDLXvp5S9izjldquuoAhDzccbskOL6tDC5jMSyx3zxE= github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAszqCJMbfTISJ7oMftp8+UGV08= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= @@ -266,14 +294,18 @@ github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:i github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -294,6 +326,7 @@ github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0Lh github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -301,12 +334,15 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -317,11 +353,15 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -329,10 +369,12 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= @@ -342,6 +384,7 @@ github.com/node-real/greenfield-bundle-service v0.0.1-beta/go.mod h1:ZK2pn7jvJ1y github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= @@ -372,13 +415,17 @@ github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HD github.com/prysmaticlabs/prysm/v5 v5.0.2 h1:xcSUvrCVfOGslKYUb5Hpyz98N9I8fC2p7DMAZfiqEIA= github.com/prysmaticlabs/prysm/v5 v5.0.2/go.mod h1:XG4nOU925zemOimoexcrFP4oA57f+RTQbp7V/TH9UOM= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -399,6 +446,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= +github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -419,6 +467,7 @@ github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNG github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e h1:cR8/SYRgyQCt5cNCMniB/ZScMkhI9nk8U5C7SbISXjo= github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e/go.mod h1:Tu4lItkATkonrYuvtVjG0/rhy15qrNGNTjPdaphtZ/8= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= @@ -428,13 +477,16 @@ github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5I github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI= +github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -626,6 +678,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -732,6 +785,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -764,6 +818,7 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= @@ -787,12 +842,14 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -815,10 +872,13 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/apimachinery v0.20.0 h1:jjzbTJRXk0unNS71L7h3lxGDH/2HPxMPaQY+MjECKL8= +k8s.io/apimachinery v0.20.0/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/klog/v2 v2.80.0 h1:lyJt0TWMPaGoODa8B8bUuxgHS3W/m/bNr2cca3brA/g= +k8s.io/klog/v2 v2.80.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/google/api/BUILD.bazel b/google/api/BUILD.bazel new file mode 100644 index 0000000..08f6d49 --- /dev/null +++ b/google/api/BUILD.bazel @@ -0,0 +1,27 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + +proto_library( + name = "annotations_proto", + srcs = [ + "annotations.proto", + "http.proto", + ], + visibility = ["//visibility:public"], + deps = ["@com_google_protobuf//:descriptor_proto"], +) + +go_proto_library( + name = "annotations_go_proto", + importpath = "google.golang.org/genproto/googleapis/api/annotations", + proto = ":annotations_proto", + visibility = ["//visibility:public"], +) + +go_library( + name = "annotations", + embed = [":annotations_go_proto"], + importpath = "google.golang.org/genproto/googleapis/api/annotations", + visibility = ["//visibility:public"], +) diff --git a/google/api/annotations.proto b/google/api/annotations.proto new file mode 100644 index 0000000..efdab3d --- /dev/null +++ b/google/api/annotations.proto @@ -0,0 +1,31 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/http.proto"; +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "AnnotationsProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // See `HttpRule`. + HttpRule http = 72295728; +} diff --git a/google/api/http.proto b/google/api/http.proto new file mode 100644 index 0000000..7d0b228 --- /dev/null +++ b/google/api/http.proto @@ -0,0 +1,375 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "HttpProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Defines the HTTP configuration for an API service. It contains a list of +// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +// to one or more HTTP REST API methods. +message Http { + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated HttpRule rules = 1; + + // When set to true, URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + bool fully_decode_reserved_expansion = 2; +} + +// # gRPC Transcoding +// +// gRPC Transcoding is a feature for mapping between a gRPC method and one or +// more HTTP REST endpoints. It allows developers to build a single API service +// that supports both gRPC APIs and REST APIs. Many systems, including [Google +// APIs](https://github.com/googleapis/googleapis), +// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC +// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), +// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature +// and use it for large scale production services. +// +// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies +// how different portions of the gRPC request message are mapped to the URL +// path, URL query parameters, and HTTP request body. It also controls how the +// gRPC response message is mapped to the HTTP response body. `HttpRule` is +// typically specified as an `google.api.http` annotation on the gRPC method. +// +// Each mapping specifies a URL path template and an HTTP method. The path +// template may refer to one or more fields in the gRPC request message, as long +// as each field is a non-repeated field with a primitive (non-message) type. +// The path template controls how fields of the request message are mapped to +// the URL path. +// +// Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/{name=messages/*}" +// }; +// } +// } +// message GetMessageRequest { +// string name = 1; // Mapped to URL path. +// } +// message Message { +// string text = 1; // The resource content. +// } +// +// This enables an HTTP REST to gRPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` +// +// Any fields in the request message which are not bound by the path template +// automatically become HTTP query parameters if there is no HTTP request body. +// For example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get:"/v1/messages/{message_id}" +// }; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // Mapped to URL path. +// int64 revision = 2; // Mapped to URL query parameter `revision`. +// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. +// } +// +// This enables a HTTP JSON to RPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | +// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: +// "foo"))` +// +// Note that fields which are mapped to URL query parameters must have a +// primitive type or a repeated primitive type or a non-repeated message type. +// In the case of a repeated type, the parameter can be repeated in the URL +// as `...?param=A¶m=B`. In the case of a message type, each field of the +// message is mapped to a separate parameter, such as +// `...?foo.a=A&foo.b=B&foo.c=C`. +// +// For HTTP methods that allow a request body, the `body` field +// specifies the mapping. Consider a REST update method on the +// message resource collection: +// +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } +// +// The following HTTP JSON to RPC mapping is enabled, where the +// representation of the JSON in the request body is determined by +// protos JSON encoding: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" message { text: "Hi!" })` +// +// The special name `*` can be used in the body mapping to define that +// every field not bound by the path template should be mapped to the +// request body. This enables the following alternative definition of +// the update method: +// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } +// +// +// The following HTTP JSON to RPC mapping is enabled: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" text: "Hi!")` +// +// Note that when using `*` in the body mapping, it is not possible to +// have HTTP parameters, as all fields not bound by the path end in +// the body. This makes this option more rarely used in practice when +// defining REST APIs. The common usage of `*` is in custom methods +// which don't use the URL at all for transferring data. +// +// It is possible to define multiple HTTP methods for one RPC by using +// the `additional_bindings` option. Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } +// +// This enables the following two alternative HTTP JSON to RPC mappings: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: +// "123456")` +// +// ## Rules for HTTP mapping +// +// 1. Leaf request fields (recursive expansion nested messages in the request +// message) are classified into three categories: +// - Fields referred by the path template. They are passed via the URL path. +// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP +// request body. +// - All other fields are passed via the URL query parameters, and the +// parameter name is the field path in the request message. A repeated +// field can be represented as multiple query parameters under the same +// name. +// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields +// are passed via URL path and HTTP request body. +// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all +// fields are passed via URL path and URL query parameters. +// +// ### Path template syntax +// +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; +// +// The syntax `*` matches a single URL path segment. The syntax `**` matches +// zero or more URL path segments, which must be the last part of the URL path +// except the `Verb`. +// +// The syntax `Variable` matches part of the URL path as specified by its +// template. A variable template must not contain other variables. If a variable +// matches a single path segment, its template may be omitted, e.g. `{var}` +// is equivalent to `{var=*}`. +// +// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` +// contains any reserved character, such characters should be percent-encoded +// before the matching. +// +// If a variable contains exactly one path segment, such as `"{var}"` or +// `"{var=*}"`, when such a variable is expanded into a URL path on the client +// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The +// server side does the reverse decoding. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{var}`. +// +// If a variable contains multiple path segments, such as `"{var=foo/*}"` +// or `"{var=**}"`, when such a variable is expanded into a URL path on the +// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. +// The server side does the reverse decoding, except "%2F" and "%2f" are left +// unchanged. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{+var}`. +// +// ## Using gRPC API Service Configuration +// +// gRPC API Service Configuration (service config) is a configuration language +// for configuring a gRPC service to become a user-facing product. The +// service config is simply the YAML representation of the `google.api.Service` +// proto message. +// +// As an alternative to annotating your proto file, you can configure gRPC +// transcoding in your service config YAML files. You do this by specifying a +// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same +// effect as the proto annotation. This can be particularly useful if you +// have a proto that is reused in multiple services. Note that any transcoding +// specified in the service config will override any matching transcoding +// configuration in the proto. +// +// Example: +// +// http: +// rules: +// # Selects a gRPC method and applies HttpRule to it. +// - selector: example.v1.Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} +// +// ## Special notes +// +// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the +// proto to JSON conversion must follow the [proto3 +// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). +// +// While the single segment variable follows the semantics of +// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String +// Expansion, the multi segment variable **does not** follow RFC 6570 Section +// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion +// does not expand special characters like `?` and `#`, which would lead +// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding +// for multi segment variables. +// +// The path variables **must not** refer to any repeated or mapped field, +// because client libraries are not capable of handling such variable expansion. +// +// The path variables **must not** capture the leading "/" character. The reason +// is that the most common use case "{var}" does not capture the leading "/" +// character. For consistency, all path variables must share the same behavior. +// +// Repeated message fields must not be mapped to URL query parameters, because +// no client library can support such complicated mapping. +// +// If an API needs to use a JSON array for request or response body, it can map +// the request or response body to a repeated field. However, some gRPC +// Transcoding implementations may not support this feature. +message HttpRule { + // Selects a method to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // Determines the URL pattern is matched by this rules. This pattern can be + // used with any of the {get|put|post|delete|patch} methods. A custom method + // can be defined using the 'custom' field. + oneof pattern { + // Maps to HTTP GET. Used for listing and getting information about + // resources. + string get = 2; + + // Maps to HTTP PUT. Used for replacing a resource. + string put = 3; + + // Maps to HTTP POST. Used for creating a resource or performing an action. + string post = 4; + + // Maps to HTTP DELETE. Used for deleting a resource. + string delete = 5; + + // Maps to HTTP PATCH. Used for updating a resource. + string patch = 6; + + // The custom pattern is used for specifying an HTTP method that is not + // included in the `pattern` field, such as HEAD, or "*" to leave the + // HTTP method unspecified for this rule. The wild-card rule is useful + // for services that provide content to Web (HTML) clients. + CustomHttpPattern custom = 8; + } + + // The name of the request field whose value is mapped to the HTTP request + // body, or `*` for mapping all request fields not captured by the path + // pattern to the HTTP body, or omitted for not having any HTTP request body. + // + // NOTE: the referred field must be present at the top-level of the request + // message type. + string body = 7; + + // Optional. The name of the response field whose value is mapped to the HTTP + // response body. When omitted, the entire response message will be used + // as the HTTP response body. + // + // NOTE: The referred field must be present at the top-level of the response + // message type. + string response_body = 12; + + // Additional HTTP bindings for the selector. Nested bindings must + // not contain an `additional_bindings` field themselves (that is, + // the nesting may only be one level deep). + repeated HttpRule additional_bindings = 11; +} + +// A custom pattern is used for defining custom HTTP verb. +message CustomHttpPattern { + // The name of this custom HTTP verb. + string kind = 1; + + // The path matched by this custom verb. + string path = 2; +} \ No newline at end of file diff --git a/metrics/metric.go b/metrics/metric.go index e694aca..e516ee7 100644 --- a/metrics/metric.go +++ b/metrics/metric.go @@ -11,12 +11,12 @@ import ( ) var ( - SyncedSlotGauge = prometheus.NewGauge(prometheus.GaugeOpts{ + SyncedBlockIDGauge = prometheus.NewGauge(prometheus.GaugeOpts{ Name: "synced_beacon_slot", Help: "Synced slot number, all blobs have been uploaded to bundle service.", }) - VerifiedSlotGauge = prometheus.NewGauge(prometheus.GaugeOpts{ + VerifiedBlockIDGauge = prometheus.NewGauge(prometheus.GaugeOpts{ Name: "verified_beacon_slot", Help: "Verified slot number, all blobs have been verified against the bundle service.", }) @@ -27,8 +27,8 @@ var ( }) MetricsItems = []prometheus.Collector{ - SyncedSlotGauge, - VerifiedSlotGauge, + SyncedBlockIDGauge, + VerifiedBlockIDGauge, BucketRemainingQuotaGauge, } ) diff --git a/models/b_s_c_blob_sidecar.go b/models/b_s_c_blob_sidecar.go new file mode 100644 index 0000000..1bec075 --- /dev/null +++ b/models/b_s_c_blob_sidecar.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// BSCBlobSidecar b s c blob sidecar +// +// swagger:model BSCBlobSidecar +type BSCBlobSidecar struct { + + // blobs + Blobs []string `json:"blobs"` + + // commitments + Commitments []string `json:"commitments"` + + // proofs + Proofs []string `json:"proofs"` +} + +// Validate validates this b s c blob sidecar +func (m *BSCBlobSidecar) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this b s c blob sidecar based on context it is used +func (m *BSCBlobSidecar) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *BSCBlobSidecar) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *BSCBlobSidecar) UnmarshalBinary(b []byte) error { + var res BSCBlobSidecar + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/models/b_s_c_blob_tx_sidecar.go b/models/b_s_c_blob_tx_sidecar.go new file mode 100644 index 0000000..677ae67 --- /dev/null +++ b/models/b_s_c_blob_tx_sidecar.go @@ -0,0 +1,116 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// BSCBlobTxSidecar b s c blob tx sidecar +// +// swagger:model BSCBlobTxSidecar +type BSCBlobTxSidecar struct { + + // blob sidecar + BlobSidecar *BSCBlobSidecar `json:"blobSidecar,omitempty"` + + // block hash + BlockHash string `json:"blockHash,omitempty"` + + // block number + BlockNumber string `json:"blockNumber,omitempty"` + + // tx hash + TxHash string `json:"txHash,omitempty"` + + // tx index + TxIndex string `json:"txIndex,omitempty"` +} + +// Validate validates this b s c blob tx sidecar +func (m *BSCBlobTxSidecar) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateBlobSidecar(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *BSCBlobTxSidecar) validateBlobSidecar(formats strfmt.Registry) error { + if swag.IsZero(m.BlobSidecar) { // not required + return nil + } + + if m.BlobSidecar != nil { + if err := m.BlobSidecar.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("blobSidecar") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("blobSidecar") + } + return err + } + } + + return nil +} + +// ContextValidate validate this b s c blob tx sidecar based on the context it is used +func (m *BSCBlobTxSidecar) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateBlobSidecar(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *BSCBlobTxSidecar) contextValidateBlobSidecar(ctx context.Context, formats strfmt.Registry) error { + + if m.BlobSidecar != nil { + if err := m.BlobSidecar.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("blobSidecar") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("blobSidecar") + } + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *BSCBlobTxSidecar) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *BSCBlobTxSidecar) UnmarshalBinary(b []byte) error { + var res BSCBlobTxSidecar + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/models/rpc_error.go b/models/rpc_error.go new file mode 100644 index 0000000..750de5e --- /dev/null +++ b/models/rpc_error.go @@ -0,0 +1,55 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RPCError RPC error +// +// swagger:model RPCError +type RPCError struct { + + // RPC error code + // Example: -32602 + Code int64 `json:"code"` + + // Error message + // Example: Invalid params + Message string `json:"message"` +} + +// Validate validates this RPC error +func (m *RPCError) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this RPC error based on context it is used +func (m *RPCError) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RPCError) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RPCError) UnmarshalBinary(b []byte) error { + var res RPCError + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/models/rpc_request.go b/models/rpc_request.go new file mode 100644 index 0000000..a42ddf2 --- /dev/null +++ b/models/rpc_request.go @@ -0,0 +1,63 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RPCRequest RPC request +// +// swagger:model RPCRequest +type RPCRequest struct { + + // id + // Example: 1 + ID int64 `json:"id,omitempty"` + + // jsonrpc + // Example: 2.0 + Jsonrpc string `json:"jsonrpc,omitempty"` + + // method + // Example: eth_getBlobSidecars + Method string `json:"method,omitempty"` + + // params + // Example: ["0x1",true] + Params []string `json:"params"` +} + +// Validate validates this RPC request +func (m *RPCRequest) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this RPC request based on context it is used +func (m *RPCRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RPCRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RPCRequest) UnmarshalBinary(b []byte) error { + var res RPCRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/models/rpc_response.go b/models/rpc_response.go new file mode 100644 index 0000000..9590728 --- /dev/null +++ b/models/rpc_response.go @@ -0,0 +1,170 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RPCResponse RPC response +// +// swagger:model RPCResponse +type RPCResponse struct { + + // error + Error *RPCError `json:"error,omitempty"` + + // id + // Example: 1 + ID int64 `json:"id,omitempty"` + + // jsonrpc + // Example: 2.0 + Jsonrpc string `json:"jsonrpc,omitempty"` + + // result + Result []*BSCBlobTxSidecar `json:"result"` +} + +// Validate validates this RPC response +func (m *RPCResponse) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateError(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResult(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RPCResponse) validateError(formats strfmt.Registry) error { + if swag.IsZero(m.Error) { // not required + return nil + } + + if m.Error != nil { + if err := m.Error.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("error") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("error") + } + return err + } + } + + return nil +} + +func (m *RPCResponse) validateResult(formats strfmt.Registry) error { + if swag.IsZero(m.Result) { // not required + return nil + } + + for i := 0; i < len(m.Result); i++ { + if swag.IsZero(m.Result[i]) { // not required + continue + } + + if m.Result[i] != nil { + if err := m.Result[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("result" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("result" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this RPC response based on the context it is used +func (m *RPCResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateError(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResult(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RPCResponse) contextValidateError(ctx context.Context, formats strfmt.Registry) error { + + if m.Error != nil { + if err := m.Error.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("error") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("error") + } + return err + } + } + + return nil +} + +func (m *RPCResponse) contextValidateResult(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Result); i++ { + + if m.Result[i] != nil { + if err := m.Result[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("result" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("result" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RPCResponse) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RPCResponse) UnmarshalBinary(b []byte) error { + var res RPCResponse + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/models/sidecar.go b/models/sidecar.go index 788d69e..c298dc6 100644 --- a/models/sidecar.go +++ b/models/sidecar.go @@ -29,13 +29,19 @@ type Sidecar struct { KzgCommitment string `json:"kzg_commitment,omitempty"` // kzg commitment inclusion proof - KzgCommitmentInclusionProof []string `json:"kzg_commitment_inclusion_proof"` + KzgCommitmentInclusionProof []string `json:"kzg_commitment_inclusion_proof,omitempty"` // kzg proof KzgProof string `json:"kzg_proof,omitempty"` // signed block header SignedBlockHeader *SidecarSignedBlockHeader `json:"signed_block_header,omitempty"` + + // tx hash + TxHash string `json:"tx_hash,omitempty"` + + // tx index + TxIndex int64 `json:"tx_index,omitempty"` } // Validate validates this sidecar diff --git a/proto/blob.pb.go b/proto/blob.pb.go new file mode 100644 index 0000000..4e488d5 --- /dev/null +++ b/proto/blob.pb.go @@ -0,0 +1,527 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.12 +// source: proto/blob.proto + +package proto + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetBlobSidecarsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BlockId string `protobuf:"bytes,1,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"` + Indices []string `protobuf:"bytes,2,rep,name=indices,proto3" json:"indices,omitempty"` +} + +func (x *GetBlobSidecarsRequest) Reset() { + *x = GetBlobSidecarsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_blob_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlobSidecarsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlobSidecarsRequest) ProtoMessage() {} + +func (x *GetBlobSidecarsRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_blob_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlobSidecarsRequest.ProtoReflect.Descriptor instead. +func (*GetBlobSidecarsRequest) Descriptor() ([]byte, []int) { + return file_proto_blob_proto_rawDescGZIP(), []int{0} +} + +func (x *GetBlobSidecarsRequest) GetBlockId() string { + if x != nil { + return x.BlockId + } + return "" +} + +func (x *GetBlobSidecarsRequest) GetIndices() []string { + if x != nil { + return x.Indices + } + return nil +} + +type GetBlobSidecarsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data []*SideCar `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` +} + +func (x *GetBlobSidecarsResponse) Reset() { + *x = GetBlobSidecarsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_blob_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBlobSidecarsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBlobSidecarsResponse) ProtoMessage() {} + +func (x *GetBlobSidecarsResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_blob_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBlobSidecarsResponse.ProtoReflect.Descriptor instead. +func (*GetBlobSidecarsResponse) Descriptor() ([]byte, []int) { + return file_proto_blob_proto_rawDescGZIP(), []int{1} +} + +func (x *GetBlobSidecarsResponse) GetData() []*SideCar { + if x != nil { + return x.Data + } + return nil +} + +type SideCar struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Blob string `protobuf:"bytes,1,opt,name=blob,proto3" json:"blob,omitempty"` + Index string `protobuf:"bytes,2,opt,name=index,proto3" json:"index,omitempty"` + KzgCommitment string `protobuf:"bytes,3,opt,name=kzg_commitment,json=kzgCommitment,proto3" json:"kzg_commitment,omitempty"` + KzgCommitmentInclusionProof []string `protobuf:"bytes,4,rep,name=kzg_commitment_inclusion_proof,json=kzgCommitmentInclusionProof,proto3" json:"kzg_commitment_inclusion_proof,omitempty"` + KzgProof string `protobuf:"bytes,5,opt,name=kzg_proof,json=kzgProof,proto3" json:"kzg_proof,omitempty"` + SignedBlockHeader *SignedBeaconBlockHeader `protobuf:"bytes,6,opt,name=signed_block_header,json=signedBlockHeader,proto3" json:"signed_block_header,omitempty"` +} + +func (x *SideCar) Reset() { + *x = SideCar{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_blob_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SideCar) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SideCar) ProtoMessage() {} + +func (x *SideCar) ProtoReflect() protoreflect.Message { + mi := &file_proto_blob_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SideCar.ProtoReflect.Descriptor instead. +func (*SideCar) Descriptor() ([]byte, []int) { + return file_proto_blob_proto_rawDescGZIP(), []int{2} +} + +func (x *SideCar) GetBlob() string { + if x != nil { + return x.Blob + } + return "" +} + +func (x *SideCar) GetIndex() string { + if x != nil { + return x.Index + } + return "" +} + +func (x *SideCar) GetKzgCommitment() string { + if x != nil { + return x.KzgCommitment + } + return "" +} + +func (x *SideCar) GetKzgCommitmentInclusionProof() []string { + if x != nil { + return x.KzgCommitmentInclusionProof + } + return nil +} + +func (x *SideCar) GetKzgProof() string { + if x != nil { + return x.KzgProof + } + return "" +} + +func (x *SideCar) GetSignedBlockHeader() *SignedBeaconBlockHeader { + if x != nil { + return x.SignedBlockHeader + } + return nil +} + +type SignedBeaconBlockHeader struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message *BeaconBlockHeader `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + Signature string `protobuf:"bytes,2,opt,name=Signature,proto3" json:"Signature,omitempty"` +} + +func (x *SignedBeaconBlockHeader) Reset() { + *x = SignedBeaconBlockHeader{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_blob_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignedBeaconBlockHeader) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignedBeaconBlockHeader) ProtoMessage() {} + +func (x *SignedBeaconBlockHeader) ProtoReflect() protoreflect.Message { + mi := &file_proto_blob_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignedBeaconBlockHeader.ProtoReflect.Descriptor instead. +func (*SignedBeaconBlockHeader) Descriptor() ([]byte, []int) { + return file_proto_blob_proto_rawDescGZIP(), []int{3} +} + +func (x *SignedBeaconBlockHeader) GetMessage() *BeaconBlockHeader { + if x != nil { + return x.Message + } + return nil +} + +func (x *SignedBeaconBlockHeader) GetSignature() string { + if x != nil { + return x.Signature + } + return "" +} + +type BeaconBlockHeader struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + BodyRoot string `protobuf:"bytes,1,opt,name=body_root,json=bodyRoot,proto3" json:"body_root,omitempty"` + ParentRoot string `protobuf:"bytes,2,opt,name=parent_root,json=parentRoot,proto3" json:"parent_root,omitempty"` + ProposerIndex string `protobuf:"bytes,3,opt,name=proposer_index,json=proposerIndex,proto3" json:"proposer_index,omitempty"` + Slot string `protobuf:"bytes,4,opt,name=slot,proto3" json:"slot,omitempty"` + StateRoot string `protobuf:"bytes,5,opt,name=state_root,json=stateRoot,proto3" json:"state_root,omitempty"` +} + +func (x *BeaconBlockHeader) Reset() { + *x = BeaconBlockHeader{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_blob_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BeaconBlockHeader) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BeaconBlockHeader) ProtoMessage() {} + +func (x *BeaconBlockHeader) ProtoReflect() protoreflect.Message { + mi := &file_proto_blob_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BeaconBlockHeader.ProtoReflect.Descriptor instead. +func (*BeaconBlockHeader) Descriptor() ([]byte, []int) { + return file_proto_blob_proto_rawDescGZIP(), []int{4} +} + +func (x *BeaconBlockHeader) GetBodyRoot() string { + if x != nil { + return x.BodyRoot + } + return "" +} + +func (x *BeaconBlockHeader) GetParentRoot() string { + if x != nil { + return x.ParentRoot + } + return "" +} + +func (x *BeaconBlockHeader) GetProposerIndex() string { + if x != nil { + return x.ProposerIndex + } + return "" +} + +func (x *BeaconBlockHeader) GetSlot() string { + if x != nil { + return x.Slot + } + return "" +} + +func (x *BeaconBlockHeader) GetStateRoot() string { + if x != nil { + return x.StateRoot + } + return "" +} + +var File_proto_blob_proto protoreflect.FileDescriptor + +var file_proto_blob_proto_rawDesc = []byte{ + 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x04, 0x75, 0x73, 0x65, 0x72, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4d, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, + 0x62, 0x53, 0x69, 0x64, 0x65, 0x63, 0x61, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x19, 0x0a, 0x08, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, + 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6e, + 0x64, 0x69, 0x63, 0x65, 0x73, 0x22, 0x3c, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, + 0x53, 0x69, 0x64, 0x65, 0x63, 0x61, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x21, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x64, 0x65, 0x43, 0x61, 0x72, 0x52, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x22, 0x8b, 0x02, 0x0a, 0x07, 0x53, 0x69, 0x64, 0x65, 0x43, 0x61, 0x72, 0x12, + 0x12, 0x0a, 0x04, 0x62, 0x6c, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, + 0x6c, 0x6f, 0x62, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x25, 0x0a, 0x0e, 0x6b, 0x7a, 0x67, + 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x6b, 0x7a, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, + 0x12, 0x43, 0x0a, 0x1e, 0x6b, 0x7a, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, + 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1b, 0x6b, 0x7a, 0x67, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x7a, 0x67, 0x5f, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x7a, 0x67, 0x50, 0x72, 0x6f, + 0x6f, 0x66, 0x12, 0x4d, 0x0a, 0x13, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x65, 0x61, + 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x11, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x22, 0x6a, 0x0a, 0x17, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x65, 0x61, 0x63, 0x6f, + 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xab, 0x01, + 0x0a, 0x11, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x72, 0x6f, 0x6f, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x6f, 0x64, 0x79, 0x52, 0x6f, 0x6f, 0x74, + 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6f, + 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x70, 0x6f, + 0x73, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12, 0x1d, 0x0a, 0x0a, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x32, 0x8e, 0x01, 0x0a, 0x0b, + 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7f, 0x0a, 0x0f, 0x47, + 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x69, 0x64, 0x65, 0x63, 0x61, 0x72, 0x73, 0x12, 0x1c, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x69, 0x64, + 0x65, 0x63, 0x61, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x53, 0x69, 0x64, 0x65, 0x63, + 0x61, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x29, 0x12, 0x27, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x65, 0x61, + 0x63, 0x6f, 0x6e, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x73, 0x69, 0x64, 0x65, 0x63, 0x61, 0x72, + 0x73, 0x2f, 0x7b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x69, 0x64, 0x7d, 0x42, 0x08, 0x5a, 0x06, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_proto_blob_proto_rawDescOnce sync.Once + file_proto_blob_proto_rawDescData = file_proto_blob_proto_rawDesc +) + +func file_proto_blob_proto_rawDescGZIP() []byte { + file_proto_blob_proto_rawDescOnce.Do(func() { + file_proto_blob_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_blob_proto_rawDescData) + }) + return file_proto_blob_proto_rawDescData +} + +var file_proto_blob_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_proto_blob_proto_goTypes = []interface{}{ + (*GetBlobSidecarsRequest)(nil), // 0: user.GetBlobSidecarsRequest + (*GetBlobSidecarsResponse)(nil), // 1: user.GetBlobSidecarsResponse + (*SideCar)(nil), // 2: user.SideCar + (*SignedBeaconBlockHeader)(nil), // 3: user.SignedBeaconBlockHeader + (*BeaconBlockHeader)(nil), // 4: user.BeaconBlockHeader +} +var file_proto_blob_proto_depIdxs = []int32{ + 2, // 0: user.GetBlobSidecarsResponse.data:type_name -> user.SideCar + 3, // 1: user.SideCar.signed_block_header:type_name -> user.SignedBeaconBlockHeader + 4, // 2: user.SignedBeaconBlockHeader.message:type_name -> user.BeaconBlockHeader + 0, // 3: user.BlobService.GetBlobSidecars:input_type -> user.GetBlobSidecarsRequest + 1, // 4: user.BlobService.GetBlobSidecars:output_type -> user.GetBlobSidecarsResponse + 4, // [4:5] is the sub-list for method output_type + 3, // [3:4] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_proto_blob_proto_init() } +func file_proto_blob_proto_init() { + if File_proto_blob_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_proto_blob_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlobSidecarsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_blob_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBlobSidecarsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_blob_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SideCar); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_blob_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignedBeaconBlockHeader); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_blob_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BeaconBlockHeader); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proto_blob_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_proto_blob_proto_goTypes, + DependencyIndexes: file_proto_blob_proto_depIdxs, + MessageInfos: file_proto_blob_proto_msgTypes, + }.Build() + File_proto_blob_proto = out.File + file_proto_blob_proto_rawDesc = nil + file_proto_blob_proto_goTypes = nil + file_proto_blob_proto_depIdxs = nil +} diff --git a/proto/blob.pb.gw.go b/proto/blob.pb.gw.go new file mode 100644 index 0000000..52b2956 --- /dev/null +++ b/proto/blob.pb.gw.go @@ -0,0 +1,207 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: proto/blob.proto + +/* +Package proto is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package proto + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +var ( + filter_BlobService_GetBlobSidecars_0 = &utilities.DoubleArray{Encoding: map[string]int{"block_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_BlobService_GetBlobSidecars_0(ctx context.Context, marshaler runtime.Marshaler, client BlobServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetBlobSidecarsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["block_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "block_id") + } + + protoReq.BlockId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "block_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_BlobService_GetBlobSidecars_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetBlobSidecars(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_BlobService_GetBlobSidecars_0(ctx context.Context, marshaler runtime.Marshaler, server BlobServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetBlobSidecarsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["block_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "block_id") + } + + protoReq.BlockId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "block_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_BlobService_GetBlobSidecars_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetBlobSidecars(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterBlobServiceHandlerServer registers the http handlers for service BlobService to "mux". +// UnaryRPC :call BlobServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterBlobServiceHandlerFromEndpoint instead. +func RegisterBlobServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server BlobServiceServer) error { + + mux.Handle("GET", pattern_BlobService_GetBlobSidecars_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_BlobService_GetBlobSidecars_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_BlobService_GetBlobSidecars_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterBlobServiceHandlerFromEndpoint is same as RegisterBlobServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterBlobServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterBlobServiceHandler(ctx, mux, conn) +} + +// RegisterBlobServiceHandler registers the http handlers for service BlobService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterBlobServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterBlobServiceHandlerClient(ctx, mux, NewBlobServiceClient(conn)) +} + +// RegisterBlobServiceHandlerClient registers the http handlers for service BlobService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "BlobServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "BlobServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "BlobServiceClient" to call the correct interceptors. +func RegisterBlobServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client BlobServiceClient) error { + + mux.Handle("GET", pattern_BlobService_GetBlobSidecars_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_BlobService_GetBlobSidecars_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_BlobService_GetBlobSidecars_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_BlobService_GetBlobSidecars_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"eth", "v1", "beacon", "blob_sidecars", "block_id"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_BlobService_GetBlobSidecars_0 = runtime.ForwardResponseMessage +) diff --git a/proto/blob.proto b/proto/blob.proto new file mode 100644 index 0000000..097f59b --- /dev/null +++ b/proto/blob.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; + +package user; + +option go_package = "/proto"; + +import "google/api/annotations.proto"; + +service BlobService { + rpc GetBlobSidecars (GetBlobSidecarsRequest) returns (GetBlobSidecarsResponse) { + option (google.api.http) = { + get: "/eth/v1/beacon/blob_sidecars/{block_id}" + }; + } +} + +message GetBlobSidecarsRequest { + string block_id = 1; + repeated string indices = 2; +} + + +message GetBlobSidecarsResponse { + repeated SideCar data = 1; +} + +message SideCar { + string blob = 1; + string index = 2; + string kzg_commitment = 3; + repeated string kzg_commitment_inclusion_proof = 4; + string kzg_proof = 5; + SignedBeaconBlockHeader signed_block_header = 6; +} + +message SignedBeaconBlockHeader { + BeaconBlockHeader message = 1; + string Signature = 2; +} + +message BeaconBlockHeader { + string body_root = 1; + string parent_root = 2; + string proposer_index = 3; + string slot = 4; + string state_root = 5; +} \ No newline at end of file diff --git a/proto/blob_grpc.pb.go b/proto/blob_grpc.pb.go new file mode 100644 index 0000000..116d669 --- /dev/null +++ b/proto/blob_grpc.pb.go @@ -0,0 +1,101 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// BlobServiceClient is the client API for BlobService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type BlobServiceClient interface { + GetBlobSidecars(ctx context.Context, in *GetBlobSidecarsRequest, opts ...grpc.CallOption) (*GetBlobSidecarsResponse, error) +} + +type blobServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewBlobServiceClient(cc grpc.ClientConnInterface) BlobServiceClient { + return &blobServiceClient{cc} +} + +func (c *blobServiceClient) GetBlobSidecars(ctx context.Context, in *GetBlobSidecarsRequest, opts ...grpc.CallOption) (*GetBlobSidecarsResponse, error) { + out := new(GetBlobSidecarsResponse) + err := c.cc.Invoke(ctx, "/user.BlobService/GetBlobSidecars", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// BlobServiceServer is the server API for BlobService service. +// All implementations must embed UnimplementedBlobServiceServer +// for forward compatibility +type BlobServiceServer interface { + GetBlobSidecars(context.Context, *GetBlobSidecarsRequest) (*GetBlobSidecarsResponse, error) + mustEmbedUnimplementedBlobServiceServer() +} + +// UnimplementedBlobServiceServer must be embedded to have forward compatible implementations. +type UnimplementedBlobServiceServer struct { +} + +func (UnimplementedBlobServiceServer) GetBlobSidecars(context.Context, *GetBlobSidecarsRequest) (*GetBlobSidecarsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetBlobSidecars not implemented") +} +func (UnimplementedBlobServiceServer) mustEmbedUnimplementedBlobServiceServer() {} + +// UnsafeBlobServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to BlobServiceServer will +// result in compilation errors. +type UnsafeBlobServiceServer interface { + mustEmbedUnimplementedBlobServiceServer() +} + +func RegisterBlobServiceServer(s grpc.ServiceRegistrar, srv BlobServiceServer) { + s.RegisterService(&BlobService_ServiceDesc, srv) +} + +func _BlobService_GetBlobSidecars_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetBlobSidecarsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BlobServiceServer).GetBlobSidecars(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.BlobService/GetBlobSidecars", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BlobServiceServer).GetBlobSidecars(ctx, req.(*GetBlobSidecarsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// BlobService_ServiceDesc is the grpc.ServiceDesc for BlobService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var BlobService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "user.BlobService", + HandlerType: (*BlobServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetBlobSidecars", + Handler: _BlobService_GetBlobSidecars_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proto/blob.proto", +} diff --git a/restapi/configure_blob_hub.go b/restapi/configure_blob_hub.go index 1dbf572..f50db2b 100644 --- a/restapi/configure_blob_hub.go +++ b/restapi/configure_blob_hub.go @@ -3,18 +3,26 @@ package restapi import ( + "context" "crypto/tls" + "fmt" + "log" + "net" "net/http" "os" "github.com/go-openapi/errors" "github.com/go-openapi/runtime" "github.com/go-openapi/swag" + grpcruntime "github.com/grpc-ecosystem/grpc-gateway/runtime" + "google.golang.org/grpc" "github.com/bnb-chain/blob-hub/cache" + "github.com/bnb-chain/blob-hub/client" "github.com/bnb-chain/blob-hub/config" syncerdb "github.com/bnb-chain/blob-hub/db" - "github.com/bnb-chain/blob-hub/external" + "github.com/bnb-chain/blob-hub/external/cmn" + blobproto "github.com/bnb-chain/blob-hub/proto" "github.com/bnb-chain/blob-hub/restapi/handlers" "github.com/bnb-chain/blob-hub/restapi/operations" "github.com/bnb-chain/blob-hub/restapi/operations/blob" @@ -54,10 +62,13 @@ func configureAPI(api *operations.BlobHubAPI) http.Handler { api.JSONProducer = runtime.JSONProducer() api.BlobGetBlobSidecarsByBlockNumHandler = blob.GetBlobSidecarsByBlockNumHandlerFunc(handlers.HandleGetBlobSidecars()) + api.BlobGetBSCBlobSidecarsByBlockNumHandler = blob.GetBSCBlobSidecarsByBlockNumHandlerFunc(handlers.HandleGetBSCBlobSidecars()) api.PreServerShutdown = func() {} api.ServerShutdown = func() {} + go grpcServer() + return setupGlobalMiddleware(api.Serve(setupMiddlewares)) } @@ -87,7 +98,7 @@ func configureServer(s *http.Server, scheme, addr string) { cfg.Validate() db := config.InitDBWithConfig(&cfg.DBConfig, false) blobDB := syncerdb.NewBlobSvcDB(db) - bundleClient, err := external.NewBundleClient(cfg.BundleServiceEndpoints[0]) + bundleClient, err := cmn.NewBundleClient(cfg.BundleServiceEndpoints[0]) if err != nil { panic(err) } @@ -105,6 +116,49 @@ func configureServer(s *http.Server, scheme, addr string) { } +func grpcServer() { + lis, err := net.Listen("tcp", "0.0.0.0:9000") + if err != nil { + log.Fatalln("Failed to listen:", err) + } + + // Create a gRPC server object + s := grpc.NewServer() + // Attach the Blob service to the server + blobproto.RegisterBlobServiceServer(s, &client.BlobServer{}) + // Serve gRPC server + log.Println("Serving gRPC on 0.0.0.0:9000") + go func() { + log.Fatalln(s.Serve(lis)) + }() + + maxMsgSize := 1024 * 1024 * 20 + // Create a client connection to the gRPC server we just started + // This is where the gRPC-Gateway proxies the requests + conn, err := grpc.DialContext( + context.Background(), + "0.0.0.0:8080", + grpc.WithBlock(), + grpc.WithInsecure(), // nolint + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize), grpc.MaxCallSendMsgSize(maxMsgSize)), + ) + if err != nil { + log.Fatalln("Failed to dial server:", err) + } + gwmux := grpcruntime.NewServeMux() + // Register User Service + err = blobproto.RegisterBlobServiceHandler(context.Background(), gwmux, conn) + if err != nil { + log.Fatalln("Failed to register gateway:", err) + } + gwServer := &http.Server{ + Addr: fmt.Sprintf(":%s", os.Getenv("server_port")), + Handler: gwmux, + } + log.Printf(fmt.Sprintf("Serving gRPC-Gateway on %s:%s", os.Getenv("server_host"), os.Getenv("server_port"))) // nolint + log.Fatalln(gwServer.ListenAndServe()) +} + // The middleware configuration is for the handler executors. These do not apply to the swagger.json document. // The middleware executes after routing but before authentication, binding and validation. func setupMiddlewares(handler http.Handler) http.Handler { diff --git a/restapi/doc.go b/restapi/doc.go index 727566a..9e113c5 100644 --- a/restapi/doc.go +++ b/restapi/doc.go @@ -6,7 +6,7 @@ // Schemes: // http // Host: blob-hub -// BasePath: /eth/v1 +// BasePath: / // Version: 1.0.0 // // Consumes: diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go index f12e85d..93db63d 100644 --- a/restapi/embedded_spec.go +++ b/restapi/embedded_spec.go @@ -28,9 +28,44 @@ func init() { "version": "1.0.0" }, "host": "blob-hub", - "basePath": "/eth/v1", "paths": { - "/beacon/blob_sidecars/{block_id}": { + "/": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "blob" + ], + "summary": "Get BSC blob sidecars by block num", + "operationId": "getBSCBlobSidecarsByBlockNum", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RPCRequest" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/RPCResponse" + } + }, + "500": { + "description": "internal server error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/eth/v1/beacon/blob_sidecars/{block_id}": { "get": { "produces": [ "application/json" @@ -89,6 +124,49 @@ func init() { } }, "definitions": { + "BSCBlobSidecar": { + "type": "object", + "properties": { + "blobs": { + "type": "array", + "items": { + "type": "string" + } + }, + "commitments": { + "type": "array", + "items": { + "type": "string" + } + }, + "proofs": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "BSCBlobTxSidecar": { + "type": "object", + "properties": { + "blobSidecar": { + "$ref": "#/definitions/BSCBlobSidecar" + }, + "blockHash": { + "type": "string" + }, + "blockNumber": { + "type": "string" + }, + "txHash": { + "type": "string" + }, + "txIndex": { + "type": "string" + } + } + }, "Error": { "type": "object", "properties": { @@ -129,6 +207,73 @@ func init() { } } }, + "RPCError": { + "type": "object", + "properties": { + "code": { + "description": "RPC error code", + "type": "integer", + "format": "int64", + "x-omitempty": false, + "example": -32602 + }, + "message": { + "description": "Error message", + "type": "string", + "x-omitempty": false, + "example": "Invalid params" + } + } + }, + "RPCRequest": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "jsonrpc": { + "type": "string", + "example": "2.0" + }, + "method": { + "type": "string", + "example": "eth_getBlobSidecars" + }, + "params": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "0x1", + true + ] + } + } + }, + "RPCResponse": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/RPCError" + }, + "id": { + "type": "integer", + "example": 1 + }, + "jsonrpc": { + "type": "string", + "example": "2.0" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/definitions/BSCBlobTxSidecar" + } + } + } + }, "Sidecar": { "type": "object", "properties": { @@ -146,7 +291,8 @@ func init() { "type": "array", "items": { "type": "string" - } + }, + "x-omitempty": true }, "kzg_proof": { "type": "string" @@ -178,6 +324,14 @@ func init() { "type": "string" } } + }, + "tx_hash": { + "type": "string" + }, + "tx_index": { + "type": "integer", + "format": "int64", + "x-omitempty": true } } } @@ -194,9 +348,44 @@ func init() { "version": "1.0.0" }, "host": "blob-hub", - "basePath": "/eth/v1", "paths": { - "/beacon/blob_sidecars/{block_id}": { + "/": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "blob" + ], + "summary": "Get BSC blob sidecars by block num", + "operationId": "getBSCBlobSidecarsByBlockNum", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RPCRequest" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/RPCResponse" + } + }, + "500": { + "description": "internal server error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/eth/v1/beacon/blob_sidecars/{block_id}": { "get": { "produces": [ "application/json" @@ -255,6 +444,49 @@ func init() { } }, "definitions": { + "BSCBlobSidecar": { + "type": "object", + "properties": { + "blobs": { + "type": "array", + "items": { + "type": "string" + } + }, + "commitments": { + "type": "array", + "items": { + "type": "string" + } + }, + "proofs": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "BSCBlobTxSidecar": { + "type": "object", + "properties": { + "blobSidecar": { + "$ref": "#/definitions/BSCBlobSidecar" + }, + "blockHash": { + "type": "string" + }, + "blockNumber": { + "type": "string" + }, + "txHash": { + "type": "string" + }, + "txIndex": { + "type": "string" + } + } + }, "Error": { "type": "object", "properties": { @@ -295,6 +527,73 @@ func init() { } } }, + "RPCError": { + "type": "object", + "properties": { + "code": { + "description": "RPC error code", + "type": "integer", + "format": "int64", + "x-omitempty": false, + "example": -32602 + }, + "message": { + "description": "Error message", + "type": "string", + "x-omitempty": false, + "example": "Invalid params" + } + } + }, + "RPCRequest": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "example": 1 + }, + "jsonrpc": { + "type": "string", + "example": "2.0" + }, + "method": { + "type": "string", + "example": "eth_getBlobSidecars" + }, + "params": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "0x1", + true + ] + } + } + }, + "RPCResponse": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/RPCError" + }, + "id": { + "type": "integer", + "example": 1 + }, + "jsonrpc": { + "type": "string", + "example": "2.0" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/definitions/BSCBlobTxSidecar" + } + } + } + }, "Sidecar": { "type": "object", "properties": { @@ -312,7 +611,8 @@ func init() { "type": "array", "items": { "type": "string" - } + }, + "x-omitempty": true }, "kzg_proof": { "type": "string" @@ -344,6 +644,14 @@ func init() { "type": "string" } } + }, + "tx_hash": { + "type": "string" + }, + "tx_index": { + "type": "integer", + "format": "int64", + "x-omitempty": true } } }, diff --git a/restapi/handlers/blob.go b/restapi/handlers/blob.go index 6d90b12..d6340d0 100644 --- a/restapi/handlers/blob.go +++ b/restapi/handlers/blob.go @@ -10,11 +10,10 @@ import ( "github.com/bnb-chain/blob-hub/models" "github.com/bnb-chain/blob-hub/restapi/operations/blob" "github.com/bnb-chain/blob-hub/service" + "github.com/bnb-chain/blob-hub/types" "github.com/bnb-chain/blob-hub/util" ) -const rootLength = 32 - func HandleGetBlobSidecars() func(params blob.GetBlobSidecarsByBlockNumParams) middleware.Responder { return func(params blob.GetBlobSidecarsByBlockNumParams) middleware.Responder { @@ -41,7 +40,7 @@ func HandleGetBlobSidecars() func(params blob.GetBlobSidecarsByBlockNumParams) m root, err = hexutil.Decode(blockID) if err == nil { - if len(root) != rootLength { + if len(root) != types.RootLength { return blob.NewGetBlobSidecarsByBlockNumBadRequest().WithPayload(service.BadRequestWithError(fmt.Errorf("invalid block root of length %d", len(root)))) } sidecars, err = service.BlobSvc.GetBlobSidecarsByRoot(hex.EncodeToString(root), indicesInx) @@ -53,7 +52,7 @@ func HandleGetBlobSidecars() func(params blob.GetBlobSidecarsByBlockNumParams) m if err != nil { return blob.NewGetBlobSidecarsByBlockNumBadRequest().WithPayload(service.BadRequestWithError(err)) } - sidecars, err = service.BlobSvc.GetBlobSidecarsBySlot(slot, indicesInx) + sidecars, err = service.BlobSvc.GetBlobSidecarsByBlockNumOrSlot(slot, indicesInx) if err != nil { return blob.NewGetBlobSidecarsByBlockNumInternalServerError().WithPayload(service.InternalErrorWithError(err)) } @@ -65,3 +64,82 @@ func HandleGetBlobSidecars() func(params blob.GetBlobSidecarsByBlockNumParams) m } } } + +func HandleGetBSCBlobSidecars() func(params blob.GetBSCBlobSidecarsByBlockNumParams) middleware.Responder { + return func(params blob.GetBSCBlobSidecarsByBlockNumParams) middleware.Responder { + + rpcRequest := params.Body + if rpcRequest.Params == nil { + return blob.NewGetBSCBlobSidecarsByBlockNumOK().WithPayload( + &models.RPCResponse{ + ID: rpcRequest.ID, + Jsonrpc: rpcRequest.Jsonrpc, + Error: &models.RPCError{ + Code: -32600, + Message: "Invalid request", + }, + }, + ) + } + + switch rpcRequest.Method { + case "eth_getBlobSidecars": + blockNum, err := util.HexToUint64(rpcRequest.Params[0]) + if err != nil { + return blob.NewGetBSCBlobSidecarsByBlockNumOK().WithPayload( + &models.RPCResponse{ + ID: rpcRequest.ID, + Jsonrpc: rpcRequest.Jsonrpc, + Error: &models.RPCError{ + Code: -32602, + Message: "invalid argument", + }, + }, + ) + } + sidecars, err := service.BlobSvc.GetBlobSidecarsByBlockNumOrSlot(blockNum, nil) + if err != nil { + return blob.NewGetBlobSidecarsByBlockNumInternalServerError().WithPayload(service.InternalErrorWithError(err)) + } + // group sidecars by tx hash + bscTxSidecars := make(map[string]*models.BSCBlobTxSidecar) + for _, sidecar := range sidecars { + txSidecar, ok := bscTxSidecars[sidecar.TxHash] + if !ok { + txSidecar = &models.BSCBlobTxSidecar{ + BlobSidecar: &models.BSCBlobSidecar{}, + TxHash: sidecar.TxHash, + } + bscTxSidecars[sidecar.TxHash] = txSidecar + } + txSidecar.BlobSidecar.Blobs = append(txSidecar.BlobSidecar.Blobs, sidecar.Blob) + txSidecar.BlobSidecar.Commitments = append(txSidecar.BlobSidecar.Commitments, sidecar.KzgCommitment) + txSidecar.BlobSidecar.Proofs = append(txSidecar.BlobSidecar.Proofs, sidecar.KzgProof) + txSidecar.TxIndex = util.Int64ToHex(sidecar.TxIndex) + txSidecar.BlockNumber = rpcRequest.Params[0] + } + // convert txSidecars to array + txSidecarsArr := make([]*models.BSCBlobTxSidecar, 0) + for _, txSidecar := range bscTxSidecars { + txSidecarsArr = append(txSidecarsArr, txSidecar) + } + response := &models.RPCResponse{ + ID: rpcRequest.ID, + Jsonrpc: rpcRequest.Jsonrpc, + Result: txSidecarsArr, + } + return blob.NewGetBSCBlobSidecarsByBlockNumOK().WithPayload(response) + default: + return blob.NewGetBSCBlobSidecarsByBlockNumOK().WithPayload( + &models.RPCResponse{ + ID: rpcRequest.ID, + Jsonrpc: rpcRequest.Jsonrpc, + Error: &models.RPCError{ + Code: -32601, + Message: "method not supported", + }, + }, + ) + } + } +} diff --git a/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num.go b/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num.go new file mode 100644 index 0000000..e99a10f --- /dev/null +++ b/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package blob + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// GetBSCBlobSidecarsByBlockNumHandlerFunc turns a function with the right signature into a get b s c blob sidecars by block num handler +type GetBSCBlobSidecarsByBlockNumHandlerFunc func(GetBSCBlobSidecarsByBlockNumParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetBSCBlobSidecarsByBlockNumHandlerFunc) Handle(params GetBSCBlobSidecarsByBlockNumParams) middleware.Responder { + return fn(params) +} + +// GetBSCBlobSidecarsByBlockNumHandler interface for that can handle valid get b s c blob sidecars by block num params +type GetBSCBlobSidecarsByBlockNumHandler interface { + Handle(GetBSCBlobSidecarsByBlockNumParams) middleware.Responder +} + +// NewGetBSCBlobSidecarsByBlockNum creates a new http.Handler for the get b s c blob sidecars by block num operation +func NewGetBSCBlobSidecarsByBlockNum(ctx *middleware.Context, handler GetBSCBlobSidecarsByBlockNumHandler) *GetBSCBlobSidecarsByBlockNum { + return &GetBSCBlobSidecarsByBlockNum{Context: ctx, Handler: handler} +} + +/* + GetBSCBlobSidecarsByBlockNum swagger:route POST / blob getBSCBlobSidecarsByBlockNum + +Get BSC blob sidecars by block num +*/ +type GetBSCBlobSidecarsByBlockNum struct { + Context *middleware.Context + Handler GetBSCBlobSidecarsByBlockNumHandler +} + +func (o *GetBSCBlobSidecarsByBlockNum) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewGetBSCBlobSidecarsByBlockNumParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_parameters.go b/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_parameters.go new file mode 100644 index 0000000..9592a88 --- /dev/null +++ b/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_parameters.go @@ -0,0 +1,84 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package blob + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "io" + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/validate" + + "github.com/bnb-chain/blob-hub/models" +) + +// NewGetBSCBlobSidecarsByBlockNumParams creates a new GetBSCBlobSidecarsByBlockNumParams object +// +// There are no default values defined in the spec. +func NewGetBSCBlobSidecarsByBlockNumParams() GetBSCBlobSidecarsByBlockNumParams { + + return GetBSCBlobSidecarsByBlockNumParams{} +} + +// GetBSCBlobSidecarsByBlockNumParams contains all the bound params for the get b s c blob sidecars by block num operation +// typically these are obtained from a http.Request +// +// swagger:parameters getBSCBlobSidecarsByBlockNum +type GetBSCBlobSidecarsByBlockNumParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /* + Required: true + In: body + */ + Body *models.RPCRequest +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewGetBSCBlobSidecarsByBlockNumParams() beforehand. +func (o *GetBSCBlobSidecarsByBlockNumParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + if runtime.HasBody(r) { + defer r.Body.Close() + var body models.RPCRequest + if err := route.Consumer.Consume(r.Body, &body); err != nil { + if err == io.EOF { + res = append(res, errors.Required("body", "body", "")) + } else { + res = append(res, errors.NewParseError("body", "body", "", err)) + } + } else { + // validate body object + if err := body.Validate(route.Formats); err != nil { + res = append(res, err) + } + + ctx := validate.WithOperationRequest(r.Context()) + if err := body.ContextValidate(ctx, route.Formats); err != nil { + res = append(res, err) + } + + if len(res) == 0 { + o.Body = &body + } + } + } else { + res = append(res, errors.Required("body", "body", "")) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_responses.go b/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_responses.go new file mode 100644 index 0000000..e617de3 --- /dev/null +++ b/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_responses.go @@ -0,0 +1,104 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package blob + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/bnb-chain/blob-hub/models" +) + +// GetBSCBlobSidecarsByBlockNumOKCode is the HTTP code returned for type GetBSCBlobSidecarsByBlockNumOK +const GetBSCBlobSidecarsByBlockNumOKCode int = 200 + +/* +GetBSCBlobSidecarsByBlockNumOK successful operation + +swagger:response getBSCBlobSidecarsByBlockNumOK +*/ +type GetBSCBlobSidecarsByBlockNumOK struct { + + /* + In: Body + */ + Payload *models.RPCResponse `json:"body,omitempty"` +} + +// NewGetBSCBlobSidecarsByBlockNumOK creates GetBSCBlobSidecarsByBlockNumOK with default headers values +func NewGetBSCBlobSidecarsByBlockNumOK() *GetBSCBlobSidecarsByBlockNumOK { + + return &GetBSCBlobSidecarsByBlockNumOK{} +} + +// WithPayload adds the payload to the get b s c blob sidecars by block num o k response +func (o *GetBSCBlobSidecarsByBlockNumOK) WithPayload(payload *models.RPCResponse) *GetBSCBlobSidecarsByBlockNumOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get b s c blob sidecars by block num o k response +func (o *GetBSCBlobSidecarsByBlockNumOK) SetPayload(payload *models.RPCResponse) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetBSCBlobSidecarsByBlockNumOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetBSCBlobSidecarsByBlockNumInternalServerErrorCode is the HTTP code returned for type GetBSCBlobSidecarsByBlockNumInternalServerError +const GetBSCBlobSidecarsByBlockNumInternalServerErrorCode int = 500 + +/* +GetBSCBlobSidecarsByBlockNumInternalServerError internal server error + +swagger:response getBSCBlobSidecarsByBlockNumInternalServerError +*/ +type GetBSCBlobSidecarsByBlockNumInternalServerError struct { + + /* + In: Body + */ + Payload *models.Error `json:"body,omitempty"` +} + +// NewGetBSCBlobSidecarsByBlockNumInternalServerError creates GetBSCBlobSidecarsByBlockNumInternalServerError with default headers values +func NewGetBSCBlobSidecarsByBlockNumInternalServerError() *GetBSCBlobSidecarsByBlockNumInternalServerError { + + return &GetBSCBlobSidecarsByBlockNumInternalServerError{} +} + +// WithPayload adds the payload to the get b s c blob sidecars by block num internal server error response +func (o *GetBSCBlobSidecarsByBlockNumInternalServerError) WithPayload(payload *models.Error) *GetBSCBlobSidecarsByBlockNumInternalServerError { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get b s c blob sidecars by block num internal server error response +func (o *GetBSCBlobSidecarsByBlockNumInternalServerError) SetPayload(payload *models.Error) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetBSCBlobSidecarsByBlockNumInternalServerError) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(500) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_urlbuilder.go b/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_urlbuilder.go new file mode 100644 index 0000000..4282805 --- /dev/null +++ b/restapi/operations/blob/get_b_s_c_blob_sidecars_by_block_num_urlbuilder.go @@ -0,0 +1,84 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package blob + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "errors" + "net/url" + golangswaggerpaths "path" +) + +// GetBSCBlobSidecarsByBlockNumURL generates an URL for the get b s c blob sidecars by block num operation +type GetBSCBlobSidecarsByBlockNumURL struct { + _basePath string +} + +// WithBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetBSCBlobSidecarsByBlockNumURL) WithBasePath(bp string) *GetBSCBlobSidecarsByBlockNumURL { + o.SetBasePath(bp) + return o +} + +// SetBasePath sets the base path for this url builder, only required when it's different from the +// base path specified in the swagger spec. +// When the value of the base path is an empty string +func (o *GetBSCBlobSidecarsByBlockNumURL) SetBasePath(bp string) { + o._basePath = bp +} + +// Build a url path and query string +func (o *GetBSCBlobSidecarsByBlockNumURL) Build() (*url.URL, error) { + var _result url.URL + + var _path = "/" + + _basePath := o._basePath + _result.Path = golangswaggerpaths.Join(_basePath, _path) + + return &_result, nil +} + +// Must is a helper function to panic when the url builder returns an error +func (o *GetBSCBlobSidecarsByBlockNumURL) Must(u *url.URL, err error) *url.URL { + if err != nil { + panic(err) + } + if u == nil { + panic("url can't be nil") + } + return u +} + +// String returns the string representation of the path with query string +func (o *GetBSCBlobSidecarsByBlockNumURL) String() string { + return o.Must(o.Build()).String() +} + +// BuildFull builds a full url with scheme, host, path and query string +func (o *GetBSCBlobSidecarsByBlockNumURL) BuildFull(scheme, host string) (*url.URL, error) { + if scheme == "" { + return nil, errors.New("scheme is required for a full url on GetBSCBlobSidecarsByBlockNumURL") + } + if host == "" { + return nil, errors.New("host is required for a full url on GetBSCBlobSidecarsByBlockNumURL") + } + + base, err := o.Build() + if err != nil { + return nil, err + } + + base.Scheme = scheme + base.Host = host + return base, nil +} + +// StringFull returns the string representation of a complete url +func (o *GetBSCBlobSidecarsByBlockNumURL) StringFull(scheme, host string) string { + return o.Must(o.BuildFull(scheme, host)).String() +} diff --git a/restapi/operations/blob/get_blob_sidecars_by_block_num.go b/restapi/operations/blob/get_blob_sidecars_by_block_num.go index 40ca57d..23aa5b1 100644 --- a/restapi/operations/blob/get_blob_sidecars_by_block_num.go +++ b/restapi/operations/blob/get_blob_sidecars_by_block_num.go @@ -30,7 +30,7 @@ func NewGetBlobSidecarsByBlockNum(ctx *middleware.Context, handler GetBlobSideca } /* - GetBlobSidecarsByBlockNum swagger:route GET /beacon/blob_sidecars/{block_id} blob getBlobSidecarsByBlockNum + GetBlobSidecarsByBlockNum swagger:route GET /eth/v1/beacon/blob_sidecars/{block_id} blob getBlobSidecarsByBlockNum Get blob sidecars by block num */ diff --git a/restapi/operations/blob/get_blob_sidecars_by_block_num_urlbuilder.go b/restapi/operations/blob/get_blob_sidecars_by_block_num_urlbuilder.go index 037eabe..82982db 100644 --- a/restapi/operations/blob/get_blob_sidecars_by_block_num_urlbuilder.go +++ b/restapi/operations/blob/get_blob_sidecars_by_block_num_urlbuilder.go @@ -44,7 +44,7 @@ func (o *GetBlobSidecarsByBlockNumURL) SetBasePath(bp string) { func (o *GetBlobSidecarsByBlockNumURL) Build() (*url.URL, error) { var _result url.URL - var _path = "/beacon/blob_sidecars/{block_id}" + var _path = "/eth/v1/beacon/blob_sidecars/{block_id}" blockID := o.BlockID if blockID != "" { @@ -54,9 +54,6 @@ func (o *GetBlobSidecarsByBlockNumURL) Build() (*url.URL, error) { } _basePath := o._basePath - if _basePath == "" { - _basePath = "/eth/v1" - } _result.Path = golangswaggerpaths.Join(_basePath, _path) qs := make(url.Values) diff --git a/restapi/operations/blob_hub_api.go b/restapi/operations/blob_hub_api.go index 1cd2281..bbdfb2b 100644 --- a/restapi/operations/blob_hub_api.go +++ b/restapi/operations/blob_hub_api.go @@ -44,6 +44,9 @@ func NewBlobHubAPI(spec *loads.Document) *BlobHubAPI { JSONProducer: runtime.JSONProducer(), + BlobGetBSCBlobSidecarsByBlockNumHandler: blob.GetBSCBlobSidecarsByBlockNumHandlerFunc(func(params blob.GetBSCBlobSidecarsByBlockNumParams) middleware.Responder { + return middleware.NotImplemented("operation blob.GetBSCBlobSidecarsByBlockNum has not yet been implemented") + }), BlobGetBlobSidecarsByBlockNumHandler: blob.GetBlobSidecarsByBlockNumHandlerFunc(func(params blob.GetBlobSidecarsByBlockNumParams) middleware.Responder { return middleware.NotImplemented("operation blob.GetBlobSidecarsByBlockNum has not yet been implemented") }), @@ -83,6 +86,8 @@ type BlobHubAPI struct { // - application/json JSONProducer runtime.Producer + // BlobGetBSCBlobSidecarsByBlockNumHandler sets the operation handler for the get b s c blob sidecars by block num operation + BlobGetBSCBlobSidecarsByBlockNumHandler blob.GetBSCBlobSidecarsByBlockNumHandler // BlobGetBlobSidecarsByBlockNumHandler sets the operation handler for the get blob sidecars by block num operation BlobGetBlobSidecarsByBlockNumHandler blob.GetBlobSidecarsByBlockNumHandler @@ -162,6 +167,9 @@ func (o *BlobHubAPI) Validate() error { unregistered = append(unregistered, "JSONProducer") } + if o.BlobGetBSCBlobSidecarsByBlockNumHandler == nil { + unregistered = append(unregistered, "blob.GetBSCBlobSidecarsByBlockNumHandler") + } if o.BlobGetBlobSidecarsByBlockNumHandler == nil { unregistered = append(unregistered, "blob.GetBlobSidecarsByBlockNumHandler") } @@ -253,10 +261,14 @@ func (o *BlobHubAPI) initHandlerCache() { o.handlers = make(map[string]map[string]http.Handler) } + if o.handlers["POST"] == nil { + o.handlers["POST"] = make(map[string]http.Handler) + } + o.handlers["POST"][""] = blob.NewGetBSCBlobSidecarsByBlockNum(o.context, o.BlobGetBSCBlobSidecarsByBlockNumHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } - o.handlers["GET"]["/beacon/blob_sidecars/{block_id}"] = blob.NewGetBlobSidecarsByBlockNum(o.context, o.BlobGetBlobSidecarsByBlockNumHandler) + o.handlers["GET"]["/eth/v1/beacon/blob_sidecars/{block_id}"] = blob.NewGetBlobSidecarsByBlockNum(o.context, o.BlobGetBlobSidecarsByBlockNumHandler) } // Serve creates a http handler to serve the API over HTTP diff --git a/scripts/.env b/scripts/.env index c520202..2c00dd4 100644 --- a/scripts/.env +++ b/scripts/.env @@ -1,7 +1,7 @@ -PRIVATE_KEY=.... -BUCKET_NAME=eth-blob -GRANTEE_BUNDLE_ACCOUNT=0x.... +PRIVATE_KEY=... +BUCKET_NAME=... +GRANTEE_BUNDLE_ACCOUNT=... GREENFIELD_RPC=https://gnfd-testnet-fullnode-tendermint-us.bnbchain.org:443 GREENFIELD_CHAIN_ID=greenfield_5600-1 ALLOWANCE=10000000000000000000 -SP_ADDRESS=0x5fff5a6c94b182fb965b40c7b9f30199b969ed2f \ No newline at end of file +SP_ADDRESS=... \ No newline at end of file diff --git a/server-distroless.dockerfile b/server-distroless.dockerfile index 172e58c..bc8279e 100644 --- a/server-distroless.dockerfile +++ b/server-distroless.dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20-alpine as builder +FROM golang:1.22-alpine as builder # Set up apk dependencies ENV PACKAGES make git libc-dev bash gcc linux-headers eudev-dev curl ca-certificates build-base diff --git a/service/blob.go b/service/blob.go index 5fe80fc..9f2c5bc 100644 --- a/service/blob.go +++ b/service/blob.go @@ -6,7 +6,7 @@ import ( "github.com/bnb-chain/blob-hub/cache" "github.com/bnb-chain/blob-hub/config" "github.com/bnb-chain/blob-hub/db" - "github.com/bnb-chain/blob-hub/external" + "github.com/bnb-chain/blob-hub/external/cmn" "github.com/bnb-chain/blob-hub/models" "github.com/bnb-chain/blob-hub/util" ) @@ -15,35 +15,35 @@ const prefixHex = "0x" type Blob interface { GetBlobSidecarsByRoot(root string, indices []int64) ([]*models.Sidecar, error) - GetBlobSidecarsBySlot(slot uint64, indices []int64) ([]*models.Sidecar, error) + GetBlobSidecarsByBlockNumOrSlot(slot uint64, indices []int64) ([]*models.Sidecar, error) } type BlobService struct { blobDB db.BlobDao - bundleClient *external.BundleClient + bundleClient *cmn.BundleClient cacheService cache.Cache - config *config.ServerConfig + cfg *config.ServerConfig } -func NewBlobService(blobDB db.BlobDao, bundleClient *external.BundleClient, cache cache.Cache, config *config.ServerConfig) Blob { +func NewBlobService(blobDB db.BlobDao, bundleClient *cmn.BundleClient, cache cache.Cache, config *config.ServerConfig) Blob { return &BlobService{ blobDB: blobDB, bundleClient: bundleClient, cacheService: cache, - config: config, + cfg: config, } } -func (b BlobService) GetBlobSidecarsBySlot(slot uint64, indices []int64) ([]*models.Sidecar, error) { +func (b BlobService) GetBlobSidecarsByBlockNumOrSlot(blockNumOrSlot uint64, indices []int64) ([]*models.Sidecar, error) { var err error - blobs, found := b.cacheService.Get(util.Uint64ToString(slot)) + blobs, found := b.cacheService.Get(util.Uint64ToString(blockNumOrSlot)) if found { blobsFound := blobs.([]*models.Sidecar) if len(indices) != 0 { blobReturn := make([]*models.Sidecar, 0) for _, idx := range indices { if int(idx) >= len(blobsFound) { - return nil, fmt.Errorf("index %d out of bound, only %d blob at slot %d", idx, len(blobsFound), slot) + return nil, fmt.Errorf("index %d out of bound, only %d blob at block %d", idx, len(blobsFound), blockNumOrSlot) } blobReturn = append(blobReturn, blobsFound[idx]) } @@ -52,19 +52,19 @@ func (b BlobService) GetBlobSidecarsBySlot(slot uint64, indices []int64) ([]*mod return blobsFound, nil } - block, err := b.blobDB.GetBlock(slot) + block, err := b.blobDB.GetBlock(blockNumOrSlot) if err != nil { return nil, err } var blobMetas []*db.Blob if len(indices) == 0 { - blobMetas, err = b.blobDB.GetBlobBySlot(slot) + blobMetas, err = b.blobDB.GetBlobByBlockID(blockNumOrSlot) if err != nil { return nil, err } } else { - blobMetas, err = b.blobDB.GetBlobBySlotAndIndices(slot, indices) + blobMetas, err = b.blobDB.GetBlobByBlockIDAndIndices(blockNumOrSlot, indices) if err != nil { return nil, err } @@ -72,19 +72,22 @@ func (b BlobService) GetBlobSidecarsBySlot(slot uint64, indices []int64) ([]*mod sideCars := make([]*models.Sidecar, 0) for _, meta := range blobMetas { - bundleObject, err := b.bundleClient.GetObject(b.config.BucketName, block.BundleName, meta.Name) + bundleObject, err := b.bundleClient.GetObject(b.cfg.BucketName, block.BundleName, meta.Name) if err != nil { return nil, err } - header := &models.SidecarSignedBlockHeader{ - Message: &models.SidecarSignedBlockHeaderMessage{ - BodyRoot: fmt.Sprintf("%s%s", prefixHex, block.BodyRoot), - ParentRoot: fmt.Sprintf("%s%s", prefixHex, block.ParentRoot), - StateRoot: fmt.Sprintf("%s%s", prefixHex, block.StateRoot), - ProposerIndex: util.Uint64ToString(block.ProposerIndex), - Slot: util.Uint64ToString(block.Slot), - }, - Signature: fmt.Sprintf("%s%s", prefixHex, block.Signature), + var header *models.SidecarSignedBlockHeader + if b.cfg.Chain == config.ETH { + header = &models.SidecarSignedBlockHeader{ + Message: &models.SidecarSignedBlockHeaderMessage{ + BodyRoot: fmt.Sprintf("%s%s", prefixHex, block.BodyRoot), + ParentRoot: fmt.Sprintf("%s%s", prefixHex, block.ParentRoot), + StateRoot: fmt.Sprintf("%s%s", prefixHex, block.StateRoot), + ProposerIndex: util.Uint64ToString(block.ProposerIndex), + Slot: util.Uint64ToString(block.Slot), + }, + Signature: fmt.Sprintf("%s%s", prefixHex, block.Signature), + } } sideCars = append(sideCars, &models.Sidecar{ @@ -94,12 +97,14 @@ func (b BlobService) GetBlobSidecarsBySlot(slot uint64, indices []int64) ([]*mod KzgCommitment: meta.KzgCommitment, KzgProof: meta.KzgProof, SignedBlockHeader: header, + TxIndex: int64(meta.TxIndex), + TxHash: meta.TxHash, }) } // cache all blobs at a specified slot if len(indices) == 0 { - b.cacheService.Set(util.Uint64ToString(slot), sideCars) + b.cacheService.Set(util.Uint64ToString(blockNumOrSlot), sideCars) } return sideCars, nil } @@ -109,5 +114,5 @@ func (b BlobService) GetBlobSidecarsByRoot(root string, indices []int64) ([]*mod if err != nil { return nil, err } - return b.GetBlobSidecarsBySlot(block.Slot, indices) + return b.GetBlobSidecarsByBlockNumOrSlot(block.Slot, indices) } diff --git a/swagger.yaml b/swagger.yaml index 8dbd557..5b3cea9 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -4,12 +4,12 @@ info: title: Blob Hub Service API description: API for handling blob query in the Blob Hub. host: 'blob-hub' -basePath: "/eth/v1" +#basePath: "/eth/v1" schemes: - http paths: - /beacon/blob_sidecars/{block_id}: + /eth/v1/beacon/blob_sidecars/{block_id}: get: tags: - "blob" @@ -48,6 +48,30 @@ paths: schema: $ref: "#/definitions/Error" + /: + post: + tags: + - "blob" + summary: "Get BSC blob sidecars by block num" + operationId: "getBSCBlobSidecarsByBlockNum" + produces: + - "application/json" + parameters: + - in: "body" + name: "body" + required: true + schema: + $ref: "#/definitions/RPCRequest" + responses: + "200": + description: "successful operation" + schema: + $ref: "#/definitions/RPCResponse" + "500": + description: 'internal server error' + schema: + $ref: "#/definitions/Error" + definitions: GetBlobSideCarsResponse: type: object @@ -79,6 +103,7 @@ definitions: type: string kzg_commitment_inclusion_proof: type: array + x-omitempty: true items: type: string signed_block_header: @@ -99,6 +124,92 @@ definitions: type: string body_root: type: string + tx_index: + type: integer + format: int64 + x-omitempty: true + tx_hash: + type: string + + RPCRequest: + type: object + properties: + jsonrpc: + type: string + example: "2.0" + method: + type: string + example: "eth_getBlobSidecars" + params: + type: array + items: + type: string + example: ["0x1", true] + id: + type: integer + example: 1 + + RPCResponse: + type: object + properties: + jsonrpc: + type: string + example: "2.0" + result: + type: array + items: + $ref: "#/definitions/BSCBlobTxSidecar" + id: + type: integer + example: 1 + error: + $ref: "#/definitions/RPCError" + + + BSCBlobSidecar: + type: object + properties: + blobs: + type: array + items: + type: string + commitments: + type: array + items: + type: string + proofs: + type: array + items: + type: "string" + + BSCBlobTxSidecar: + type: object + properties: + blobSidecar: + $ref: "#/definitions/BSCBlobSidecar" + blockNumber: + type: string + blockHash: + type: string + txIndex: + type: string + txHash: + type: string + + RPCError: + type: object + properties: + code: + x-omitempty: false + type: integer + format: int64 + description: "RPC error code" + example: -32602 + message: + x-omitempty: false + type: string + description: "Error message" + example: "Invalid params" Error: type: object diff --git a/syncer-distroless.dockerfile b/syncer-distroless.dockerfile index f2765b9..43ac7ef 100644 --- a/syncer-distroless.dockerfile +++ b/syncer-distroless.dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20-alpine as builder +FROM golang:1.22-alpine as builder # Set up apk dependencies ENV PACKAGES make git libc-dev bash gcc linux-headers eudev-dev curl ca-certificates build-base diff --git a/syncer/syncer.go b/syncer/syncer.go index cd9bda5..3a634fd 100644 --- a/syncer/syncer.go +++ b/syncer/syncer.go @@ -22,6 +22,8 @@ import ( "github.com/bnb-chain/blob-hub/config" "github.com/bnb-chain/blob-hub/db" "github.com/bnb-chain/blob-hub/external" + "github.com/bnb-chain/blob-hub/external/cmn" + "github.com/bnb-chain/blob-hub/external/eth" "github.com/bnb-chain/blob-hub/logging" "github.com/bnb-chain/blob-hub/metrics" "github.com/bnb-chain/blob-hub/types" @@ -33,48 +35,49 @@ const ( BundleStatusCreatedOnChain = 2 BundleStatusSealedOnChain = 3 - LoopSleepTime = 10 * time.Millisecond - PauseTime = 90 * time.Second + LoopSleepTime = 10 * time.Millisecond + BSCPauseTime = 3 * time.Second + + ETHPauseTime = 90 * time.Second RPCTimeout = 20 * time.Second MonitorQuotaInterval = 5 * time.Minute ) type curBundleDetail struct { - name string - startSlot uint64 - finalizeSlot uint64 + name string + startBlockID uint64 + finalizeBlockID uint64 } type BlobSyncer struct { blobDao db.BlobDao - ethClients *external.ETHClient - bundleClient *external.BundleClient + client external.IClient + bundleClient *cmn.BundleClient config *config.SyncerConfig bundleDetail *curBundleDetail - spClient *external.SPClient + spClient *cmn.SPClient } func NewBlobSyncer( blobDao db.BlobDao, - config *config.SyncerConfig, + cfg *config.SyncerConfig, ) *BlobSyncer { - pkBz, err := hex.DecodeString(config.PrivateKey) + pkBz, err := hex.DecodeString(cfg.PrivateKey) if err != nil { panic(err) } - bundleClient, err := external.NewBundleClient(config.BundleServiceEndpoints[0], external.WithPrivateKey(pkBz)) + bundleClient, err := cmn.NewBundleClient(cfg.BundleServiceEndpoints[0], cmn.WithPrivateKey(pkBz)) if err != nil { panic(err) } - clients := external.NewETHClient(config.ETHRPCAddrs[0], config.BeaconRPCAddrs[0]) bs := &BlobSyncer{ blobDao: blobDao, - ethClients: clients, bundleClient: bundleClient, - config: config, + config: cfg, } - if config.MetricsConfig.Enable && len(config.MetricsConfig.SPEndpoint) > 0 { - spClient, err := external.NewSPClient(config.MetricsConfig.SPEndpoint) + bs.client = external.NewClient(cfg) + if cfg.MetricsConfig.Enable && len(cfg.MetricsConfig.SPEndpoint) > 0 { + spClient, err := cmn.NewSPClient(cfg.MetricsConfig.SPEndpoint) if err != nil { panic(err) } @@ -85,11 +88,12 @@ func NewBlobSyncer( func (s *BlobSyncer) StartLoop() { go func() { - nextSlot, err := s.calNextSlot() + // nextBlockID defines the block number (BSC) or slot(ETH) + nextBlockID, err := s.getNextBlockNumOrSlot() if err != nil { panic(err) } - err = s.LoadProgressAndResume(nextSlot) + err = s.LoadProgressAndResume(nextBlockID) if err != nil { panic(err) } @@ -115,103 +119,126 @@ func (s *BlobSyncer) StartLoop() { func (s *BlobSyncer) sync() error { var ( - nextSlot uint64 - err error - block, latestBlockResp *structs.GetBlockV2Response + blockID uint64 + err error + block *structs.GetBlockV2Response ) - nextSlot, err = s.calNextSlot() + blockID, err = s.getNextBlockNumOrSlot() if err != nil { return err } ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout) defer cancel() + var isForkedBlock bool - block, err = s.ethClients.BeaconClient.GetBlock(ctx, nextSlot) - if err != nil { - if err != external.ErrBlockNotFound { - return err - } - // Both try to get forked block and non-exist block will return 404. When the response is ErrBlockNotFound, - // check whether nextSlot is >= latest slot, otherwise it is a forked block, should skip it. - latestBlockResp, err = s.ethClients.BeaconClient.GetLatestBlock(ctx) + if s.BSCChain() { + finalizedBlockNum, err := s.client.GetFinalizedBlockNum(context.Background()) if err != nil { - logging.Logger.Errorf("failed to get latest becon block, err=%s", err.Error()) return err } - clBlock, _, err := ToBlockAndExecutionPayloadDeneb(latestBlockResp) + if int64(blockID) >= int64(finalizedBlockNum) { + time.Sleep(BSCPauseTime) + return nil + } + } else { + var latestBlockResp *structs.GetBlockV2Response + block, err = s.client.GetBeaconBlock(ctx, blockID) if err != nil { - logging.Logger.Errorf("failed to ToBlockAndExecutionPayloadDeneb, err=%s", err.Error()) - return err + if err != eth.ErrBlockNotFound { + return err + } + // Both try to get forked block and non-exist block will return 404. When the response is ErrBlockNotFound, + // check whether nextSlot is >= latest slot, otherwise it is a forked block, should skip it. + latestBlockResp, err = s.client.GetLatestBeaconBlock(ctx) + if err != nil { + logging.Logger.Errorf("failed to get latest becon block, err=%s", err.Error()) + return err + } + clBlock, _, err := ToBlockAndExecutionPayloadDeneb(latestBlockResp) + if err != nil { + logging.Logger.Errorf("failed to ToBlockAndExecutionPayloadDeneb, err=%s", err.Error()) + return err + } + if blockID >= uint64(clBlock.Slot) { + logging.Logger.Debugf("the next slot %d is larger than current block slot %d\n", blockID, clBlock.Slot) + time.Sleep(ETHPauseTime) + return nil + } + isForkedBlock = true } - if nextSlot >= uint64(clBlock.Slot) { - logging.Logger.Debugf("the next slot %d is larger than current block slot %d\n", nextSlot, clBlock.Slot) - time.Sleep(PauseTime) + if block != nil && !block.Finalized { + logging.Logger.Infof("current block(slot=%d) is not finalized yet", blockID) + time.Sleep(ETHPauseTime) return nil } - isForkedBlock = true } - if block != nil && !block.Finalized { - logging.Logger.Infof("current block(slot=%d) is not finalized yet", nextSlot) - time.Sleep(PauseTime) - return nil - } + var sideCars []*types.GeneralSideCar - var sideCars []*structs.Sidecar if !isForkedBlock { ctx, cancel = context.WithTimeout(context.Background(), RPCTimeout) defer cancel() - sideCars, err = s.ethClients.BeaconClient.GetBlob(ctx, nextSlot) + sideCars, err = s.client.GetBlob(ctx, blockID) if err != nil { return err } } bundleName := s.bundleDetail.name - // create a new bundle in local. - if nextSlot == s.bundleDetail.startSlot { - if err = s.createLocalBundleDir(); err != nil { - logging.Logger.Errorf("failed to create local bundle dir, bundle=%s, err=%s", bundleName, err.Error()) - return err - } - } - if err = s.writeBlobToFile(nextSlot, bundleName, sideCars); err != nil { + err = s.process(bundleName, blockID, sideCars) + if err != nil { return err } - if nextSlot == s.bundleDetail.finalizeSlot { - err = s.finalizeCurBundle(bundleName) - if err != nil { - return err - } - logging.Logger.Infof("finalized bundle, bundle_name=%s, bucket_name=%s\n", bundleName, s.getBucketName()) - // init next bundle - startSlot := nextSlot + 1 - endSlot := nextSlot + s.getCreateBundleSlotInterval() - s.bundleDetail = &curBundleDetail{ - name: types.GetBundleName(startSlot, endSlot), - startSlot: startSlot, - finalizeSlot: endSlot, - } - } if isForkedBlock { return s.blobDao.SaveBlockAndBlob(&db.Block{ - Slot: nextSlot, + Slot: blockID, BundleName: bundleName, }, nil) } - blockToSave, blobToSave, err := s.ToBlockAndBlobs(block, sideCars, nextSlot, bundleName) + blockToSave, blobToSave, err := s.toBlockAndBlobs(block, sideCars, blockID, bundleName) if err != nil { return err } + err = s.blobDao.SaveBlockAndBlob(blockToSave, blobToSave) if err != nil { logging.Logger.Errorf("failed to save block(h=%d) and Blob(count=%d), err=%s", blockToSave.Slot, len(blobToSave), err.Error()) return err } - metrics.SyncedSlotGauge.Set(float64(nextSlot)) - logging.Logger.Infof("saved block(slot=%d) and blobs(num=%d) to DB \n", nextSlot, len(blobToSave)) + metrics.SyncedBlockIDGauge.Set(float64(blockID)) + logging.Logger.Infof("saved block(block_id=%d) and blobs(num=%d) to DB \n", blockID, len(blobToSave)) + return nil +} + +func (s *BlobSyncer) process(bundleName string, blockID uint64, sidecars []*types.GeneralSideCar) error { + var err error + // create a new bundle in local. + if blockID == s.bundleDetail.startBlockID { + if err = s.createLocalBundleDir(); err != nil { + logging.Logger.Errorf("failed to create local bundle dir, bundle=%s, err=%s", bundleName, err.Error()) + return err + } + } + if err = s.writeBlobToFile(blockID, bundleName, sidecars); err != nil { + return err + } + if blockID == s.bundleDetail.finalizeBlockID { + err = s.finalizeCurBundle(bundleName) + if err != nil { + return err + } + logging.Logger.Infof("finalized bundle, bundle_name=%s, bucket_name=%s\n", bundleName, s.getBucketName()) + // init next bundle + startBlockID := blockID + 1 + endBlockID := blockID + s.getCreateBundleInterval() + s.bundleDetail = &curBundleDetail{ + name: types.GetBundleName(startBlockID, endBlockID), + startBlockID: startBlockID, + finalizeBlockID: endBlockID, + } + } return nil } @@ -219,21 +246,21 @@ func (s *BlobSyncer) getBucketName() string { return s.config.BucketName } -func (s *BlobSyncer) getCreateBundleSlotInterval() uint64 { - return s.config.GetCreateBundleSlotInterval() +func (s *BlobSyncer) getCreateBundleInterval() uint64 { + return s.config.GetCreateBundleInterval() } -func (s *BlobSyncer) calNextSlot() (uint64, error) { +func (s *BlobSyncer) getNextBlockNumOrSlot() (uint64, error) { latestProcessedBlock, err := s.blobDao.GetLatestProcessedBlock() if err != nil { return 0, fmt.Errorf("failed to get latest polled block from db, error: %s", err.Error()) } latestPolledBlockSlot := latestProcessedBlock.Slot - nextSlot := s.config.StartSlot - if nextSlot <= latestPolledBlockSlot { - nextSlot = latestPolledBlockSlot + 1 + nextBlockID := s.config.StartSlotOrBlock + if nextBlockID <= latestPolledBlockSlot { + nextBlockID = latestPolledBlockSlot + 1 } - return nextSlot, nil + return nextBlockID, nil } // createLocalBundleDir creates an empty dir to hold blob files among a range of blocks, the blobs in this dir will be assembled into a bundle and uploaded to bundle service @@ -275,7 +302,7 @@ func (s *BlobSyncer) finalizeCurBundle(bundleName string) error { return s.finalizeBundle(bundleName, s.getBundleDir(bundleName), s.getBundleFilePath(bundleName)) } -func (s *BlobSyncer) writeBlobToFile(slot uint64, bundleName string, blobs []*structs.Sidecar) error { +func (s *BlobSyncer) writeBlobToFile(slot uint64, bundleName string, blobs []*types.GeneralSideCar) error { for i, b := range blobs { blobName := types.GetBlobName(slot, i) file, err := os.Create(s.getBlobPath(bundleName, blobName)) @@ -305,11 +332,11 @@ func (s *BlobSyncer) getBundleFilePath(bundleName string) string { return fmt.Sprintf("%s/%s.bundle", s.config.TempDir, bundleName) } -func (s *BlobSyncer) LoadProgressAndResume(nextSlot uint64) error { +func (s *BlobSyncer) LoadProgressAndResume(nextBlockID uint64) error { var ( - startSlot uint64 - endSlot uint64 - err error + startBlockID uint64 + endBlockID uint64 + err error ) finalizingBundle, err := s.blobDao.GetLatestFinalizingBundle() if err != nil { @@ -318,131 +345,182 @@ func (s *BlobSyncer) LoadProgressAndResume(nextSlot uint64) error { } // There is no pending(finalizing) bundle, start a new bundle. e.g. a bundle includes // blobs from block slot 0-9 when the block interval is config to 10 - startSlot = nextSlot - endSlot = nextSlot + s.getCreateBundleSlotInterval() - 1 + startBlockID = nextBlockID + endBlockID = nextBlockID + s.getCreateBundleInterval() - 1 } else { // resume - startSlot, endSlot, err = types.ParseBundleName(finalizingBundle.Name) + startBlockID, endBlockID, err = types.ParseBundleName(finalizingBundle.Name) if err != nil { return err } // might no longer need to process the bundle even-thought it is not finalized if the user set the config to skip it. - if nextSlot > endSlot { - err = s.blobDao.UpdateBlocksStatus(startSlot, endSlot, db.Skipped) + if nextBlockID > endBlockID { + err = s.blobDao.UpdateBlocksStatus(startBlockID, endBlockID, db.Skipped) if err != nil { - logging.Logger.Errorf("failed to update blocks status, startSlot=%d, endSlot=%d", startSlot, endSlot) + logging.Logger.Errorf("failed to update blocks status, startSlot=%d, endSlot=%d", startBlockID, endBlockID) return err } - logging.Logger.Infof("the config slot number %d is larger than the recorded bundle end slot %d, will resume from the config slot", nextSlot, endSlot) + logging.Logger.Infof("the config slot number %d is larger than the recorded bundle end slot %d, will resume from the config slot", nextBlockID, endBlockID) if err = s.blobDao.UpdateBundleStatus(finalizingBundle.Name, db.Deprecated); err != nil { return err } - startSlot = nextSlot - endSlot = nextSlot + s.getCreateBundleSlotInterval() - 1 + startBlockID = nextBlockID + endBlockID = nextBlockID + s.getCreateBundleInterval() - 1 } } s.bundleDetail = &curBundleDetail{ - name: types.GetBundleName(startSlot, endSlot), - startSlot: startSlot, - finalizeSlot: endSlot, + name: types.GetBundleName(startBlockID, endBlockID), + startBlockID: startBlockID, + finalizeBlockID: endBlockID, } return nil } -func (s *BlobSyncer) ToBlockAndBlobs(blockResp *structs.GetBlockV2Response, blobs []*structs.Sidecar, slot uint64, bundleName string) (*db.Block, []*db.Blob, error) { +func (s *BlobSyncer) toBlockAndBlobs(blockResp *structs.GetBlockV2Response, sidecars []*types.GeneralSideCar, blockNumOrSlot uint64, bundleName string) (*db.Block, []*db.Blob, error) { + var blockReturn *db.Block blobsReturn := make([]*db.Blob, 0) - var ( - clBlock *ethpb.BeaconBlockDeneb - executionPayload *v1.ExecutionPayloadDeneb - err error - ) - - switch blockResp.Version { - case version.String(version.Deneb): - clBlock, executionPayload, err = ToBlockAndExecutionPayloadDeneb(blockResp) + populateBlobTxDetails := func(blockNum uint64) error { + elBlock, err := s.client.BlockByNumber(context.Background(), big.NewInt(int64(blockNum))) if err != nil { - logging.Logger.Errorf("failed to convert to ToBlockAndExecutionPayloadDeneb, err=%s", err.Error()) - return nil, nil, err + return fmt.Errorf("failed to get block at height %d, err=%s", blockNum, err.Error()) + } + blobIndex := 0 + for _, tx := range elBlock.Body().Transactions { + if tx.Type() == ethtypes.BlobTxType { + for _, bs := range tx.BlobHashes() { + blobsReturn[blobIndex].TxHash = hex.EncodeToString(tx.Hash().Bytes()) + blobsReturn[blobIndex].ToAddr = tx.To().String() + blobsReturn[blobIndex].VersionedHash = bs.String() + blobIndex++ + } + } } + return nil + } - bodyRoot, err := clBlock.GetBody().HashTreeRoot() + switch { + case s.BSCChain(): + header, err := s.client.GetBlockHeader(context.Background(), blockNumOrSlot) if err != nil { return nil, nil, err } - ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout) - defer cancel() - header, err := s.ethClients.BeaconClient.GetHeader(ctx, slot) - if err != nil { - logging.Logger.Errorf("failed to get header, slot=%d, err=%s", slot, err.Error()) - return nil, nil, err + blockReturn = &db.Block{ + Root: hex.EncodeToString(header.Root.Bytes()), + Slot: blockNumOrSlot, + BlobCount: len(sidecars), + BundleName: bundleName, } - rootBz, err := hexutil.Decode(header.Data.Root) - if err != nil { - logging.Logger.Errorf("failed to decode header.Data.Root=%s, err=%s", header.Data.Root, err.Error()) - return nil, nil, err + if len(sidecars) == 0 { + return blockReturn, blobsReturn, nil } - sigBz, err := hexutil.Decode(header.Data.Header.Signature) + for _, blob := range sidecars { + index, err := strconv.Atoi(blob.Index) + if err != nil { + return nil, nil, err + } + b := &db.Blob{ + Name: types.GetBlobName(blockNumOrSlot, index), + Slot: blockNumOrSlot, + Idx: index, + TxIndex: int(blob.TxIndex), + TxHash: blob.TxHash, + KzgProof: blob.KzgProof, + KzgCommitment: blob.KzgCommitment, + } + blobsReturn = append(blobsReturn, b) + } + err = populateBlobTxDetails(blockNumOrSlot) if err != nil { - logging.Logger.Errorf("failed to decode header.Data.Header.Signature=%s, err=%s", header.Data.Header.Signature, err.Error()) return nil, nil, err } - - blockReturn = &db.Block{ - Root: hex.EncodeToString(rootBz), // get rid of 0x saved to DB - ParentRoot: hex.EncodeToString(clBlock.GetParentRoot()), - StateRoot: hex.EncodeToString(clBlock.GetStateRoot()), - BodyRoot: hex.EncodeToString(bodyRoot[:]), - Signature: hex.EncodeToString(sigBz[:]), - ProposerIndex: uint64(clBlock.ProposerIndex), - Slot: uint64(clBlock.GetSlot()), - ELBlockHeight: executionPayload.GetBlockNumber(), - BlobCount: len(blobs), - BundleName: bundleName, - } - default: - return nil, nil, fmt.Errorf("un-expected block version %s", blockResp.Version) - } - - if len(blobs) == 0 { return blockReturn, blobsReturn, nil - } + case s.ETHChain(): + // Process ETH beacon and execution layer block + var ( + clBlock *ethpb.BeaconBlockDeneb + executionPayload *v1.ExecutionPayloadDeneb + err error + ) + switch blockResp.Version { + case version.String(version.Deneb): + clBlock, executionPayload, err = ToBlockAndExecutionPayloadDeneb(blockResp) + if err != nil { + logging.Logger.Errorf("failed to convert to ToBlockAndExecutionPayloadDeneb, err=%s", err.Error()) + return nil, nil, err + } - for _, blob := range blobs { - index, err := strconv.Atoi(blob.Index) - if err != nil { - return nil, nil, err + bodyRoot, err := clBlock.GetBody().HashTreeRoot() + if err != nil { + return nil, nil, err + } + ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout) + defer cancel() + header, err := s.client.GetBeaconHeader(ctx, blockNumOrSlot) + if err != nil { + logging.Logger.Errorf("failed to get header, slot=%d, err=%s", blockNumOrSlot, err.Error()) + return nil, nil, err + } + + rootBz, err := hexutil.Decode(header.Data.Root) + if err != nil { + logging.Logger.Errorf("failed to decode header.Data.Root=%s, err=%s", header.Data.Root, err.Error()) + return nil, nil, err + } + sigBz, err := hexutil.Decode(header.Data.Header.Signature) + if err != nil { + logging.Logger.Errorf("failed to decode header.Data.Header.Signature=%s, err=%s", header.Data.Header.Signature, err.Error()) + return nil, nil, err + } + blockReturn = &db.Block{ + Root: hex.EncodeToString(rootBz), // get rid of 0x saved to DB + ParentRoot: hex.EncodeToString(clBlock.GetParentRoot()), + StateRoot: hex.EncodeToString(clBlock.GetStateRoot()), + BodyRoot: hex.EncodeToString(bodyRoot[:]), + Signature: hex.EncodeToString(sigBz[:]), + ProposerIndex: uint64(clBlock.ProposerIndex), + Slot: uint64(clBlock.GetSlot()), + ELBlockHeight: executionPayload.GetBlockNumber(), + BlobCount: len(sidecars), + BundleName: bundleName, + } + default: + return nil, nil, fmt.Errorf("un-expected block version %s", blockResp.Version) } - b := &db.Blob{ - Name: types.GetBlobName(slot, index), - Slot: slot, - Idx: index, - KzgProof: blob.KzgProof, - KzgCommitment: blob.KzgCommitment, - CommitmentInclusionProof: util.JoinWithComma(blob.CommitmentInclusionProof), + if len(sidecars) == 0 { + return blockReturn, blobsReturn, nil } - blobsReturn = append(blobsReturn, b) - } - - ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout) - defer cancel() - elBlock, err := s.ethClients.Eth1Client.BlockByNumber(ctx, big.NewInt(int64(executionPayload.GetBlockNumber()))) - if err != nil { - return nil, nil, fmt.Errorf("failed to get block at height %d, err=%s", executionPayload.GetBlockNumber(), err.Error()) - } - blobIndex := 0 - for _, tx := range elBlock.Body().Transactions { - if tx.Type() == ethtypes.BlobTxType { - for _, bs := range tx.BlobHashes() { - blobsReturn[blobIndex].TxHash = hex.EncodeToString(tx.Hash().Bytes()) - blobsReturn[blobIndex].ToAddr = tx.To().String() - blobsReturn[blobIndex].VersionedHash = bs.String() - blobIndex++ + for _, blob := range sidecars { + index, err := strconv.Atoi(blob.Index) + if err != nil { + return nil, nil, err + } + b := &db.Blob{ + Name: types.GetBlobName(blockNumOrSlot, index), + Slot: blockNumOrSlot, + Idx: index, + KzgProof: blob.KzgProof, + KzgCommitment: blob.KzgCommitment, + CommitmentInclusionProof: util.JoinWithComma(blob.CommitmentInclusionProof), } + blobsReturn = append(blobsReturn, b) + } + err = populateBlobTxDetails(executionPayload.GetBlockNumber()) + if err != nil { + return nil, nil, err } + return blockReturn, blobsReturn, nil } return blockReturn, blobsReturn, nil } + +func (s *BlobSyncer) BSCChain() bool { + return s.config.Chain == config.BSC +} + +func (s *BlobSyncer) ETHChain() bool { + return s.config.Chain == config.ETH +} diff --git a/syncer/verifier.go b/syncer/verifier.go index 3015242..d088fad 100644 --- a/syncer/verifier.go +++ b/syncer/verifier.go @@ -4,22 +4,25 @@ import ( "bytes" "context" "errors" + "fmt" "os" "path/filepath" "time" - "gorm.io/gorm" - "github.com/prysmaticlabs/prysm/v5/api/server/structs" + "gorm.io/gorm" "github.com/bnb-chain/blob-hub/db" - "github.com/bnb-chain/blob-hub/external" + "github.com/bnb-chain/blob-hub/external/cmn" + "github.com/bnb-chain/blob-hub/external/eth" "github.com/bnb-chain/blob-hub/logging" "github.com/bnb-chain/blob-hub/metrics" "github.com/bnb-chain/blob-hub/types" "github.com/bnb-chain/blob-hub/util" ) +const VerifyPauseTime = 90 * time.Second + var ( ErrVerificationFailed = errors.New("verification failed") ) @@ -32,22 +35,21 @@ var ( // // a new bundle should be re-uploaded. func (s *BlobSyncer) verify() error { - var err error verifyBlock, err := s.blobDao.GetEarliestUnverifiedBlock() if err != nil { if err == gorm.ErrRecordNotFound { logging.Logger.Debugf("found no unverified block in DB") - time.Sleep(PauseTime) + time.Sleep(VerifyPauseTime) return nil } return err } bundleName := verifyBlock.BundleName - bundleStartSlot, bundleEndSlot, err := types.ParseBundleName(bundleName) + bundleStartBlockID, bundleEndBlockID, err := types.ParseBundleName(bundleName) if err != nil { return err } - verifyBlockSlot := verifyBlock.Slot + verifyBlockID := verifyBlock.Slot // check if the bundle has been submitted to bundle service bundle, err := s.blobDao.GetBundle(bundleName) @@ -56,21 +58,40 @@ func (s *BlobSyncer) verify() error { } if bundle.Status == db.Finalizing { logging.Logger.Debugf("the bundle has not been submitted to bundle service yet, bundleName=%s", bundleName) - time.Sleep(PauseTime) + time.Sleep(VerifyPauseTime) return nil } // validate the bundle info at the start slot of a bundle - if verifyBlockSlot == bundleStartSlot { + if verifyBlockID == bundleStartBlockID { // the bundle is recorded finalized in DB, validate the bundle is sealed onchain bundleInfo, err := s.bundleClient.GetBundleInfo(s.getBucketName(), bundleName) if err != nil { - logging.Logger.Errorf("failed to get bundle info, bundleName=%s", bundleName) - return err + if err != cmn.ErrorBundleNotExist { + logging.Logger.Errorf("failed to get bundle info, bundleName=%s", bundleName) + return err + } + + // verify if there are no blobs within the range + blobs, err := s.blobDao.GetBlobBetweenBlocks(bundleStartBlockID, bundleEndBlockID) + if err != nil { + return err + } + if len(blobs) != 0 { + return fmt.Errorf("%d blobs within block_id[%d, %d] not found in bundle service", len(blobs), bundleStartBlockID, bundleEndBlockID) + } + if err = s.blobDao.UpdateBlocksStatus(bundleEndBlockID, bundleEndBlockID, db.Verified); err != nil { + return err + } + if err = s.blobDao.UpdateBundleStatus(bundleName, db.Sealed); err != nil { + return err + } + return nil } // the bundle is not sealed yet if bundleInfo.Status == BundleStatusFinalized || bundleInfo.Status == BundleStatusCreatedOnChain { if bundle.CreatedTime > 0 && time.Now().Unix()-bundle.CreatedTime > s.config.GetReUploadBundleThresh() { + logging.Logger.Infof("the bundle %s is not sealed and exceed the re-upload threshold %d ", bundleName, s.config.GetReUploadBundleThresh()) return s.reUploadBundle(bundleName) } return nil @@ -78,70 +99,70 @@ func (s *BlobSyncer) verify() error { } if verifyBlock.BlobCount == 0 { - if err = s.blobDao.UpdateBlockStatus(verifyBlockSlot, db.Verified); err != nil { - logging.Logger.Errorf("failed to update block status, slot=%d err=%s", verifyBlockSlot, err.Error()) + if err = s.blobDao.UpdateBlockStatus(verifyBlockID, db.Verified); err != nil { + logging.Logger.Errorf("failed to update block status, block_id=%d err=%s", verifyBlockID, err.Error()) return err } - if verifyBlockSlot == bundleEndSlot { - logging.Logger.Debugf("update bundle status to sealed, name=%s , slot %d ", bundleName, verifyBlockSlot) + if verifyBlockID == bundleEndBlockID { + logging.Logger.Debugf("update bundle status to sealed, name=%s , block_id %d ", bundleName, verifyBlockID) if err = s.blobDao.UpdateBundleStatus(bundleName, db.Sealed); err != nil { - logging.Logger.Errorf("failed to update bundle status to sealed, name=%s , slot %d ", bundleName, verifyBlockSlot) + logging.Logger.Errorf("failed to update bundle status to sealed, name=%s , block_id %d ", bundleName, verifyBlockID) return err } } return nil } - // get blob from beacon chain again + // get blob from beacon chain or BSC again ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout) defer cancel() - sideCars, err := s.ethClients.BeaconClient.GetBlob(ctx, verifyBlockSlot) + sideCars, err := s.client.GetBlob(ctx, verifyBlockID) if err != nil { - logging.Logger.Errorf("failed to get blob at slot=%d, err=%s", verifyBlockSlot, err.Error()) + logging.Logger.Errorf("failed to get blob at block_id=%d, err=%s", verifyBlockID, err.Error()) return err } // get blob meta from DB - blobMetas, err := s.blobDao.GetBlobBySlot(verifyBlockSlot) + blobMetas, err := s.blobDao.GetBlobByBlockID(verifyBlockID) if err != nil { return err } if len(blobMetas) != len(sideCars) { - logging.Logger.Errorf("found blob number mismatch at slot=%d, bundleName=%s", verifyBlockSlot, bundleName) + logging.Logger.Errorf("found blob number mismatch at block_id=%d, bundleName=%s, expected=%d, actual=%d", verifyBlockID, bundleName, len(sideCars), len(blobMetas)) return s.reUploadBundle(bundleName) } - err = s.verifyBlobAtSlot(verifyBlockSlot, sideCars, blobMetas, bundleName) + err = s.verifyBlob(verifyBlockID, sideCars, blobMetas, bundleName) if err != nil { if err == ErrVerificationFailed { return s.reUploadBundle(bundleName) } return err } - if err = s.blobDao.UpdateBlockStatus(verifyBlockSlot, db.Verified); err != nil { - logging.Logger.Errorf("failed to update block status to verified, slot=%d err=%s", verifyBlockSlot, err.Error()) + if err = s.blobDao.UpdateBlockStatus(verifyBlockID, db.Verified); err != nil { + logging.Logger.Errorf("failed to update block status to verified, block_id=%d err=%s", verifyBlockID, err.Error()) return err } - metrics.VerifiedSlotGauge.Set(float64(verifyBlockSlot)) - if bundleEndSlot == verifyBlockSlot { - logging.Logger.Debugf("update bundle status to sealed, name=%s , slot=%d ", bundleName, verifyBlockSlot) + metrics.VerifiedBlockIDGauge.Set(float64(verifyBlockID)) + if bundleEndBlockID == verifyBlockID { + logging.Logger.Debugf("update bundle status to sealed, name=%s , block_id=%d ", bundleName, verifyBlockID) if err = s.blobDao.UpdateBundleStatus(bundleName, db.Sealed); err != nil { - logging.Logger.Errorf("failed to update bundle status to sealed, name=%s, slot %d ", bundleName, verifyBlockSlot) + logging.Logger.Errorf("failed to update bundle status to sealed, name=%s, block_id %d ", bundleName, verifyBlockID) return err } } - logging.Logger.Infof("successfully verify at block slot %d ", verifyBlockSlot) + logging.Logger.Infof("successfully verify at block block_id=%d ", verifyBlockID) return nil } -func (s *BlobSyncer) verifyBlobAtSlot(slot uint64, sidecars []*structs.Sidecar, blobMetas []*db.Blob, bundleName string) error { +func (s *BlobSyncer) verifyBlob(blockID uint64, sidecars []*types.GeneralSideCar, blobMetas []*db.Blob, bundleName string) error { for i := 0; i < len(sidecars); i++ { // get blob from bundle service - blobFromBundle, err := s.bundleClient.GetObject(s.getBucketName(), bundleName, types.GetBlobName(slot, i)) + blobFromBundle, err := s.bundleClient.GetObject(s.getBucketName(), bundleName, types.GetBlobName(blockID, i)) if err != nil { - if err == external.ErrorBundleObjectNotExist { - logging.Logger.Errorf("the bundle object not found in bundle service, object=%s", types.GetBlobName(slot, i)) + if err == cmn.ErrorBundleObjectNotExist { + logging.Logger.Errorf("the bundle object not found in bundle service, object=%s", types.GetBlobName(blockID, i)) return ErrVerificationFailed } return err @@ -192,7 +213,7 @@ func (s *BlobSyncer) reUploadBundle(bundleName string) error { } newBundleName := bundleName + "_calibrated_" + util.Int64ToString(time.Now().Unix()) - startSlot, endSlot, err := types.ParseBundleName(bundleName) + startBlockID, endBlockID, err := types.ParseBundleName(bundleName) if err != nil { return err } @@ -213,32 +234,38 @@ func (s *BlobSyncer) reUploadBundle(bundleName string) error { }); err != nil { return err } - for slot := startSlot; slot <= endSlot; slot++ { + for bi := startBlockID; bi <= endBlockID; bi++ { ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout) defer cancel() - sideCars, err := s.ethClients.BeaconClient.GetBlob(ctx, slot) + sideCars, err := s.client.GetBlob(ctx, bi) if err != nil { return err } - if err = s.writeBlobToFile(slot, newBundleName, sideCars); err != nil { + if err = s.writeBlobToFile(bi, newBundleName, sideCars); err != nil { return err } - block, err := s.ethClients.BeaconClient.GetBlock(ctx, slot) - if err != nil { - if err == external.ErrBlockNotFound { - continue + + // not needed by BSC + var block *structs.GetBlockV2Response + if s.ETHChain() { + block, err = s.client.GetBeaconBlock(ctx, bi) + if err != nil { + if err == eth.ErrBlockNotFound { + continue + } + return err } - return err } - blockMeta, err := s.blobDao.GetBlock(slot) + + blockMeta, err := s.blobDao.GetBlock(bi) if err != nil { return err } - blobMetas, err := s.blobDao.GetBlobBySlot(slot) + blobMetas, err := s.blobDao.GetBlobByBlockID(bi) if err != nil { return err } - blockToSave, blobToSave, err := s.ToBlockAndBlobs(block, sideCars, slot, newBundleName) + blockToSave, blobToSave, err := s.toBlockAndBlobs(block, sideCars, bi, newBundleName) if err != nil { return err } @@ -253,7 +280,7 @@ func (s *BlobSyncer) reUploadBundle(bundleName string) error { logging.Logger.Errorf("failed to save block(h=%d) and Blob(count=%d), err=%s", blockToSave.Slot, len(blobToSave), err.Error()) return err } - logging.Logger.Infof("save calibrated block(slot=%d) and blobs(num=%d) to DB \n", slot, len(blobToSave)) + logging.Logger.Infof("save calibrated block(block_id=%d) and blobs(num=%d) to DB \n", bi, len(blobToSave)) } if err = s.finalizeBundle(newBundleName, s.getBundleDir(newBundleName), s.getBundleFilePath(newBundleName)); err != nil { logging.Logger.Errorf("failed to finalized bundle, name=%s, err=%s", newBundleName, err.Error()) diff --git a/types/key.go b/types/key.go index 3042779..a0c65ef 100644 --- a/types/key.go +++ b/types/key.go @@ -6,6 +6,8 @@ import ( "strings" ) +const RootLength = 32 + func GetBlobName(slot uint64, index int) string { return fmt.Sprintf("blob_h%d_i%d", slot, index) } diff --git a/types/types.go b/types/types.go new file mode 100644 index 0000000..72e9507 --- /dev/null +++ b/types/types.go @@ -0,0 +1,12 @@ +package types + +import ( + "github.com/prysmaticlabs/prysm/v5/api/server/structs" +) + +// GeneralSideCar is a general sidecar struct for both BSC and ETH +type GeneralSideCar struct { + structs.Sidecar + TxIndex int64 `json:"tx_index,omitempty"` + TxHash string `json:"tx_hash,omitempty"` +} diff --git a/util/util.go b/util/util.go index 2f6f859..5bbc886 100644 --- a/util/util.go +++ b/util/util.go @@ -64,3 +64,17 @@ func Uint64ToString(u uint64) string { func Int64ToString(u int64) string { return strconv.FormatInt(u, 10) } + +// HexToUint64 converts hex string to uint64 +func HexToUint64(hexStr string) (uint64, error) { + intValue, err := strconv.ParseUint(hexStr, 0, 64) + if err != nil { + return 0, err + } + return intValue, nil +} + +// Int64ToHex converts int64 to hex string +func Int64ToHex(int64 int64) string { + return "0x" + strconv.FormatInt(int64, 16) +}