mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-27 14:18:13 -05:00
Compare commits
5 Commits
gRPC-fallb
...
gloas-ligh
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06aaf4aa36 | ||
|
|
2cbb743606 | ||
|
|
ce9c968dcc | ||
|
|
60e5c29b92 | ||
|
|
e27445bae2 |
@@ -3,16 +3,13 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"grpc_connection_provider.go",
|
||||
"grpcutils.go",
|
||||
"log.go",
|
||||
"mock_grpc_provider.go",
|
||||
"parameters.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/api/grpc",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
"@org_golang_google_grpc//metadata:go_default_library",
|
||||
@@ -21,17 +18,12 @@ go_library(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"grpc_connection_provider_test.go",
|
||||
"grpcutils_test.go",
|
||||
],
|
||||
srcs = ["grpcutils_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
"@org_golang_google_grpc//credentials/insecure:go_default_library",
|
||||
"@org_golang_google_grpc//metadata:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// GrpcConnectionProvider manages gRPC connections for failover support.
|
||||
// It allows switching between different beacon node endpoints when the current one becomes unavailable.
|
||||
// Only one connection is maintained at a time - when switching hosts, the old connection is closed.
|
||||
type GrpcConnectionProvider interface {
|
||||
// CurrentConn returns the currently active gRPC connection.
|
||||
// The connection is created lazily on first call.
|
||||
// Returns nil if the provider has been closed.
|
||||
CurrentConn() *grpc.ClientConn
|
||||
// CurrentHost returns the address of the currently active endpoint.
|
||||
CurrentHost() string
|
||||
// Hosts returns all configured endpoint addresses.
|
||||
Hosts() []string
|
||||
// SwitchHost switches to the endpoint at the given index.
|
||||
// The new connection is created lazily on next CurrentConn() call.
|
||||
SwitchHost(index int) error
|
||||
// Close closes the current connection.
|
||||
Close()
|
||||
}
|
||||
|
||||
type grpcConnectionProvider struct {
|
||||
// Immutable after construction - no lock needed for reads
|
||||
endpoints []string
|
||||
ctx context.Context
|
||||
dialOpts []grpc.DialOption
|
||||
|
||||
// Current connection state (protected by mutex)
|
||||
currentIndex uint64
|
||||
conn *grpc.ClientConn
|
||||
|
||||
mu sync.Mutex
|
||||
closed bool
|
||||
}
|
||||
|
||||
// NewGrpcConnectionProvider creates a new connection provider that manages gRPC connections.
|
||||
// The endpoint parameter can be a comma-separated list of addresses (e.g., "host1:4000,host2:4000").
|
||||
// Only one connection is maintained at a time, created lazily on first use.
|
||||
func NewGrpcConnectionProvider(
|
||||
ctx context.Context,
|
||||
endpoint string,
|
||||
dialOpts []grpc.DialOption,
|
||||
) (GrpcConnectionProvider, error) {
|
||||
endpoints := parseEndpoints(endpoint)
|
||||
if len(endpoints) == 0 {
|
||||
return nil, errors.New("no gRPC endpoints provided")
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"endpoints": endpoints,
|
||||
"count": len(endpoints),
|
||||
}).Info("Initialized gRPC connection provider")
|
||||
|
||||
return &grpcConnectionProvider{
|
||||
endpoints: endpoints,
|
||||
ctx: ctx,
|
||||
dialOpts: dialOpts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseEndpoints splits a comma-separated endpoint string into individual endpoints.
|
||||
func parseEndpoints(endpoint string) []string {
|
||||
if endpoint == "" {
|
||||
return nil
|
||||
}
|
||||
endpoints := make([]string, 0, 1)
|
||||
for p := range strings.SplitSeq(endpoint, ",") {
|
||||
if p = strings.TrimSpace(p); p != "" {
|
||||
endpoints = append(endpoints, p)
|
||||
}
|
||||
}
|
||||
return endpoints
|
||||
}
|
||||
|
||||
func (p *grpcConnectionProvider) CurrentConn() *grpc.ClientConn {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if p.closed {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return existing connection if available
|
||||
if p.conn != nil {
|
||||
return p.conn
|
||||
}
|
||||
|
||||
// Create connection lazily
|
||||
ep := p.endpoints[p.currentIndex]
|
||||
conn, err := grpc.DialContext(p.ctx, ep, p.dialOpts...)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("endpoint", ep).Error("Failed to create gRPC connection")
|
||||
return nil
|
||||
}
|
||||
|
||||
p.conn = conn
|
||||
log.WithField("endpoint", ep).Debug("Created gRPC connection")
|
||||
return conn
|
||||
}
|
||||
|
||||
func (p *grpcConnectionProvider) CurrentHost() string {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
return p.endpoints[p.currentIndex]
|
||||
}
|
||||
|
||||
func (p *grpcConnectionProvider) Hosts() []string {
|
||||
// Return a copy to maintain immutability
|
||||
hosts := make([]string, len(p.endpoints))
|
||||
copy(hosts, p.endpoints)
|
||||
return hosts
|
||||
}
|
||||
|
||||
func (p *grpcConnectionProvider) SwitchHost(index int) error {
|
||||
if index < 0 || index >= len(p.endpoints) {
|
||||
return errors.Errorf("invalid host index %d, must be between 0 and %d", index, len(p.endpoints)-1)
|
||||
}
|
||||
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if uint64(index) == p.currentIndex {
|
||||
return nil // Already on this host
|
||||
}
|
||||
|
||||
oldHost := p.endpoints[p.currentIndex]
|
||||
|
||||
// Close existing connection if any
|
||||
if p.conn != nil {
|
||||
if err := p.conn.Close(); err != nil {
|
||||
log.WithError(err).WithField("endpoint", oldHost).Debug("Failed to close previous connection")
|
||||
}
|
||||
p.conn = nil
|
||||
}
|
||||
|
||||
p.currentIndex = uint64(index)
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"previousHost": oldHost,
|
||||
"newHost": p.endpoints[index],
|
||||
}).Debug("Switched gRPC endpoint")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *grpcConnectionProvider) Close() {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if p.closed {
|
||||
return
|
||||
}
|
||||
p.closed = true
|
||||
|
||||
if p.conn != nil {
|
||||
if err := p.conn.Close(); err != nil {
|
||||
log.WithError(err).WithField("endpoint", p.endpoints[p.currentIndex]).Debug("Failed to close gRPC connection")
|
||||
}
|
||||
p.conn = nil
|
||||
}
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
func TestParseEndpoints(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected []string
|
||||
}{
|
||||
{"single endpoint", "localhost:4000", []string{"localhost:4000"}},
|
||||
{"multiple endpoints", "host1:4000,host2:4000,host3:4000", []string{"host1:4000", "host2:4000", "host3:4000"}},
|
||||
{"endpoints with spaces", "host1:4000, host2:4000 , host3:4000", []string{"host1:4000", "host2:4000", "host3:4000"}},
|
||||
{"empty string", "", nil},
|
||||
{"only commas", ",,,", []string{}},
|
||||
{"trailing comma", "host1:4000,host2:4000,", []string{"host1:4000", "host2:4000"}},
|
||||
{"leading comma", ",host1:4000,host2:4000", []string{"host1:4000", "host2:4000"}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := parseEndpoints(tt.input)
|
||||
if !reflect.DeepEqual(tt.expected, got) {
|
||||
t.Errorf("parseEndpoints(%q) = %v, want %v", tt.input, got, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewGrpcConnectionProvider_Errors(t *testing.T) {
|
||||
t.Run("no endpoints", func(t *testing.T) {
|
||||
dialOpts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
|
||||
_, err := NewGrpcConnectionProvider(context.Background(), "", dialOpts)
|
||||
require.ErrorContains(t, "no gRPC endpoints provided", err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGrpcConnectionProvider_LazyConnection(t *testing.T) {
|
||||
// Start only one server but configure provider with two endpoints
|
||||
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
server := grpc.NewServer()
|
||||
go func() { _ = server.Serve(lis) }()
|
||||
defer server.Stop()
|
||||
|
||||
validAddr := lis.Addr().String()
|
||||
invalidAddr := "127.0.0.1:1" // Port 1 is unlikely to be listening
|
||||
|
||||
// Provider should succeed even though second endpoint is invalid (lazy connections)
|
||||
endpoint := validAddr + "," + invalidAddr
|
||||
ctx := context.Background()
|
||||
dialOpts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
|
||||
provider, err := NewGrpcConnectionProvider(ctx, endpoint, dialOpts)
|
||||
require.NoError(t, err, "Provider creation should succeed with lazy connections")
|
||||
defer func() { provider.Close() }()
|
||||
|
||||
// First endpoint should work
|
||||
conn := provider.CurrentConn()
|
||||
assert.NotNil(t, conn, "First connection should be created lazily")
|
||||
}
|
||||
|
||||
func TestGrpcConnectionProvider_SingleConnectionModel(t *testing.T) {
|
||||
// Create provider with 3 endpoints
|
||||
var addrs []string
|
||||
var servers []*grpc.Server
|
||||
|
||||
for range 3 {
|
||||
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
server := grpc.NewServer()
|
||||
go func() { _ = server.Serve(lis) }()
|
||||
addrs = append(addrs, lis.Addr().String())
|
||||
servers = append(servers, server)
|
||||
}
|
||||
defer func() {
|
||||
for _, s := range servers {
|
||||
s.Stop()
|
||||
}
|
||||
}()
|
||||
|
||||
endpoint := strings.Join(addrs, ",")
|
||||
ctx := context.Background()
|
||||
dialOpts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
|
||||
provider, err := NewGrpcConnectionProvider(ctx, endpoint, dialOpts)
|
||||
require.NoError(t, err)
|
||||
defer func() { provider.Close() }()
|
||||
|
||||
// Access the internal state to verify single connection behavior
|
||||
p := provider.(*grpcConnectionProvider)
|
||||
|
||||
// Initially no connection
|
||||
p.mu.Lock()
|
||||
assert.Equal(t, (*grpc.ClientConn)(nil), p.conn, "Connection should be nil before access")
|
||||
p.mu.Unlock()
|
||||
|
||||
// Access connection - should create one
|
||||
conn0 := provider.CurrentConn()
|
||||
assert.NotNil(t, conn0)
|
||||
|
||||
p.mu.Lock()
|
||||
assert.NotNil(t, p.conn, "Connection should be created after CurrentConn()")
|
||||
firstConn := p.conn
|
||||
p.mu.Unlock()
|
||||
|
||||
// Call CurrentConn again - should return same connection
|
||||
conn0Again := provider.CurrentConn()
|
||||
assert.Equal(t, conn0, conn0Again, "Should return same connection")
|
||||
|
||||
// Switch to different host - old connection should be closed, new one created lazily
|
||||
require.NoError(t, provider.SwitchHost(1))
|
||||
|
||||
p.mu.Lock()
|
||||
assert.Equal(t, (*grpc.ClientConn)(nil), p.conn, "Connection should be nil after SwitchHost (lazy)")
|
||||
p.mu.Unlock()
|
||||
|
||||
// Get new connection
|
||||
conn1 := provider.CurrentConn()
|
||||
assert.NotNil(t, conn1)
|
||||
assert.NotEqual(t, firstConn, conn1, "Should be a different connection after switching hosts")
|
||||
}
|
||||
|
||||
// testProvider creates a provider with n test servers and returns cleanup function.
|
||||
func testProvider(t *testing.T, n int) (GrpcConnectionProvider, []string, func()) {
|
||||
var addrs []string
|
||||
var cleanups []func()
|
||||
|
||||
for range n {
|
||||
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err)
|
||||
server := grpc.NewServer()
|
||||
go func() { _ = server.Serve(lis) }()
|
||||
addrs = append(addrs, lis.Addr().String())
|
||||
cleanups = append(cleanups, server.Stop)
|
||||
}
|
||||
|
||||
endpoint := strings.Join(addrs, ",")
|
||||
|
||||
ctx := context.Background()
|
||||
dialOpts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
|
||||
provider, err := NewGrpcConnectionProvider(ctx, endpoint, dialOpts)
|
||||
require.NoError(t, err)
|
||||
|
||||
cleanup := func() {
|
||||
provider.Close()
|
||||
for _, c := range cleanups {
|
||||
c()
|
||||
}
|
||||
}
|
||||
return provider, addrs, cleanup
|
||||
}
|
||||
|
||||
func TestGrpcConnectionProvider(t *testing.T) {
|
||||
provider, addrs, cleanup := testProvider(t, 3)
|
||||
defer cleanup()
|
||||
|
||||
t.Run("initial state", func(t *testing.T) {
|
||||
assert.Equal(t, 3, len(provider.Hosts()))
|
||||
assert.Equal(t, addrs[0], provider.CurrentHost())
|
||||
assert.NotNil(t, provider.CurrentConn())
|
||||
})
|
||||
|
||||
t.Run("SwitchHost", func(t *testing.T) {
|
||||
require.NoError(t, provider.SwitchHost(1))
|
||||
assert.Equal(t, addrs[1], provider.CurrentHost())
|
||||
assert.NotNil(t, provider.CurrentConn()) // New connection created lazily
|
||||
require.NoError(t, provider.SwitchHost(0))
|
||||
assert.Equal(t, addrs[0], provider.CurrentHost())
|
||||
require.ErrorContains(t, "invalid host index", provider.SwitchHost(-1))
|
||||
require.ErrorContains(t, "invalid host index", provider.SwitchHost(3))
|
||||
})
|
||||
|
||||
t.Run("SwitchHost circular", func(t *testing.T) {
|
||||
// Test round-robin style switching using SwitchHost with manual index
|
||||
indices := []int{1, 2, 0, 1} // Simulate circular switching
|
||||
for i, idx := range indices {
|
||||
require.NoError(t, provider.SwitchHost(idx))
|
||||
assert.Equal(t, addrs[idx], provider.CurrentHost(), "iteration %d", i)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Hosts returns copy", func(t *testing.T) {
|
||||
hosts := provider.Hosts()
|
||||
original := hosts[0]
|
||||
hosts[0] = "modified"
|
||||
assert.Equal(t, original, provider.Hosts()[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestGrpcConnectionProvider_Close(t *testing.T) {
|
||||
provider, _, cleanup := testProvider(t, 1)
|
||||
defer cleanup()
|
||||
|
||||
assert.NotNil(t, provider.CurrentConn())
|
||||
provider.Close()
|
||||
assert.Equal(t, (*grpc.ClientConn)(nil), provider.CurrentConn())
|
||||
provider.Close() // Double close is safe
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import "google.golang.org/grpc"
|
||||
|
||||
// MockGrpcProvider implements GrpcConnectionProvider for testing.
|
||||
type MockGrpcProvider struct {
|
||||
MockConn *grpc.ClientConn
|
||||
MockHosts []string
|
||||
}
|
||||
|
||||
func (m *MockGrpcProvider) CurrentConn() *grpc.ClientConn { return m.MockConn }
|
||||
func (m *MockGrpcProvider) CurrentHost() string {
|
||||
if len(m.MockHosts) > 0 {
|
||||
return m.MockHosts[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (m *MockGrpcProvider) Hosts() []string { return m.MockHosts }
|
||||
func (m *MockGrpcProvider) SwitchHost(int) error { return nil }
|
||||
func (m *MockGrpcProvider) Close() {}
|
||||
@@ -1,34 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"log.go",
|
||||
"mock_rest_provider.go",
|
||||
"rest_connection_provider.go",
|
||||
"rest_handler.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/api/rest",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api:go_default_library",
|
||||
"//api/apiutil:go_default_library",
|
||||
"//api/client:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//network/httputil:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opentelemetry_go_contrib_instrumentation_net_http_otelhttp//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["rest_connection_provider_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,22 +0,0 @@
|
||||
package rest
|
||||
|
||||
import "net/http"
|
||||
|
||||
// MockRestProvider implements RestConnectionProvider for testing.
|
||||
type MockRestProvider struct {
|
||||
MockClient *http.Client
|
||||
MockHandler RestHandler
|
||||
MockHosts []string
|
||||
HostIndex int
|
||||
}
|
||||
|
||||
func (m *MockRestProvider) HttpClient() *http.Client { return m.MockClient }
|
||||
func (m *MockRestProvider) RestHandler() RestHandler { return m.MockHandler }
|
||||
func (m *MockRestProvider) CurrentHost() string {
|
||||
if len(m.MockHosts) > 0 {
|
||||
return m.MockHosts[m.HostIndex%len(m.MockHosts)]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (m *MockRestProvider) Hosts() []string { return m.MockHosts }
|
||||
func (m *MockRestProvider) SwitchHost(index int) error { m.HostIndex = index; return nil }
|
||||
@@ -1,158 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api/client"
|
||||
pkgErrors "github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
)
|
||||
|
||||
// RestConnectionProvider manages HTTP client configuration for REST API with failover support.
|
||||
// It allows switching between different beacon node REST endpoints when the current one becomes unavailable.
|
||||
type RestConnectionProvider interface {
|
||||
// HttpClient returns the configured HTTP client with headers, timeout, and optional tracing.
|
||||
HttpClient() *http.Client
|
||||
// RestHandler returns the REST handler for making API requests.
|
||||
RestHandler() RestHandler
|
||||
// CurrentHost returns the current REST API endpoint URL.
|
||||
CurrentHost() string
|
||||
// Hosts returns all configured REST API endpoint URLs.
|
||||
Hosts() []string
|
||||
// SwitchHost switches to the endpoint at the given index.
|
||||
SwitchHost(index int) error
|
||||
}
|
||||
|
||||
// RestConnectionProviderOption is a functional option for configuring the REST connection provider.
|
||||
type RestConnectionProviderOption func(*restConnectionProvider)
|
||||
|
||||
// WithHttpTimeout sets the HTTP client timeout.
|
||||
func WithHttpTimeout(timeout time.Duration) RestConnectionProviderOption {
|
||||
return func(p *restConnectionProvider) {
|
||||
p.timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// WithHttpHeaders sets custom HTTP headers to include in all requests.
|
||||
func WithHttpHeaders(headers map[string][]string) RestConnectionProviderOption {
|
||||
return func(p *restConnectionProvider) {
|
||||
p.headers = headers
|
||||
}
|
||||
}
|
||||
|
||||
// WithTracing enables OpenTelemetry tracing for HTTP requests.
|
||||
func WithTracing() RestConnectionProviderOption {
|
||||
return func(p *restConnectionProvider) {
|
||||
p.enableTracing = true
|
||||
}
|
||||
}
|
||||
|
||||
type restConnectionProvider struct {
|
||||
endpoints []string
|
||||
httpClient *http.Client
|
||||
restHandler RestHandler
|
||||
currentIndex atomic.Uint64
|
||||
timeout time.Duration
|
||||
headers map[string][]string
|
||||
enableTracing bool
|
||||
}
|
||||
|
||||
// NewRestConnectionProvider creates a new REST connection provider that manages HTTP client configuration.
|
||||
// The endpoint parameter can be a comma-separated list of URLs (e.g., "http://host1:3500,http://host2:3500").
|
||||
func NewRestConnectionProvider(endpoint string, opts ...RestConnectionProviderOption) (RestConnectionProvider, error) {
|
||||
endpoints := parseEndpoints(endpoint)
|
||||
if len(endpoints) == 0 {
|
||||
return nil, pkgErrors.New("no REST API endpoints provided")
|
||||
}
|
||||
|
||||
p := &restConnectionProvider{
|
||||
endpoints: endpoints,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(p)
|
||||
}
|
||||
|
||||
// Build the HTTP transport chain
|
||||
var transport http.RoundTripper = http.DefaultTransport
|
||||
|
||||
// Add custom headers if configured
|
||||
if len(p.headers) > 0 {
|
||||
transport = client.NewCustomHeadersTransport(transport, p.headers)
|
||||
}
|
||||
|
||||
// Add tracing if enabled
|
||||
if p.enableTracing {
|
||||
transport = otelhttp.NewTransport(transport)
|
||||
}
|
||||
|
||||
p.httpClient = &http.Client{
|
||||
Timeout: p.timeout,
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
// Create the REST handler with the HTTP client and initial host
|
||||
p.restHandler = newRestHandler(*p.httpClient, endpoints[0])
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"endpoints": endpoints,
|
||||
"count": len(endpoints),
|
||||
}).Info("Initialized REST connection provider")
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// parseEndpoints splits a comma-separated endpoint string into individual endpoints.
|
||||
func parseEndpoints(endpoint string) []string {
|
||||
if endpoint == "" {
|
||||
return nil
|
||||
}
|
||||
endpoints := make([]string, 0, 1)
|
||||
for p := range strings.SplitSeq(endpoint, ",") {
|
||||
if p = strings.TrimSpace(p); p != "" {
|
||||
endpoints = append(endpoints, p)
|
||||
}
|
||||
}
|
||||
return endpoints
|
||||
}
|
||||
|
||||
func (p *restConnectionProvider) HttpClient() *http.Client {
|
||||
return p.httpClient
|
||||
}
|
||||
|
||||
func (p *restConnectionProvider) RestHandler() RestHandler {
|
||||
return p.restHandler
|
||||
}
|
||||
|
||||
func (p *restConnectionProvider) CurrentHost() string {
|
||||
return p.endpoints[p.currentIndex.Load()]
|
||||
}
|
||||
|
||||
func (p *restConnectionProvider) Hosts() []string {
|
||||
// Return a copy to maintain immutability
|
||||
hosts := make([]string, len(p.endpoints))
|
||||
copy(hosts, p.endpoints)
|
||||
return hosts
|
||||
}
|
||||
|
||||
func (p *restConnectionProvider) SwitchHost(index int) error {
|
||||
if index < 0 || index >= len(p.endpoints) {
|
||||
return pkgErrors.Errorf("invalid host index %d, must be between 0 and %d", index, len(p.endpoints)-1)
|
||||
}
|
||||
|
||||
oldIdx := p.currentIndex.Load()
|
||||
p.currentIndex.Store(uint64(index))
|
||||
|
||||
// Update the rest handler's host
|
||||
p.restHandler.SwitchHost(p.endpoints[index])
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"previousHost": p.endpoints[oldIdx],
|
||||
"newHost": p.endpoints[index],
|
||||
}).Debug("Switched REST endpoint")
|
||||
return nil
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
)
|
||||
|
||||
func TestParseEndpoints(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected []string
|
||||
}{
|
||||
{"single endpoint", "http://localhost:3500", []string{"http://localhost:3500"}},
|
||||
{"multiple endpoints", "http://host1:3500,http://host2:3500,http://host3:3500", []string{"http://host1:3500", "http://host2:3500", "http://host3:3500"}},
|
||||
{"endpoints with spaces", "http://host1:3500, http://host2:3500 , http://host3:3500", []string{"http://host1:3500", "http://host2:3500", "http://host3:3500"}},
|
||||
{"empty string", "", nil},
|
||||
{"only commas", ",,,", []string{}},
|
||||
{"trailing comma", "http://host1:3500,http://host2:3500,", []string{"http://host1:3500", "http://host2:3500"}},
|
||||
{"leading comma", ",http://host1:3500,http://host2:3500", []string{"http://host1:3500", "http://host2:3500"}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := parseEndpoints(tt.input)
|
||||
if !reflect.DeepEqual(tt.expected, got) {
|
||||
t.Errorf("parseEndpoints(%q) = %v, want %v", tt.input, got, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRestConnectionProvider_Errors(t *testing.T) {
|
||||
t.Run("no endpoints", func(t *testing.T) {
|
||||
_, err := NewRestConnectionProvider("")
|
||||
require.ErrorContains(t, "no REST API endpoints provided", err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRestConnectionProvider(t *testing.T) {
|
||||
provider, err := NewRestConnectionProvider("http://host1:3500,http://host2:3500,http://host3:3500")
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("initial state", func(t *testing.T) {
|
||||
assert.Equal(t, 3, len(provider.Hosts()))
|
||||
assert.Equal(t, "http://host1:3500", provider.CurrentHost())
|
||||
assert.NotNil(t, provider.HttpClient())
|
||||
})
|
||||
|
||||
t.Run("SwitchHost", func(t *testing.T) {
|
||||
require.NoError(t, provider.SwitchHost(1))
|
||||
assert.Equal(t, "http://host2:3500", provider.CurrentHost())
|
||||
require.NoError(t, provider.SwitchHost(0))
|
||||
assert.Equal(t, "http://host1:3500", provider.CurrentHost())
|
||||
require.ErrorContains(t, "invalid host index", provider.SwitchHost(-1))
|
||||
require.ErrorContains(t, "invalid host index", provider.SwitchHost(3))
|
||||
})
|
||||
|
||||
t.Run("Hosts returns copy", func(t *testing.T) {
|
||||
hosts := provider.Hosts()
|
||||
original := hosts[0]
|
||||
hosts[0] = "modified"
|
||||
assert.Equal(t, original, provider.Hosts()[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestRestConnectionProvider_WithOptions(t *testing.T) {
|
||||
headers := map[string][]string{"Authorization": {"Bearer token"}}
|
||||
provider, err := NewRestConnectionProvider(
|
||||
"http://localhost:3500",
|
||||
WithHttpHeaders(headers),
|
||||
WithHttpTimeout(30000000000), // 30 seconds in nanoseconds
|
||||
WithTracing(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, provider.HttpClient())
|
||||
assert.Equal(t, "http://localhost:3500", provider.CurrentHost())
|
||||
}
|
||||
@@ -503,3 +503,77 @@ func (s *SignedBlindedBeaconBlockFulu) MessageRawJson() ([]byte, error) {
|
||||
func (s *SignedBlindedBeaconBlockFulu) SigString() string {
|
||||
return s.Signature
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Gloas
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type ExecutionPayloadBid struct {
|
||||
ParentBlockHash string `json:"parent_block_hash"`
|
||||
ParentBlockRoot string `json:"parent_block_root"`
|
||||
BlockHash string `json:"block_hash"`
|
||||
PrevRandao string `json:"prev_randao"`
|
||||
FeeRecipient string `json:"fee_recipient"`
|
||||
GasLimit string `json:"gas_limit"`
|
||||
BuilderIndex string `json:"builder_index"`
|
||||
Slot string `json:"slot"`
|
||||
Value string `json:"value"`
|
||||
ExecutionPayment string `json:"execution_payment"`
|
||||
BlobKzgCommitmentsRoot string `json:"blob_kzg_commitments_root"`
|
||||
}
|
||||
|
||||
type SignedExecutionPayloadBid struct {
|
||||
Message *ExecutionPayloadBid `json:"message"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
|
||||
type PayloadAttestationData struct {
|
||||
BeaconBlockRoot string `json:"beacon_block_root"`
|
||||
Slot string `json:"slot"`
|
||||
PayloadPresent bool `json:"payload_present"`
|
||||
BlobDataAvailable bool `json:"blob_data_available"`
|
||||
}
|
||||
|
||||
type PayloadAttestation struct {
|
||||
AggregationBits string `json:"aggregation_bits"`
|
||||
Data *PayloadAttestationData `json:"data"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
|
||||
type BeaconBlockBodyGloas struct {
|
||||
RandaoReveal string `json:"randao_reveal"`
|
||||
Eth1Data *Eth1Data `json:"eth1_data"`
|
||||
Graffiti string `json:"graffiti"`
|
||||
ProposerSlashings []*ProposerSlashing `json:"proposer_slashings"`
|
||||
AttesterSlashings []*AttesterSlashingElectra `json:"attester_slashings"`
|
||||
Attestations []*AttestationElectra `json:"attestations"`
|
||||
Deposits []*Deposit `json:"deposits"`
|
||||
VoluntaryExits []*SignedVoluntaryExit `json:"voluntary_exits"`
|
||||
SyncAggregate *SyncAggregate `json:"sync_aggregate"`
|
||||
BLSToExecutionChanges []*SignedBLSToExecutionChange `json:"bls_to_execution_changes"`
|
||||
SignedExecutionPayloadBid *SignedExecutionPayloadBid `json:"signed_execution_payload_bid"`
|
||||
PayloadAttestations []*PayloadAttestation `json:"payload_attestations"`
|
||||
}
|
||||
|
||||
type BeaconBlockGloas struct {
|
||||
Slot string `json:"slot"`
|
||||
ProposerIndex string `json:"proposer_index"`
|
||||
ParentRoot string `json:"parent_root"`
|
||||
StateRoot string `json:"state_root"`
|
||||
Body *BeaconBlockBodyGloas `json:"body"`
|
||||
}
|
||||
|
||||
type SignedBeaconBlockGloas struct {
|
||||
Message *BeaconBlockGloas `json:"message"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
|
||||
var _ SignedMessageJsoner = &SignedBeaconBlockGloas{}
|
||||
|
||||
func (s *SignedBeaconBlockGloas) MessageRawJson() ([]byte, error) {
|
||||
return json.Marshal(s.Message)
|
||||
}
|
||||
|
||||
func (s *SignedBeaconBlockGloas) SigString() string {
|
||||
return s.Signature
|
||||
}
|
||||
|
||||
@@ -268,6 +268,8 @@ func SignedBeaconBlockMessageJsoner(block interfaces.ReadOnlySignedBeaconBlock)
|
||||
return SignedBlindedBeaconBlockFuluFromConsensus(pbStruct)
|
||||
case *eth.SignedBeaconBlockFulu:
|
||||
return SignedBeaconBlockFuluFromConsensus(pbStruct)
|
||||
case *eth.SignedBeaconBlockGloas:
|
||||
return SignedBeaconBlockGloasFromConsensus(pbStruct)
|
||||
default:
|
||||
return nil, ErrUnsupportedConversion
|
||||
}
|
||||
@@ -2885,3 +2887,379 @@ func SignedBeaconBlockFuluFromConsensus(b *eth.SignedBeaconBlockFulu) (*SignedBe
|
||||
Signature: hexutil.Encode(b.Signature),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Gloas
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
func SignedBeaconBlockGloasFromConsensus(b *eth.SignedBeaconBlockGloas) (*SignedBeaconBlockGloas, error) {
|
||||
block, err := BeaconBlockGloasFromConsensus(b.Block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SignedBeaconBlockGloas{
|
||||
Message: block,
|
||||
Signature: hexutil.Encode(b.Signature),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func BeaconBlockGloasFromConsensus(b *eth.BeaconBlockGloas) (*BeaconBlockGloas, error) {
|
||||
payloadAttestations := make([]*PayloadAttestation, len(b.Body.PayloadAttestations))
|
||||
for i, pa := range b.Body.PayloadAttestations {
|
||||
payloadAttestations[i] = PayloadAttestationFromConsensus(pa)
|
||||
}
|
||||
|
||||
return &BeaconBlockGloas{
|
||||
Slot: fmt.Sprintf("%d", b.Slot),
|
||||
ProposerIndex: fmt.Sprintf("%d", b.ProposerIndex),
|
||||
ParentRoot: hexutil.Encode(b.ParentRoot),
|
||||
StateRoot: hexutil.Encode(b.StateRoot),
|
||||
Body: &BeaconBlockBodyGloas{
|
||||
RandaoReveal: hexutil.Encode(b.Body.RandaoReveal),
|
||||
Eth1Data: Eth1DataFromConsensus(b.Body.Eth1Data),
|
||||
Graffiti: hexutil.Encode(b.Body.Graffiti),
|
||||
ProposerSlashings: ProposerSlashingsFromConsensus(b.Body.ProposerSlashings),
|
||||
AttesterSlashings: AttesterSlashingsElectraFromConsensus(b.Body.AttesterSlashings),
|
||||
Attestations: AttsElectraFromConsensus(b.Body.Attestations),
|
||||
Deposits: DepositsFromConsensus(b.Body.Deposits),
|
||||
VoluntaryExits: SignedExitsFromConsensus(b.Body.VoluntaryExits),
|
||||
SyncAggregate: SyncAggregateFromConsensus(b.Body.SyncAggregate),
|
||||
BLSToExecutionChanges: SignedBLSChangesFromConsensus(b.Body.BlsToExecutionChanges),
|
||||
SignedExecutionPayloadBid: SignedExecutionPayloadBidFromConsensus(b.Body.SignedExecutionPayloadBid),
|
||||
PayloadAttestations: payloadAttestations,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func SignedExecutionPayloadBidFromConsensus(b *eth.SignedExecutionPayloadBid) *SignedExecutionPayloadBid {
|
||||
return &SignedExecutionPayloadBid{
|
||||
Message: ExecutionPayloadBidFromConsensus(b.Message),
|
||||
Signature: hexutil.Encode(b.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
func ExecutionPayloadBidFromConsensus(b *eth.ExecutionPayloadBid) *ExecutionPayloadBid {
|
||||
return &ExecutionPayloadBid{
|
||||
ParentBlockHash: hexutil.Encode(b.ParentBlockHash),
|
||||
ParentBlockRoot: hexutil.Encode(b.ParentBlockRoot),
|
||||
BlockHash: hexutil.Encode(b.BlockHash),
|
||||
PrevRandao: hexutil.Encode(b.PrevRandao),
|
||||
FeeRecipient: hexutil.Encode(b.FeeRecipient),
|
||||
GasLimit: fmt.Sprintf("%d", b.GasLimit),
|
||||
BuilderIndex: fmt.Sprintf("%d", b.BuilderIndex),
|
||||
Slot: fmt.Sprintf("%d", b.Slot),
|
||||
Value: fmt.Sprintf("%d", b.Value),
|
||||
ExecutionPayment: fmt.Sprintf("%d", b.ExecutionPayment),
|
||||
BlobKzgCommitmentsRoot: hexutil.Encode(b.BlobKzgCommitmentsRoot),
|
||||
}
|
||||
}
|
||||
|
||||
func PayloadAttestationFromConsensus(pa *eth.PayloadAttestation) *PayloadAttestation {
|
||||
return &PayloadAttestation{
|
||||
AggregationBits: hexutil.Encode(pa.AggregationBits),
|
||||
Data: PayloadAttestationDataFromConsensus(pa.Data),
|
||||
Signature: hexutil.Encode(pa.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
func PayloadAttestationDataFromConsensus(d *eth.PayloadAttestationData) *PayloadAttestationData {
|
||||
return &PayloadAttestationData{
|
||||
BeaconBlockRoot: hexutil.Encode(d.BeaconBlockRoot),
|
||||
Slot: fmt.Sprintf("%d", d.Slot),
|
||||
PayloadPresent: d.PayloadPresent,
|
||||
BlobDataAvailable: d.BlobDataAvailable,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SignedBeaconBlockGloas) ToConsensus() (*eth.SignedBeaconBlockGloas, error) {
|
||||
if b == nil {
|
||||
return nil, errNilValue
|
||||
}
|
||||
|
||||
sig, err := bytesutil.DecodeHexWithLength(b.Signature, fieldparams.BLSSignatureLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Signature")
|
||||
}
|
||||
block, err := b.Message.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Message")
|
||||
}
|
||||
return ð.SignedBeaconBlockGloas{
|
||||
Block: block,
|
||||
Signature: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlockGloas) ToConsensus() (*eth.BeaconBlockGloas, error) {
|
||||
if b == nil {
|
||||
return nil, errNilValue
|
||||
}
|
||||
if b.Body == nil {
|
||||
return nil, server.NewDecodeError(errNilValue, "Body")
|
||||
}
|
||||
if b.Body.Eth1Data == nil {
|
||||
return nil, server.NewDecodeError(errNilValue, "Body.Eth1Data")
|
||||
}
|
||||
if b.Body.SyncAggregate == nil {
|
||||
return nil, server.NewDecodeError(errNilValue, "Body.SyncAggregate")
|
||||
}
|
||||
if b.Body.SignedExecutionPayloadBid == nil {
|
||||
return nil, server.NewDecodeError(errNilValue, "Body.SignedExecutionPayloadBid")
|
||||
}
|
||||
|
||||
slot, err := strconv.ParseUint(b.Slot, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Slot")
|
||||
}
|
||||
proposerIndex, err := strconv.ParseUint(b.ProposerIndex, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "ProposerIndex")
|
||||
}
|
||||
parentRoot, err := bytesutil.DecodeHexWithLength(b.ParentRoot, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "ParentRoot")
|
||||
}
|
||||
stateRoot, err := bytesutil.DecodeHexWithLength(b.StateRoot, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "StateRoot")
|
||||
}
|
||||
body, err := b.Body.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Body")
|
||||
}
|
||||
return ð.BeaconBlockGloas{
|
||||
Slot: primitives.Slot(slot),
|
||||
ProposerIndex: primitives.ValidatorIndex(proposerIndex),
|
||||
ParentRoot: parentRoot,
|
||||
StateRoot: stateRoot,
|
||||
Body: body,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlockBodyGloas) ToConsensus() (*eth.BeaconBlockBodyGloas, error) {
|
||||
if b == nil {
|
||||
return nil, errNilValue
|
||||
}
|
||||
|
||||
randaoReveal, err := bytesutil.DecodeHexWithLength(b.RandaoReveal, fieldparams.BLSSignatureLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "RandaoReveal")
|
||||
}
|
||||
depositRoot, err := bytesutil.DecodeHexWithLength(b.Eth1Data.DepositRoot, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Eth1Data.DepositRoot")
|
||||
}
|
||||
depositCount, err := strconv.ParseUint(b.Eth1Data.DepositCount, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Eth1Data.DepositCount")
|
||||
}
|
||||
blockHash, err := bytesutil.DecodeHexWithLength(b.Eth1Data.BlockHash, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Eth1Data.BlockHash")
|
||||
}
|
||||
graffiti, err := bytesutil.DecodeHexWithLength(b.Graffiti, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Graffiti")
|
||||
}
|
||||
proposerSlashings, err := ProposerSlashingsToConsensus(b.ProposerSlashings)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "ProposerSlashings")
|
||||
}
|
||||
attesterSlashings, err := AttesterSlashingsElectraToConsensus(b.AttesterSlashings)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "AttesterSlashings")
|
||||
}
|
||||
atts, err := AttsElectraToConsensus(b.Attestations)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Attestations")
|
||||
}
|
||||
deposits, err := DepositsToConsensus(b.Deposits)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Deposits")
|
||||
}
|
||||
exits, err := SignedExitsToConsensus(b.VoluntaryExits)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "VoluntaryExits")
|
||||
}
|
||||
syncCommitteeBits, err := bytesutil.DecodeHexWithLength(b.SyncAggregate.SyncCommitteeBits, fieldparams.SyncAggregateSyncCommitteeBytesLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "SyncAggregate.SyncCommitteeBits")
|
||||
}
|
||||
syncCommitteeSig, err := bytesutil.DecodeHexWithLength(b.SyncAggregate.SyncCommitteeSignature, fieldparams.BLSSignatureLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "SyncAggregate.SyncCommitteeSignature")
|
||||
}
|
||||
blsChanges, err := SignedBLSChangesToConsensus(b.BLSToExecutionChanges)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "BLSToExecutionChanges")
|
||||
}
|
||||
signedBid, err := b.SignedExecutionPayloadBid.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "SignedExecutionPayloadBid")
|
||||
}
|
||||
payloadAttestations, err := PayloadAttestationsToConsensus(b.PayloadAttestations)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "PayloadAttestations")
|
||||
}
|
||||
|
||||
return ð.BeaconBlockBodyGloas{
|
||||
RandaoReveal: randaoReveal,
|
||||
Eth1Data: ð.Eth1Data{
|
||||
DepositRoot: depositRoot,
|
||||
DepositCount: depositCount,
|
||||
BlockHash: blockHash,
|
||||
},
|
||||
Graffiti: graffiti,
|
||||
ProposerSlashings: proposerSlashings,
|
||||
AttesterSlashings: attesterSlashings,
|
||||
Attestations: atts,
|
||||
Deposits: deposits,
|
||||
VoluntaryExits: exits,
|
||||
SyncAggregate: ð.SyncAggregate{
|
||||
SyncCommitteeBits: syncCommitteeBits,
|
||||
SyncCommitteeSignature: syncCommitteeSig,
|
||||
},
|
||||
BlsToExecutionChanges: blsChanges,
|
||||
SignedExecutionPayloadBid: signedBid,
|
||||
PayloadAttestations: payloadAttestations,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *SignedExecutionPayloadBid) ToConsensus() (*eth.SignedExecutionPayloadBid, error) {
|
||||
if b == nil {
|
||||
return nil, errNilValue
|
||||
}
|
||||
sig, err := bytesutil.DecodeHexWithLength(b.Signature, fieldparams.BLSSignatureLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Signature")
|
||||
}
|
||||
message, err := b.Message.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Message")
|
||||
}
|
||||
return ð.SignedExecutionPayloadBid{
|
||||
Message: message,
|
||||
Signature: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *ExecutionPayloadBid) ToConsensus() (*eth.ExecutionPayloadBid, error) {
|
||||
if b == nil {
|
||||
return nil, errNilValue
|
||||
}
|
||||
parentBlockHash, err := bytesutil.DecodeHexWithLength(b.ParentBlockHash, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "ParentBlockHash")
|
||||
}
|
||||
parentBlockRoot, err := bytesutil.DecodeHexWithLength(b.ParentBlockRoot, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "ParentBlockRoot")
|
||||
}
|
||||
blockHash, err := bytesutil.DecodeHexWithLength(b.BlockHash, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "BlockHash")
|
||||
}
|
||||
prevRandao, err := bytesutil.DecodeHexWithLength(b.PrevRandao, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "PrevRandao")
|
||||
}
|
||||
feeRecipient, err := bytesutil.DecodeHexWithLength(b.FeeRecipient, fieldparams.FeeRecipientLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "FeeRecipient")
|
||||
}
|
||||
gasLimit, err := strconv.ParseUint(b.GasLimit, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "GasLimit")
|
||||
}
|
||||
builderIndex, err := strconv.ParseUint(b.BuilderIndex, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "BuilderIndex")
|
||||
}
|
||||
slot, err := strconv.ParseUint(b.Slot, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Slot")
|
||||
}
|
||||
value, err := strconv.ParseUint(b.Value, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Value")
|
||||
}
|
||||
executionPayment, err := strconv.ParseUint(b.ExecutionPayment, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "ExecutionPayment")
|
||||
}
|
||||
blobKzgCommitmentsRoot, err := bytesutil.DecodeHexWithLength(b.BlobKzgCommitmentsRoot, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "BlobKzgCommitmentsRoot")
|
||||
}
|
||||
return ð.ExecutionPayloadBid{
|
||||
ParentBlockHash: parentBlockHash,
|
||||
ParentBlockRoot: parentBlockRoot,
|
||||
BlockHash: blockHash,
|
||||
PrevRandao: prevRandao,
|
||||
FeeRecipient: feeRecipient,
|
||||
GasLimit: gasLimit,
|
||||
BuilderIndex: primitives.BuilderIndex(builderIndex),
|
||||
Slot: primitives.Slot(slot),
|
||||
Value: primitives.Gwei(value),
|
||||
ExecutionPayment: primitives.Gwei(executionPayment),
|
||||
BlobKzgCommitmentsRoot: blobKzgCommitmentsRoot,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func PayloadAttestationsToConsensus(pa []*PayloadAttestation) ([]*eth.PayloadAttestation, error) {
|
||||
if pa == nil {
|
||||
return nil, errNilValue
|
||||
}
|
||||
result := make([]*eth.PayloadAttestation, len(pa))
|
||||
for i, p := range pa {
|
||||
converted, err := p.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, fmt.Sprintf("[%d]", i))
|
||||
}
|
||||
result[i] = converted
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *PayloadAttestation) ToConsensus() (*eth.PayloadAttestation, error) {
|
||||
if p == nil {
|
||||
return nil, errNilValue
|
||||
}
|
||||
aggregationBits, err := hexutil.Decode(p.AggregationBits)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "AggregationBits")
|
||||
}
|
||||
data, err := p.Data.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Data")
|
||||
}
|
||||
sig, err := bytesutil.DecodeHexWithLength(p.Signature, fieldparams.BLSSignatureLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Signature")
|
||||
}
|
||||
return ð.PayloadAttestation{
|
||||
AggregationBits: aggregationBits,
|
||||
Data: data,
|
||||
Signature: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *PayloadAttestationData) ToConsensus() (*eth.PayloadAttestationData, error) {
|
||||
if d == nil {
|
||||
return nil, errNilValue
|
||||
}
|
||||
beaconBlockRoot, err := bytesutil.DecodeHexWithLength(d.BeaconBlockRoot, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "BeaconBlockRoot")
|
||||
}
|
||||
slot, err := strconv.ParseUint(d.Slot, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Slot")
|
||||
}
|
||||
return ð.PayloadAttestationData{
|
||||
BeaconBlockRoot: beaconBlockRoot,
|
||||
Slot: primitives.Slot(slot),
|
||||
PayloadPresent: d.PayloadPresent,
|
||||
BlobDataAvailable: d.BlobDataAvailable,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"bid.go",
|
||||
"payload_attestation.go",
|
||||
"pending_payment.go",
|
||||
"proposer_slashing.go",
|
||||
],
|
||||
@@ -14,12 +15,16 @@ go_library(
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
@@ -30,6 +35,7 @@ go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"bid_test.go",
|
||||
"payload_attestation_test.go",
|
||||
"pending_payment_test.go",
|
||||
"proposer_slashing_test.go",
|
||||
],
|
||||
@@ -40,6 +46,7 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
@@ -50,8 +57,10 @@ go_test(
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
253
beacon-chain/core/gloas/payload_attestation.go
Normal file
253
beacon-chain/core/gloas/payload_attestation.go
Normal file
@@ -0,0 +1,253 @@
|
||||
package gloas
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
consensus_types "github.com/OffchainLabs/prysm/v7/consensus-types"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/hash"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ProcessPayloadAttestations validates payload attestations in a block body.
|
||||
// Spec v1.7.0-alpha.0 (pseudocode):
|
||||
// process_payload_attestation(state: BeaconState, payload_attestation: PayloadAttestation):
|
||||
//
|
||||
// data = payload_attestation.data
|
||||
// assert data.beacon_block_root == state.latest_block_header.parent_root
|
||||
// assert data.slot + 1 == state.slot
|
||||
// indexed = get_indexed_payload_attestation(state, data.slot, payload_attestation)
|
||||
// assert is_valid_indexed_payload_attestation(state, indexed)
|
||||
func ProcessPayloadAttestations(ctx context.Context, st state.BeaconState, body interfaces.ReadOnlyBeaconBlockBody) error {
|
||||
atts, err := body.PayloadAttestations()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get payload attestations from block body")
|
||||
}
|
||||
if len(atts) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
header := st.LatestBlockHeader()
|
||||
|
||||
for i, att := range atts {
|
||||
data := att.Data
|
||||
if !bytes.Equal(data.BeaconBlockRoot, header.ParentRoot) {
|
||||
return fmt.Errorf("payload attestation %d has wrong parent: got %x want %x", i, data.BeaconBlockRoot, header.ParentRoot)
|
||||
}
|
||||
|
||||
dataSlot, err := data.Slot.SafeAdd(1)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "payload attestation %d has invalid slot addition", i)
|
||||
}
|
||||
if dataSlot != st.Slot() {
|
||||
return fmt.Errorf("payload attestation %d has wrong slot: got %d want %d", i, data.Slot+1, st.Slot())
|
||||
}
|
||||
|
||||
indexed, err := indexedPayloadAttestation(ctx, st, att)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "payload attestation %d failed to convert to indexed form", i)
|
||||
}
|
||||
if err := validIndexedPayloadAttestation(st, indexed); err != nil {
|
||||
return errors.Wrapf(err, "payload attestation %d failed to verify indexed form", i)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// indexedPayloadAttestation converts a payload attestation into its indexed form.
|
||||
func indexedPayloadAttestation(ctx context.Context, st state.ReadOnlyBeaconState, att *eth.PayloadAttestation) (*consensus_types.IndexedPayloadAttestation, error) {
|
||||
committee, err := payloadCommittee(ctx, st, att.Data.Slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
indices := make([]primitives.ValidatorIndex, 0, len(committee))
|
||||
for i, idx := range committee {
|
||||
if att.AggregationBits.BitAt(uint64(i)) {
|
||||
indices = append(indices, idx)
|
||||
}
|
||||
}
|
||||
slices.Sort(indices)
|
||||
|
||||
return &consensus_types.IndexedPayloadAttestation{
|
||||
AttestingIndices: indices,
|
||||
Data: att.Data,
|
||||
Signature: att.Signature,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// payloadCommittee returns the payload timeliness committee for a given slot for the state.
|
||||
// Spec v1.7.0-alpha.0 (pseudocode):
|
||||
// get_ptc(state: BeaconState, slot: Slot) -> Vector[ValidatorIndex, PTC_SIZE]:
|
||||
//
|
||||
// epoch = compute_epoch_at_slot(slot)
|
||||
// seed = hash(get_seed(state, epoch, DOMAIN_PTC_ATTESTER) + uint_to_bytes(slot))
|
||||
// indices = []
|
||||
// committees_per_slot = get_committee_count_per_slot(state, epoch)
|
||||
// for i in range(committees_per_slot):
|
||||
// committee = get_beacon_committee(state, slot, CommitteeIndex(i))
|
||||
// indices.extend(committee)
|
||||
// return compute_balance_weighted_selection(state, indices, seed, size=PTC_SIZE, shuffle_indices=False)
|
||||
func payloadCommittee(ctx context.Context, st state.ReadOnlyBeaconState, slot primitives.Slot) ([]primitives.ValidatorIndex, error) {
|
||||
epoch := slots.ToEpoch(slot)
|
||||
seed, err := ptcSeed(st, epoch, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
activeCount, err := helpers.ActiveValidatorCount(ctx, st, epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
committeesPerSlot := helpers.SlotCommitteeCount(activeCount)
|
||||
out := make([]primitives.ValidatorIndex, 0, activeCount/uint64(params.BeaconConfig().SlotsPerEpoch))
|
||||
|
||||
for i := primitives.CommitteeIndex(0); i < primitives.CommitteeIndex(committeesPerSlot); i++ {
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, st, slot, i)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get beacon committee %d", i)
|
||||
}
|
||||
out = append(out, committee...)
|
||||
}
|
||||
|
||||
return selectByBalance(ctx, st, out, seed, fieldparams.PTCSize)
|
||||
}
|
||||
|
||||
// ptcSeed computes the seed for the payload timeliness committee.
|
||||
func ptcSeed(st state.ReadOnlyBeaconState, epoch primitives.Epoch, slot primitives.Slot) ([32]byte, error) {
|
||||
seed, err := helpers.Seed(st, epoch, params.BeaconConfig().DomainPTCAttester)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
return hash.Hash(append(seed[:], bytesutil.Bytes8(uint64(slot))...)), nil
|
||||
}
|
||||
|
||||
// selectByBalance selects a balance-weighted subset of input candidates.
|
||||
// Spec v1.7.0-alpha.0 (pseudocode):
|
||||
// compute_balance_weighted_selection(state, indices, seed, size, shuffle_indices):
|
||||
// Note: shuffle_indices is false for PTC.
|
||||
//
|
||||
// total = len(indices); selected = []; i = 0
|
||||
// while len(selected) < size:
|
||||
// next = i % total
|
||||
// if shuffle_indices: next = compute_shuffled_index(next, total, seed)
|
||||
// if compute_balance_weighted_acceptance(state, indices[next], seed, i):
|
||||
// selected.append(indices[next])
|
||||
// i += 1
|
||||
func selectByBalance(ctx context.Context, st state.ReadOnlyBeaconState, candidates []primitives.ValidatorIndex, seed [32]byte, count uint64) ([]primitives.ValidatorIndex, error) {
|
||||
if len(candidates) == 0 {
|
||||
return nil, errors.New("no candidates for balance weighted selection")
|
||||
}
|
||||
|
||||
hashFunc := hash.CustomSHA256Hasher()
|
||||
// Pre-allocate buffer for hash input: seed (32 bytes) + round counter (8 bytes).
|
||||
var buf [40]byte
|
||||
copy(buf[:], seed[:])
|
||||
maxBalance := params.BeaconConfig().MaxEffectiveBalanceElectra
|
||||
|
||||
selected := make([]primitives.ValidatorIndex, 0, count)
|
||||
total := uint64(len(candidates))
|
||||
for i := uint64(0); uint64(len(selected)) < count; i++ {
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
idx := candidates[i%total]
|
||||
ok, err := acceptByBalance(st, idx, buf[:], hashFunc, maxBalance, i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
selected = append(selected, idx)
|
||||
}
|
||||
}
|
||||
return selected, nil
|
||||
}
|
||||
|
||||
// acceptByBalance determines if a validator is accepted based on its effective balance.
|
||||
// Spec v1.7.0-alpha.0 (pseudocode):
|
||||
// compute_balance_weighted_acceptance(state, index, seed, i):
|
||||
//
|
||||
// MAX_RANDOM_VALUE = 2**16 - 1
|
||||
// random_bytes = hash(seed + uint_to_bytes(i // 16))
|
||||
// offset = i % 16 * 2
|
||||
// random_value = bytes_to_uint64(random_bytes[offset:offset+2])
|
||||
// effective_balance = state.validators[index].effective_balance
|
||||
// return effective_balance * MAX_RANDOM_VALUE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_value
|
||||
func acceptByBalance(st state.ReadOnlyBeaconState, idx primitives.ValidatorIndex, seedBuf []byte, hashFunc func([]byte) [32]byte, maxBalance uint64, round uint64) (bool, error) {
|
||||
// Reuse the seed buffer by overwriting the last 8 bytes with the round counter.
|
||||
binary.LittleEndian.PutUint64(seedBuf[len(seedBuf)-8:], round/16)
|
||||
random := hashFunc(seedBuf)
|
||||
offset := (round % 16) * 2
|
||||
randomValue := uint64(binary.LittleEndian.Uint16(random[offset : offset+2])) // 16-bit draw per spec
|
||||
|
||||
val, err := st.ValidatorAtIndex(idx)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "validator %d", idx)
|
||||
}
|
||||
|
||||
return val.EffectiveBalance*fieldparams.MaxRandomValueElectra >= maxBalance*randomValue, nil
|
||||
}
|
||||
|
||||
// validIndexedPayloadAttestation verifies the signature of an indexed payload attestation.
|
||||
// Spec v1.7.0-alpha.0 (pseudocode):
|
||||
// is_valid_indexed_payload_attestation(state: BeaconState, indexed_payload_attestation: IndexedPayloadAttestation) -> bool:
|
||||
//
|
||||
// indices = indexed_payload_attestation.attesting_indices
|
||||
// return len(indices) > 0 and indices == sorted(indices) and
|
||||
// bls.FastAggregateVerify(
|
||||
// [state.validators[i].pubkey for i in indices],
|
||||
// compute_signing_root(indexed_payload_attestation.data, get_domain(state, DOMAIN_PTC_ATTESTER, compute_epoch_at_slot(attestation.data.slot)),
|
||||
// indexed_payload_attestation.signature,
|
||||
// )
|
||||
func validIndexedPayloadAttestation(st state.ReadOnlyBeaconState, att *consensus_types.IndexedPayloadAttestation) error {
|
||||
indices := att.AttestingIndices
|
||||
if len(indices) == 0 || !slices.IsSorted(indices) {
|
||||
return errors.New("attesting indices empty or unsorted")
|
||||
}
|
||||
|
||||
pubkeys := make([]bls.PublicKey, len(indices))
|
||||
for i, idx := range indices {
|
||||
val, err := st.ValidatorAtIndexReadOnly(idx)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "validator %d", idx)
|
||||
}
|
||||
keyBytes := val.PublicKey()
|
||||
key, err := bls.PublicKeyFromBytes(keyBytes[:])
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "pubkey %d", idx)
|
||||
}
|
||||
pubkeys[i] = key
|
||||
}
|
||||
|
||||
domain, err := signing.Domain(st.Fork(), slots.ToEpoch(att.Data.Slot), params.BeaconConfig().DomainPTCAttester, st.GenesisValidatorsRoot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
root, err := signing.ComputeSigningRoot(att.Data, domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sig, err := bls.SignatureFromBytes(att.Signature)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !sig.FastAggregateVerify(pubkeys, root) {
|
||||
return errors.New("invalid signature")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
305
beacon-chain/core/gloas/payload_attestation_test.go
Normal file
305
beacon-chain/core/gloas/payload_attestation_test.go
Normal file
@@ -0,0 +1,305 @@
|
||||
package gloas_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/go-bitfield"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls/common"
|
||||
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
testutil "github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
)
|
||||
|
||||
func TestProcessPayloadAttestations_WrongParent(t *testing.T) {
|
||||
setupTestConfig(t)
|
||||
|
||||
_, pk := newKey(t)
|
||||
st := newTestState(t, []*eth.Validator{activeValidator(pk)}, 1)
|
||||
require.NoError(t, st.SetSlot(2))
|
||||
parentRoot := bytes.Repeat([]byte{0xaa}, 32)
|
||||
require.NoError(t, st.SetLatestBlockHeader(ð.BeaconBlockHeader{ParentRoot: parentRoot}))
|
||||
|
||||
att := ð.PayloadAttestation{
|
||||
Data: ð.PayloadAttestationData{
|
||||
BeaconBlockRoot: bytes.Repeat([]byte{0xbb}, 32),
|
||||
Slot: 1,
|
||||
},
|
||||
AggregationBits: bitfield.NewBitvector512(),
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
body := buildBody(t, att)
|
||||
|
||||
err := gloas.ProcessPayloadAttestations(t.Context(), st, body)
|
||||
require.ErrorContains(t, "wrong parent", err)
|
||||
}
|
||||
|
||||
func TestProcessPayloadAttestations_WrongSlot(t *testing.T) {
|
||||
setupTestConfig(t)
|
||||
|
||||
_, pk := newKey(t)
|
||||
st := newTestState(t, []*eth.Validator{activeValidator(pk)}, 1)
|
||||
require.NoError(t, st.SetSlot(3))
|
||||
parentRoot := bytes.Repeat([]byte{0xaa}, 32)
|
||||
require.NoError(t, st.SetLatestBlockHeader(ð.BeaconBlockHeader{ParentRoot: parentRoot}))
|
||||
|
||||
att := ð.PayloadAttestation{
|
||||
Data: ð.PayloadAttestationData{
|
||||
BeaconBlockRoot: parentRoot,
|
||||
Slot: 1,
|
||||
},
|
||||
AggregationBits: bitfield.NewBitvector512(),
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
body := buildBody(t, att)
|
||||
|
||||
err := gloas.ProcessPayloadAttestations(t.Context(), st, body)
|
||||
require.ErrorContains(t, "wrong slot", err)
|
||||
}
|
||||
|
||||
func TestProcessPayloadAttestations_InvalidSignature(t *testing.T) {
|
||||
setupTestConfig(t)
|
||||
|
||||
_, pk1 := newKey(t)
|
||||
sk2, pk2 := newKey(t)
|
||||
vals := []*eth.Validator{activeValidator(pk1), activeValidator(pk2)}
|
||||
st := newTestState(t, vals, 2)
|
||||
parentRoot := bytes.Repeat([]byte{0xaa}, 32)
|
||||
require.NoError(t, st.SetLatestBlockHeader(ð.BeaconBlockHeader{ParentRoot: parentRoot}))
|
||||
|
||||
attData := ð.PayloadAttestationData{
|
||||
BeaconBlockRoot: parentRoot,
|
||||
Slot: 1,
|
||||
}
|
||||
att := ð.PayloadAttestation{
|
||||
Data: attData,
|
||||
AggregationBits: setBits(bitfield.NewBitvector512(), 0),
|
||||
Signature: signAttestation(t, st, attData, []common.SecretKey{sk2}),
|
||||
}
|
||||
body := buildBody(t, att)
|
||||
|
||||
err := gloas.ProcessPayloadAttestations(t.Context(), st, body)
|
||||
require.ErrorContains(t, "failed to verify indexed form", err)
|
||||
require.ErrorContains(t, "invalid signature", err)
|
||||
}
|
||||
|
||||
func TestProcessPayloadAttestations_EmptyAggregationBits(t *testing.T) {
|
||||
setupTestConfig(t)
|
||||
|
||||
_, pk := newKey(t)
|
||||
st := newTestState(t, []*eth.Validator{activeValidator(pk)}, 1)
|
||||
require.NoError(t, st.SetSlot(2))
|
||||
parentRoot := bytes.Repeat([]byte{0xaa}, 32)
|
||||
require.NoError(t, st.SetLatestBlockHeader(ð.BeaconBlockHeader{ParentRoot: parentRoot}))
|
||||
|
||||
attData := ð.PayloadAttestationData{
|
||||
BeaconBlockRoot: parentRoot,
|
||||
Slot: 1,
|
||||
}
|
||||
att := ð.PayloadAttestation{
|
||||
Data: attData,
|
||||
AggregationBits: bitfield.NewBitvector512(),
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
body := buildBody(t, att)
|
||||
|
||||
err := gloas.ProcessPayloadAttestations(t.Context(), st, body)
|
||||
require.ErrorContains(t, "failed to verify indexed form", err)
|
||||
require.ErrorContains(t, "attesting indices empty or unsorted", err)
|
||||
}
|
||||
|
||||
func TestProcessPayloadAttestations_HappyPath(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
setupTestConfig(t)
|
||||
|
||||
sk1, pk1 := newKey(t)
|
||||
sk2, pk2 := newKey(t)
|
||||
vals := []*eth.Validator{activeValidator(pk1), activeValidator(pk2)}
|
||||
|
||||
st := newTestState(t, vals, 2)
|
||||
parentRoot := bytes.Repeat([]byte{0xaa}, 32)
|
||||
require.NoError(t, st.SetLatestBlockHeader(ð.BeaconBlockHeader{ParentRoot: parentRoot}))
|
||||
|
||||
attData := ð.PayloadAttestationData{
|
||||
BeaconBlockRoot: parentRoot,
|
||||
Slot: 1,
|
||||
}
|
||||
aggBits := bitfield.NewBitvector512()
|
||||
aggBits.SetBitAt(0, true)
|
||||
aggBits.SetBitAt(1, true)
|
||||
|
||||
att := ð.PayloadAttestation{
|
||||
Data: attData,
|
||||
AggregationBits: aggBits,
|
||||
Signature: signAttestation(t, st, attData, []common.SecretKey{sk1, sk2}),
|
||||
}
|
||||
body := buildBody(t, att)
|
||||
|
||||
err := gloas.ProcessPayloadAttestations(t.Context(), st, body)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestProcessPayloadAttestations_MultipleAttestations(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
setupTestConfig(t)
|
||||
|
||||
sk1, pk1 := newKey(t)
|
||||
sk2, pk2 := newKey(t)
|
||||
vals := []*eth.Validator{activeValidator(pk1), activeValidator(pk2)}
|
||||
|
||||
st := newTestState(t, vals, 2)
|
||||
parentRoot := bytes.Repeat([]byte{0xaa}, 32)
|
||||
require.NoError(t, st.SetLatestBlockHeader(ð.BeaconBlockHeader{ParentRoot: parentRoot}))
|
||||
|
||||
attData1 := ð.PayloadAttestationData{
|
||||
BeaconBlockRoot: parentRoot,
|
||||
Slot: 1,
|
||||
}
|
||||
attData2 := ð.PayloadAttestationData{
|
||||
BeaconBlockRoot: parentRoot,
|
||||
Slot: 1,
|
||||
}
|
||||
|
||||
att1 := ð.PayloadAttestation{
|
||||
Data: attData1,
|
||||
AggregationBits: setBits(bitfield.NewBitvector512(), 0),
|
||||
Signature: signAttestation(t, st, attData1, []common.SecretKey{sk1}),
|
||||
}
|
||||
att2 := ð.PayloadAttestation{
|
||||
Data: attData2,
|
||||
AggregationBits: setBits(bitfield.NewBitvector512(), 1),
|
||||
Signature: signAttestation(t, st, attData2, []common.SecretKey{sk2}),
|
||||
}
|
||||
|
||||
body := buildBody(t, att1, att2)
|
||||
|
||||
err := gloas.ProcessPayloadAttestations(t.Context(), st, body)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestProcessPayloadAttestations_IndexedVerificationError(t *testing.T) {
|
||||
setupTestConfig(t)
|
||||
|
||||
_, pk := newKey(t)
|
||||
st := newTestState(t, []*eth.Validator{activeValidator(pk)}, 1)
|
||||
parentRoot := bytes.Repeat([]byte{0xaa}, 32)
|
||||
require.NoError(t, st.SetLatestBlockHeader(ð.BeaconBlockHeader{ParentRoot: parentRoot}))
|
||||
|
||||
attData := ð.PayloadAttestationData{
|
||||
BeaconBlockRoot: parentRoot,
|
||||
Slot: 0,
|
||||
}
|
||||
att := ð.PayloadAttestation{
|
||||
Data: attData,
|
||||
AggregationBits: setBits(bitfield.NewBitvector512(), 0),
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
body := buildBody(t, att)
|
||||
|
||||
errState := &validatorLookupErrState{
|
||||
BeaconState: st,
|
||||
errIndex: 0,
|
||||
}
|
||||
err := gloas.ProcessPayloadAttestations(t.Context(), errState, body)
|
||||
require.ErrorContains(t, "failed to verify indexed form", err)
|
||||
require.ErrorContains(t, "validator 0", err)
|
||||
}
|
||||
|
||||
func newTestState(t *testing.T, vals []*eth.Validator, slot primitives.Slot) state.BeaconState {
|
||||
st, err := testutil.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
for _, v := range vals {
|
||||
require.NoError(t, st.AppendValidator(v))
|
||||
require.NoError(t, st.AppendBalance(v.EffectiveBalance))
|
||||
}
|
||||
require.NoError(t, st.SetSlot(slot))
|
||||
require.NoError(t, helpers.UpdateCommitteeCache(t.Context(), st, slots.ToEpoch(slot)))
|
||||
return st
|
||||
}
|
||||
|
||||
func setupTestConfig(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.SlotsPerEpoch = 1
|
||||
cfg.MaxEffectiveBalanceElectra = cfg.MaxEffectiveBalance
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
}
|
||||
|
||||
func buildBody(t *testing.T, atts ...*eth.PayloadAttestation) interfaces.ReadOnlyBeaconBlockBody {
|
||||
body := ð.BeaconBlockBodyGloas{
|
||||
PayloadAttestations: atts,
|
||||
RandaoReveal: make([]byte, 96),
|
||||
Eth1Data: ð.Eth1Data{},
|
||||
Graffiti: make([]byte, 32),
|
||||
ProposerSlashings: []*eth.ProposerSlashing{},
|
||||
AttesterSlashings: []*eth.AttesterSlashingElectra{},
|
||||
Attestations: []*eth.AttestationElectra{},
|
||||
Deposits: []*eth.Deposit{},
|
||||
VoluntaryExits: []*eth.SignedVoluntaryExit{},
|
||||
SyncAggregate: ð.SyncAggregate{},
|
||||
BlsToExecutionChanges: []*eth.SignedBLSToExecutionChange{},
|
||||
}
|
||||
wrapped, err := blocks.NewBeaconBlockBody(body)
|
||||
require.NoError(t, err)
|
||||
return wrapped
|
||||
}
|
||||
|
||||
func setBits(bits bitfield.Bitvector512, idx uint64) bitfield.Bitvector512 {
|
||||
bits.SetBitAt(idx, true)
|
||||
return bits
|
||||
}
|
||||
|
||||
func activeValidator(pub []byte) *eth.Validator {
|
||||
return ð.Validator{
|
||||
PublicKey: pub,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ActivationEligibilityEpoch: 0,
|
||||
ActivationEpoch: 0,
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
func newKey(t *testing.T) (common.SecretKey, []byte) {
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
return sk, sk.PublicKey().Marshal()
|
||||
}
|
||||
|
||||
func signAttestation(t *testing.T, st state.ReadOnlyBeaconState, data *eth.PayloadAttestationData, sks []common.SecretKey) []byte {
|
||||
domain, err := signing.Domain(st.Fork(), slots.ToEpoch(data.Slot), params.BeaconConfig().DomainPTCAttester, st.GenesisValidatorsRoot())
|
||||
require.NoError(t, err)
|
||||
root, err := signing.ComputeSigningRoot(data, domain)
|
||||
require.NoError(t, err)
|
||||
|
||||
sigs := make([]common.Signature, len(sks))
|
||||
for i, sk := range sks {
|
||||
sigs[i] = sk.Sign(root[:])
|
||||
}
|
||||
agg := bls.AggregateSignatures(sigs)
|
||||
return agg.Marshal()
|
||||
}
|
||||
|
||||
type validatorLookupErrState struct {
|
||||
state.BeaconState
|
||||
errIndex primitives.ValidatorIndex
|
||||
}
|
||||
|
||||
// ValidatorAtIndexReadOnly is overridden to simulate a missing validator lookup.
|
||||
func (s *validatorLookupErrState) ValidatorAtIndexReadOnly(idx primitives.ValidatorIndex) (state.ReadOnlyValidator, error) {
|
||||
if idx == s.errIndex {
|
||||
return nil, state.ErrNilValidatorsInState
|
||||
}
|
||||
return s.BeaconState.ValidatorAtIndexReadOnly(idx)
|
||||
}
|
||||
@@ -413,7 +413,7 @@ func CreateDefaultLightClientUpdate(attestedBlock interfaces.ReadOnlySignedBeaco
|
||||
SyncCommitteeSignature: make([]byte, 96),
|
||||
},
|
||||
}
|
||||
case version.Electra, version.Fulu:
|
||||
case version.Electra, version.Fulu, version.Gloas:
|
||||
m = &pb.LightClientUpdateElectra{
|
||||
AttestedHeader: &pb.LightClientHeaderDeneb{
|
||||
Beacon: &pb.BeaconBlockHeader{
|
||||
@@ -515,7 +515,7 @@ func ComputeWithdrawalsRoot(payload interfaces.ExecutionData) ([]byte, error) {
|
||||
|
||||
func BlockToLightClientHeader(
|
||||
ctx context.Context,
|
||||
attestedBlockVersion int, // this is the version that the light client header should be in, based on the attested block.
|
||||
attestedBlockVersion int, // this is the version that the light client header should be in, based on the attested block.
|
||||
block interfaces.ReadOnlySignedBeaconBlock, // this block is either the attested block, or the finalized block. in case of the latter, we might need to upgrade it to the attested block's version.
|
||||
) (interfaces.LightClientHeader, error) {
|
||||
if block.Version() > attestedBlockVersion {
|
||||
@@ -543,7 +543,7 @@ func BlockToLightClientHeader(
|
||||
Execution: payloadHeader,
|
||||
ExecutionBranch: payloadProof,
|
||||
}
|
||||
case version.Deneb, version.Electra, version.Fulu:
|
||||
case version.Deneb, version.Electra, version.Fulu, version.Gloas:
|
||||
payloadHeader, payloadProof, err := makeExecutionAndProofDeneb(ctx, block)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not make execution payload header and proof")
|
||||
|
||||
@@ -50,6 +50,14 @@ import (
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// fillGloasBlockTestData populates a Gloas block with non-zero test values for the
|
||||
// Gloas-specific fields: SignedExecutionPayloadBid and PayloadAttestations.
|
||||
func fillGloasBlockTestData(b *eth.SignedBeaconBlockGloas, numPayloadAttestations int) {
|
||||
slot := b.Block.Slot
|
||||
b.Block.Body.SignedExecutionPayloadBid = util.GenerateTestSignedExecutionPayloadBid(slot)
|
||||
b.Block.Body.PayloadAttestations = util.GenerateTestPayloadAttestations(numPayloadAttestations, slot)
|
||||
}
|
||||
|
||||
func fillDBTestBlocks(ctx context.Context, t *testing.T, beaconDB db.Database) (*eth.SignedBeaconBlock, []*eth.BeaconBlockContainer) {
|
||||
parentRoot := [32]byte{1, 2, 3}
|
||||
genBlk := util.NewBeaconBlock()
|
||||
@@ -335,6 +343,50 @@ func TestGetBlockV2(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, blk, b)
|
||||
})
|
||||
t.Run("gloas", func(t *testing.T) {
|
||||
b := util.NewBeaconBlockGloas()
|
||||
b.Block.Slot = 123
|
||||
fillGloasBlockTestData(b, 2)
|
||||
sb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
mockBlockFetcher := &testutil.MockBlocker{BlockToReturn: sb}
|
||||
mockChainService := &chainMock.ChainService{
|
||||
FinalizedRoots: map[[32]byte]bool{},
|
||||
}
|
||||
s := &Server{
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
FinalizationFetcher: mockChainService,
|
||||
Blocker: mockBlockFetcher,
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockV2(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &structs.GetBlockV2Response{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
assert.Equal(t, version.String(version.Gloas), resp.Version)
|
||||
sbb := &structs.SignedBeaconBlockGloas{Message: &structs.BeaconBlockGloas{}}
|
||||
require.NoError(t, json.Unmarshal(resp.Data.Message, sbb.Message))
|
||||
sbb.Signature = resp.Data.Signature
|
||||
blk, err := sbb.ToConsensus()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, blk, b)
|
||||
|
||||
// Verify Gloas-specific fields are correctly serialized/deserialized
|
||||
require.NotNil(t, blk.Block.Body.SignedExecutionPayloadBid)
|
||||
assert.Equal(t, primitives.Slot(123), blk.Block.Body.SignedExecutionPayloadBid.Message.Slot)
|
||||
assert.Equal(t, primitives.BuilderIndex(1), blk.Block.Body.SignedExecutionPayloadBid.Message.BuilderIndex)
|
||||
require.Equal(t, 2, len(blk.Block.Body.PayloadAttestations))
|
||||
for _, att := range blk.Block.Body.PayloadAttestations {
|
||||
assert.Equal(t, primitives.Slot(123), att.Data.Slot)
|
||||
assert.Equal(t, true, att.Data.PayloadPresent)
|
||||
assert.Equal(t, true, att.Data.BlobDataAvailable)
|
||||
}
|
||||
})
|
||||
t.Run("execution optimistic", func(t *testing.T) {
|
||||
b := util.NewBeaconBlockBellatrix()
|
||||
sb, err := blocks.NewSignedBeaconBlock(b)
|
||||
@@ -574,6 +626,37 @@ func TestGetBlockSSZV2(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, sszExpected, writer.Body.Bytes())
|
||||
})
|
||||
t.Run("gloas", func(t *testing.T) {
|
||||
b := util.NewBeaconBlockGloas()
|
||||
b.Block.Slot = 123
|
||||
fillGloasBlockTestData(b, 2)
|
||||
sb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
|
||||
s := &Server{
|
||||
Blocker: &testutil.MockBlocker{BlockToReturn: sb},
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v2/beacon/blocks/{block_id}", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetBlockV2(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
assert.Equal(t, version.String(version.Gloas), writer.Header().Get(api.VersionHeader))
|
||||
sszExpected, err := b.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, sszExpected, writer.Body.Bytes())
|
||||
|
||||
// Verify SSZ round-trip preserves Gloas-specific fields
|
||||
decoded := ð.SignedBeaconBlockGloas{}
|
||||
require.NoError(t, decoded.UnmarshalSSZ(writer.Body.Bytes()))
|
||||
require.NotNil(t, decoded.Block.Body.SignedExecutionPayloadBid)
|
||||
assert.Equal(t, primitives.Slot(123), decoded.Block.Body.SignedExecutionPayloadBid.Message.Slot)
|
||||
require.Equal(t, 2, len(decoded.Block.Body.PayloadAttestations))
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetBlockAttestationsV2(t *testing.T) {
|
||||
|
||||
@@ -197,6 +197,9 @@ func TestGetSpec(t *testing.T) {
|
||||
var dbb [4]byte
|
||||
copy(dbb[:], []byte{'0', '0', '0', '8'})
|
||||
config.DomainBeaconBuilder = dbb
|
||||
var dptc [4]byte
|
||||
copy(dptc[:], []byte{'0', '0', '0', '8'})
|
||||
config.DomainPTCAttester = dptc
|
||||
var dam [4]byte
|
||||
copy(dam[:], []byte{'1', '0', '0', '0'})
|
||||
config.DomainApplicationMask = dam
|
||||
@@ -212,7 +215,7 @@ func TestGetSpec(t *testing.T) {
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp))
|
||||
data, ok := resp.Data.(map[string]any)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, 186, len(data))
|
||||
assert.Equal(t, 187, len(data))
|
||||
for k, v := range data {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
switch k {
|
||||
@@ -414,6 +417,8 @@ func TestGetSpec(t *testing.T) {
|
||||
assert.Equal(t, "0x30303036", v)
|
||||
case "DOMAIN_AGGREGATE_AND_PROOF":
|
||||
assert.Equal(t, "0x30303037", v)
|
||||
case "DOMAIN_PTC_ATTESTER":
|
||||
assert.Equal(t, "0x30303038", v)
|
||||
case "DOMAIN_APPLICATION_MASK":
|
||||
assert.Equal(t, "0x31303030", v)
|
||||
case "DOMAIN_SYNC_COMMITTEE":
|
||||
|
||||
3
changelog/bastin_add-cmd-to-gen-log.md
Normal file
3
changelog/bastin_add-cmd-to-gen-log.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Ignored
|
||||
|
||||
- add `cmd` and all it's subcategories to the log.go generation process.
|
||||
3
changelog/james-prysm_gloas-getblockv2-rest.md
Normal file
3
changelog/james-prysm_gloas-getblockv2-rest.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- gloas block return support for /eth/v2/beacon/blocks/{block_id} and /eth/v1/beacon/blocks/{block_id}/root endpoints.
|
||||
@@ -1,7 +0,0 @@
|
||||
### Changed
|
||||
|
||||
- gRPC fallback now matches rest api implementation and will also check and connect to only synced nodes.
|
||||
|
||||
### Removed
|
||||
|
||||
- gRPC resolver for load balancing, the new implementation matches rest api's so we should remove the resolver so it's handled the same way for consistency.
|
||||
2
changelog/potuz_hashtree_builds.md
Normal file
2
changelog/potuz_hashtree_builds.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Fixed
|
||||
- Fix hashtree release builds.
|
||||
3
changelog/ttsao_add-gloas-process-payload-att.md
Normal file
3
changelog/ttsao_add-gloas-process-payload-att.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- Add Gloas process payload attestation
|
||||
@@ -9,6 +9,7 @@ go_library(
|
||||
"defaults.go",
|
||||
"flags.go",
|
||||
"helpers.go",
|
||||
"log.go",
|
||||
"password_reader.go",
|
||||
"wrap_flags.go",
|
||||
],
|
||||
|
||||
@@ -2,7 +2,10 @@ load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["db.go"],
|
||||
srcs = [
|
||||
"db.go",
|
||||
"log.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/db",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
||||
@@ -4,12 +4,9 @@ import (
|
||||
beacondb "github.com/OffchainLabs/prysm/v7/beacon-chain/db"
|
||||
"github.com/OffchainLabs/prysm/v7/cmd"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/tos"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "db")
|
||||
|
||||
// Commands for interacting with a beacon chain database.
|
||||
var Commands = &cli.Command{
|
||||
Name: "db",
|
||||
|
||||
9
cmd/beacon-chain/db/log.go
Normal file
9
cmd/beacon-chain/db/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package db
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/beacon-chain/db")
|
||||
@@ -1,5 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package flags
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
var log = logrus.WithField("prefix", "flags")
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/beacon-chain/flags")
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package genesis
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
var log = logrus.WithField("prefix", "genesis")
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/beacon-chain/genesis")
|
||||
|
||||
@@ -2,7 +2,10 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["jwt.go"],
|
||||
srcs = [
|
||||
"jwt.go",
|
||||
"log.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/jwt",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/api"
|
||||
"github.com/OffchainLabs/prysm/v7/cmd"
|
||||
"github.com/OffchainLabs/prysm/v7/io/file"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -23,7 +22,7 @@ var Commands = &cli.Command{
|
||||
}),
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
if err := generateAuthSecretInFile(cliCtx); err != nil {
|
||||
logrus.WithError(err).Fatal("Could not generate jwt")
|
||||
log.WithError(err).Fatal("Could not generate jwt")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@@ -57,6 +56,6 @@ func generateAuthSecretInFile(c *cli.Context) error {
|
||||
if err := file.WriteFile(fileName, []byte(secret)); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Infof("Successfully wrote JSON-RPC authentication secret to file %s", fileName)
|
||||
log.Infof("Successfully wrote JSON-RPC authentication secret to file %s", fileName)
|
||||
return nil
|
||||
}
|
||||
|
||||
9
cmd/beacon-chain/jwt/log.go
Normal file
9
cmd/beacon-chain/jwt/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package jwt
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/beacon-chain/jwt")
|
||||
@@ -1,5 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package main
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
var log = logrus.WithField("prefix", "main")
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/beacon-chain")
|
||||
|
||||
@@ -2,7 +2,10 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["options.go"],
|
||||
srcs = [
|
||||
"log.go",
|
||||
"options.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/storage",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
||||
9
cmd/beacon-chain/storage/log.go
Normal file
9
cmd/beacon-chain/storage/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package storage
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/beacon-chain/storage")
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package main
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
var log = logrus.WithField("prefix", "main")
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/client-stats")
|
||||
|
||||
@@ -14,8 +14,6 @@ import (
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "node")
|
||||
|
||||
// ConfirmAction uses the passed in actionText as the confirmation text displayed in the terminal.
|
||||
// The user must enter Y or N to indicate whether they confirm the action detailed in the warning text.
|
||||
// Returns a boolean representing the user's answer.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package rest
|
||||
package cmd
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "api/rest")
|
||||
var log = logrus.WithField("package", "cmd")
|
||||
@@ -4,7 +4,10 @@ load("//tools:prysm_image.bzl", "prysm_image_upload")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["main.go"],
|
||||
srcs = [
|
||||
"log.go",
|
||||
"main.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/cmd/prysmctl",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"cmd.go",
|
||||
"download.go",
|
||||
"log.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/cmd/prysmctl/checkpointsync",
|
||||
visibility = ["//visibility:public"],
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/api/client"
|
||||
"github.com/OffchainLabs/prysm/v7/api/client/beacon"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/sync/checkpoint"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
|
||||
9
cmd/prysmctl/checkpointsync/log.go
Normal file
9
cmd/prysmctl/checkpointsync/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package checkpointsync
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/prysmctl/checkpointsync")
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"buckets.go",
|
||||
"cmd.go",
|
||||
"log.go",
|
||||
"query.go",
|
||||
"span.go",
|
||||
],
|
||||
|
||||
9
cmd/prysmctl/db/log.go
Normal file
9
cmd/prysmctl/db/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package db
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/prysmctl/db")
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
9
cmd/prysmctl/log.go
Normal file
9
cmd/prysmctl/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package main
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/prysmctl")
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/cmd/prysmctl/testnet"
|
||||
"github.com/OffchainLabs/prysm/v7/cmd/prysmctl/validator"
|
||||
"github.com/OffchainLabs/prysm/v7/cmd/prysmctl/weaksubjectivity"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package p2p
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
var log = logrus.WithField("prefix", "prysmctl-p2p")
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/prysmctl/p2p")
|
||||
|
||||
@@ -4,6 +4,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"generate_genesis.go",
|
||||
"log.go",
|
||||
"testnet.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/cmd/prysmctl/testnet",
|
||||
|
||||
@@ -43,7 +43,6 @@ var (
|
||||
GethGenesisJsonIn string
|
||||
GethGenesisJsonOut string
|
||||
}{}
|
||||
log = logrus.WithField("prefix", "genesis")
|
||||
outputSSZFlag = &cli.StringFlag{
|
||||
Name: "output-ssz",
|
||||
Destination: &generateGenesisStateFlags.OutputSSZ,
|
||||
|
||||
9
cmd/prysmctl/testnet/log.go
Normal file
9
cmd/prysmctl/testnet/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package testnet
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/prysmctl/testnet")
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"cmd.go",
|
||||
"error.go",
|
||||
"log.go",
|
||||
"proposer_settings.go",
|
||||
"withdraw.go",
|
||||
],
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/config/features"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/tos"
|
||||
"github.com/logrusorgru/aurora"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
|
||||
9
cmd/prysmctl/validator/log.go
Normal file
9
cmd/prysmctl/validator/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package validator
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/prysmctl/validator")
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
|
||||
validatorpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -143,7 +143,7 @@ func checkIfWithdrawsAreInPool(ctx context.Context, client *beacon.Client, reque
|
||||
}
|
||||
if len(requestMap) != 0 {
|
||||
for key, address := range requestMap {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"validatorIndex": key,
|
||||
"executionAddress:": address,
|
||||
}).Warn("Set withdrawal address message not found in the node's operations pool.")
|
||||
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"checkpoint.go",
|
||||
"cmd.go",
|
||||
"log.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/cmd/prysmctl/weaksubjectivity",
|
||||
visibility = ["//visibility:public"],
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/api/client"
|
||||
"github.com/OffchainLabs/prysm/v7/api/client/beacon"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/sync/checkpoint"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
|
||||
9
cmd/prysmctl/weaksubjectivity/log.go
Normal file
9
cmd/prysmctl/weaksubjectivity/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package weaksubjectivity
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/prysmctl/weaksubjectivity")
|
||||
@@ -5,6 +5,7 @@ load("//tools:prysm_image.bzl", "prysm_image_upload")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"log.go",
|
||||
"main.go",
|
||||
"usage.go",
|
||||
],
|
||||
|
||||
@@ -9,6 +9,7 @@ go_library(
|
||||
"exit.go",
|
||||
"import.go",
|
||||
"list.go",
|
||||
"log.go",
|
||||
"wallet_utils.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/cmd/validator/accounts",
|
||||
|
||||
@@ -7,12 +7,9 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/cmd/validator/flags"
|
||||
"github.com/OffchainLabs/prysm/v7/config/features"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/tos"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "accounts")
|
||||
|
||||
// Commands for managing Prysm validator accounts.
|
||||
var Commands = &cli.Command{
|
||||
Name: "accounts",
|
||||
|
||||
9
cmd/validator/accounts/log.go
Normal file
9
cmd/validator/accounts/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package accounts
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/validator/accounts")
|
||||
@@ -2,7 +2,10 @@ load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["db.go"],
|
||||
srcs = [
|
||||
"db.go",
|
||||
"log.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/cmd/validator/db",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
||||
@@ -4,12 +4,9 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/cmd"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/tos"
|
||||
validatordb "github.com/OffchainLabs/prysm/v7/validator/db"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "db")
|
||||
|
||||
var (
|
||||
// SourceDataDirFlag defines a path on disk where source Prysm databases are stored. Used for conversion.
|
||||
SourceDataDirFlag = &cli.StringFlag{
|
||||
|
||||
9
cmd/validator/db/log.go
Normal file
9
cmd/validator/db/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package db
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/validator/db")
|
||||
9
cmd/validator/log.go
Normal file
9
cmd/validator/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package main
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/validator")
|
||||
@@ -34,8 +34,6 @@ import (
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "main")
|
||||
|
||||
func startNode(ctx *cli.Context) error {
|
||||
// Verify if ToS is accepted.
|
||||
if err := tos.VerifyTosAcceptedOrPrompt(ctx); err != nil {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package historycmd
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
var log = logrus.WithField("prefix", "historycmd")
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/validator/slashing-protection")
|
||||
|
||||
@@ -4,6 +4,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"create.go",
|
||||
"log.go",
|
||||
"recover.go",
|
||||
"wallet.go",
|
||||
],
|
||||
|
||||
9
cmd/validator/wallet/log.go
Normal file
9
cmd/validator/wallet/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package wallet
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/validator/wallet")
|
||||
@@ -5,12 +5,9 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/cmd/validator/flags"
|
||||
"github.com/OffchainLabs/prysm/v7/config/features"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/tos"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "wallet")
|
||||
|
||||
// Commands for wallets for Prysm validators.
|
||||
var Commands = &cli.Command{
|
||||
Name: "wallet",
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
|
||||
// This file is created and regenerated automatically. Anything added here might get removed.
|
||||
package web
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
var log = logrus.WithField("prefix", "web")
|
||||
// The prefix for logs from this package will be the text after the last slash in the package path.
|
||||
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
|
||||
var log = logrus.WithField("package", "cmd/validator/web")
|
||||
|
||||
@@ -50,4 +50,7 @@ const (
|
||||
// Introduced in Fulu network upgrade.
|
||||
NumberOfColumns = 128 // NumberOfColumns refers to the specified number of data columns that can exist in a network.
|
||||
CellsPerBlob = 64 // CellsPerBlob refers to the number of cells in a (non-extended) blob.
|
||||
|
||||
// Introduced in Gloas network upgrade.
|
||||
PTCSize = 512 // PTCSize is the size of the payload timeliness committee.
|
||||
)
|
||||
|
||||
@@ -50,4 +50,7 @@ const (
|
||||
// Introduced in Fulu network upgrade.
|
||||
NumberOfColumns = 128 // NumberOfColumns refers to the specified number of data columns that can exist in a network.
|
||||
CellsPerBlob = 64 // CellsPerBlob refers to the number of cells in a (non-extended) blob.
|
||||
|
||||
// Introduced in Gloas network upgrade.
|
||||
PTCSize = 2 // PTCSize is the size of the payload timeliness committee.
|
||||
)
|
||||
|
||||
@@ -142,6 +142,7 @@ type BeaconChainConfig struct {
|
||||
DomainApplicationBuilder [4]byte `yaml:"DOMAIN_APPLICATION_BUILDER" spec:"true"` // DomainApplicationBuilder defines the BLS signature domain for application builder.
|
||||
DomainBLSToExecutionChange [4]byte `yaml:"DOMAIN_BLS_TO_EXECUTION_CHANGE" spec:"true"` // DomainBLSToExecutionChange defines the BLS signature domain to change withdrawal addresses to ETH1 prefix
|
||||
DomainBeaconBuilder [4]byte `yaml:"DOMAIN_BEACON_BUILDER" spec:"true"` // DomainBeaconBuilder defines the BLS signature domain for beacon block builder.
|
||||
DomainPTCAttester [4]byte `yaml:"DOMAIN_PTC_ATTESTER" spec:"true"` // DomainPTCAttester defines the BLS signature domain for payload transaction committee attester.
|
||||
|
||||
// Prysm constants.
|
||||
GenesisValidatorsRoot [32]byte // GenesisValidatorsRoot is the root hash of the genesis validators.
|
||||
|
||||
@@ -185,6 +185,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
DomainApplicationBuilder: bytesutil.Uint32ToBytes4(0x00000001),
|
||||
DomainBLSToExecutionChange: bytesutil.Uint32ToBytes4(0x0A000000),
|
||||
DomainBeaconBuilder: bytesutil.Uint32ToBytes4(0x0B000000),
|
||||
DomainPTCAttester: bytesutil.Uint32ToBytes4(0x0C000000),
|
||||
|
||||
// Prysm constants.
|
||||
GenesisValidatorsRoot: [32]byte{75, 54, 61, 185, 78, 40, 97, 32, 215, 110, 185, 5, 52, 15, 221, 78, 84, 191, 233, 240, 107, 243, 63, 246, 207, 90, 210, 127, 81, 27, 254, 149},
|
||||
|
||||
@@ -2,10 +2,15 @@ load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["types.go"],
|
||||
srcs = [
|
||||
"indexed_payload_attestation.go",
|
||||
"types.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/consensus-types",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
|
||||
36
consensus-types/indexed_payload_attestation.go
Normal file
36
consensus-types/indexed_payload_attestation.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package consensus_types
|
||||
|
||||
import (
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
type IndexedPayloadAttestation struct {
|
||||
AttestingIndices []primitives.ValidatorIndex
|
||||
Data *eth.PayloadAttestationData
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
// GetAttestingIndices returns the attesting indices or nil when the receiver is nil.
|
||||
func (x *IndexedPayloadAttestation) GetAttestingIndices() []primitives.ValidatorIndex {
|
||||
if x == nil {
|
||||
return nil
|
||||
}
|
||||
return x.AttestingIndices
|
||||
}
|
||||
|
||||
// GetData returns the attestation data or nil when the receiver is nil.
|
||||
func (x *IndexedPayloadAttestation) GetData() *eth.PayloadAttestationData {
|
||||
if x == nil {
|
||||
return nil
|
||||
}
|
||||
return x.Data
|
||||
}
|
||||
|
||||
// GetSignature returns the signature bytes or nil when the receiver is nil.
|
||||
func (x *IndexedPayloadAttestation) GetSignature() []byte {
|
||||
if x == nil {
|
||||
return nil
|
||||
}
|
||||
return x.Signature
|
||||
}
|
||||
@@ -14,7 +14,6 @@ EXCLUDED_PATH_PREFIXES=(
|
||||
"runtime"
|
||||
"monitoring"
|
||||
"io"
|
||||
"cmd"
|
||||
".well-known"
|
||||
"changelog"
|
||||
"hack"
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
package prefixed
|
||||
|
||||
var prefixReplacements = map[string]string{
|
||||
"cmd/beacon-chain": "main",
|
||||
"cmd/client-stats": "main",
|
||||
"cmd/prysmctl/p2p": "prysmctl-p2p",
|
||||
"cmd/prysmctl/testnet": "genesis",
|
||||
"cmd/validator/slashing-protection": "historycmd",
|
||||
"cmd/validator": "main",
|
||||
"cmd": "node",
|
||||
"beacon-chain/cache/depositsnapshot": "cache",
|
||||
"beacon-chain/core/transition": "state",
|
||||
"beacon-chain/db/kv": "db",
|
||||
|
||||
@@ -202,6 +202,7 @@ go_test(
|
||||
"fulu__ssz_static__ssz_static_test.go",
|
||||
"gloas__epoch_processing__process_builder_pending_payments_test.go",
|
||||
"gloas__operations__execution_payload_header_test.go",
|
||||
"gloas__operations__payload_attestation_test.go",
|
||||
"gloas__operations__proposer_slashing_test.go",
|
||||
"gloas__sanity__slots_test.go",
|
||||
"gloas__ssz_static__ssz_static_test.go",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package mainnet
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations"
|
||||
)
|
||||
|
||||
func TestMainnet_Gloas_Operations_PayloadAttestation(t *testing.T) {
|
||||
operations.RunPayloadAttestationTest(t, "mainnet")
|
||||
}
|
||||
@@ -208,6 +208,7 @@ go_test(
|
||||
"fulu__ssz_static__ssz_static_test.go",
|
||||
"gloas__epoch_processing__process_builder_pending_payments_test.go",
|
||||
"gloas__operations__execution_payload_bid_test.go",
|
||||
"gloas__operations__payload_attestation_test.go",
|
||||
"gloas__operations__proposer_slashing_test.go",
|
||||
"gloas__sanity__slots_test.go",
|
||||
"gloas__ssz_static__ssz_static_test.go",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package minimal
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations"
|
||||
)
|
||||
|
||||
func TestMinimal_Gloas_Operations_PayloadAttestation(t *testing.T) {
|
||||
operations.RunPayloadAttestationTest(t, "minimal")
|
||||
}
|
||||
@@ -13,6 +13,7 @@ go_library(
|
||||
"deposit_request.go",
|
||||
"execution_payload.go",
|
||||
"execution_payload_bid.go",
|
||||
"payload_attestation.go",
|
||||
"proposer_slashing.go",
|
||||
"slashing.go",
|
||||
"sync_aggregate.go",
|
||||
|
||||
122
testing/spectest/shared/common/operations/payload_attestation.go
Normal file
122
testing/spectest/shared/common/operations/payload_attestation.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/spectest/utils"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
"github.com/golang/snappy"
|
||||
)
|
||||
|
||||
type PayloadAttestationOperation func(ctx context.Context, s state.BeaconState, att *eth.PayloadAttestation) (state.BeaconState, error)
|
||||
|
||||
func RunPayloadAttestationTest(t *testing.T, config string, fork string, sszToState SSZToState) {
|
||||
runPayloadAttestationTest(t, config, fork, "payload_attestation", sszToState, func(ctx context.Context, s state.BeaconState, att *eth.PayloadAttestation) (state.BeaconState, error) {
|
||||
// Create a mock block body with the payload attestation
|
||||
body, err := createMockBlockBodyWithPayloadAttestation(att)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
// Wrap the protobuf body in the interface
|
||||
wrappedBody, err := blocks.NewBeaconBlockBody(body)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
err = gloas.ProcessPayloadAttestations(ctx, s, wrappedBody)
|
||||
return s, err
|
||||
})
|
||||
}
|
||||
|
||||
func runPayloadAttestationTest(t *testing.T, config string, fork string, objName string, sszToState SSZToState, operationFn PayloadAttestationOperation) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, fork, "operations/"+objName+"/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, fork, "operations/"+objName+"/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
|
||||
// Load payload attestation from payload_attestation.ssz_snappy
|
||||
attestationFile, err := util.BazelFileBytes(folderPath, "payload_attestation.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
attestationSSZ, err := snappy.Decode(nil /* dst */, attestationFile)
|
||||
require.NoError(t, err, "Failed to decompress payload attestation")
|
||||
|
||||
// Unmarshal payload attestation
|
||||
att := ð.PayloadAttestation{}
|
||||
err = att.UnmarshalSSZ(attestationSSZ)
|
||||
require.NoError(t, err, "Failed to unmarshal payload attestation")
|
||||
|
||||
runPayloadAttestationOperationTest(t, folderPath, att, sszToState, operationFn)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// runPayloadAttestationOperationTest runs a single payload attestation operation test
|
||||
func runPayloadAttestationOperationTest(t *testing.T, folderPath string, att *eth.PayloadAttestation, sszToState SSZToState, operationFn PayloadAttestationOperation) {
|
||||
preBeaconStateFile, err := util.BazelFileBytes(folderPath, "pre.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
beaconState, err := sszToState(preBeaconStateSSZ)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check if post state exists
|
||||
postStateExists := true
|
||||
postBeaconStateFile, err := util.BazelFileBytes(folderPath, "post.ssz_snappy")
|
||||
if err != nil {
|
||||
postStateExists = false
|
||||
}
|
||||
|
||||
ctx := t.Context()
|
||||
resultState, err := operationFn(ctx, beaconState, att)
|
||||
|
||||
if postStateExists {
|
||||
// Test should succeed
|
||||
require.NoError(t, err, "Operation should succeed")
|
||||
|
||||
// Compare with expected post state
|
||||
postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress post state")
|
||||
expectedState, err := sszToState(postBeaconStateSSZ)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedRoot, err := expectedState.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
resultRoot, err := resultState.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, expectedRoot, resultRoot, "Post state does not match expected")
|
||||
} else {
|
||||
// Test should fail (no post.ssz_snappy means the operation should error)
|
||||
require.NotNil(t, err, "Operation should fail but succeeded")
|
||||
}
|
||||
}
|
||||
|
||||
// createMockBlockBodyWithPayloadAttestation creates a mock block body containing the payload attestation
|
||||
func createMockBlockBodyWithPayloadAttestation(att *eth.PayloadAttestation) (*eth.BeaconBlockBodyGloas, error) {
|
||||
body := ð.BeaconBlockBodyGloas{
|
||||
PayloadAttestations: []*eth.PayloadAttestation{att},
|
||||
// Default values
|
||||
RandaoReveal: make([]byte, 96),
|
||||
Eth1Data: ð.Eth1Data{},
|
||||
Graffiti: make([]byte, 32),
|
||||
ProposerSlashings: []*eth.ProposerSlashing{},
|
||||
AttesterSlashings: []*eth.AttesterSlashingElectra{},
|
||||
Attestations: []*eth.AttestationElectra{},
|
||||
Deposits: []*eth.Deposit{},
|
||||
VoluntaryExits: []*eth.SignedVoluntaryExit{},
|
||||
SyncAggregate: ð.SyncAggregate{},
|
||||
BlsToExecutionChanges: []*eth.SignedBLSToExecutionChange{},
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
@@ -6,6 +6,7 @@ go_library(
|
||||
srcs = [
|
||||
"execution_payload_bid.go",
|
||||
"helpers.go",
|
||||
"payload_attestation.go",
|
||||
"proposer_slashing.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations",
|
||||
|
||||
@@ -15,7 +15,6 @@ func sszToState(b []byte) (state.BeaconState, error) {
|
||||
}
|
||||
return state_native.InitializeFromProtoGloas(base)
|
||||
}
|
||||
|
||||
func sszToBlock(b []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
base := ðpb.BeaconBlockGloas{}
|
||||
if err := base.UnmarshalSSZ(b); err != nil {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
common "github.com/OffchainLabs/prysm/v7/testing/spectest/shared/common/operations"
|
||||
)
|
||||
|
||||
func RunPayloadAttestationTest(t *testing.T, config string) {
|
||||
common.RunPayloadAttestationTest(t, config, version.String(version.Gloas), sszToState)
|
||||
}
|
||||
@@ -1473,3 +1473,185 @@ func HydrateBlindedBeaconBlockBodyFulu(b *ethpb.BlindedBeaconBlockBodyElectra) *
|
||||
b.ExecutionRequests = HydrateExecutionRequests(b.ExecutionRequests)
|
||||
return b
|
||||
}
|
||||
|
||||
// HydrateSignedBeaconBlockGloas hydrates a signed beacon block with correct field length sizes
|
||||
// to comply with fssz marshalling and unmarshalling rules.
|
||||
func HydrateSignedBeaconBlockGloas(b *ethpb.SignedBeaconBlockGloas) *ethpb.SignedBeaconBlockGloas {
|
||||
if b == nil {
|
||||
b = ðpb.SignedBeaconBlockGloas{}
|
||||
}
|
||||
if b.Signature == nil {
|
||||
b.Signature = make([]byte, fieldparams.BLSSignatureLength)
|
||||
}
|
||||
b.Block = HydrateBeaconBlockGloas(b.Block)
|
||||
return b
|
||||
}
|
||||
|
||||
// HydrateBeaconBlockGloas hydrates a beacon block with correct field length sizes
|
||||
// to comply with fssz marshalling and unmarshalling rules.
|
||||
func HydrateBeaconBlockGloas(b *ethpb.BeaconBlockGloas) *ethpb.BeaconBlockGloas {
|
||||
if b == nil {
|
||||
b = ðpb.BeaconBlockGloas{}
|
||||
}
|
||||
if b.ParentRoot == nil {
|
||||
b.ParentRoot = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
if b.StateRoot == nil {
|
||||
b.StateRoot = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
b.Body = HydrateBeaconBlockBodyGloas(b.Body)
|
||||
return b
|
||||
}
|
||||
|
||||
// HydrateBeaconBlockBodyGloas hydrates a beacon block body with correct field length sizes
|
||||
// to comply with fssz marshalling and unmarshalling rules.
|
||||
func HydrateBeaconBlockBodyGloas(b *ethpb.BeaconBlockBodyGloas) *ethpb.BeaconBlockBodyGloas {
|
||||
if b == nil {
|
||||
b = ðpb.BeaconBlockBodyGloas{}
|
||||
}
|
||||
if b.RandaoReveal == nil {
|
||||
b.RandaoReveal = make([]byte, fieldparams.BLSSignatureLength)
|
||||
}
|
||||
if b.Graffiti == nil {
|
||||
b.Graffiti = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
if b.Eth1Data == nil {
|
||||
b.Eth1Data = ðpb.Eth1Data{
|
||||
DepositRoot: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
}
|
||||
}
|
||||
if b.SyncAggregate == nil {
|
||||
b.SyncAggregate = ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: make([]byte, fieldparams.SyncAggregateSyncCommitteeBytesLength),
|
||||
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
}
|
||||
}
|
||||
b.SignedExecutionPayloadBid = HydrateSignedExecutionPayloadBid(b.SignedExecutionPayloadBid)
|
||||
if b.PayloadAttestations == nil {
|
||||
b.PayloadAttestations = make([]*ethpb.PayloadAttestation, 0)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// HydrateSignedExecutionPayloadBid hydrates a signed execution payload bid with correct field length sizes
|
||||
// to comply with fssz marshalling and unmarshalling rules.
|
||||
func HydrateSignedExecutionPayloadBid(b *ethpb.SignedExecutionPayloadBid) *ethpb.SignedExecutionPayloadBid {
|
||||
if b == nil {
|
||||
b = ðpb.SignedExecutionPayloadBid{}
|
||||
}
|
||||
if b.Signature == nil {
|
||||
b.Signature = make([]byte, fieldparams.BLSSignatureLength)
|
||||
}
|
||||
b.Message = HydrateExecutionPayloadBid(b.Message)
|
||||
return b
|
||||
}
|
||||
|
||||
// HydrateExecutionPayloadBid hydrates an execution payload bid with correct field length sizes
|
||||
// to comply with fssz marshalling and unmarshalling rules.
|
||||
func HydrateExecutionPayloadBid(b *ethpb.ExecutionPayloadBid) *ethpb.ExecutionPayloadBid {
|
||||
if b == nil {
|
||||
b = ðpb.ExecutionPayloadBid{}
|
||||
}
|
||||
if b.ParentBlockHash == nil {
|
||||
b.ParentBlockHash = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
if b.ParentBlockRoot == nil {
|
||||
b.ParentBlockRoot = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
if b.BlockHash == nil {
|
||||
b.BlockHash = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
if b.PrevRandao == nil {
|
||||
b.PrevRandao = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
if b.FeeRecipient == nil {
|
||||
b.FeeRecipient = make([]byte, fieldparams.FeeRecipientLength)
|
||||
}
|
||||
if b.BlobKzgCommitmentsRoot == nil {
|
||||
b.BlobKzgCommitmentsRoot = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// HydratePayloadAttestation hydrates a payload attestation with correct field length sizes
|
||||
// to comply with fssz marshalling and unmarshalling rules.
|
||||
func HydratePayloadAttestation(p *ethpb.PayloadAttestation) *ethpb.PayloadAttestation {
|
||||
if p == nil {
|
||||
p = ðpb.PayloadAttestation{}
|
||||
}
|
||||
if p.AggregationBits == nil {
|
||||
p.AggregationBits = make([]byte, 64)
|
||||
}
|
||||
if p.Signature == nil {
|
||||
p.Signature = make([]byte, fieldparams.BLSSignatureLength)
|
||||
}
|
||||
p.Data = HydratePayloadAttestationData(p.Data)
|
||||
return p
|
||||
}
|
||||
|
||||
// HydratePayloadAttestationData hydrates a payload attestation data with correct field length sizes
|
||||
// to comply with fssz marshalling and unmarshalling rules.
|
||||
func HydratePayloadAttestationData(d *ethpb.PayloadAttestationData) *ethpb.PayloadAttestationData {
|
||||
if d == nil {
|
||||
d = ðpb.PayloadAttestationData{}
|
||||
}
|
||||
if d.BeaconBlockRoot == nil {
|
||||
d.BeaconBlockRoot = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// GenerateTestPayloadAttestations generates a slice of payload attestations with non-zero test values.
|
||||
// This is useful for testing Gloas-specific fields.
|
||||
func GenerateTestPayloadAttestations(count int, slot primitives.Slot) []*ethpb.PayloadAttestation {
|
||||
attestations := make([]*ethpb.PayloadAttestation, count)
|
||||
for i := range count {
|
||||
aggregationBits := make([]byte, 64)
|
||||
aggregationBits[0] = 0x01 // Set at least one bit
|
||||
signature := make([]byte, fieldparams.BLSSignatureLength)
|
||||
signature[0] = byte(i + 1) // Make each signature unique
|
||||
beaconBlockRoot := make([]byte, fieldparams.RootLength)
|
||||
beaconBlockRoot[0] = byte(i + 1) // Make each root unique
|
||||
|
||||
attestations[i] = ðpb.PayloadAttestation{
|
||||
AggregationBits: aggregationBits,
|
||||
Signature: signature,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: beaconBlockRoot,
|
||||
Slot: slot,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
return attestations
|
||||
}
|
||||
|
||||
// GenerateTestSignedExecutionPayloadBid generates a signed execution payload bid with non-zero test values.
|
||||
// This is useful for testing Gloas-specific fields.
|
||||
func GenerateTestSignedExecutionPayloadBid(slot primitives.Slot) *ethpb.SignedExecutionPayloadBid {
|
||||
parentBlockHash := bytesutil.PadTo([]byte{0x01}, fieldparams.RootLength)
|
||||
parentBlockRoot := bytesutil.PadTo([]byte{0x02}, fieldparams.RootLength)
|
||||
blockHash := bytesutil.PadTo([]byte{0x03}, fieldparams.RootLength)
|
||||
prevRandao := bytesutil.PadTo([]byte{0x04}, fieldparams.RootLength)
|
||||
feeRecipient := bytesutil.PadTo([]byte{0x05}, fieldparams.FeeRecipientLength)
|
||||
blobKzgRoot := bytesutil.PadTo([]byte{0x06}, fieldparams.RootLength)
|
||||
signature := bytesutil.PadTo([]byte{0x07}, fieldparams.BLSSignatureLength)
|
||||
|
||||
return ðpb.SignedExecutionPayloadBid{
|
||||
Message: ðpb.ExecutionPayloadBid{
|
||||
Slot: slot,
|
||||
BuilderIndex: 1,
|
||||
ParentBlockHash: parentBlockHash,
|
||||
ParentBlockRoot: parentBlockRoot,
|
||||
BlockHash: blockHash,
|
||||
GasLimit: 30000000,
|
||||
PrevRandao: prevRandao,
|
||||
FeeRecipient: feeRecipient,
|
||||
Value: 1000000,
|
||||
BlobKzgCommitmentsRoot: blobKzgRoot,
|
||||
},
|
||||
Signature: signature,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,3 +348,81 @@ func Test_PostDenebPbGenericBlock_ErrorsForPlainBlock(t *testing.T) {
|
||||
require.ErrorContains(t, "PbGenericBlock() only supports block content type but got", err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHydrateSignedBeaconBlockGloas_NoError(t *testing.T) {
|
||||
b := ðpbalpha.SignedBeaconBlockGloas{}
|
||||
b = HydrateSignedBeaconBlockGloas(b)
|
||||
_, err := b.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
_, err = b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
_, err = b.Block.Body.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestHydratePayloadAttestation_NoError(t *testing.T) {
|
||||
p := ðpbalpha.PayloadAttestation{}
|
||||
p = HydratePayloadAttestation(p)
|
||||
_, err := p.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
_, err = p.Data.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGenerateTestPayloadAttestations(t *testing.T) {
|
||||
slot := primitives.Slot(123)
|
||||
attestations := GenerateTestPayloadAttestations(3, slot)
|
||||
|
||||
require.Equal(t, 3, len(attestations))
|
||||
for i, att := range attestations {
|
||||
// Verify non-nil fields
|
||||
require.NotNil(t, att.AggregationBits)
|
||||
require.NotNil(t, att.Signature)
|
||||
require.NotNil(t, att.Data)
|
||||
require.NotNil(t, att.Data.BeaconBlockRoot)
|
||||
|
||||
// Verify slot is set correctly
|
||||
require.Equal(t, slot, att.Data.Slot)
|
||||
|
||||
// Verify PayloadPresent and BlobDataAvailable are set
|
||||
require.Equal(t, true, att.Data.PayloadPresent)
|
||||
require.Equal(t, true, att.Data.BlobDataAvailable)
|
||||
|
||||
// Verify unique values
|
||||
require.Equal(t, byte(i+1), att.Signature[0])
|
||||
require.Equal(t, byte(i+1), att.Data.BeaconBlockRoot[0])
|
||||
|
||||
// Verify HashTreeRoot works
|
||||
_, err := att.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateTestSignedExecutionPayloadBid(t *testing.T) {
|
||||
slot := primitives.Slot(456)
|
||||
bid := GenerateTestSignedExecutionPayloadBid(slot)
|
||||
|
||||
require.NotNil(t, bid)
|
||||
require.NotNil(t, bid.Message)
|
||||
require.NotNil(t, bid.Signature)
|
||||
|
||||
// Verify slot is set correctly
|
||||
require.Equal(t, slot, bid.Message.Slot)
|
||||
|
||||
// Verify non-zero test values
|
||||
require.Equal(t, primitives.BuilderIndex(1), bid.Message.BuilderIndex)
|
||||
require.Equal(t, uint64(30000000), bid.Message.GasLimit)
|
||||
require.Equal(t, primitives.Gwei(1000000), bid.Message.Value)
|
||||
|
||||
// Verify fields are populated
|
||||
require.NotNil(t, bid.Message.ParentBlockHash)
|
||||
require.NotNil(t, bid.Message.ParentBlockRoot)
|
||||
require.NotNil(t, bid.Message.BlockHash)
|
||||
require.NotNil(t, bid.Message.PrevRandao)
|
||||
require.NotNil(t, bid.Message.FeeRecipient)
|
||||
require.NotNil(t, bid.Message.BlobKzgCommitmentsRoot)
|
||||
|
||||
// Verify HashTreeRoot works
|
||||
_, err := bid.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -88,3 +88,12 @@ func NewBeaconBlockContentsFulu() *ethpb.SignedBeaconBlockContentsFulu {
|
||||
func NewBlindedBeaconBlockFulu() *ethpb.SignedBlindedBeaconBlockFulu {
|
||||
return HydrateSignedBlindedBeaconBlockFulu(ðpb.SignedBlindedBeaconBlockFulu{})
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Gloas
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// NewBeaconBlockGloas creates a beacon block with minimum marshalable fields.
|
||||
func NewBeaconBlockGloas() *ethpb.SignedBeaconBlockGloas {
|
||||
return HydrateSignedBeaconBlockGloas(ðpb.SignedBeaconBlockGloas{})
|
||||
}
|
||||
|
||||
12
testing/validator-mock/validator_client_mock.go
generated
12
testing/validator-mock/validator_client_mock.go
generated
@@ -283,16 +283,16 @@ func (mr *MockValidatorClientMockRecorder) ProposeExit(ctx, in any) *gomock.Call
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProposeExit", reflect.TypeOf((*MockValidatorClient)(nil).ProposeExit), ctx, in)
|
||||
}
|
||||
|
||||
// SwitchHost mocks base method.
|
||||
func (m *MockValidatorClient) SwitchHost(host string) {
|
||||
// SetHost mocks base method.
|
||||
func (m *MockValidatorClient) SetHost(host string) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SwitchHost", host)
|
||||
m.ctrl.Call(m, "SetHost", host)
|
||||
}
|
||||
|
||||
// SwitchHost indicates an expected call of SwitchHost.
|
||||
func (mr *MockValidatorClientMockRecorder) SwitchHost(host any) *gomock.Call {
|
||||
// SetHost indicates an expected call of SetHost.
|
||||
func (mr *MockValidatorClientMockRecorder) SetHost(host any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SwitchHost", reflect.TypeOf((*MockValidatorClient)(nil).SwitchHost), host)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHost", reflect.TypeOf((*MockValidatorClient)(nil).SetHost), host)
|
||||
}
|
||||
|
||||
// StartEventStream mocks base method.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
diff -urN a/BUILD.bazel b/BUILD.bazel
|
||||
--- a/BUILD.bazel 1969-12-31 18:00:00.000000000 -0600
|
||||
+++ b/BUILD.bazel 2025-01-05 12:00:00.000000000 -0600
|
||||
@@ -0,0 +1,86 @@
|
||||
@@ -0,0 +1,89 @@
|
||||
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
+
|
||||
+go_library(
|
||||
@@ -44,14 +44,14 @@ diff -urN a/BUILD.bazel b/BUILD.bazel
|
||||
+ name = "hashtree_arm64_syso",
|
||||
+ srcs = [":hashtree_arm64"],
|
||||
+ outs = ["hashtree_arm64.syso"],
|
||||
+ cmd = "cp $(location :hashtree_arm64) $@",
|
||||
+ cmd = "cp $$(echo $(locations :hashtree_arm64) | tr ' ' '\\n' | grep -v '\\.pic\\.' | head -1) $@",
|
||||
+)
|
||||
+
|
||||
+genrule(
|
||||
+ name = "hashtree_amd64_syso",
|
||||
+ srcs = [":hashtree_amd64"],
|
||||
+ outs = ["hashtree_amd64.syso"],
|
||||
+ cmd = "cp $(location :hashtree_amd64) $@",
|
||||
+ cmd = "cp $$(echo $(locations :hashtree_amd64) | tr ' ' '\\n' | grep -v '\\.pic\\.' | head -1) $@",
|
||||
+)
|
||||
+
|
||||
+cc_library(
|
||||
@@ -83,7 +83,10 @@ diff -urN a/BUILD.bazel b/BUILD.bazel
|
||||
+ "src/sha256_sse_x1.S",
|
||||
+ ],
|
||||
+ hdrs = ["src/hashtree.h"],
|
||||
+ copts = ["-O3", "-Wall", "-fno-integrated-as"],
|
||||
+ copts = ["-O3", "-Wall"] + select({
|
||||
+ "@platforms//os:windows": [],
|
||||
+ "//conditions:default": ["-fno-integrated-as"],
|
||||
+ }),
|
||||
+ linkstatic = True,
|
||||
+ strip_include_prefix = "src",
|
||||
+ visibility = ["//visibility:public"],
|
||||
|
||||
@@ -25,7 +25,6 @@ go_library(
|
||||
],
|
||||
deps = [
|
||||
"//api/grpc:go_default_library",
|
||||
"//api/rest:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//cmd/validator/flags:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
|
||||
@@ -3,13 +3,14 @@ package accounts
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
grpcutil "github.com/OffchainLabs/prysm/v7/api/grpc"
|
||||
"github.com/OffchainLabs/prysm/v7/api/rest"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
"github.com/OffchainLabs/prysm/v7/validator/accounts/wallet"
|
||||
beaconApi "github.com/OffchainLabs/prysm/v7/validator/client/beacon-api"
|
||||
iface "github.com/OffchainLabs/prysm/v7/validator/client/iface"
|
||||
nodeClientFactory "github.com/OffchainLabs/prysm/v7/validator/client/node-client-factory"
|
||||
validatorClientFactory "github.com/OffchainLabs/prysm/v7/validator/client/validator-client-factory"
|
||||
@@ -76,17 +77,22 @@ func (acm *CLIManager) prepareBeaconClients(ctx context.Context) (*iface.Validat
|
||||
}
|
||||
|
||||
ctx = grpcutil.AppendHeaders(ctx, acm.grpcHeaders)
|
||||
|
||||
conn, err := validatorHelpers.NewNodeConnection(
|
||||
validatorHelpers.WithGrpc(ctx, acm.beaconRPCProvider, acm.dialOpts),
|
||||
validatorHelpers.WithREST(acm.beaconApiEndpoint, rest.WithHttpTimeout(acm.beaconApiTimeout)),
|
||||
)
|
||||
grpcConn, err := grpc.DialContext(ctx, acm.beaconRPCProvider, acm.dialOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, errors.Wrapf(err, "could not dial endpoint %s", acm.beaconRPCProvider)
|
||||
}
|
||||
conn := validatorHelpers.NewNodeConnection(
|
||||
grpcConn,
|
||||
acm.beaconApiEndpoint,
|
||||
validatorHelpers.WithBeaconApiTimeout(acm.beaconApiTimeout),
|
||||
)
|
||||
|
||||
validatorClient := validatorClientFactory.NewValidatorClient(conn)
|
||||
nodeClient := nodeClientFactory.NewNodeClient(conn)
|
||||
restHandler := beaconApi.NewBeaconApiRestHandler(
|
||||
http.Client{Timeout: acm.beaconApiTimeout},
|
||||
acm.beaconApiEndpoint,
|
||||
)
|
||||
validatorClient := validatorClientFactory.NewValidatorClient(conn, restHandler)
|
||||
nodeClient := nodeClientFactory.NewNodeClient(conn, restHandler)
|
||||
|
||||
return &validatorClient, &nodeClient, nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ go_library(
|
||||
"log.go",
|
||||
"log_helpers.go",
|
||||
"metrics.go",
|
||||
"multiple_endpoints_grpc_resolver.go",
|
||||
"propose.go",
|
||||
"registration.go",
|
||||
"runner.go",
|
||||
@@ -28,7 +29,6 @@ go_library(
|
||||
"//api/client:go_default_library",
|
||||
"//api/client/event:go_default_library",
|
||||
"//api/grpc:go_default_library",
|
||||
"//api/rest:go_default_library",
|
||||
"//api/server/structs:go_default_library",
|
||||
"//async:go_default_library",
|
||||
"//async/event:go_default_library",
|
||||
@@ -58,6 +58,7 @@ go_library(
|
||||
"//time/slots:go_default_library",
|
||||
"//validator/accounts/iface:go_default_library",
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
"//validator/client/beacon-api:go_default_library",
|
||||
"//validator/client/beacon-chain-client-factory:go_default_library",
|
||||
"//validator/client/iface:go_default_library",
|
||||
"//validator/client/node-client-factory:go_default_library",
|
||||
@@ -85,11 +86,13 @@ go_library(
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opentelemetry_go_contrib_instrumentation_google_golang_org_grpc_otelgrpc//:go_default_library",
|
||||
"@io_opentelemetry_go_contrib_instrumentation_net_http_otelhttp//:go_default_library",
|
||||
"@io_opentelemetry_go_otel_trace//:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//credentials:go_default_library",
|
||||
"@org_golang_google_grpc//metadata:go_default_library",
|
||||
"@org_golang_google_grpc//resolver:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/emptypb:go_default_library",
|
||||
@@ -121,8 +124,6 @@ go_test(
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//api/grpc:go_default_library",
|
||||
"//api/rest:go_default_library",
|
||||
"//api/server/structs:go_default_library",
|
||||
"//async/event:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
|
||||
@@ -26,6 +26,7 @@ go_library(
|
||||
"propose_exit.go",
|
||||
"prysm_beacon_chain_client.go",
|
||||
"registration.go",
|
||||
"rest_handler_client.go",
|
||||
"state_validators.go",
|
||||
"status.go",
|
||||
"stream_blocks.go",
|
||||
@@ -42,7 +43,6 @@ go_library(
|
||||
"//api:go_default_library",
|
||||
"//api/apiutil:go_default_library",
|
||||
"//api/client/event:go_default_library",
|
||||
"//api/rest:go_default_library",
|
||||
"//api/server/structs:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
@@ -111,7 +111,6 @@ go_test(
|
||||
deps = [
|
||||
"//api:go_default_library",
|
||||
"//api/apiutil:go_default_library",
|
||||
"//api/rest:go_default_library",
|
||||
"//api/server/structs:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/rpc/eth/shared/testing:go_default_library",
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api/rest"
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
@@ -18,7 +17,7 @@ import (
|
||||
|
||||
type beaconApiChainClient struct {
|
||||
fallbackClient iface.ChainClient
|
||||
jsonRestHandler rest.RestHandler
|
||||
jsonRestHandler RestHandler
|
||||
stateValidatorsProvider StateValidatorsProvider
|
||||
}
|
||||
|
||||
@@ -328,7 +327,7 @@ func (c beaconApiChainClient) ValidatorParticipation(ctx context.Context, in *et
|
||||
return nil, errors.New("beaconApiChainClient.ValidatorParticipation is not implemented. To use a fallback client, pass a fallback client as the last argument of NewBeaconApiChainClientWithFallback.")
|
||||
}
|
||||
|
||||
func NewBeaconApiChainClientWithFallback(jsonRestHandler rest.RestHandler, fallbackClient iface.ChainClient) iface.ChainClient {
|
||||
func NewBeaconApiChainClientWithFallback(jsonRestHandler RestHandler, fallbackClient iface.ChainClient) iface.ChainClient {
|
||||
return &beaconApiChainClient{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
fallbackClient: fallbackClient,
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api/rest"
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/validator/client/iface"
|
||||
@@ -21,7 +20,7 @@ var (
|
||||
|
||||
type beaconApiNodeClient struct {
|
||||
fallbackClient iface.NodeClient
|
||||
jsonRestHandler rest.RestHandler
|
||||
jsonRestHandler RestHandler
|
||||
genesisProvider GenesisProvider
|
||||
}
|
||||
|
||||
@@ -116,7 +115,7 @@ func (c *beaconApiNodeClient) IsReady(ctx context.Context) bool {
|
||||
return statusCode == http.StatusOK
|
||||
}
|
||||
|
||||
func NewNodeClientWithFallback(jsonRestHandler rest.RestHandler, fallbackClient iface.NodeClient) iface.NodeClient {
|
||||
func NewNodeClientWithFallback(jsonRestHandler RestHandler, fallbackClient iface.NodeClient) iface.NodeClient {
|
||||
b := &beaconApiNodeClient{
|
||||
jsonRestHandler: jsonRestHandler,
|
||||
fallbackClient: fallbackClient,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user