mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 03:30:35 +00:00
replace receive slot with event stream (#13563)
* 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>
This commit is contained in:
parent
d49afb370c
commit
d6ae838bbf
@ -6,12 +6,14 @@ go_library(
|
||||
"checkpoint.go",
|
||||
"client.go",
|
||||
"doc.go",
|
||||
"health.go",
|
||||
"log.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/api/client/beacon",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api/client:go_default_library",
|
||||
"//api/client/beacon/iface:go_default_library",
|
||||
"//api/server:go_default_library",
|
||||
"//api/server/structs:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
@ -37,10 +39,12 @@ go_test(
|
||||
srcs = [
|
||||
"checkpoint_test.go",
|
||||
"client_test.go",
|
||||
"health_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//api/client:go_default_library",
|
||||
"//api/client/beacon/testing:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
@ -54,5 +58,6 @@ go_test(
|
||||
"//testing/util:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@org_uber_go_mock//gomock:go_default_library",
|
||||
],
|
||||
)
|
||||
|
55
api/client/beacon/health.go
Normal file
55
api/client/beacon/health.go
Normal file
@ -0,0 +1,55 @@
|
||||
package beacon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon/iface"
|
||||
)
|
||||
|
||||
type NodeHealthTracker struct {
|
||||
isHealthy *bool
|
||||
healthChan chan bool
|
||||
node iface.HealthNode
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func NewNodeHealthTracker(node iface.HealthNode) *NodeHealthTracker {
|
||||
return &NodeHealthTracker{
|
||||
node: node,
|
||||
healthChan: make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
// HealthUpdates provides a read-only channel for health updates.
|
||||
func (n *NodeHealthTracker) HealthUpdates() <-chan bool {
|
||||
return n.healthChan
|
||||
}
|
||||
|
||||
func (n *NodeHealthTracker) IsHealthy() bool {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
if n.isHealthy == nil {
|
||||
return false
|
||||
}
|
||||
return *n.isHealthy
|
||||
}
|
||||
|
||||
func (n *NodeHealthTracker) CheckHealth(ctx context.Context) bool {
|
||||
n.RLock()
|
||||
newStatus := n.node.IsHealthy(ctx)
|
||||
if n.isHealthy == nil {
|
||||
n.isHealthy = &newStatus
|
||||
}
|
||||
isStatusChanged := newStatus != *n.isHealthy
|
||||
n.RUnlock()
|
||||
|
||||
if isStatusChanged {
|
||||
n.Lock()
|
||||
// Double-check the condition to ensure it hasn't changed since the first check.
|
||||
n.isHealthy = &newStatus
|
||||
n.Unlock() // It's better to unlock as soon as the protected section is over.
|
||||
n.healthChan <- newStatus
|
||||
}
|
||||
return newStatus
|
||||
}
|
118
api/client/beacon/health_test.go
Normal file
118
api/client/beacon/health_test.go
Normal file
@ -0,0 +1,118 @@
|
||||
package beacon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
healthTesting "github.com/prysmaticlabs/prysm/v5/api/client/beacon/testing"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func TestNodeHealth_IsHealthy(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
isHealthy bool
|
||||
want bool
|
||||
}{
|
||||
{"initially healthy", true, true},
|
||||
{"initially unhealthy", false, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
n := &NodeHealthTracker{
|
||||
isHealthy: &tt.isHealthy,
|
||||
healthChan: make(chan bool, 1),
|
||||
}
|
||||
if got := n.IsHealthy(); got != tt.want {
|
||||
t.Errorf("IsHealthy() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeHealth_UpdateNodeHealth(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
initial bool // Initial health status
|
||||
newStatus bool // Status to update to
|
||||
shouldSend bool // Should a message be sent through the channel
|
||||
}{
|
||||
{"healthy to unhealthy", true, false, true},
|
||||
{"unhealthy to healthy", false, true, true},
|
||||
{"remain healthy", true, true, false},
|
||||
{"remain unhealthy", false, false, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
client := healthTesting.NewMockHealthClient(ctrl)
|
||||
client.EXPECT().IsHealthy(gomock.Any()).Return(tt.newStatus)
|
||||
n := &NodeHealthTracker{
|
||||
isHealthy: &tt.initial,
|
||||
node: client,
|
||||
healthChan: make(chan bool, 1),
|
||||
}
|
||||
|
||||
s := n.CheckHealth(context.Background())
|
||||
// Check if health status was updated
|
||||
if s != tt.newStatus {
|
||||
t.Errorf("UpdateNodeHealth() failed to update isHealthy from %v to %v", tt.initial, tt.newStatus)
|
||||
}
|
||||
|
||||
select {
|
||||
case status := <-n.HealthUpdates():
|
||||
if !tt.shouldSend {
|
||||
t.Errorf("UpdateNodeHealth() unexpectedly sent status %v to HealthCh", status)
|
||||
} else if status != tt.newStatus {
|
||||
t.Errorf("UpdateNodeHealth() sent wrong status %v, want %v", status, tt.newStatus)
|
||||
}
|
||||
default:
|
||||
if tt.shouldSend {
|
||||
t.Error("UpdateNodeHealth() did not send any status to HealthCh when expected")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeHealth_Concurrency(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
client := healthTesting.NewMockHealthClient(ctrl)
|
||||
n := NewNodeHealthTracker(client)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Number of goroutines to spawn for both reading and writing
|
||||
numGoroutines := 6
|
||||
|
||||
go func() {
|
||||
for range n.HealthUpdates() {
|
||||
// Consume values to avoid blocking on channel send.
|
||||
}
|
||||
}()
|
||||
|
||||
wg.Add(numGoroutines * 2) // for readers and writers
|
||||
|
||||
// Concurrently update health status
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
client.EXPECT().IsHealthy(gomock.Any()).Return(false)
|
||||
n.CheckHealth(context.Background())
|
||||
client.EXPECT().IsHealthy(gomock.Any()).Return(true)
|
||||
n.CheckHealth(context.Background())
|
||||
}()
|
||||
}
|
||||
|
||||
// Concurrently read health status
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_ = n.IsHealthy() // Just read the value
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait() // Wait for all goroutines to finish
|
||||
}
|
8
api/client/beacon/iface/BUILD.bazel
Normal file
8
api/client/beacon/iface/BUILD.bazel
Normal file
@ -0,0 +1,8 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["health.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/api/client/beacon/iface",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
13
api/client/beacon/iface/health.go
Normal file
13
api/client/beacon/iface/health.go
Normal file
@ -0,0 +1,13 @@
|
||||
package iface
|
||||
|
||||
import "context"
|
||||
|
||||
type HealthTracker interface {
|
||||
HealthUpdates() <-chan bool
|
||||
IsHealthy() bool
|
||||
CheckHealth(ctx context.Context) bool
|
||||
}
|
||||
|
||||
type HealthNode interface {
|
||||
IsHealthy(ctx context.Context) bool
|
||||
}
|
12
api/client/beacon/testing/BUILD.bazel
Normal file
12
api/client/beacon/testing/BUILD.bazel
Normal file
@ -0,0 +1,12 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["mock.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/api/client/beacon/testing",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api/client/beacon/iface:go_default_library",
|
||||
"@org_uber_go_mock//gomock:go_default_library",
|
||||
],
|
||||
)
|
53
api/client/beacon/testing/mock.go
Normal file
53
api/client/beacon/testing/mock.go
Normal file
@ -0,0 +1,53 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon/iface"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
var (
|
||||
_ = iface.HealthNode(&MockHealthClient{})
|
||||
)
|
||||
|
||||
// MockHealthClient is a mock of HealthClient interface.
|
||||
type MockHealthClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockHealthClientMockRecorder
|
||||
}
|
||||
|
||||
// MockHealthClientMockRecorder is the mock recorder for MockHealthClient.
|
||||
type MockHealthClientMockRecorder struct {
|
||||
mock *MockHealthClient
|
||||
}
|
||||
|
||||
// IsHealthy mocks base method.
|
||||
func (m *MockHealthClient) IsHealthy(arg0 context.Context) bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsHealthy", arg0)
|
||||
ret0, ok := ret[0].(bool)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return ret0
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockHealthClient) EXPECT() *MockHealthClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// IsHealthy indicates an expected call of IsHealthy.
|
||||
func (mr *MockHealthClientMockRecorder) IsHealthy(arg0 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsHealthy", reflect.TypeOf((*MockHealthClient)(nil).IsHealthy), arg0)
|
||||
}
|
||||
|
||||
// NewMockHealthClient creates a new mock instance.
|
||||
func NewMockHealthClient(ctrl *gomock.Controller) *MockHealthClient {
|
||||
mock := &MockHealthClient{ctrl: ctrl}
|
||||
mock.recorder = &MockHealthClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
@ -21,6 +21,9 @@ var ErrNotFound = errors.Wrap(ErrNotOK, "recv 404 NotFound response from API")
|
||||
// ErrInvalidNodeVersion indicates that the /eth/v1/node/version API response format was not recognized.
|
||||
var ErrInvalidNodeVersion = errors.New("invalid node version response")
|
||||
|
||||
// ErrConnectionIssue represents a connection problem.
|
||||
var ErrConnectionIssue = errors.New("could not connect")
|
||||
|
||||
// Non200Err is a function that parses an HTTP response to handle responses that are not 200 with a formatted error.
|
||||
func Non200Err(response *http.Response) error {
|
||||
bodyBytes, err := io.ReadAll(response.Body)
|
||||
|
24
api/client/event/BUILD.bazel
Normal file
24
api/client/event/BUILD.bazel
Normal file
@ -0,0 +1,24 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["event_stream.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/api/client/event",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api:go_default_library",
|
||||
"//api/client:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["event_stream_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
],
|
||||
)
|
148
api/client/event/event_stream.go
Normal file
148
api/client/event/event_stream.go
Normal file
@ -0,0 +1,148 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/api"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
EventHead = "head"
|
||||
EventBlock = "block"
|
||||
EventAttestation = "attestation"
|
||||
EventVoluntaryExit = "voluntary_exit"
|
||||
EventBlsToExecutionChange = "bls_to_execution_change"
|
||||
EventProposerSlashing = "proposer_slashing"
|
||||
EventAttesterSlashing = "attester_slashing"
|
||||
EventFinalizedCheckpoint = "finalized_checkpoint"
|
||||
EventChainReorg = "chain_reorg"
|
||||
EventContributionAndProof = "contribution_and_proof"
|
||||
EventLightClientFinalityUpdate = "light_client_finality_update"
|
||||
EventLightClientOptimisticUpdate = "light_client_optimistic_update"
|
||||
EventPayloadAttributes = "payload_attributes"
|
||||
EventBlobSidecar = "blob_sidecar"
|
||||
EventError = "error"
|
||||
EventConnectionError = "connection_error"
|
||||
)
|
||||
|
||||
var (
|
||||
_ = EventStreamClient(&EventStream{})
|
||||
)
|
||||
|
||||
var DefaultEventTopics = []string{EventHead}
|
||||
|
||||
type EventStreamClient interface {
|
||||
Subscribe(eventsChannel chan<- *Event)
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
EventType string
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// EventStream is responsible for subscribing to the Beacon API events endpoint
|
||||
// and dispatching received events to subscribers.
|
||||
type EventStream struct {
|
||||
ctx context.Context
|
||||
httpClient *http.Client
|
||||
host string
|
||||
topics []string
|
||||
}
|
||||
|
||||
func NewEventStream(ctx context.Context, httpClient *http.Client, host string, topics []string) (*EventStream, error) {
|
||||
// Check if the host is a valid URL
|
||||
_, err := url.ParseRequestURI(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(topics) == 0 {
|
||||
return nil, errors.New("no topics provided")
|
||||
}
|
||||
|
||||
return &EventStream{
|
||||
ctx: ctx,
|
||||
httpClient: httpClient,
|
||||
host: host,
|
||||
topics: topics,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *EventStream) Subscribe(eventsChannel chan<- *Event) {
|
||||
allTopics := strings.Join(h.topics, ",")
|
||||
log.WithField("topics", allTopics).Info("Listening to Beacon API events")
|
||||
fullUrl := h.host + "/eth/v1/events?topics=" + allTopics
|
||||
req, err := http.NewRequestWithContext(h.ctx, http.MethodGet, fullUrl, nil)
|
||||
if err != nil {
|
||||
eventsChannel <- &Event{
|
||||
EventType: EventConnectionError,
|
||||
Data: []byte(errors.Wrap(err, "failed to create HTTP request").Error()),
|
||||
}
|
||||
}
|
||||
req.Header.Set("Accept", api.EventStreamMediaType)
|
||||
req.Header.Set("Connection", api.KeepAlive)
|
||||
resp, err := h.httpClient.Do(req)
|
||||
if err != nil {
|
||||
eventsChannel <- &Event{
|
||||
EventType: EventConnectionError,
|
||||
Data: []byte(errors.Wrap(err, client.ErrConnectionIssue.Error()).Error()),
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if closeErr := resp.Body.Close(); closeErr != nil {
|
||||
log.WithError(closeErr).Error("Failed to close events response body")
|
||||
}
|
||||
}()
|
||||
// Create a new scanner to read lines from the response body
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
|
||||
var eventType, data string // Variables to store event type and data
|
||||
|
||||
// Iterate over lines of the event stream
|
||||
for scanner.Scan() {
|
||||
select {
|
||||
case <-h.ctx.Done():
|
||||
log.Info("Context canceled, stopping event stream")
|
||||
close(eventsChannel)
|
||||
return
|
||||
default:
|
||||
line := scanner.Text() // TODO(13730): scanner does not handle /r and does not fully adhere to https://html.spec.whatwg.org/multipage/server-sent-events.html#the-eventsource-interface
|
||||
// Handle the event based on your specific format
|
||||
if line == "" {
|
||||
// Empty line indicates the end of an event
|
||||
if eventType != "" && data != "" {
|
||||
// Process the event when both eventType and data are set
|
||||
eventsChannel <- &Event{EventType: eventType, Data: []byte(data)}
|
||||
}
|
||||
|
||||
// Reset eventType and data for the next event
|
||||
eventType, data = "", ""
|
||||
continue
|
||||
}
|
||||
et, ok := strings.CutPrefix(line, "event: ")
|
||||
if ok {
|
||||
// Extract event type from the "event" field
|
||||
eventType = et
|
||||
}
|
||||
d, ok := strings.CutPrefix(line, "data: ")
|
||||
if ok {
|
||||
// Extract data from the "data" field
|
||||
data = d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
eventsChannel <- &Event{
|
||||
EventType: EventConnectionError,
|
||||
Data: []byte(errors.Wrap(err, errors.Wrap(client.ErrConnectionIssue, "scanner failed").Error()).Error()),
|
||||
}
|
||||
}
|
||||
}
|
80
api/client/event/event_stream_test.go
Normal file
80
api/client/event/event_stream_test.go
Normal file
@ -0,0 +1,80 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func TestNewEventStream(t *testing.T) {
|
||||
validURL := "http://localhost:8080"
|
||||
invalidURL := "://invalid"
|
||||
topics := []string{"topic1", "topic2"}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
host string
|
||||
topics []string
|
||||
wantErr bool
|
||||
}{
|
||||
{"Valid input", validURL, topics, false},
|
||||
{"Invalid URL", invalidURL, topics, true},
|
||||
{"No topics", validURL, []string{}, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := NewEventStream(context.Background(), &http.Client{}, tt.host, tt.topics)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("NewEventStream() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEventStream(t *testing.T) {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/eth/v1/events", func(w http.ResponseWriter, r *http.Request) {
|
||||
flusher, ok := w.(http.Flusher)
|
||||
require.Equal(t, true, ok)
|
||||
for i := 1; i <= 2; i++ {
|
||||
_, err := fmt.Fprintf(w, "event: head\ndata: data%d\n\n", i)
|
||||
require.NoError(t, err)
|
||||
flusher.Flush() // Trigger flush to simulate streaming data
|
||||
time.Sleep(100 * time.Millisecond) // Simulate delay between events
|
||||
}
|
||||
})
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
topics := []string{"head"}
|
||||
eventsChannel := make(chan *Event, 1)
|
||||
stream, err := NewEventStream(context.Background(), http.DefaultClient, server.URL, topics)
|
||||
require.NoError(t, err)
|
||||
go stream.Subscribe(eventsChannel)
|
||||
|
||||
// Collect events
|
||||
var events []*Event
|
||||
|
||||
for len(events) != 2 {
|
||||
select {
|
||||
case event := <-eventsChannel:
|
||||
log.Info(event)
|
||||
events = append(events, event)
|
||||
}
|
||||
}
|
||||
|
||||
// Assertions to verify the events content
|
||||
expectedData := []string{"data1", "data2"}
|
||||
for i, event := range events {
|
||||
if string(event.Data) != expectedData[i] {
|
||||
t.Errorf("Expected event data %q, got %q", expectedData[i], string(event.Data))
|
||||
}
|
||||
}
|
||||
}
|
@ -18,8 +18,10 @@ go_library(
|
||||
"@com_github_golang_protobuf//ptypes/timestamp",
|
||||
"@com_github_libp2p_go_libp2p//core/network:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//core/peer:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//metadata:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
|
||||
],
|
||||
@ -45,7 +47,9 @@ go_test(
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//crypto:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
|
||||
"@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
"@org_golang_google_grpc//metadata:go_default_library",
|
||||
"@org_golang_google_grpc//reflection:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
|
||||
|
@ -6,7 +6,9 @@ package node
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
@ -21,8 +23,10 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/io/logs"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
"go.opencensus.io/trace"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
@ -45,6 +49,35 @@ type Server struct {
|
||||
BeaconMonitoringPort int
|
||||
}
|
||||
|
||||
// GetHealth checks the health of the node
|
||||
func (ns *Server) GetHealth(ctx context.Context, request *ethpb.HealthRequest) (*empty.Empty, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "node.GetHealth")
|
||||
defer span.End()
|
||||
|
||||
// Set a timeout for the health check operation
|
||||
timeoutDuration := 10 * time.Second
|
||||
ctx, cancel := context.WithTimeout(ctx, timeoutDuration)
|
||||
defer cancel() // Important to avoid a context leak
|
||||
|
||||
if ns.SyncChecker.Synced() {
|
||||
return &empty.Empty{}, nil
|
||||
}
|
||||
if ns.SyncChecker.Syncing() || ns.SyncChecker.Initialized() {
|
||||
if request.SyncingStatus != 0 {
|
||||
// override the 200 success with the provided request status
|
||||
if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.FormatUint(request.SyncingStatus, 10))); err != nil {
|
||||
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set custom success code header: %v", err)
|
||||
}
|
||||
return &empty.Empty{}, nil
|
||||
}
|
||||
if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", strconv.FormatUint(http.StatusPartialContent, 10))); err != nil {
|
||||
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set custom success code header: %v", err)
|
||||
}
|
||||
return &empty.Empty{}, nil
|
||||
}
|
||||
return &empty.Empty{}, status.Errorf(codes.Unavailable, "service unavailable")
|
||||
}
|
||||
|
||||
// GetSyncStatus checks the current network sync status of the node.
|
||||
func (ns *Server) GetSyncStatus(_ context.Context, _ *empty.Empty) (*ethpb.SyncStatus, error) {
|
||||
return ðpb.SyncStatus{
|
||||
|
@ -3,12 +3,14 @@ package node
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
|
||||
dbutil "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p"
|
||||
@ -22,6 +24,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/reflection"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
@ -170,3 +173,53 @@ func TestNodeServer_GetETH1ConnectionStatus(t *testing.T) {
|
||||
assert.Equal(t, ep, res.CurrentAddress)
|
||||
assert.Equal(t, errStr, res.CurrentConnectionError)
|
||||
}
|
||||
|
||||
func TestNodeServer_GetHealth(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input *mockSync.Sync
|
||||
customStatus uint64
|
||||
wantedErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
input: &mockSync.Sync{IsSyncing: false, IsSynced: true},
|
||||
},
|
||||
{
|
||||
name: "syncing",
|
||||
input: &mockSync.Sync{IsSyncing: false},
|
||||
wantedErr: "service unavailable",
|
||||
},
|
||||
{
|
||||
name: "custom sync status",
|
||||
input: &mockSync.Sync{IsSyncing: true},
|
||||
customStatus: 206,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
server := grpc.NewServer()
|
||||
ns := &Server{
|
||||
SyncChecker: tt.input,
|
||||
}
|
||||
ethpb.RegisterNodeServer(server, ns)
|
||||
reflection.Register(server)
|
||||
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
|
||||
_, err := ns.GetHealth(ctx, ðpb.HealthRequest{SyncingStatus: tt.customStatus})
|
||||
if tt.wantedErr == "" {
|
||||
require.NoError(t, err)
|
||||
return
|
||||
}
|
||||
if tt.customStatus != 0 {
|
||||
// Assuming the call was successful, now extract the headers
|
||||
headers, _ := metadata.FromIncomingContext(ctx)
|
||||
// Check for the specific header
|
||||
values, ok := headers["x-http-code"]
|
||||
require.Equal(t, true, ok && len(values) > 0)
|
||||
require.Equal(t, fmt.Sprintf("%d", tt.customStatus), values[0])
|
||||
|
||||
}
|
||||
require.ErrorContains(t, tt.wantedErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
515
proto/prysm/v1alpha1/node.pb.go
generated
515
proto/prysm/v1alpha1/node.pb.go
generated
@ -130,6 +130,53 @@ func (ConnectionState) EnumDescriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type HealthRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
SyncingStatus uint64 `protobuf:"varint,1,opt,name=syncing_status,json=syncingStatus,proto3" json:"syncing_status,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HealthRequest) Reset() {
|
||||
*x = HealthRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HealthRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HealthRequest) ProtoMessage() {}
|
||||
|
||||
func (x *HealthRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_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 HealthRequest.ProtoReflect.Descriptor instead.
|
||||
func (*HealthRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *HealthRequest) GetSyncingStatus() uint64 {
|
||||
if x != nil {
|
||||
return x.SyncingStatus
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type SyncStatus struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -141,7 +188,7 @@ type SyncStatus struct {
|
||||
func (x *SyncStatus) Reset() {
|
||||
*x = SyncStatus{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[0]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -154,7 +201,7 @@ func (x *SyncStatus) String() string {
|
||||
func (*SyncStatus) ProtoMessage() {}
|
||||
|
||||
func (x *SyncStatus) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[0]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -167,7 +214,7 @@ func (x *SyncStatus) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use SyncStatus.ProtoReflect.Descriptor instead.
|
||||
func (*SyncStatus) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{0}
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *SyncStatus) GetSyncing() bool {
|
||||
@ -190,7 +237,7 @@ type Genesis struct {
|
||||
func (x *Genesis) Reset() {
|
||||
*x = Genesis{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[1]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -203,7 +250,7 @@ func (x *Genesis) String() string {
|
||||
func (*Genesis) ProtoMessage() {}
|
||||
|
||||
func (x *Genesis) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[1]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -216,7 +263,7 @@ func (x *Genesis) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Genesis.ProtoReflect.Descriptor instead.
|
||||
func (*Genesis) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{1}
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Genesis) GetGenesisTime() *timestamppb.Timestamp {
|
||||
@ -252,7 +299,7 @@ type Version struct {
|
||||
func (x *Version) Reset() {
|
||||
*x = Version{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[2]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -265,7 +312,7 @@ func (x *Version) String() string {
|
||||
func (*Version) ProtoMessage() {}
|
||||
|
||||
func (x *Version) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[2]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -278,7 +325,7 @@ func (x *Version) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Version.ProtoReflect.Descriptor instead.
|
||||
func (*Version) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{2}
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Version) GetVersion() string {
|
||||
@ -306,7 +353,7 @@ type ImplementedServices struct {
|
||||
func (x *ImplementedServices) Reset() {
|
||||
*x = ImplementedServices{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[3]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -319,7 +366,7 @@ func (x *ImplementedServices) String() string {
|
||||
func (*ImplementedServices) ProtoMessage() {}
|
||||
|
||||
func (x *ImplementedServices) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[3]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -332,7 +379,7 @@ func (x *ImplementedServices) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ImplementedServices.ProtoReflect.Descriptor instead.
|
||||
func (*ImplementedServices) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{3}
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ImplementedServices) GetServices() []string {
|
||||
@ -353,7 +400,7 @@ type PeerRequest struct {
|
||||
func (x *PeerRequest) Reset() {
|
||||
*x = PeerRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[4]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -366,7 +413,7 @@ func (x *PeerRequest) String() string {
|
||||
func (*PeerRequest) ProtoMessage() {}
|
||||
|
||||
func (x *PeerRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[4]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -379,7 +426,7 @@ func (x *PeerRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use PeerRequest.ProtoReflect.Descriptor instead.
|
||||
func (*PeerRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{4}
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *PeerRequest) GetPeerId() string {
|
||||
@ -400,7 +447,7 @@ type Peers struct {
|
||||
func (x *Peers) Reset() {
|
||||
*x = Peers{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[5]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -413,7 +460,7 @@ func (x *Peers) String() string {
|
||||
func (*Peers) ProtoMessage() {}
|
||||
|
||||
func (x *Peers) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[5]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -426,7 +473,7 @@ func (x *Peers) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Peers.ProtoReflect.Descriptor instead.
|
||||
func (*Peers) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{5}
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *Peers) GetPeers() []*Peer {
|
||||
@ -451,7 +498,7 @@ type Peer struct {
|
||||
func (x *Peer) Reset() {
|
||||
*x = Peer{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[6]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -464,7 +511,7 @@ func (x *Peer) String() string {
|
||||
func (*Peer) ProtoMessage() {}
|
||||
|
||||
func (x *Peer) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[6]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[7]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -477,7 +524,7 @@ func (x *Peer) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Peer.ProtoReflect.Descriptor instead.
|
||||
func (*Peer) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{6}
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *Peer) GetAddress() string {
|
||||
@ -528,7 +575,7 @@ type HostData struct {
|
||||
func (x *HostData) Reset() {
|
||||
*x = HostData{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[7]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -541,7 +588,7 @@ func (x *HostData) String() string {
|
||||
func (*HostData) ProtoMessage() {}
|
||||
|
||||
func (x *HostData) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[7]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -554,7 +601,7 @@ func (x *HostData) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use HostData.ProtoReflect.Descriptor instead.
|
||||
func (*HostData) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{7}
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *HostData) GetAddresses() []string {
|
||||
@ -592,7 +639,7 @@ type ETH1ConnectionStatus struct {
|
||||
func (x *ETH1ConnectionStatus) Reset() {
|
||||
*x = ETH1ConnectionStatus{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[8]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -605,7 +652,7 @@ func (x *ETH1ConnectionStatus) String() string {
|
||||
func (*ETH1ConnectionStatus) ProtoMessage() {}
|
||||
|
||||
func (x *ETH1ConnectionStatus) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[8]
|
||||
mi := &file_proto_prysm_v1alpha1_node_proto_msgTypes[9]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -618,7 +665,7 @@ func (x *ETH1ConnectionStatus) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ETH1ConnectionStatus.ProtoReflect.Descriptor instead.
|
||||
func (*ETH1ConnectionStatus) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{8}
|
||||
return file_proto_prysm_v1alpha1_node_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *ETH1ConnectionStatus) GetCurrentAddress() string {
|
||||
@ -663,143 +710,154 @@ var file_proto_prysm_v1alpha1_node_proto_rawDesc = []byte{
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x74, 0x68, 0x2f,
|
||||
0x65, 0x78, 0x74, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x22, 0x26, 0x0a, 0x0a, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x22, 0xc2, 0x01, 0x0a, 0x07, 0x47, 0x65,
|
||||
0x6e, 0x65, 0x73, 0x69, 0x73, 0x12, 0x3d, 0x0a, 0x0c, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73,
|
||||
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
|
||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x18, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x5f,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x16, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x43,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e,
|
||||
0x0a, 0x17, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61,
|
||||
0x74, 0x6f, 0x72, 0x73, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42,
|
||||
0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x15, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73,
|
||||
0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x3f,
|
||||
0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22,
|
||||
0x31, 0x0a, 0x13, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x22, 0x26, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0x3a, 0x0a, 0x05, 0x50, 0x65,
|
||||
0x65, 0x72, 0x73, 0x12, 0x31, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74,
|
||||
0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52,
|
||||
0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0xe2, 0x01, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x42, 0x0a, 0x09, 0x64, 0x69, 0x72,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x65,
|
||||
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c,
|
||||
0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a,
|
||||
0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65,
|
||||
0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e,
|
||||
0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52,
|
||||
0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65,
|
||||
0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x72,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x72, 0x22, 0x53, 0x0a, 0x08, 0x48,
|
||||
0x6f, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65,
|
||||
0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10,
|
||||
0x0a, 0x03, 0x65, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x72,
|
||||
0x22, 0xc4, 0x01, 0x0a, 0x14, 0x45, 0x54, 0x48, 0x31, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x75, 0x72,
|
||||
0x72, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65,
|
||||
0x73, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e,
|
||||
0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09,
|
||||
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18,
|
||||
0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2a, 0x37, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x44,
|
||||
0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e,
|
||||
0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x42, 0x4f, 0x55, 0x4e, 0x44,
|
||||
0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4f, 0x55, 0x54, 0x42, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02,
|
||||
0x2a, 0x55, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
|
||||
0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43,
|
||||
0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e,
|
||||
0x45, 0x43, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x4e,
|
||||
0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x4f, 0x4e, 0x4e, 0x45,
|
||||
0x43, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x32, 0x93, 0x07, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65,
|
||||
0x12, 0x6e, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x21, 0x2e, 0x65, 0x74, 0x68, 0x65,
|
||||
0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
|
||||
0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x22, 0x82, 0xd3,
|
||||
0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70,
|
||||
0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67,
|
||||
0x12, 0x68, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x47, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x12, 0x16,
|
||||
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1e, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75,
|
||||
0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x47,
|
||||
0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a,
|
||||
0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f,
|
||||
0x64, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x12, 0x68, 0x0a, 0x0a, 0x47, 0x65,
|
||||
0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
|
||||
0x1a, 0x1e, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e,
|
||||
0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76,
|
||||
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x76, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x82, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
|
||||
0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2a, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72,
|
||||
0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,
|
||||
0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x65,
|
||||
0x6f, 0x22, 0x36, 0x0a, 0x0d, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x73, 0x79, 0x6e, 0x63,
|
||||
0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x26, 0x0a, 0x0a, 0x53, 0x79, 0x6e,
|
||||
0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69,
|
||||
0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e,
|
||||
0x67, 0x22, 0xc2, 0x01, 0x0a, 0x07, 0x47, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x12, 0x3d, 0x0a,
|
||||
0x0c, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
|
||||
0x0b, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x18,
|
||||
0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74,
|
||||
0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x16,
|
||||
0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41,
|
||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e, 0x0a, 0x17, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69,
|
||||
0x73, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x72, 0x6f, 0x6f,
|
||||
0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52,
|
||||
0x15, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f,
|
||||
0x72, 0x73, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x3f, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6d,
|
||||
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d,
|
||||
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x31, 0x0a, 0x13, 0x49, 0x6d, 0x70, 0x6c, 0x65,
|
||||
0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
|
||||
0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x26, 0x0a, 0x0b, 0x50, 0x65,
|
||||
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65,
|
||||
0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72,
|
||||
0x49, 0x64, 0x22, 0x3a, 0x0a, 0x05, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x31, 0x0a, 0x05, 0x70,
|
||||
0x65, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x74, 0x68,
|
||||
0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68,
|
||||
0x61, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0xe2,
|
||||
0x01, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
|
||||
0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||
0x73, 0x12, 0x42, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e,
|
||||
0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x65, 0x65,
|
||||
0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x26, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76,
|
||||
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49,
|
||||
0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
||||
0x65, 0x6e, 0x72, 0x22, 0x53, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12,
|
||||
0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x17, 0x0a,
|
||||
0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x72, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x72, 0x22, 0xc4, 0x01, 0x0a, 0x14, 0x45, 0x54, 0x48,
|
||||
0x31, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64,
|
||||
0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72,
|
||||
0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x63, 0x75,
|
||||
0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x75,
|
||||
0x72, 0x72, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45,
|
||||
0x72, 0x72, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65,
|
||||
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
|
||||
0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2a,
|
||||
0x37, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a,
|
||||
0x07, 0x49, 0x4e, 0x42, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x4f, 0x55,
|
||||
0x54, 0x42, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x2a, 0x55, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x6e,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x44,
|
||||
0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a,
|
||||
0x0d, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01,
|
||||
0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12,
|
||||
0x0e, 0x0a, 0x0a, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x32,
|
||||
0x81, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x6e, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x53,
|
||||
0x79, 0x6e, 0x63, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
|
||||
0x79, 0x1a, 0x21, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68,
|
||||
0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x65,
|
||||
0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65,
|
||||
0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x62, 0x0a, 0x07, 0x47, 0x65, 0x74,
|
||||
0x48, 0x6f, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1f, 0x2e, 0x65,
|
||||
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c,
|
||||
0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x22, 0x1e, 0x82,
|
||||
0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c,
|
||||
0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x32, 0x70, 0x12, 0x6b, 0x0a,
|
||||
0x07, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72,
|
||||
0x2f, 0x73, 0x79, 0x6e, 0x63, 0x69, 0x6e, 0x67, 0x12, 0x68, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x47,
|
||||
0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1e,
|
||||
0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31,
|
||||
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x22, 0x22,
|
||||
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61,
|
||||
0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x73,
|
||||
0x69, 0x73, 0x12, 0x68, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1e, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72,
|
||||
0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,
|
||||
0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x65,
|
||||
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c,
|
||||
0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
||||
0x19, 0x12, 0x17, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,
|
||||
0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x65, 0x65, 0x72, 0x12, 0x63, 0x0a, 0x09, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
|
||||
0x1c, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76,
|
||||
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x73, 0x22, 0x20, 0x82,
|
||||
0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c,
|
||||
0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x65, 0x65, 0x72, 0x73, 0x12,
|
||||
0x8b, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x45, 0x54, 0x48, 0x31, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
|
||||
0x70, 0x74, 0x79, 0x1a, 0x2b, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65,
|
||||
0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x54, 0x48, 0x31,
|
||||
0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76,
|
||||
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x65, 0x74, 0x68,
|
||||
0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x94, 0x01,
|
||||
0x0a, 0x19, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65,
|
||||
0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x42, 0x09, 0x4e, 0x6f, 0x64,
|
||||
0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61,
|
||||
0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31,
|
||||
0x3b, 0x65, 0x74, 0x68, 0xaa, 0x02, 0x15, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e,
|
||||
0x45, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0xca, 0x02, 0x15, 0x45,
|
||||
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, 0x74, 0x68, 0x5c, 0x76, 0x31, 0x61, 0x6c,
|
||||
0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c,
|
||||
0x12, 0x1a, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f,
|
||||
0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x6c, 0x0a, 0x09,
|
||||
0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x24, 0x2e, 0x65, 0x74, 0x68, 0x65,
|
||||
0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
|
||||
0x31, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12,
|
||||
0x19, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e,
|
||||
0x6f, 0x64, 0x65, 0x2f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x82, 0x01, 0x0a, 0x17, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2a,
|
||||
0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31,
|
||||
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||
0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93,
|
||||
0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
|
||||
0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12,
|
||||
0x62, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
|
||||
0x74, 0x79, 0x1a, 0x1f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74,
|
||||
0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x44,
|
||||
0x61, 0x74, 0x61, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x65, 0x74,
|
||||
0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f,
|
||||
0x70, 0x32, 0x70, 0x12, 0x6b, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x22,
|
||||
0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31,
|
||||
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74,
|
||||
0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x22,
|
||||
0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31,
|
||||
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x70, 0x65, 0x65, 0x72,
|
||||
0x12, 0x63, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x16, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d,
|
||||
0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x50, 0x65,
|
||||
0x65, 0x72, 0x73, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x65, 0x74,
|
||||
0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2f,
|
||||
0x70, 0x65, 0x65, 0x72, 0x73, 0x12, 0x8b, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x45, 0x54, 0x48,
|
||||
0x31, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2b, 0x2e, 0x65, 0x74, 0x68, 0x65,
|
||||
0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
|
||||
0x31, 0x2e, 0x45, 0x54, 0x48, 0x31, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23,
|
||||
0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x6e, 0x6f,
|
||||
0x64, 0x65, 0x2f, 0x65, 0x74, 0x68, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x42, 0x94, 0x01, 0x0a, 0x19, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68, 0x65,
|
||||
0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61,
|
||||
0x31, 0x42, 0x09, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a,
|
||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d,
|
||||
0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76,
|
||||
0x35, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x31,
|
||||
0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x65, 0x74, 0x68, 0xaa, 0x02, 0x15, 0x45, 0x74, 0x68,
|
||||
0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x45, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68,
|
||||
0x61, 0x31, 0xca, 0x02, 0x15, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, 0x74,
|
||||
0x68, 0x5c, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -815,45 +873,48 @@ func file_proto_prysm_v1alpha1_node_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_proto_prysm_v1alpha1_node_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_proto_prysm_v1alpha1_node_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
||||
var file_proto_prysm_v1alpha1_node_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_proto_prysm_v1alpha1_node_proto_goTypes = []interface{}{
|
||||
(PeerDirection)(0), // 0: ethereum.eth.v1alpha1.PeerDirection
|
||||
(ConnectionState)(0), // 1: ethereum.eth.v1alpha1.ConnectionState
|
||||
(*SyncStatus)(nil), // 2: ethereum.eth.v1alpha1.SyncStatus
|
||||
(*Genesis)(nil), // 3: ethereum.eth.v1alpha1.Genesis
|
||||
(*Version)(nil), // 4: ethereum.eth.v1alpha1.Version
|
||||
(*ImplementedServices)(nil), // 5: ethereum.eth.v1alpha1.ImplementedServices
|
||||
(*PeerRequest)(nil), // 6: ethereum.eth.v1alpha1.PeerRequest
|
||||
(*Peers)(nil), // 7: ethereum.eth.v1alpha1.Peers
|
||||
(*Peer)(nil), // 8: ethereum.eth.v1alpha1.Peer
|
||||
(*HostData)(nil), // 9: ethereum.eth.v1alpha1.HostData
|
||||
(*ETH1ConnectionStatus)(nil), // 10: ethereum.eth.v1alpha1.ETH1ConnectionStatus
|
||||
(*timestamppb.Timestamp)(nil), // 11: google.protobuf.Timestamp
|
||||
(*emptypb.Empty)(nil), // 12: google.protobuf.Empty
|
||||
(*HealthRequest)(nil), // 2: ethereum.eth.v1alpha1.HealthRequest
|
||||
(*SyncStatus)(nil), // 3: ethereum.eth.v1alpha1.SyncStatus
|
||||
(*Genesis)(nil), // 4: ethereum.eth.v1alpha1.Genesis
|
||||
(*Version)(nil), // 5: ethereum.eth.v1alpha1.Version
|
||||
(*ImplementedServices)(nil), // 6: ethereum.eth.v1alpha1.ImplementedServices
|
||||
(*PeerRequest)(nil), // 7: ethereum.eth.v1alpha1.PeerRequest
|
||||
(*Peers)(nil), // 8: ethereum.eth.v1alpha1.Peers
|
||||
(*Peer)(nil), // 9: ethereum.eth.v1alpha1.Peer
|
||||
(*HostData)(nil), // 10: ethereum.eth.v1alpha1.HostData
|
||||
(*ETH1ConnectionStatus)(nil), // 11: ethereum.eth.v1alpha1.ETH1ConnectionStatus
|
||||
(*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp
|
||||
(*emptypb.Empty)(nil), // 13: google.protobuf.Empty
|
||||
}
|
||||
var file_proto_prysm_v1alpha1_node_proto_depIdxs = []int32{
|
||||
11, // 0: ethereum.eth.v1alpha1.Genesis.genesis_time:type_name -> google.protobuf.Timestamp
|
||||
8, // 1: ethereum.eth.v1alpha1.Peers.peers:type_name -> ethereum.eth.v1alpha1.Peer
|
||||
12, // 0: ethereum.eth.v1alpha1.Genesis.genesis_time:type_name -> google.protobuf.Timestamp
|
||||
9, // 1: ethereum.eth.v1alpha1.Peers.peers:type_name -> ethereum.eth.v1alpha1.Peer
|
||||
0, // 2: ethereum.eth.v1alpha1.Peer.direction:type_name -> ethereum.eth.v1alpha1.PeerDirection
|
||||
1, // 3: ethereum.eth.v1alpha1.Peer.connection_state:type_name -> ethereum.eth.v1alpha1.ConnectionState
|
||||
12, // 4: ethereum.eth.v1alpha1.Node.GetSyncStatus:input_type -> google.protobuf.Empty
|
||||
12, // 5: ethereum.eth.v1alpha1.Node.GetGenesis:input_type -> google.protobuf.Empty
|
||||
12, // 6: ethereum.eth.v1alpha1.Node.GetVersion:input_type -> google.protobuf.Empty
|
||||
12, // 7: ethereum.eth.v1alpha1.Node.ListImplementedServices:input_type -> google.protobuf.Empty
|
||||
12, // 8: ethereum.eth.v1alpha1.Node.GetHost:input_type -> google.protobuf.Empty
|
||||
6, // 9: ethereum.eth.v1alpha1.Node.GetPeer:input_type -> ethereum.eth.v1alpha1.PeerRequest
|
||||
12, // 10: ethereum.eth.v1alpha1.Node.ListPeers:input_type -> google.protobuf.Empty
|
||||
12, // 11: ethereum.eth.v1alpha1.Node.GetETH1ConnectionStatus:input_type -> google.protobuf.Empty
|
||||
2, // 12: ethereum.eth.v1alpha1.Node.GetSyncStatus:output_type -> ethereum.eth.v1alpha1.SyncStatus
|
||||
3, // 13: ethereum.eth.v1alpha1.Node.GetGenesis:output_type -> ethereum.eth.v1alpha1.Genesis
|
||||
4, // 14: ethereum.eth.v1alpha1.Node.GetVersion:output_type -> ethereum.eth.v1alpha1.Version
|
||||
5, // 15: ethereum.eth.v1alpha1.Node.ListImplementedServices:output_type -> ethereum.eth.v1alpha1.ImplementedServices
|
||||
9, // 16: ethereum.eth.v1alpha1.Node.GetHost:output_type -> ethereum.eth.v1alpha1.HostData
|
||||
8, // 17: ethereum.eth.v1alpha1.Node.GetPeer:output_type -> ethereum.eth.v1alpha1.Peer
|
||||
7, // 18: ethereum.eth.v1alpha1.Node.ListPeers:output_type -> ethereum.eth.v1alpha1.Peers
|
||||
10, // 19: ethereum.eth.v1alpha1.Node.GetETH1ConnectionStatus:output_type -> ethereum.eth.v1alpha1.ETH1ConnectionStatus
|
||||
12, // [12:20] is the sub-list for method output_type
|
||||
4, // [4:12] is the sub-list for method input_type
|
||||
13, // 4: ethereum.eth.v1alpha1.Node.GetSyncStatus:input_type -> google.protobuf.Empty
|
||||
13, // 5: ethereum.eth.v1alpha1.Node.GetGenesis:input_type -> google.protobuf.Empty
|
||||
13, // 6: ethereum.eth.v1alpha1.Node.GetVersion:input_type -> google.protobuf.Empty
|
||||
2, // 7: ethereum.eth.v1alpha1.Node.GetHealth:input_type -> ethereum.eth.v1alpha1.HealthRequest
|
||||
13, // 8: ethereum.eth.v1alpha1.Node.ListImplementedServices:input_type -> google.protobuf.Empty
|
||||
13, // 9: ethereum.eth.v1alpha1.Node.GetHost:input_type -> google.protobuf.Empty
|
||||
7, // 10: ethereum.eth.v1alpha1.Node.GetPeer:input_type -> ethereum.eth.v1alpha1.PeerRequest
|
||||
13, // 11: ethereum.eth.v1alpha1.Node.ListPeers:input_type -> google.protobuf.Empty
|
||||
13, // 12: ethereum.eth.v1alpha1.Node.GetETH1ConnectionStatus:input_type -> google.protobuf.Empty
|
||||
3, // 13: ethereum.eth.v1alpha1.Node.GetSyncStatus:output_type -> ethereum.eth.v1alpha1.SyncStatus
|
||||
4, // 14: ethereum.eth.v1alpha1.Node.GetGenesis:output_type -> ethereum.eth.v1alpha1.Genesis
|
||||
5, // 15: ethereum.eth.v1alpha1.Node.GetVersion:output_type -> ethereum.eth.v1alpha1.Version
|
||||
13, // 16: ethereum.eth.v1alpha1.Node.GetHealth:output_type -> google.protobuf.Empty
|
||||
6, // 17: ethereum.eth.v1alpha1.Node.ListImplementedServices:output_type -> ethereum.eth.v1alpha1.ImplementedServices
|
||||
10, // 18: ethereum.eth.v1alpha1.Node.GetHost:output_type -> ethereum.eth.v1alpha1.HostData
|
||||
9, // 19: ethereum.eth.v1alpha1.Node.GetPeer:output_type -> ethereum.eth.v1alpha1.Peer
|
||||
8, // 20: ethereum.eth.v1alpha1.Node.ListPeers:output_type -> ethereum.eth.v1alpha1.Peers
|
||||
11, // 21: ethereum.eth.v1alpha1.Node.GetETH1ConnectionStatus:output_type -> ethereum.eth.v1alpha1.ETH1ConnectionStatus
|
||||
13, // [13:22] is the sub-list for method output_type
|
||||
4, // [4:13] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
@ -866,7 +927,7 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SyncStatus); i {
|
||||
switch v := v.(*HealthRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -878,7 +939,7 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Genesis); i {
|
||||
switch v := v.(*SyncStatus); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -890,7 +951,7 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Version); i {
|
||||
switch v := v.(*Genesis); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -902,7 +963,7 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ImplementedServices); i {
|
||||
switch v := v.(*Version); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -914,7 +975,7 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PeerRequest); i {
|
||||
switch v := v.(*ImplementedServices); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -926,7 +987,7 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Peers); i {
|
||||
switch v := v.(*PeerRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -938,7 +999,7 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Peer); i {
|
||||
switch v := v.(*Peers); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -950,7 +1011,7 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HostData); i {
|
||||
switch v := v.(*Peer); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -962,6 +1023,18 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
}
|
||||
}
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HostData); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_prysm_v1alpha1_node_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ETH1ConnectionStatus); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@ -980,7 +1053,7 @@ func file_proto_prysm_v1alpha1_node_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proto_prysm_v1alpha1_node_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumMessages: 9,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
@ -1010,6 +1083,7 @@ type NodeClient interface {
|
||||
GetSyncStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SyncStatus, error)
|
||||
GetGenesis(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Genesis, error)
|
||||
GetVersion(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Version, error)
|
||||
GetHealth(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
ListImplementedServices(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ImplementedServices, error)
|
||||
GetHost(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*HostData, error)
|
||||
GetPeer(ctx context.Context, in *PeerRequest, opts ...grpc.CallOption) (*Peer, error)
|
||||
@ -1052,6 +1126,15 @@ func (c *nodeClient) GetVersion(ctx context.Context, in *emptypb.Empty, opts ...
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *nodeClient) GetHealth(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||
out := new(emptypb.Empty)
|
||||
err := c.cc.Invoke(ctx, "/ethereum.eth.v1alpha1.Node/GetHealth", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *nodeClient) ListImplementedServices(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ImplementedServices, error) {
|
||||
out := new(ImplementedServices)
|
||||
err := c.cc.Invoke(ctx, "/ethereum.eth.v1alpha1.Node/ListImplementedServices", in, out, opts...)
|
||||
@ -1102,6 +1185,7 @@ type NodeServer interface {
|
||||
GetSyncStatus(context.Context, *emptypb.Empty) (*SyncStatus, error)
|
||||
GetGenesis(context.Context, *emptypb.Empty) (*Genesis, error)
|
||||
GetVersion(context.Context, *emptypb.Empty) (*Version, error)
|
||||
GetHealth(context.Context, *HealthRequest) (*emptypb.Empty, error)
|
||||
ListImplementedServices(context.Context, *emptypb.Empty) (*ImplementedServices, error)
|
||||
GetHost(context.Context, *emptypb.Empty) (*HostData, error)
|
||||
GetPeer(context.Context, *PeerRequest) (*Peer, error)
|
||||
@ -1122,6 +1206,9 @@ func (*UnimplementedNodeServer) GetGenesis(context.Context, *emptypb.Empty) (*Ge
|
||||
func (*UnimplementedNodeServer) GetVersion(context.Context, *emptypb.Empty) (*Version, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetVersion not implemented")
|
||||
}
|
||||
func (*UnimplementedNodeServer) GetHealth(context.Context, *HealthRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetHealth not implemented")
|
||||
}
|
||||
func (*UnimplementedNodeServer) ListImplementedServices(context.Context, *emptypb.Empty) (*ImplementedServices, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListImplementedServices not implemented")
|
||||
}
|
||||
@ -1196,6 +1283,24 @@ func _Node_GetVersion_Handler(srv interface{}, ctx context.Context, dec func(int
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Node_GetHealth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HealthRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(NodeServer).GetHealth(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/ethereum.eth.v1alpha1.Node/GetHealth",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(NodeServer).GetHealth(ctx, req.(*HealthRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Node_ListImplementedServices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(emptypb.Empty)
|
||||
if err := dec(in); err != nil {
|
||||
@ -1302,6 +1407,10 @@ var _Node_serviceDesc = grpc.ServiceDesc{
|
||||
MethodName: "GetVersion",
|
||||
Handler: _Node_GetVersion_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetHealth",
|
||||
Handler: _Node_GetHealth_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListImplementedServices",
|
||||
Handler: _Node_ListImplementedServices_Handler,
|
||||
|
@ -89,6 +89,42 @@ func local_request_Node_GetVersion_0(ctx context.Context, marshaler runtime.Mars
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Node_GetHealth_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Node_GetHealth_0(ctx context.Context, marshaler runtime.Marshaler, client NodeClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq HealthRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Node_GetHealth_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetHealth(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Node_GetHealth_0(ctx context.Context, marshaler runtime.Marshaler, server NodeServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq HealthRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Node_GetHealth_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetHealth(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_Node_ListImplementedServices_0(ctx context.Context, marshaler runtime.Marshaler, client NodeClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq emptypb.Empty
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -272,6 +308,29 @@ func RegisterNodeHandlerServer(ctx context.Context, mux *runtime.ServeMux, serve
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Node_GetHealth_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, "/ethereum.eth.v1alpha1.Node/GetHealth")
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Node_GetHealth_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_Node_GetHealth_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Node_ListImplementedServices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@ -488,6 +547,26 @@ func RegisterNodeHandlerClient(ctx context.Context, mux *runtime.ServeMux, clien
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Node_GetHealth_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, "/ethereum.eth.v1alpha1.Node/GetHealth")
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Node_GetHealth_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Node_GetHealth_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Node_ListImplementedServices_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@ -598,6 +677,8 @@ var (
|
||||
|
||||
pattern_Node_GetVersion_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"eth", "v1alpha1", "node", "version"}, ""))
|
||||
|
||||
pattern_Node_GetHealth_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"eth", "v1alpha1", "node", "health"}, ""))
|
||||
|
||||
pattern_Node_ListImplementedServices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"eth", "v1alpha1", "node", "services"}, ""))
|
||||
|
||||
pattern_Node_GetHost_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"eth", "v1alpha1", "node", "p2p"}, ""))
|
||||
@ -616,6 +697,8 @@ var (
|
||||
|
||||
forward_Node_GetVersion_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Node_GetHealth_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Node_ListImplementedServices_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Node_GetHost_0 = runtime.ForwardResponseMessage
|
||||
|
@ -54,6 +54,13 @@ service Node {
|
||||
};
|
||||
}
|
||||
|
||||
// Retrieve the current health of the node.
|
||||
rpc GetHealth(HealthRequest) returns (google.protobuf.Empty) {
|
||||
option (google.api.http) = {
|
||||
get: "/eth/v1alpha1/node/health"
|
||||
};
|
||||
}
|
||||
|
||||
// Retrieve the list of services implemented and enabled by this node.
|
||||
//
|
||||
// Any service not present in this list may return UNIMPLEMENTED or
|
||||
@ -94,6 +101,10 @@ service Node {
|
||||
}
|
||||
}
|
||||
|
||||
message HealthRequest {
|
||||
uint64 syncing_status = 1;
|
||||
}
|
||||
|
||||
// Information about the current network sync status of the node.
|
||||
message SyncStatus {
|
||||
// Whether or not the node is currently syncing.
|
||||
|
@ -13,6 +13,8 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/testing/validator-mock",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api/client/beacon:go_default_library",
|
||||
"//api/client/event:go_default_library",
|
||||
"//consensus-types/validator:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//validator/client/iface:go_default_library",
|
||||
|
7
testing/validator-mock/node_client_mock.go
generated
7
testing/validator-mock/node_client_mock.go
generated
@ -13,6 +13,7 @@ import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
@ -22,6 +23,7 @@ import (
|
||||
type MockNodeClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockNodeClientMockRecorder
|
||||
healthTracker *beacon.NodeHealthTracker
|
||||
}
|
||||
|
||||
// MockNodeClientMockRecorder is the mock recorder for MockNodeClient.
|
||||
@ -33,6 +35,7 @@ type MockNodeClientMockRecorder struct {
|
||||
func NewMockNodeClient(ctrl *gomock.Controller) *MockNodeClient {
|
||||
mock := &MockNodeClient{ctrl: ctrl}
|
||||
mock.recorder = &MockNodeClientMockRecorder{mock}
|
||||
mock.healthTracker = beacon.NewNodeHealthTracker(mock)
|
||||
return mock
|
||||
}
|
||||
|
||||
@ -114,3 +117,7 @@ func (mr *MockNodeClientMockRecorder) ListPeers(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPeers", reflect.TypeOf((*MockNodeClient)(nil).ListPeers), arg0, arg1)
|
||||
}
|
||||
|
||||
func (m *MockNodeClient) HealthTracker() *beacon.NodeHealthTracker {
|
||||
return m.healthTracker
|
||||
}
|
||||
|
55
testing/validator-mock/validator_client_mock.go
generated
55
testing/validator-mock/validator_client_mock.go
generated
@ -13,6 +13,8 @@ import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
iface "github.com/prysmaticlabs/prysm/v5/validator/client/iface"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
@ -297,32 +299,57 @@ func (mr *MockValidatorClientMockRecorder) ProposeExit(arg0, arg1 any) *gomock.C
|
||||
}
|
||||
|
||||
// StartEventStream mocks base method.
|
||||
func (m *MockValidatorClient) StartEventStream(arg0 context.Context) error {
|
||||
func (m *MockValidatorClient) StartEventStream(arg0 context.Context, arg1 []string, arg2 chan<- *event.Event){
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StartEventStream", arg0)
|
||||
_ = m.ctrl.Call(m, "StartEventStream", arg0,arg1,arg2)
|
||||
}
|
||||
|
||||
// StartEventStream indicates an expected call of StartEventStream.
|
||||
func (mr *MockValidatorClientMockRecorder) StartEventStream(arg0,arg1,arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartEventStream", reflect.TypeOf((*MockValidatorClient)(nil).StartEventStream), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ProcessEvent mocks base method.
|
||||
func (m *MockValidatorClient) ProcessEvent(arg0 *event.Event) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ProcessEvent", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// StartEventStream indicates an expected call of StartEventStream.
|
||||
func (mr *MockValidatorClientMockRecorder) StartEventStream(arg0 any) *gomock.Call {
|
||||
// ProcessEvent indicates an expected call of ProcessEvent.
|
||||
func (mr *MockValidatorClientMockRecorder) ProcessEvent(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartEventStream", reflect.TypeOf((*MockValidatorClient)(nil).StartEventStream), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProcessEvent", reflect.TypeOf((*MockValidatorClient)(nil).ProcessEvent), arg0)
|
||||
}
|
||||
|
||||
// StreamSlots mocks base method.
|
||||
func (m *MockValidatorClient) StreamSlots(arg0 context.Context, arg1 *eth.StreamSlotsRequest) (eth.BeaconNodeValidator_StreamSlotsClient, error) {
|
||||
// NodeIsHealthy mocks base method.
|
||||
func (m *MockValidatorClient) NodeIsHealthy(arg0 context.Context) bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StreamSlots", arg0, arg1)
|
||||
ret0, _ := ret[0].(eth.BeaconNodeValidator_StreamSlotsClient)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
ret := m.ctrl.Call(m, "NodeIsHealthy",arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// StreamSlots indicates an expected call of StreamSlots.
|
||||
func (mr *MockValidatorClientMockRecorder) StreamSlots(arg0, arg1 any) *gomock.Call {
|
||||
// NodeIsHealthy indicates an expected call of NodeIsHealthy.
|
||||
func (mr *MockValidatorClientMockRecorder) NodeIsHealthy(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StreamSlots", reflect.TypeOf((*MockValidatorClient)(nil).StreamSlots), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeIsHealthy", reflect.TypeOf((*MockValidatorClient)(nil).NodeIsHealthy), arg0)
|
||||
}
|
||||
|
||||
// NodeHealthTracker mocks base method.
|
||||
func (m *MockValidatorClient) NodeHealthTracker() *beacon.NodeHealthTracker {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NodeHealthTracker")
|
||||
ret0, _ := ret[0].(*beacon.NodeHealthTracker)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// NodeHealthTracker indicates an expected call of NodeHealthTracker.
|
||||
func (mr *MockValidatorClientMockRecorder) NodeHealthTracker() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeHealthTracker", reflect.TypeOf((*MockValidatorClient)(nil).NodeHealthTracker))
|
||||
}
|
||||
|
||||
// SubmitAggregateSelectionProof mocks base method.
|
||||
|
@ -87,10 +87,7 @@ func (acm *CLIManager) prepareBeaconClients(ctx context.Context) (*iface.Validat
|
||||
acm.beaconApiTimeout,
|
||||
)
|
||||
|
||||
restHandler := &beaconApi.BeaconApiJsonRestHandler{
|
||||
HttpClient: http.Client{Timeout: acm.beaconApiTimeout},
|
||||
Host: acm.beaconApiEndpoint,
|
||||
}
|
||||
restHandler := beaconApi.NewBeaconApiJsonRestHandler(http.Client{Timeout: acm.beaconApiTimeout}, acm.beaconApiEndpoint)
|
||||
validatorClient := validatorClientFactory.NewValidatorClient(conn, restHandler)
|
||||
nodeClient := nodeClientFactory.NewNodeClient(conn, restHandler)
|
||||
|
||||
|
@ -10,6 +10,8 @@ go_library(
|
||||
"//validator:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//api/client/beacon:go_default_library",
|
||||
"//api/client/event:go_default_library",
|
||||
"//config/proposer:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
|
@ -7,6 +7,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/proposer"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
@ -213,14 +215,18 @@ func (m *Validator) SetProposerSettings(_ context.Context, settings *proposer.Se
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Validator) StartEventStream(_ context.Context) error {
|
||||
func (*Validator) StartEventStream(_ context.Context, _ []string, _ chan<- *event.Event) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (_ *Validator) EventStreamIsRunning() bool {
|
||||
func (*Validator) ProcessEvent(event *event.Event) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (_ *Validator) NodeIsHealthy(ctx context.Context) bool {
|
||||
func (*Validator) EventStreamIsRunning() bool {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (*Validator) HealthTracker() *beacon.NodeHealthTracker {
|
||||
panic("implement me")
|
||||
}
|
||||
|
@ -23,7 +23,11 @@ go_library(
|
||||
"//validator:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//api/client:go_default_library",
|
||||
"//api/client/beacon:go_default_library",
|
||||
"//api/client/event:go_default_library",
|
||||
"//api/grpc:go_default_library",
|
||||
"//api/server/structs:go_default_library",
|
||||
"//async:go_default_library",
|
||||
"//async/event:go_default_library",
|
||||
"//beacon-chain/builder:go_default_library",
|
||||
@ -115,6 +119,8 @@ go_test(
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//api/client/beacon:go_default_library",
|
||||
"//api/client/beacon/testing:go_default_library",
|
||||
"//async/event:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//cache/lru:go_default_library",
|
||||
|
@ -16,7 +16,6 @@ go_library(
|
||||
"domain_data.go",
|
||||
"doppelganger.go",
|
||||
"duties.go",
|
||||
"event_handler.go",
|
||||
"genesis.go",
|
||||
"get_beacon_block.go",
|
||||
"index.go",
|
||||
@ -43,10 +42,11 @@ go_library(
|
||||
visibility = ["//validator:__subpackages__"],
|
||||
deps = [
|
||||
"//api:go_default_library",
|
||||
"//api/client/beacon:go_default_library",
|
||||
"//api/client/event:go_default_library",
|
||||
"//api/server/structs:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//beacon-chain/rpc/eth/events:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/validator:go_default_library",
|
||||
@ -86,7 +86,6 @@ go_test(
|
||||
"domain_data_test.go",
|
||||
"doppelganger_test.go",
|
||||
"duties_test.go",
|
||||
"event_handler_test.go",
|
||||
"genesis_test.go",
|
||||
"get_beacon_block_test.go",
|
||||
"index_test.go",
|
||||
@ -138,7 +137,6 @@ go_test(
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_golang_protobuf//ptypes/empty",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
|
||||
"@org_uber_go_mock//gomock:go_default_library",
|
||||
|
@ -7,16 +7,22 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/validator/client/iface"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
var (
|
||||
_ = iface.NodeClient(&beaconApiNodeClient{})
|
||||
)
|
||||
|
||||
type beaconApiNodeClient struct {
|
||||
fallbackClient iface.NodeClient
|
||||
jsonRestHandler JsonRestHandler
|
||||
genesisProvider GenesisProvider
|
||||
healthTracker *beacon.NodeHealthTracker
|
||||
}
|
||||
|
||||
func (c *beaconApiNodeClient) GetSyncStatus(ctx context.Context, _ *empty.Empty) (*ethpb.SyncStatus, error) {
|
||||
@ -101,10 +107,16 @@ func (c *beaconApiNodeClient) IsHealthy(ctx context.Context) bool {
|
||||
return c.jsonRestHandler.Get(ctx, "/eth/v1/node/health", nil) == nil
|
||||
}
|
||||
|
||||
func (c *beaconApiNodeClient) HealthTracker() *beacon.NodeHealthTracker {
|
||||
return c.healthTracker
|
||||
}
|
||||
|
||||
func NewNodeClientWithFallback(jsonRestHandler JsonRestHandler, fallbackClient iface.NodeClient) iface.NodeClient {
|
||||
return &beaconApiNodeClient{
|
||||
b := &beaconApiNodeClient{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
fallbackClient: fallbackClient,
|
||||
genesisProvider: beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler},
|
||||
}
|
||||
b.healthTracker = beacon.NewNodeHealthTracker(b)
|
||||
return b
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/validator/client/iface"
|
||||
@ -14,20 +15,14 @@ import (
|
||||
|
||||
type ValidatorClientOpt func(*beaconApiValidatorClient)
|
||||
|
||||
func WithEventHandler(h *EventHandler) ValidatorClientOpt {
|
||||
return func(c *beaconApiValidatorClient) {
|
||||
c.eventHandler = h
|
||||
}
|
||||
}
|
||||
|
||||
type beaconApiValidatorClient struct {
|
||||
genesisProvider GenesisProvider
|
||||
dutiesProvider dutiesProvider
|
||||
stateValidatorsProvider StateValidatorsProvider
|
||||
jsonRestHandler JsonRestHandler
|
||||
eventHandler *EventHandler
|
||||
beaconBlockConverter BeaconBlockConverter
|
||||
prysmBeaconChainCLient iface.PrysmBeaconChainClient
|
||||
isEventStreamRunning bool
|
||||
}
|
||||
|
||||
func NewBeaconApiValidatorClient(jsonRestHandler JsonRestHandler, opts ...ValidatorClientOpt) iface.ValidatorClient {
|
||||
@ -41,6 +36,7 @@ func NewBeaconApiValidatorClient(jsonRestHandler JsonRestHandler, opts ...Valida
|
||||
nodeClient: &beaconApiNodeClient{jsonRestHandler: jsonRestHandler},
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
},
|
||||
isEventStreamRunning: false,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(c)
|
||||
@ -135,10 +131,6 @@ func (c *beaconApiValidatorClient) ProposeExit(ctx context.Context, in *ethpb.Si
|
||||
})
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) StreamSlots(ctx context.Context, in *ethpb.StreamSlotsRequest) (ethpb.BeaconNodeValidator_StreamSlotsClient, error) {
|
||||
return c.streamSlots(ctx, in, time.Second), nil
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) StreamBlocksAltair(ctx context.Context, in *ethpb.StreamBlocksRequest) (ethpb.BeaconNodeValidator_StreamBlocksAltairClient, error) {
|
||||
return c.streamBlocks(ctx, in, time.Second), nil
|
||||
}
|
||||
@ -198,17 +190,22 @@ func (c *beaconApiValidatorClient) WaitForChainStart(ctx context.Context, _ *emp
|
||||
return c.waitForChainStart(ctx)
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) StartEventStream(ctx context.Context) error {
|
||||
if c.eventHandler != nil {
|
||||
if err := c.eventHandler.get(ctx, []string{"head"}); err != nil {
|
||||
return errors.Wrapf(err, "could not invoke event handler")
|
||||
func (c *beaconApiValidatorClient) StartEventStream(ctx context.Context, topics []string, eventsChannel chan<- *event.Event) {
|
||||
eventStream, err := event.NewEventStream(ctx, c.jsonRestHandler.HttpClient(), c.jsonRestHandler.Host(), topics)
|
||||
if err != nil {
|
||||
eventsChannel <- &event.Event{
|
||||
EventType: event.EventError,
|
||||
Data: []byte(errors.Wrap(err, "failed to start event stream").Error()),
|
||||
}
|
||||
return
|
||||
}
|
||||
return nil
|
||||
c.isEventStreamRunning = true
|
||||
eventStream.Subscribe(eventsChannel)
|
||||
c.isEventStreamRunning = false
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) EventStreamIsRunning() bool {
|
||||
return c.eventHandler.running
|
||||
return c.isEventStreamRunning
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) GetAggregatedSelections(ctx context.Context, selections []iface.BeaconCommitteeSelection) ([]iface.BeaconCommitteeSelection, error) {
|
||||
|
@ -1,134 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/api"
|
||||
)
|
||||
|
||||
// Currently set to the first power of 2 bigger than the size of the `head` event
|
||||
// which is 446 bytes
|
||||
const eventByteLimit = 512
|
||||
|
||||
// EventHandler is responsible for subscribing to the Beacon API events endpoint
|
||||
// and dispatching received events to subscribers.
|
||||
type EventHandler struct {
|
||||
httpClient *http.Client
|
||||
host string
|
||||
running bool
|
||||
subs []eventSub
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type eventSub struct {
|
||||
name string
|
||||
ch chan<- event
|
||||
}
|
||||
|
||||
type event struct {
|
||||
eventType string
|
||||
data string
|
||||
}
|
||||
|
||||
// NewEventHandler returns a new handler.
|
||||
func NewEventHandler(httpClient *http.Client, host string) *EventHandler {
|
||||
return &EventHandler{
|
||||
httpClient: httpClient,
|
||||
host: host,
|
||||
running: false,
|
||||
subs: make([]eventSub, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *EventHandler) subscribe(sub eventSub) {
|
||||
h.Lock()
|
||||
h.subs = append(h.subs, sub)
|
||||
h.Unlock()
|
||||
}
|
||||
|
||||
func (h *EventHandler) get(ctx context.Context, topics []string) error {
|
||||
if len(topics) == 0 {
|
||||
return errors.New("no topics provided")
|
||||
}
|
||||
if h.running {
|
||||
log.Warn("Event listener is already running, ignoring function call")
|
||||
}
|
||||
|
||||
go func() {
|
||||
h.running = true
|
||||
defer func() { h.running = false }()
|
||||
|
||||
allTopics := strings.Join(topics, ",")
|
||||
log.Info("Starting listening to Beacon API events on topics: " + allTopics)
|
||||
url := h.host + "/eth/v1/events?topics=" + allTopics
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create HTTP request")
|
||||
return
|
||||
}
|
||||
req.Header.Set("Accept", api.EventStreamMediaType)
|
||||
req.Header.Set("Connection", api.KeepAlive)
|
||||
resp, err := h.httpClient.Do(req)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to perform HTTP request")
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if closeErr := resp.Body.Close(); closeErr != nil {
|
||||
log.WithError(closeErr).Error("Failed to close events response body")
|
||||
}
|
||||
}()
|
||||
|
||||
// We signal an EOF error in a special way. When we get this error while reading the response body,
|
||||
// there might still be an event received in the body that we should handle.
|
||||
eof := false
|
||||
for {
|
||||
if ctx.Err() != nil {
|
||||
log.WithError(ctx.Err()).Error("Stopping listening to Beacon API events")
|
||||
return
|
||||
}
|
||||
|
||||
rawData := make([]byte, eventByteLimit)
|
||||
_, err = resp.Body.Read(rawData)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "EOF") {
|
||||
log.Error("Received EOF while reading events response body. Stopping listening to Beacon API events")
|
||||
eof = true
|
||||
} else {
|
||||
log.WithError(err).Error("Stopping listening to Beacon API events")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
e := strings.Split(string(rawData), "\n")
|
||||
// We expect that the event format will contain event type and data separated with a newline
|
||||
if len(e) < 2 {
|
||||
// We reached EOF and there is no event to send
|
||||
if eof {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
for _, sub := range h.subs {
|
||||
select {
|
||||
case sub.ch <- event{eventType: e[0], data: e[1]}:
|
||||
// Event sent successfully.
|
||||
default:
|
||||
log.Warn("Subscriber '" + sub.name + "' not ready to receive events")
|
||||
}
|
||||
}
|
||||
// We reached EOF and sent the last event
|
||||
if eof {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
logtest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
func TestEventHandler(t *testing.T) {
|
||||
logHook := logtest.NewGlobal()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/eth/v1/events", func(w http.ResponseWriter, r *http.Request) {
|
||||
flusher, ok := w.(http.Flusher)
|
||||
require.Equal(t, true, ok)
|
||||
_, err := fmt.Fprint(w, "head\ndata\n\n")
|
||||
require.NoError(t, err)
|
||||
flusher.Flush()
|
||||
})
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
handler := NewEventHandler(http.DefaultClient, server.URL)
|
||||
ch1 := make(chan event, 1)
|
||||
sub1 := eventSub{ch: ch1}
|
||||
ch2 := make(chan event, 1)
|
||||
sub2 := eventSub{ch: ch2}
|
||||
ch3 := make(chan event, 1)
|
||||
sub3 := eventSub{name: "sub3", ch: ch3}
|
||||
// fill up the channel so that it can't receive more events
|
||||
ch3 <- event{}
|
||||
handler.subscribe(sub1)
|
||||
handler.subscribe(sub2)
|
||||
handler.subscribe(sub3)
|
||||
|
||||
require.NoError(t, handler.get(context.Background(), []string{"head"}))
|
||||
// make sure the goroutine inside handler.get is invoked
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
e := <-ch1
|
||||
assert.Equal(t, "head", e.eventType)
|
||||
assert.Equal(t, "data", e.data)
|
||||
e = <-ch2
|
||||
assert.Equal(t, "head", e.eventType)
|
||||
assert.Equal(t, "data", e.data)
|
||||
|
||||
assert.LogsContain(t, logHook, "Subscriber 'sub3' not ready to receive events")
|
||||
}
|
@ -16,23 +16,43 @@ import (
|
||||
type JsonRestHandler interface {
|
||||
Get(ctx context.Context, endpoint string, resp interface{}) error
|
||||
Post(ctx context.Context, endpoint string, headers map[string]string, data *bytes.Buffer, resp interface{}) error
|
||||
HttpClient() *http.Client
|
||||
Host() string
|
||||
}
|
||||
|
||||
type BeaconApiJsonRestHandler struct {
|
||||
HttpClient http.Client
|
||||
Host string
|
||||
client http.Client
|
||||
host string
|
||||
}
|
||||
|
||||
// NewBeaconApiJsonRestHandler returns a JsonRestHandler
|
||||
func NewBeaconApiJsonRestHandler(client http.Client, host string) JsonRestHandler {
|
||||
return &BeaconApiJsonRestHandler{
|
||||
client: client,
|
||||
host: host,
|
||||
}
|
||||
}
|
||||
|
||||
// GetHttpClient returns the underlying HTTP client of the handler
|
||||
func (c BeaconApiJsonRestHandler) HttpClient() *http.Client {
|
||||
return &c.client
|
||||
}
|
||||
|
||||
// GetHost returns the underlying HTTP host
|
||||
func (c BeaconApiJsonRestHandler) Host() string {
|
||||
return c.host
|
||||
}
|
||||
|
||||
// Get sends a GET request and decodes the response body as a JSON object into the passed in object.
|
||||
// If an HTTP error is returned, the body is decoded as a DefaultJsonError JSON object and returned as the first return value.
|
||||
func (c BeaconApiJsonRestHandler) Get(ctx context.Context, endpoint string, resp interface{}) error {
|
||||
url := c.Host + endpoint
|
||||
url := c.host + endpoint
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to create request for endpoint %s", url)
|
||||
}
|
||||
|
||||
httpResp, err := c.HttpClient.Do(req)
|
||||
httpResp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to perform request for endpoint %s", url)
|
||||
}
|
||||
@ -58,7 +78,7 @@ func (c BeaconApiJsonRestHandler) Post(
|
||||
return errors.New("data is nil")
|
||||
}
|
||||
|
||||
url := c.Host + apiEndpoint
|
||||
url := c.host + apiEndpoint
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, data)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to create request for endpoint %s", url)
|
||||
@ -69,7 +89,7 @@ func (c BeaconApiJsonRestHandler) Post(
|
||||
}
|
||||
req.Header.Set("Content-Type", api.JsonMediaType)
|
||||
|
||||
httpResp, err := c.HttpClient.Do(req)
|
||||
httpResp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to perform request for endpoint %s", url)
|
||||
}
|
||||
|
@ -41,8 +41,8 @@ func TestGet(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
jsonRestHandler := BeaconApiJsonRestHandler{
|
||||
HttpClient: http.Client{Timeout: time.Second * 5},
|
||||
Host: server.URL,
|
||||
client: http.Client{Timeout: time.Second * 5},
|
||||
host: server.URL,
|
||||
}
|
||||
resp := &structs.GetGenesisResponse{}
|
||||
require.NoError(t, jsonRestHandler.Get(ctx, endpoint+"?arg1=abc&arg2=def", resp))
|
||||
@ -87,8 +87,8 @@ func TestPost(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
jsonRestHandler := BeaconApiJsonRestHandler{
|
||||
HttpClient: http.Client{Timeout: time.Second * 5},
|
||||
Host: server.URL,
|
||||
client: http.Client{Timeout: time.Second * 5},
|
||||
host: server.URL,
|
||||
}
|
||||
resp := &structs.GetGenesisResponse{}
|
||||
require.NoError(t, jsonRestHandler.Post(ctx, endpoint, headers, bytes.NewBuffer(dataBytes), resp))
|
||||
|
@ -12,6 +12,7 @@ package mock
|
||||
import (
|
||||
bytes "bytes"
|
||||
context "context"
|
||||
"net/http"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
@ -35,6 +36,14 @@ func NewMockJsonRestHandler(ctrl *gomock.Controller) *MockJsonRestHandler {
|
||||
return mock
|
||||
}
|
||||
|
||||
func (mr *MockJsonRestHandler) HttpClient() *http.Client {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mr *MockJsonRestHandler) Host() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockJsonRestHandler) EXPECT() *MockJsonRestHandlerMockRecorder {
|
||||
return m.recorder
|
||||
@ -67,3 +76,4 @@ func (mr *MockJsonRestHandlerMockRecorder) Post(ctx, endpoint, headers, data, re
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Post", reflect.TypeOf((*MockJsonRestHandler)(nil).Post), ctx, endpoint, headers, data, resp)
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,11 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"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/beacon-chain/rpc/eth/events"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"google.golang.org/grpc"
|
||||
@ -23,15 +21,6 @@ type abstractSignedBlockResponseJson struct {
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
type streamSlotsClient struct {
|
||||
grpc.ClientStream
|
||||
ctx context.Context
|
||||
beaconApiClient beaconApiValidatorClient
|
||||
streamSlotsRequest *ethpb.StreamSlotsRequest
|
||||
pingDelay time.Duration
|
||||
ch chan event
|
||||
}
|
||||
|
||||
type streamBlocksAltairClient struct {
|
||||
grpc.ClientStream
|
||||
ctx context.Context
|
||||
@ -47,18 +36,6 @@ type headSignedBeaconBlockResult struct {
|
||||
slot primitives.Slot
|
||||
}
|
||||
|
||||
func (c beaconApiValidatorClient) streamSlots(ctx context.Context, in *ethpb.StreamSlotsRequest, pingDelay time.Duration) ethpb.BeaconNodeValidator_StreamSlotsClient {
|
||||
ch := make(chan event, 1)
|
||||
c.eventHandler.subscribe(eventSub{name: "stream slots", ch: ch})
|
||||
return &streamSlotsClient{
|
||||
ctx: ctx,
|
||||
beaconApiClient: c,
|
||||
streamSlotsRequest: in,
|
||||
pingDelay: pingDelay,
|
||||
ch: ch,
|
||||
}
|
||||
}
|
||||
|
||||
func (c beaconApiValidatorClient) streamBlocks(ctx context.Context, in *ethpb.StreamBlocksRequest, pingDelay time.Duration) ethpb.BeaconNodeValidator_StreamBlocksAltairClient {
|
||||
return &streamBlocksAltairClient{
|
||||
ctx: ctx,
|
||||
@ -68,30 +45,6 @@ func (c beaconApiValidatorClient) streamBlocks(ctx context.Context, in *ethpb.St
|
||||
}
|
||||
}
|
||||
|
||||
func (c *streamSlotsClient) Recv() (*ethpb.StreamSlotsResponse, error) {
|
||||
for {
|
||||
select {
|
||||
case rawEvent := <-c.ch:
|
||||
if rawEvent.eventType != events.HeadTopic {
|
||||
continue
|
||||
}
|
||||
e := &structs.HeadEvent{}
|
||||
if err := json.Unmarshal([]byte(rawEvent.data), e); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal head event into JSON")
|
||||
}
|
||||
uintSlot, err := strconv.ParseUint(e.Slot, 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse slot")
|
||||
}
|
||||
return ðpb.StreamSlotsResponse{
|
||||
Slot: primitives.Slot(uintSlot),
|
||||
}, nil
|
||||
case <-c.ctx.Done():
|
||||
return nil, errors.New("context canceled")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *streamBlocksAltairClient) Recv() (*ethpb.StreamBlocksResponse, error) {
|
||||
result, err := c.beaconApiClient.getHeadSignedBeaconBlock(c.ctx)
|
||||
if err != nil {
|
||||
|
@ -11,6 +11,10 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/validator/client/grpc-api",
|
||||
visibility = ["//validator:__subpackages__"],
|
||||
deps = [
|
||||
"//api/client:go_default_library",
|
||||
"//api/client/beacon:go_default_library",
|
||||
"//api/client/event:go_default_library",
|
||||
"//api/server/structs:go_default_library",
|
||||
"//beacon-chain/rpc/eth/helpers:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
@ -20,6 +24,8 @@ go_library(
|
||||
"//validator/client/iface:go_default_library",
|
||||
"@com_github_golang_protobuf//ptypes/empty",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
],
|
||||
)
|
||||
@ -33,6 +39,8 @@ go_test(
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//api/client/event:go_default_library",
|
||||
"//api/server/structs:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/validator:go_default_library",
|
||||
@ -43,6 +51,7 @@ go_test(
|
||||
"//testing/util:go_default_library",
|
||||
"//testing/validator-mock:go_default_library",
|
||||
"//validator/client/iface:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
|
||||
"@org_uber_go_mock//gomock:go_default_library",
|
||||
],
|
||||
|
@ -4,13 +4,20 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/validator/client/iface"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var (
|
||||
_ = iface.NodeClient(&grpcNodeClient{})
|
||||
)
|
||||
|
||||
type grpcNodeClient struct {
|
||||
nodeClient ethpb.NodeClient
|
||||
nodeClient ethpb.NodeClient
|
||||
healthTracker *beacon.NodeHealthTracker
|
||||
}
|
||||
|
||||
func (c *grpcNodeClient) GetSyncStatus(ctx context.Context, in *empty.Empty) (*ethpb.SyncStatus, error) {
|
||||
@ -29,10 +36,21 @@ func (c *grpcNodeClient) ListPeers(ctx context.Context, in *empty.Empty) (*ethpb
|
||||
return c.nodeClient.ListPeers(ctx, in)
|
||||
}
|
||||
|
||||
func (c *grpcNodeClient) IsHealthy(context.Context) bool {
|
||||
panic("function not supported for gRPC client")
|
||||
func (c *grpcNodeClient) IsHealthy(ctx context.Context) bool {
|
||||
_, err := c.nodeClient.GetHealth(ctx, ðpb.HealthRequest{})
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("failed to get health of node")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *grpcNodeClient) HealthTracker() *beacon.NodeHealthTracker {
|
||||
return c.healthTracker
|
||||
}
|
||||
|
||||
func NewNodeClient(cc grpc.ClientConnInterface) iface.NodeClient {
|
||||
return &grpcNodeClient{ethpb.NewNodeClient(cc)}
|
||||
g := &grpcNodeClient{nodeClient: ethpb.NewNodeClient(cc)}
|
||||
g.healthTracker = beacon.NewNodeHealthTracker(g)
|
||||
return g
|
||||
}
|
||||
|
@ -2,16 +2,24 @@ package grpc_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client"
|
||||
eventClient "github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/validator/client/iface"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type grpcValidatorClient struct {
|
||||
beaconNodeValidatorClient ethpb.BeaconNodeValidatorClient
|
||||
isEventStreamRunning bool
|
||||
}
|
||||
|
||||
func (c *grpcValidatorClient) GetDuties(ctx context.Context, in *ethpb.DutiesRequest) (*ethpb.DutiesResponse, error) {
|
||||
@ -70,10 +78,6 @@ func (c *grpcValidatorClient) ProposeExit(ctx context.Context, in *ethpb.SignedV
|
||||
return c.beaconNodeValidatorClient.ProposeExit(ctx, in)
|
||||
}
|
||||
|
||||
func (c *grpcValidatorClient) StreamSlots(ctx context.Context, in *ethpb.StreamSlotsRequest) (ethpb.BeaconNodeValidator_StreamSlotsClient, error) {
|
||||
return c.beaconNodeValidatorClient.StreamSlots(ctx, in)
|
||||
}
|
||||
|
||||
func (c *grpcValidatorClient) StreamBlocksAltair(ctx context.Context, in *ethpb.StreamBlocksRequest) (ethpb.BeaconNodeValidator_StreamBlocksAltairClient, error) {
|
||||
return c.beaconNodeValidatorClient.StreamBlocksAltair(ctx, in)
|
||||
}
|
||||
@ -119,7 +123,7 @@ func (c *grpcValidatorClient) WaitForChainStart(ctx context.Context, in *empty.E
|
||||
stream, err := c.beaconNodeValidatorClient.WaitForChainStart(ctx, in)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(
|
||||
iface.ErrConnectionIssue,
|
||||
client.ErrConnectionIssue,
|
||||
errors.Wrap(err, "could not setup beacon chain ChainStart streaming client").Error(),
|
||||
)
|
||||
}
|
||||
@ -146,13 +150,97 @@ func (grpcValidatorClient) GetAggregatedSyncSelections(context.Context, []iface.
|
||||
}
|
||||
|
||||
func NewGrpcValidatorClient(cc grpc.ClientConnInterface) iface.ValidatorClient {
|
||||
return &grpcValidatorClient{ethpb.NewBeaconNodeValidatorClient(cc)}
|
||||
return &grpcValidatorClient{ethpb.NewBeaconNodeValidatorClient(cc), false}
|
||||
}
|
||||
|
||||
func (c *grpcValidatorClient) StartEventStream(context.Context) error {
|
||||
panic("function not supported for gRPC client")
|
||||
func (c *grpcValidatorClient) StartEventStream(ctx context.Context, topics []string, eventsChannel chan<- *eventClient.Event) {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.gRPCClient.StartEventStream")
|
||||
defer span.End()
|
||||
if len(topics) == 0 {
|
||||
eventsChannel <- &eventClient.Event{
|
||||
EventType: eventClient.EventError,
|
||||
Data: []byte(errors.New("no topics were added").Error()),
|
||||
}
|
||||
return
|
||||
}
|
||||
// TODO(13563): ONLY WORKS WITH HEAD TOPIC RIGHT NOW/ONLY PROVIDES THE SLOT
|
||||
containsHead := false
|
||||
for i := range topics {
|
||||
if topics[i] == eventClient.EventHead {
|
||||
containsHead = true
|
||||
}
|
||||
}
|
||||
if !containsHead {
|
||||
eventsChannel <- &eventClient.Event{
|
||||
EventType: eventClient.EventConnectionError,
|
||||
Data: []byte(errors.Wrap(client.ErrConnectionIssue, "gRPC only supports the head topic, and head topic was not passed").Error()),
|
||||
}
|
||||
}
|
||||
if containsHead && len(topics) > 1 {
|
||||
log.Warn("gRPC only supports the head topic, other topics will be ignored")
|
||||
}
|
||||
|
||||
stream, err := c.beaconNodeValidatorClient.StreamSlots(ctx, ðpb.StreamSlotsRequest{VerifiedOnly: true})
|
||||
if err != nil {
|
||||
eventsChannel <- &eventClient.Event{
|
||||
EventType: eventClient.EventConnectionError,
|
||||
Data: []byte(errors.Wrap(client.ErrConnectionIssue, err.Error()).Error()),
|
||||
}
|
||||
return
|
||||
}
|
||||
c.isEventStreamRunning = true
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Info("Context canceled, stopping event stream")
|
||||
close(eventsChannel)
|
||||
c.isEventStreamRunning = false
|
||||
return
|
||||
default:
|
||||
if ctx.Err() != nil {
|
||||
c.isEventStreamRunning = false
|
||||
if errors.Is(ctx.Err(), context.Canceled) {
|
||||
eventsChannel <- &eventClient.Event{
|
||||
EventType: eventClient.EventConnectionError,
|
||||
Data: []byte(errors.Wrap(client.ErrConnectionIssue, ctx.Err().Error()).Error()),
|
||||
}
|
||||
return
|
||||
}
|
||||
eventsChannel <- &eventClient.Event{
|
||||
EventType: eventClient.EventError,
|
||||
Data: []byte(ctx.Err().Error()),
|
||||
}
|
||||
return
|
||||
}
|
||||
res, err := stream.Recv()
|
||||
if err != nil {
|
||||
c.isEventStreamRunning = false
|
||||
eventsChannel <- &eventClient.Event{
|
||||
EventType: eventClient.EventConnectionError,
|
||||
Data: []byte(errors.Wrap(client.ErrConnectionIssue, err.Error()).Error()),
|
||||
}
|
||||
return
|
||||
}
|
||||
if res == nil {
|
||||
continue
|
||||
}
|
||||
b, err := json.Marshal(structs.HeadEvent{
|
||||
Slot: strconv.FormatUint(uint64(res.Slot), 10),
|
||||
})
|
||||
if err != nil {
|
||||
eventsChannel <- &eventClient.Event{
|
||||
EventType: eventClient.EventError,
|
||||
Data: []byte(errors.Wrap(err, "failed to marshal Head Event").Error()),
|
||||
}
|
||||
}
|
||||
eventsChannel <- &eventClient.Event{
|
||||
EventType: eventClient.EventHead,
|
||||
Data: b,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *grpcValidatorClient) EventStreamIsRunning() bool {
|
||||
panic("function not supported for gRPC client")
|
||||
return c.isEventStreamRunning
|
||||
}
|
||||
|
@ -2,11 +2,18 @@ package grpc_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
eventClient "github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
||||
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
mock2 "github.com/prysmaticlabs/prysm/v5/testing/mock"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
"go.uber.org/mock/gomock"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
@ -21,8 +28,105 @@ func TestWaitForChainStart_StreamSetupFails(t *testing.T) {
|
||||
gomock.Any(),
|
||||
).Return(nil, errors.New("failed stream"))
|
||||
|
||||
validatorClient := &grpcValidatorClient{beaconNodeValidatorClient}
|
||||
validatorClient := &grpcValidatorClient{beaconNodeValidatorClient, true}
|
||||
_, err := validatorClient.WaitForChainStart(context.Background(), &emptypb.Empty{})
|
||||
want := "could not setup beacon chain ChainStart streaming client"
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
func TestStartEventStream(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
beaconNodeValidatorClient := mock2.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
grpcClient := &grpcValidatorClient{beaconNodeValidatorClient, true}
|
||||
tests := []struct {
|
||||
name string
|
||||
topics []string
|
||||
prepare func()
|
||||
verify func(t *testing.T, event *eventClient.Event)
|
||||
}{
|
||||
{
|
||||
name: "Happy path Head topic",
|
||||
topics: []string{"head"},
|
||||
prepare: func() {
|
||||
stream := mock2.NewMockBeaconNodeValidator_StreamSlotsClient(ctrl)
|
||||
beaconNodeValidatorClient.EXPECT().StreamSlots(gomock.Any(),
|
||||
ð.StreamSlotsRequest{VerifiedOnly: true}).Return(stream, nil)
|
||||
stream.EXPECT().Context().Return(ctx).AnyTimes()
|
||||
stream.EXPECT().Recv().Return(
|
||||
ð.StreamSlotsResponse{Slot: 123},
|
||||
nil,
|
||||
).AnyTimes()
|
||||
},
|
||||
verify: func(t *testing.T, event *eventClient.Event) {
|
||||
require.Equal(t, event.EventType, eventClient.EventHead)
|
||||
head := structs.HeadEvent{}
|
||||
require.NoError(t, json.Unmarshal(event.Data, &head))
|
||||
require.Equal(t, head.Slot, "123")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no head produces error",
|
||||
topics: []string{"unsupportedTopic"},
|
||||
prepare: func() {
|
||||
stream := mock2.NewMockBeaconNodeValidator_StreamSlotsClient(ctrl)
|
||||
beaconNodeValidatorClient.EXPECT().StreamSlots(gomock.Any(),
|
||||
ð.StreamSlotsRequest{VerifiedOnly: true}).Return(stream, nil)
|
||||
stream.EXPECT().Context().Return(ctx).AnyTimes()
|
||||
stream.EXPECT().Recv().Return(
|
||||
ð.StreamSlotsResponse{Slot: 123},
|
||||
nil,
|
||||
).AnyTimes()
|
||||
},
|
||||
verify: func(t *testing.T, event *eventClient.Event) {
|
||||
require.Equal(t, event.EventType, eventClient.EventConnectionError)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Unsupported topics warning",
|
||||
topics: []string{"head", "unsupportedTopic"},
|
||||
prepare: func() {
|
||||
stream := mock2.NewMockBeaconNodeValidator_StreamSlotsClient(ctrl)
|
||||
beaconNodeValidatorClient.EXPECT().StreamSlots(gomock.Any(),
|
||||
ð.StreamSlotsRequest{VerifiedOnly: true}).Return(stream, nil)
|
||||
stream.EXPECT().Context().Return(ctx).AnyTimes()
|
||||
stream.EXPECT().Recv().Return(
|
||||
ð.StreamSlotsResponse{Slot: 123},
|
||||
nil,
|
||||
).AnyTimes()
|
||||
},
|
||||
verify: func(t *testing.T, event *eventClient.Event) {
|
||||
require.Equal(t, event.EventType, eventClient.EventHead)
|
||||
head := structs.HeadEvent{}
|
||||
require.NoError(t, json.Unmarshal(event.Data, &head))
|
||||
require.Equal(t, head.Slot, "123")
|
||||
assert.LogsContain(t, hook, "gRPC only supports the head topic")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "No topics error",
|
||||
topics: []string{},
|
||||
prepare: func() {},
|
||||
verify: func(t *testing.T, event *eventClient.Event) {
|
||||
require.Equal(t, event.EventType, eventClient.EventError)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
eventsChannel := make(chan *eventClient.Event, 1) // Buffer to prevent blocking
|
||||
tc.prepare() // Setup mock expectations
|
||||
|
||||
go grpcClient.StartEventStream(ctx, tc.topics, eventsChannel)
|
||||
|
||||
event := <-eventsChannel
|
||||
// Depending on what you're testing, you may need a timeout or a specific number of events to read
|
||||
time.AfterFunc(1*time.Second, cancel) // Prevents hanging forever
|
||||
tc.verify(t, event)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/validator/client/iface",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api/client/beacon:go_default_library",
|
||||
"//api/client/event:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/proposer:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
@ -12,5 +13,5 @@ type NodeClient interface {
|
||||
GetGenesis(ctx context.Context, in *empty.Empty) (*ethpb.Genesis, error)
|
||||
GetVersion(ctx context.Context, in *empty.Empty) (*ethpb.Version, error)
|
||||
ListPeers(ctx context.Context, in *empty.Empty) (*ethpb.Peers, error)
|
||||
IsHealthy(ctx context.Context) bool
|
||||
HealthTracker() *beacon.NodeHealthTracker
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ package iface
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/proposer"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
@ -14,9 +15,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/validator/keymanager"
|
||||
)
|
||||
|
||||
// ErrConnectionIssue represents a connection problem.
|
||||
var ErrConnectionIssue = errors.New("could not connect")
|
||||
|
||||
// ValidatorRole defines the validator role.
|
||||
type ValidatorRole int8
|
||||
|
||||
@ -57,16 +55,16 @@ type Validator interface {
|
||||
UpdateDomainDataCaches(ctx context.Context, slot primitives.Slot)
|
||||
WaitForKeymanagerInitialization(ctx context.Context) error
|
||||
Keymanager() (keymanager.IKeymanager, error)
|
||||
ReceiveSlots(ctx context.Context, connectionErrorChannel chan<- error)
|
||||
HandleKeyReload(ctx context.Context, currentKeys [][fieldparams.BLSPubkeyLength]byte) (bool, error)
|
||||
CheckDoppelGanger(ctx context.Context) error
|
||||
PushProposerSettings(ctx context.Context, km keymanager.IKeymanager, slot primitives.Slot, deadline time.Time) error
|
||||
SignValidatorRegistrationRequest(ctx context.Context, signer SigningFunc, newValidatorRegistration *ethpb.ValidatorRegistrationV1) (*ethpb.SignedValidatorRegistrationV1, error)
|
||||
StartEventStream(ctx context.Context, topics []string, eventsChan chan<- *event.Event)
|
||||
ProcessEvent(event *event.Event)
|
||||
ProposerSettings() *proposer.Settings
|
||||
SetProposerSettings(context.Context, *proposer.Settings) error
|
||||
StartEventStream(ctx context.Context) error
|
||||
EventStreamIsRunning() bool
|
||||
NodeIsHealthy(ctx context.Context) bool
|
||||
HealthTracker() *beacon.NodeHealthTracker
|
||||
}
|
||||
|
||||
// SigningFunc interface defines a type for the a function that signs a message
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
)
|
||||
@ -144,9 +145,8 @@ type ValidatorClient interface {
|
||||
GetSyncSubcommitteeIndex(ctx context.Context, in *ethpb.SyncSubcommitteeIndexRequest) (*ethpb.SyncSubcommitteeIndexResponse, error)
|
||||
GetSyncCommitteeContribution(ctx context.Context, in *ethpb.SyncCommitteeContributionRequest) (*ethpb.SyncCommitteeContribution, error)
|
||||
SubmitSignedContributionAndProof(ctx context.Context, in *ethpb.SignedContributionAndProof) (*empty.Empty, error)
|
||||
StreamSlots(ctx context.Context, in *ethpb.StreamSlotsRequest) (ethpb.BeaconNodeValidator_StreamSlotsClient, error)
|
||||
SubmitValidatorRegistrations(ctx context.Context, in *ethpb.SignedValidatorRegistrationsV1) (*empty.Empty, error)
|
||||
StartEventStream(ctx context.Context) error
|
||||
StartEventStream(ctx context.Context, topics []string, eventsChannel chan<- *event.Event)
|
||||
EventStreamIsRunning() bool
|
||||
GetAggregatedSelections(ctx context.Context, selections []BeaconCommitteeSelection) ([]BeaconCommitteeSelection, error)
|
||||
GetAggregatedSyncSelections(ctx context.Context, selections []SyncCommitteeSelection) ([]SyncCommitteeSelection, error)
|
||||
|
@ -7,7 +7,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
@ -40,12 +41,12 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
if err != nil {
|
||||
return // Exit if context is canceled.
|
||||
}
|
||||
|
||||
connectionErrorChannel := make(chan error, 1)
|
||||
go v.ReceiveSlots(ctx, connectionErrorChannel)
|
||||
if err := v.UpdateDuties(ctx, headSlot); err != nil {
|
||||
handleAssignmentError(err, headSlot)
|
||||
}
|
||||
eventsChan := make(chan *event.Event, 1)
|
||||
healthTracker := v.HealthTracker()
|
||||
runHealthCheckRoutine(ctx, v, eventsChan)
|
||||
|
||||
accountsChangedChan := make(chan [][fieldparams.BLSPubkeyLength]byte, 1)
|
||||
km, err := v.Keymanager()
|
||||
@ -76,15 +77,10 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
sub.Unsubscribe()
|
||||
close(accountsChangedChan)
|
||||
return // Exit if context is canceled.
|
||||
case slotsError := <-connectionErrorChannel:
|
||||
if slotsError != nil {
|
||||
log.WithError(slotsError).Warn("slots stream interrupted")
|
||||
go v.ReceiveSlots(ctx, connectionErrorChannel)
|
||||
case slot := <-v.NextSlot():
|
||||
if !healthTracker.IsHealthy() {
|
||||
continue
|
||||
}
|
||||
case currentKeys := <-accountsChangedChan:
|
||||
onAccountsChanged(ctx, v, currentKeys, accountsChangedChan)
|
||||
case slot := <-v.NextSlot():
|
||||
span.AddAttributes(trace.Int64Attribute("slot", int64(slot))) // lint:ignore uintcast -- This conversion is OK for tracing.
|
||||
|
||||
deadline := v.SlotDeadline(slot)
|
||||
@ -128,6 +124,22 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
continue
|
||||
}
|
||||
performRoles(slotCtx, allRoles, v, slot, &wg, span)
|
||||
case isHealthyAgain := <-healthTracker.HealthUpdates():
|
||||
if isHealthyAgain {
|
||||
headSlot, err = initializeValidatorAndGetHeadSlot(ctx, v)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to re initialize validator and get head slot")
|
||||
continue
|
||||
}
|
||||
if err := v.UpdateDuties(ctx, headSlot); err != nil {
|
||||
handleAssignmentError(err, headSlot)
|
||||
continue
|
||||
}
|
||||
}
|
||||
case e := <-eventsChan:
|
||||
v.ProcessEvent(e)
|
||||
case currentKeys := <-accountsChangedChan: // should be less of a priority than next slot
|
||||
onAccountsChanged(ctx, v, currentKeys, accountsChangedChan)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -196,13 +208,6 @@ func initializeValidatorAndGetHeadSlot(ctx context.Context, v iface.Validator) (
|
||||
log.WithError(err).Fatal("Could not wait for validator activation")
|
||||
}
|
||||
|
||||
if features.Get().EnableBeaconRESTApi {
|
||||
if err = v.StartEventStream(ctx); err != nil {
|
||||
log.WithError(err).Fatal("Could not start API event stream")
|
||||
}
|
||||
runHealthCheckRoutine(ctx, v)
|
||||
}
|
||||
|
||||
headSlot, err = v.CanonicalHeadSlot(ctx)
|
||||
if isConnectionError(err) {
|
||||
log.WithError(err).Warn("Could not get current canonical head slot")
|
||||
@ -273,7 +278,7 @@ func performRoles(slotCtx context.Context, allRoles map[[48]byte][]iface.Validat
|
||||
}
|
||||
|
||||
func isConnectionError(err error) bool {
|
||||
return err != nil && errors.Is(err, iface.ErrConnectionIssue)
|
||||
return err != nil && errors.Is(err, client.ErrConnectionIssue)
|
||||
}
|
||||
|
||||
func handleAssignmentError(err error, slot primitives.Slot) {
|
||||
@ -288,24 +293,23 @@ func handleAssignmentError(err error, slot primitives.Slot) {
|
||||
}
|
||||
}
|
||||
|
||||
func runHealthCheckRoutine(ctx context.Context, v iface.Validator) {
|
||||
func runHealthCheckRoutine(ctx context.Context, v iface.Validator, eventsChan chan<- *event.Event) {
|
||||
log.Info("Starting health check routine for beacon node apis")
|
||||
healthCheckTicker := time.NewTicker(time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second)
|
||||
tracker := v.HealthTracker()
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-healthCheckTicker.C:
|
||||
if v.NodeIsHealthy(ctx) && !v.EventStreamIsRunning() {
|
||||
if err := v.StartEventStream(ctx); err != nil {
|
||||
log.WithError(err).Error("Could not start API event stream")
|
||||
}
|
||||
}
|
||||
case <-ctx.Done():
|
||||
if ctx.Err() != nil {
|
||||
log.WithError(ctx.Err()).Error("Context cancelled")
|
||||
}
|
||||
log.Error("Context cancelled")
|
||||
// trigger the healthcheck immediately the first time
|
||||
for ; true; <-healthCheckTicker.C {
|
||||
if ctx.Err() != nil {
|
||||
log.WithError(ctx.Err()).Error("Context cancelled")
|
||||
return
|
||||
}
|
||||
isHealthy := tracker.CheckHealth(ctx)
|
||||
// in case of node returning healthy but event stream died
|
||||
if isHealthy && !v.EventStreamIsRunning() {
|
||||
log.Info("Event stream reconnecting...")
|
||||
go v.StartEventStream(ctx, event.DefaultEventTopics, eventsChan)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
healthTesting "github.com/prysmaticlabs/prysm/v5/api/client/beacon/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/async/event"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
@ -18,6 +20,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/validator/client/iface"
|
||||
"github.com/prysmaticlabs/prysm/v5/validator/client/testutil"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func cancelledContext() context.Context {
|
||||
@ -27,21 +30,41 @@ func cancelledContext() context.Context {
|
||||
}
|
||||
|
||||
func TestCancelledContext_CleansUpValidator(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
v := &testutil.FakeValidator{
|
||||
Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}},
|
||||
Tracker: tracker,
|
||||
}
|
||||
run(cancelledContext(), v)
|
||||
assert.Equal(t, true, v.DoneCalled, "Expected Done() to be called")
|
||||
}
|
||||
|
||||
func TestCancelledContext_WaitsForChainStart(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
v := &testutil.FakeValidator{
|
||||
Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}},
|
||||
Tracker: tracker,
|
||||
}
|
||||
run(cancelledContext(), v)
|
||||
assert.Equal(t, 1, v.WaitForChainStartCalled, "Expected WaitForChainStart() to be called")
|
||||
}
|
||||
|
||||
func TestRetry_On_ConnectionError(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
retry := 10
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true)
|
||||
v := &testutil.FakeValidator{
|
||||
Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}},
|
||||
Tracker: tracker,
|
||||
RetryTillSuccess: retry,
|
||||
}
|
||||
backOffPeriod = 10 * time.Millisecond
|
||||
@ -55,18 +78,31 @@ func TestRetry_On_ConnectionError(t *testing.T) {
|
||||
assert.Equal(t, retry*3, v.WaitForChainStartCalled, "Expected WaitForChainStart() to be called")
|
||||
assert.Equal(t, retry*2, v.WaitForSyncCalled, "Expected WaitForSync() to be called")
|
||||
assert.Equal(t, retry, v.WaitForActivationCalled, "Expected WaitForActivation() to be called")
|
||||
assert.Equal(t, retry, v.CanonicalHeadSlotCalled, "Expected WaitForActivation() to be called")
|
||||
assert.Equal(t, retry, v.ReceiveBlocksCalled, "Expected WaitForActivation() to be called")
|
||||
assert.Equal(t, retry, v.CanonicalHeadSlotCalled, "Expected CanonicalHeadSlotCalled() to be called")
|
||||
}
|
||||
|
||||
func TestCancelledContext_WaitsForActivation(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
v := &testutil.FakeValidator{
|
||||
Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}},
|
||||
Tracker: tracker,
|
||||
}
|
||||
run(cancelledContext(), v)
|
||||
assert.Equal(t, 1, v.WaitForActivationCalled, "Expected WaitForActivation() to be called")
|
||||
}
|
||||
|
||||
func TestUpdateDuties_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
// avoid race condition between the cancellation of the context in the go stream from slot and the setting of IsHealthy
|
||||
_ = tracker.CheckHealth(context.Background())
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}, Tracker: tracker}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
@ -86,7 +122,14 @@ func TestUpdateDuties_NextSlot(t *testing.T) {
|
||||
|
||||
func TestUpdateDuties_HandlesError(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
// avoid race condition between the cancellation of the context in the go stream from slot and the setting of IsHealthy
|
||||
_ = tracker.CheckHealth(context.Background())
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}, Tracker: tracker}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
@ -105,7 +148,14 @@ func TestUpdateDuties_HandlesError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRoleAt_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
// avoid race condition between the cancellation of the context in the go stream from slot and the setting of IsHealthy
|
||||
_ = tracker.CheckHealth(context.Background())
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}, Tracker: tracker}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
@ -124,7 +174,14 @@ func TestRoleAt_NextSlot(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAttests_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
// avoid race condition between the cancellation of the context in the go stream from slot and the setting of IsHealthy
|
||||
_ = tracker.CheckHealth(context.Background())
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}, Tracker: tracker}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
@ -144,7 +201,14 @@ func TestAttests_NextSlot(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProposes_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
// avoid race condition between the cancellation of the context in the go stream from slot and the setting of IsHealthy
|
||||
_ = tracker.CheckHealth(context.Background())
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}, Tracker: tracker}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
@ -164,7 +228,14 @@ func TestProposes_NextSlot(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBothProposesAndAttests_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
// avoid race condition between the cancellation of the context in the go stream from slot and the setting of IsHealthy
|
||||
_ = tracker.CheckHealth(context.Background())
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}, Tracker: tracker}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
@ -188,7 +259,12 @@ func TestBothProposesAndAttests_NextSlot(t *testing.T) {
|
||||
func TestKeyReload_ActiveKey(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
km := &mockKeymanager{}
|
||||
v := &testutil.FakeValidator{Km: km}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
v := &testutil.FakeValidator{Km: km, Tracker: tracker}
|
||||
ac := make(chan [][fieldparams.BLSPubkeyLength]byte)
|
||||
current := [][fieldparams.BLSPubkeyLength]byte{testutil.ActiveKey}
|
||||
onAccountsChanged(ctx, v, current, ac)
|
||||
@ -202,7 +278,12 @@ func TestKeyReload_NoActiveKey(t *testing.T) {
|
||||
na := notActive(t)
|
||||
ctx := context.Background()
|
||||
km := &mockKeymanager{}
|
||||
v := &testutil.FakeValidator{Km: km}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
v := &testutil.FakeValidator{Km: km, Tracker: tracker}
|
||||
ac := make(chan [][fieldparams.BLSPubkeyLength]byte)
|
||||
current := [][fieldparams.BLSPubkeyLength]byte{na}
|
||||
onAccountsChanged(ctx, v, current, ac)
|
||||
@ -224,7 +305,12 @@ func notActive(t *testing.T) [fieldparams.BLSPubkeyLength]byte {
|
||||
}
|
||||
|
||||
func TestUpdateProposerSettingsAt_EpochStart(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}, Tracker: tracker}
|
||||
err := v.SetProposerSettings(context.Background(), &proposer.Settings{
|
||||
DefaultConfig: &proposer.Option{
|
||||
FeeRecipientConfig: &proposer.FeeRecipientConfig{
|
||||
@ -249,7 +335,16 @@ func TestUpdateProposerSettingsAt_EpochStart(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUpdateProposerSettingsAt_EpochEndOk(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}, ProposerSettingWait: time.Duration(params.BeaconConfig().SecondsPerSlot-1) * time.Second}
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
v := &testutil.FakeValidator{
|
||||
Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}},
|
||||
ProposerSettingWait: time.Duration(params.BeaconConfig().SecondsPerSlot-1) * time.Second,
|
||||
Tracker: tracker,
|
||||
}
|
||||
err := v.SetProposerSettings(context.Background(), &proposer.Settings{
|
||||
DefaultConfig: &proposer.Option{
|
||||
FeeRecipientConfig: &proposer.FeeRecipientConfig{
|
||||
@ -275,9 +370,15 @@ func TestUpdateProposerSettingsAt_EpochEndOk(t *testing.T) {
|
||||
|
||||
func TestUpdateProposerSettings_ContinuesAfterValidatorRegistrationFails(t *testing.T) {
|
||||
errSomeotherError := errors.New("some internal error")
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
node := healthTesting.NewMockHealthClient(ctrl)
|
||||
tracker := beacon.NewNodeHealthTracker(node)
|
||||
node.EXPECT().IsHealthy(gomock.Any()).Return(true).AnyTimes()
|
||||
v := &testutil.FakeValidator{
|
||||
ProposerSettingsErr: errors.Wrap(ErrBuilderValidatorRegistration, errSomeotherError.Error()),
|
||||
Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}},
|
||||
Tracker: tracker,
|
||||
}
|
||||
err := v.SetProposerSettings(context.Background(), &proposer.Settings{
|
||||
DefaultConfig: &proposer.Option{
|
||||
|
@ -194,14 +194,12 @@ func (v *ValidatorService) Start() {
|
||||
return
|
||||
}
|
||||
|
||||
restHandler := &beaconApi.BeaconApiJsonRestHandler{
|
||||
HttpClient: http.Client{Timeout: v.conn.GetBeaconApiTimeout()},
|
||||
Host: v.conn.GetBeaconApiUrl(),
|
||||
}
|
||||
restHandler := beaconApi.NewBeaconApiJsonRestHandler(
|
||||
http.Client{Timeout: v.conn.GetBeaconApiTimeout()},
|
||||
v.conn.GetBeaconApiUrl(),
|
||||
)
|
||||
|
||||
evHandler := beaconApi.NewEventHandler(http.DefaultClient, v.conn.GetBeaconApiUrl())
|
||||
opts := []beaconApi.ValidatorClientOpt{beaconApi.WithEventHandler(evHandler)}
|
||||
validatorClient := validatorClientFactory.NewValidatorClient(v.conn, restHandler, opts...)
|
||||
validatorClient := validatorClientFactory.NewValidatorClient(v.conn, restHandler)
|
||||
|
||||
valStruct := &validator{
|
||||
validatorClient: validatorClient,
|
||||
|
@ -10,6 +10,9 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/validator/client/testutil",
|
||||
visibility = ["//validator:__subpackages__"],
|
||||
deps = [
|
||||
"//api/client:go_default_library",
|
||||
"//api/client/beacon:go_default_library",
|
||||
"//api/client/event:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/proposer:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
|
@ -5,6 +5,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
api "github.com/prysmaticlabs/prysm/v5/api/client"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/proposer"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
@ -55,6 +58,7 @@ type FakeValidator struct {
|
||||
proposerSettings *proposer.Settings
|
||||
ProposerSettingWait time.Duration
|
||||
Km keymanager.IKeymanager
|
||||
Tracker *beacon.NodeHealthTracker
|
||||
}
|
||||
|
||||
// Done for mocking.
|
||||
@ -75,7 +79,7 @@ func (fv *FakeValidator) LogSubmittedSyncCommitteeMessages() {}
|
||||
func (fv *FakeValidator) WaitForChainStart(_ context.Context) error {
|
||||
fv.WaitForChainStartCalled++
|
||||
if fv.RetryTillSuccess >= fv.WaitForChainStartCalled {
|
||||
return iface.ErrConnectionIssue
|
||||
return api.ErrConnectionIssue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -87,7 +91,7 @@ func (fv *FakeValidator) WaitForActivation(_ context.Context, accountChan chan [
|
||||
return nil
|
||||
}
|
||||
if fv.RetryTillSuccess >= fv.WaitForActivationCalled {
|
||||
return iface.ErrConnectionIssue
|
||||
return api.ErrConnectionIssue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -96,7 +100,7 @@ func (fv *FakeValidator) WaitForActivation(_ context.Context, accountChan chan [
|
||||
func (fv *FakeValidator) WaitForSync(_ context.Context) error {
|
||||
fv.WaitForSyncCalled++
|
||||
if fv.RetryTillSuccess >= fv.WaitForSyncCalled {
|
||||
return iface.ErrConnectionIssue
|
||||
return api.ErrConnectionIssue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -111,7 +115,7 @@ func (fv *FakeValidator) SlasherReady(_ context.Context) error {
|
||||
func (fv *FakeValidator) CanonicalHeadSlot(_ context.Context) (primitives.Slot, error) {
|
||||
fv.CanonicalHeadSlotCalled++
|
||||
if fv.RetryTillSuccess > fv.CanonicalHeadSlotCalled {
|
||||
return 0, iface.ErrConnectionIssue
|
||||
return 0, api.ErrConnectionIssue
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
@ -217,14 +221,6 @@ func (*FakeValidator) CheckDoppelGanger(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReceiveSlots for mocking
|
||||
func (fv *FakeValidator) ReceiveSlots(_ context.Context, connectionErrorChannel chan<- error) {
|
||||
fv.ReceiveBlocksCalled++
|
||||
if fv.RetryTillSuccess > fv.ReceiveBlocksCalled {
|
||||
connectionErrorChannel <- iface.ErrConnectionIssue
|
||||
}
|
||||
}
|
||||
|
||||
// HandleKeyReload for mocking
|
||||
func (fv *FakeValidator) HandleKeyReload(_ context.Context, newKeys [][fieldparams.BLSPubkeyLength]byte) (anyActive bool, err error) {
|
||||
fv.HandleKeyReloadCalled = true
|
||||
@ -286,14 +282,15 @@ func (fv *FakeValidator) SetProposerSettings(_ context.Context, settings *propos
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fv *FakeValidator) StartEventStream(_ context.Context) error {
|
||||
return nil
|
||||
func (*FakeValidator) StartEventStream(_ context.Context, _ []string, _ chan<- *event.Event) {
|
||||
}
|
||||
|
||||
func (fv *FakeValidator) EventStreamIsRunning() bool {
|
||||
func (*FakeValidator) ProcessEvent(_ *event.Event) {}
|
||||
|
||||
func (*FakeValidator) EventStreamIsRunning() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (fv *FakeValidator) NodeIsHealthy(context.Context) bool {
|
||||
return true
|
||||
func (fv *FakeValidator) HealthTracker() *beacon.NodeHealthTracker {
|
||||
return fv.Tracker
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@ -20,6 +21,10 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/client/beacon"
|
||||
eventClient "github.com/prysmaticlabs/prysm/v5/api/client/event"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
||||
"github.com/prysmaticlabs/prysm/v5/async/event"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/cmd"
|
||||
@ -248,7 +253,7 @@ func (v *validator) WaitForChainStart(ctx context.Context) error {
|
||||
|
||||
chainStartRes, err := v.validatorClient.WaitForChainStart(ctx, &emptypb.Empty{})
|
||||
if err == io.EOF {
|
||||
return iface.ErrConnectionIssue
|
||||
return client.ErrConnectionIssue
|
||||
}
|
||||
|
||||
if ctx.Err() == context.Canceled {
|
||||
@ -257,7 +262,7 @@ func (v *validator) WaitForChainStart(ctx context.Context) error {
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(
|
||||
iface.ErrConnectionIssue,
|
||||
client.ErrConnectionIssue,
|
||||
errors.Wrap(err, "could not receive ChainStart from stream").Error(),
|
||||
)
|
||||
}
|
||||
@ -310,7 +315,7 @@ func (v *validator) WaitForSync(ctx context.Context) error {
|
||||
|
||||
s, err := v.nodeClient.GetSyncStatus(ctx, &emptypb.Empty{})
|
||||
if err != nil {
|
||||
return errors.Wrap(iface.ErrConnectionIssue, errors.Wrap(err, "could not get sync status").Error())
|
||||
return errors.Wrap(client.ErrConnectionIssue, errors.Wrap(err, "could not get sync status").Error())
|
||||
}
|
||||
if !s.Syncing {
|
||||
return nil
|
||||
@ -322,7 +327,7 @@ func (v *validator) WaitForSync(ctx context.Context) error {
|
||||
case <-time.After(slots.DivideSlotBy(2 /* twice per slot */)):
|
||||
s, err := v.nodeClient.GetSyncStatus(ctx, &emptypb.Empty{})
|
||||
if err != nil {
|
||||
return errors.Wrap(iface.ErrConnectionIssue, errors.Wrap(err, "could not get sync status").Error())
|
||||
return errors.Wrap(client.ErrConnectionIssue, errors.Wrap(err, "could not get sync status").Error())
|
||||
}
|
||||
if !s.Syncing {
|
||||
return nil
|
||||
@ -334,35 +339,6 @@ func (v *validator) WaitForSync(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
// ReceiveSlots starts a stream listener to obtain
|
||||
// slots from the beacon node when it imports a block. Upon receiving a slot, the service
|
||||
// broadcasts it to a feed for other usages to subscribe to.
|
||||
func (v *validator) ReceiveSlots(ctx context.Context, connectionErrorChannel chan<- error) {
|
||||
stream, err := v.validatorClient.StreamSlots(ctx, ðpb.StreamSlotsRequest{VerifiedOnly: true})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to retrieve slots stream, " + iface.ErrConnectionIssue.Error())
|
||||
connectionErrorChannel <- errors.Wrap(iface.ErrConnectionIssue, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
if ctx.Err() == context.Canceled {
|
||||
log.WithError(ctx.Err()).Error("Context canceled - shutting down slots receiver")
|
||||
return
|
||||
}
|
||||
res, err := stream.Recv()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not receive slots from beacon node: " + iface.ErrConnectionIssue.Error())
|
||||
connectionErrorChannel <- errors.Wrap(iface.ErrConnectionIssue, err.Error())
|
||||
return
|
||||
}
|
||||
if res == nil {
|
||||
continue
|
||||
}
|
||||
v.setHighestSlot(res.Slot)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *validator) checkAndLogValidatorStatus(statuses []*validatorStatus, activeValCount int64) bool {
|
||||
nonexistentIndex := primitives.ValidatorIndex(^uint64(0))
|
||||
var validatorActivated bool
|
||||
@ -429,7 +405,7 @@ func (v *validator) CanonicalHeadSlot(ctx context.Context) (primitives.Slot, err
|
||||
defer span.End()
|
||||
head, err := v.beaconClient.GetChainHead(ctx, &emptypb.Empty{})
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(iface.ErrConnectionIssue, err.Error())
|
||||
return 0, errors.Wrap(client.ErrConnectionIssue, err.Error())
|
||||
}
|
||||
return head.HeadSlot, nil
|
||||
}
|
||||
@ -1092,16 +1068,43 @@ func (v *validator) PushProposerSettings(ctx context.Context, km keymanager.IKey
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *validator) StartEventStream(ctx context.Context) error {
|
||||
return v.validatorClient.StartEventStream(ctx)
|
||||
func (v *validator) StartEventStream(ctx context.Context, topics []string, eventsChannel chan<- *eventClient.Event) {
|
||||
log.WithField("topics", topics).Info("Starting event stream")
|
||||
v.validatorClient.StartEventStream(ctx, topics, eventsChannel)
|
||||
}
|
||||
|
||||
func (v *validator) ProcessEvent(event *eventClient.Event) {
|
||||
if event == nil || event.Data == nil {
|
||||
log.Warn("Received empty event")
|
||||
}
|
||||
switch event.EventType {
|
||||
case eventClient.EventError:
|
||||
log.Error(string(event.Data))
|
||||
case eventClient.EventConnectionError:
|
||||
log.WithError(errors.New(string(event.Data))).Error("Event stream interrupted")
|
||||
case eventClient.EventHead:
|
||||
log.Debug("Received head event")
|
||||
head := &structs.HeadEvent{}
|
||||
if err := json.Unmarshal(event.Data, head); err != nil {
|
||||
log.WithError(err).Error("Failed to unmarshal head Event into JSON")
|
||||
}
|
||||
uintSlot, err := strconv.ParseUint(head.Slot, 10, 64)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to parse slot")
|
||||
}
|
||||
v.setHighestSlot(primitives.Slot(uintSlot))
|
||||
default:
|
||||
// just keep going and log the error
|
||||
log.WithField("type", event.EventType).WithField("data", string(event.Data)).Warn("Received an unknown event")
|
||||
}
|
||||
}
|
||||
|
||||
func (v *validator) EventStreamIsRunning() bool {
|
||||
return v.validatorClient.EventStreamIsRunning()
|
||||
}
|
||||
|
||||
func (v *validator) NodeIsHealthy(ctx context.Context) bool {
|
||||
return v.nodeClient.IsHealthy(ctx)
|
||||
func (v *validator) HealthTracker() *beacon.NodeHealthTracker {
|
||||
return v.nodeClient.HealthTracker()
|
||||
}
|
||||
|
||||
func (v *validator) filterAndCacheActiveKeys(ctx context.Context, pubkeys [][fieldparams.BLSPubkeyLength]byte, slot primitives.Slot) ([][fieldparams.BLSPubkeyLength]byte, error) {
|
||||
|
@ -943,33 +943,6 @@ func TestCheckAndLogValidatorStatus_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestService_ReceiveSlots_SetHighest(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
client := validatormock.NewMockValidatorClient(ctrl)
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
slotFeed: new(event.Feed),
|
||||
}
|
||||
stream := mock2.NewMockBeaconNodeValidator_StreamSlotsClient(ctrl)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
client.EXPECT().StreamSlots(
|
||||
gomock.Any(),
|
||||
ðpb.StreamSlotsRequest{VerifiedOnly: true},
|
||||
).Return(stream, nil)
|
||||
stream.EXPECT().Context().Return(ctx).AnyTimes()
|
||||
stream.EXPECT().Recv().Return(
|
||||
ðpb.StreamSlotsResponse{Slot: 123},
|
||||
nil,
|
||||
).Do(func() {
|
||||
cancel()
|
||||
})
|
||||
connectionErrorChannel := make(chan error)
|
||||
v.ReceiveSlots(ctx, connectionErrorChannel)
|
||||
require.Equal(t, primitives.Slot(123), v.highestValidSlot)
|
||||
}
|
||||
|
||||
type doppelGangerRequestMatcher struct {
|
||||
req *ethpb.DoppelGangerRequest
|
||||
}
|
||||
|
@ -54,10 +54,8 @@ func (s *Server) registerBeaconClient() error {
|
||||
s.beaconApiTimeout,
|
||||
)
|
||||
|
||||
restHandler := &beaconApi.BeaconApiJsonRestHandler{
|
||||
HttpClient: http.Client{Timeout: s.beaconApiTimeout},
|
||||
Host: s.beaconApiEndpoint,
|
||||
}
|
||||
restHandler := beaconApi.NewBeaconApiJsonRestHandler(http.Client{Timeout: s.beaconApiTimeout}, s.beaconApiEndpoint)
|
||||
|
||||
s.beaconChainClient = beaconChainClientFactory.NewBeaconChainClient(conn, restHandler)
|
||||
s.beaconNodeClient = nodeClientFactory.NewNodeClient(conn, restHandler)
|
||||
s.beaconNodeValidatorClient = validatorClientFactory.NewValidatorClient(conn, restHandler)
|
||||
|
Loading…
Reference in New Issue
Block a user