mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-08 02:31:19 +00:00
d6ae838bbf
* WIP * event stream wip * returning nil * temp removing some tests * wip health checks * fixing conficts * updating fields based on linting * fixing more errors * fixing mocks * fixing more mocks * fixing more linting * removing white space for lint * fixing log format * gaz * reverting changes on grpc * fixing unit tests * adding in tests for health tracker and event stream * adding more tests for streaming slot * gaz * Update api/client/event/event_stream.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * review comments * Update validator/client/runner.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/client/validator.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/client/validator.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/client/validator.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/client/validator.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/client/beacon-api/beacon_api_validator_client.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/client/validator.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/client/validator.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * addressing radek comments * Update validator/client/validator.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * addressing review feedback * moving things to below next slot ticker * fixing tests * update naming * adding TODO comment * Update api/client/beacon/health.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * addressing comments * fixing broken linting * fixing more import issues * fixing more import issues * linting * updating based on radek's comments * addressing more comments * fixing nogo error * fixing duplicate import * gaz * adding radek's review suggestion * Update proto/prysm/v1alpha1/node.proto Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com> * preston review comments * Update api/client/event/event_stream.go Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com> * Update validator/client/validator.go Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com> * addressing some more preston review items * fixing tests for linting * fixing missed linting * updating based on feedback to simplify * adding interface check at the top * reverting some comments * cleaning up intatiations * reworking the health tracker * fixing linting * fixing more linting to adhear to interface * adding interface check at the the top of the file * fixing unit tests * attempting to fix dependency cycle * addressing radek's comment * Update validator/client/beacon-api/beacon_api_validator_client.go Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com> * adding more tests and feedback items * fixing TODO comment --------- Co-authored-by: Radosław Kapka <rkapka@wp.pl> Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
215 lines
7.0 KiB
Go
215 lines
7.0 KiB
Go
package beacon_api
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/pkg/errors"
|
|
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
|
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
type abstractSignedBlockResponseJson struct {
|
|
Version string `json:"version" enum:"true"`
|
|
ExecutionOptimistic bool `json:"execution_optimistic"`
|
|
Finalized bool `json:"finalized"`
|
|
Data json.RawMessage `json:"data"`
|
|
}
|
|
|
|
type streamBlocksAltairClient struct {
|
|
grpc.ClientStream
|
|
ctx context.Context
|
|
beaconApiClient beaconApiValidatorClient
|
|
streamBlocksRequest *ethpb.StreamBlocksRequest
|
|
prevBlockSlot primitives.Slot
|
|
pingDelay time.Duration
|
|
}
|
|
|
|
type headSignedBeaconBlockResult struct {
|
|
streamBlocksResponse *ethpb.StreamBlocksResponse
|
|
executionOptimistic bool
|
|
slot primitives.Slot
|
|
}
|
|
|
|
func (c beaconApiValidatorClient) streamBlocks(ctx context.Context, in *ethpb.StreamBlocksRequest, pingDelay time.Duration) ethpb.BeaconNodeValidator_StreamBlocksAltairClient {
|
|
return &streamBlocksAltairClient{
|
|
ctx: ctx,
|
|
beaconApiClient: c,
|
|
streamBlocksRequest: in,
|
|
pingDelay: pingDelay,
|
|
}
|
|
}
|
|
|
|
func (c *streamBlocksAltairClient) Recv() (*ethpb.StreamBlocksResponse, error) {
|
|
result, err := c.beaconApiClient.getHeadSignedBeaconBlock(c.ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get latest signed block")
|
|
}
|
|
|
|
// We keep querying the beacon chain for the latest block until we receive a new slot
|
|
for (c.streamBlocksRequest.VerifiedOnly && result.executionOptimistic) || c.prevBlockSlot == result.slot {
|
|
select {
|
|
case <-time.After(c.pingDelay):
|
|
result, err = c.beaconApiClient.getHeadSignedBeaconBlock(c.ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get latest signed block")
|
|
}
|
|
case <-c.ctx.Done():
|
|
return nil, errors.New("context canceled")
|
|
}
|
|
}
|
|
|
|
c.prevBlockSlot = result.slot
|
|
return result.streamBlocksResponse, nil
|
|
}
|
|
|
|
func (c beaconApiValidatorClient) getHeadSignedBeaconBlock(ctx context.Context) (*headSignedBeaconBlockResult, error) {
|
|
// Since we don't know yet what the json looks like, we unmarshal into an abstract structure that has only a version
|
|
// and a blob of data
|
|
signedBlockResponseJson := abstractSignedBlockResponseJson{}
|
|
if err := c.jsonRestHandler.Get(ctx, "/eth/v2/beacon/blocks/head", &signedBlockResponseJson); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Once we know what the consensus version is, we can go ahead and unmarshal into the specific structs unique to each version
|
|
decoder := json.NewDecoder(bytes.NewReader(signedBlockResponseJson.Data))
|
|
|
|
response := ðpb.StreamBlocksResponse{}
|
|
var slot primitives.Slot
|
|
|
|
switch signedBlockResponseJson.Version {
|
|
case "phase0":
|
|
jsonPhase0Block := structs.SignedBeaconBlock{}
|
|
if err := decoder.Decode(&jsonPhase0Block); err != nil {
|
|
return nil, errors.Wrap(err, "failed to decode signed phase0 block response json")
|
|
}
|
|
|
|
phase0Block, err := c.beaconBlockConverter.ConvertRESTPhase0BlockToProto(jsonPhase0Block.Message)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get signed phase0 block")
|
|
}
|
|
|
|
decodedSignature, err := hexutil.Decode(jsonPhase0Block.Signature)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to decode phase0 block signature `%s`", jsonPhase0Block.Signature)
|
|
}
|
|
|
|
response.Block = ðpb.StreamBlocksResponse_Phase0Block{
|
|
Phase0Block: ðpb.SignedBeaconBlock{
|
|
Signature: decodedSignature,
|
|
Block: phase0Block,
|
|
},
|
|
}
|
|
|
|
slot = phase0Block.Slot
|
|
|
|
case "altair":
|
|
jsonAltairBlock := structs.SignedBeaconBlockAltair{}
|
|
if err := decoder.Decode(&jsonAltairBlock); err != nil {
|
|
return nil, errors.Wrap(err, "failed to decode signed altair block response json")
|
|
}
|
|
|
|
altairBlock, err := c.beaconBlockConverter.ConvertRESTAltairBlockToProto(jsonAltairBlock.Message)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get signed altair block")
|
|
}
|
|
|
|
decodedSignature, err := hexutil.Decode(jsonAltairBlock.Signature)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to decode altair block signature `%s`", jsonAltairBlock.Signature)
|
|
}
|
|
|
|
response.Block = ðpb.StreamBlocksResponse_AltairBlock{
|
|
AltairBlock: ðpb.SignedBeaconBlockAltair{
|
|
Signature: decodedSignature,
|
|
Block: altairBlock,
|
|
},
|
|
}
|
|
|
|
slot = altairBlock.Slot
|
|
|
|
case "bellatrix":
|
|
jsonBellatrixBlock := structs.SignedBeaconBlockBellatrix{}
|
|
if err := decoder.Decode(&jsonBellatrixBlock); err != nil {
|
|
return nil, errors.Wrap(err, "failed to decode signed bellatrix block response json")
|
|
}
|
|
|
|
bellatrixBlock, err := c.beaconBlockConverter.ConvertRESTBellatrixBlockToProto(jsonBellatrixBlock.Message)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get signed bellatrix block")
|
|
}
|
|
|
|
decodedSignature, err := hexutil.Decode(jsonBellatrixBlock.Signature)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to decode bellatrix block signature `%s`", jsonBellatrixBlock.Signature)
|
|
}
|
|
|
|
response.Block = ðpb.StreamBlocksResponse_BellatrixBlock{
|
|
BellatrixBlock: ðpb.SignedBeaconBlockBellatrix{
|
|
Signature: decodedSignature,
|
|
Block: bellatrixBlock,
|
|
},
|
|
}
|
|
|
|
slot = bellatrixBlock.Slot
|
|
|
|
case "capella":
|
|
jsonCapellaBlock := structs.SignedBeaconBlockCapella{}
|
|
if err := decoder.Decode(&jsonCapellaBlock); err != nil {
|
|
return nil, errors.Wrap(err, "failed to decode signed capella block response json")
|
|
}
|
|
|
|
capellaBlock, err := c.beaconBlockConverter.ConvertRESTCapellaBlockToProto(jsonCapellaBlock.Message)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get signed capella block")
|
|
}
|
|
|
|
decodedSignature, err := hexutil.Decode(jsonCapellaBlock.Signature)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to decode capella block signature `%s`", jsonCapellaBlock.Signature)
|
|
}
|
|
|
|
response.Block = ðpb.StreamBlocksResponse_CapellaBlock{
|
|
CapellaBlock: ðpb.SignedBeaconBlockCapella{
|
|
Signature: decodedSignature,
|
|
Block: capellaBlock,
|
|
},
|
|
}
|
|
|
|
slot = capellaBlock.Slot
|
|
case "deneb":
|
|
jsonDenebBlock := structs.SignedBeaconBlockDeneb{}
|
|
if err := decoder.Decode(&jsonDenebBlock); err != nil {
|
|
return nil, errors.Wrap(err, "failed to decode signed deneb block response json")
|
|
}
|
|
|
|
denebBlock, err := jsonDenebBlock.ToConsensus()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get signed deneb block")
|
|
}
|
|
|
|
response.Block = ðpb.StreamBlocksResponse_DenebBlock{
|
|
DenebBlock: ðpb.SignedBeaconBlockDeneb{
|
|
Signature: denebBlock.Signature,
|
|
Block: denebBlock.Block,
|
|
},
|
|
}
|
|
|
|
slot = denebBlock.Block.Slot
|
|
|
|
default:
|
|
return nil, errors.Errorf("unsupported consensus version `%s`", signedBlockResponseJson.Version)
|
|
}
|
|
|
|
return &headSignedBeaconBlockResult{
|
|
streamBlocksResponse: response,
|
|
executionOptimistic: signedBlockResponseJson.ExecutionOptimistic,
|
|
slot: slot,
|
|
}, nil
|
|
}
|