mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-04-19 03:01:06 -04:00
Compare commits
12 Commits
defer-sync
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
495056625e | ||
|
|
c298c504ef | ||
|
|
486e479a99 | ||
|
|
fbb65f6700 | ||
|
|
f0c7633c87 | ||
|
|
321828e775 | ||
|
|
e2ffb42abe | ||
|
|
d1bb9018d3 | ||
|
|
8c70e4bbb1 | ||
|
|
c004abc89d | ||
|
|
85316c5d16 | ||
|
|
9069afc6d0 |
@@ -3,14 +3,15 @@ package api
|
||||
import "net/http"
|
||||
|
||||
const (
|
||||
VersionHeader = "Eth-Consensus-Version"
|
||||
ExecutionPayloadBlindedHeader = "Eth-Execution-Payload-Blinded"
|
||||
ExecutionPayloadValueHeader = "Eth-Execution-Payload-Value"
|
||||
ConsensusBlockValueHeader = "Eth-Consensus-Block-Value"
|
||||
JsonMediaType = "application/json"
|
||||
OctetStreamMediaType = "application/octet-stream"
|
||||
EventStreamMediaType = "text/event-stream"
|
||||
KeepAlive = "keep-alive"
|
||||
VersionHeader = "Eth-Consensus-Version"
|
||||
ExecutionPayloadBlindedHeader = "Eth-Execution-Payload-Blinded"
|
||||
ExecutionPayloadValueHeader = "Eth-Execution-Payload-Value"
|
||||
ConsensusBlockValueHeader = "Eth-Consensus-Block-Value"
|
||||
ExecutionPayloadIncludedHeader = "Eth-Execution-Payload-Included"
|
||||
JsonMediaType = "application/json"
|
||||
OctetStreamMediaType = "application/octet-stream"
|
||||
EventStreamMediaType = "text/event-stream"
|
||||
KeepAlive = "keep-alive"
|
||||
)
|
||||
|
||||
// SetSSEHeaders sets the headers needed for a server-sent event response.
|
||||
|
||||
@@ -29,6 +29,8 @@ type Server struct {
|
||||
startFailure error
|
||||
}
|
||||
|
||||
const eventStreamPath = "/eth/v1/events"
|
||||
|
||||
// New returns a new instance of the Server.
|
||||
func New(ctx context.Context, opts ...Option) (*Server, error) {
|
||||
g := &Server{
|
||||
@@ -48,7 +50,17 @@ func New(ctx context.Context, opts ...Option) (*Server, error) {
|
||||
handler = middleware.MiddlewareChain(g.cfg.router, g.cfg.middlewares)
|
||||
if g.cfg.timeout > 0*time.Second {
|
||||
defaultReadHeaderTimeout = g.cfg.timeout
|
||||
handler = http.TimeoutHandler(handler, g.cfg.timeout, "request timed out")
|
||||
baseHandler := handler
|
||||
timeoutHandler := http.TimeoutHandler(baseHandler, g.cfg.timeout, "request timed out")
|
||||
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// SSE streams stay open indefinitely, so the global timeout wrapper must not
|
||||
// cancel `/eth/v1/events` before the handler starts streaming responses.
|
||||
if r.URL != nil && r.URL.Path == eventStreamPath {
|
||||
baseHandler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
timeoutHandler.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
g.server = &http.Server{
|
||||
Addr: g.cfg.httpAddr,
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/flags"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
@@ -37,10 +39,18 @@ func TestServer_StartStop(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
g.Start()
|
||||
go func() {
|
||||
require.LogsContain(t, hook, "Starting HTTP server")
|
||||
require.LogsDoNotContain(t, hook, "Starting API middleware")
|
||||
}()
|
||||
require.Eventually(t, func() bool {
|
||||
foundStart := false
|
||||
for _, entry := range hook.AllEntries() {
|
||||
if strings.Contains(entry.Message, "Starting HTTP server") {
|
||||
foundStart = true
|
||||
}
|
||||
if strings.Contains(entry.Message, "Starting API middleware") {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return foundStart
|
||||
}, time.Second, 10*time.Millisecond)
|
||||
err = g.Stop()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
@@ -68,3 +78,51 @@ func TestServer_NilHandler_NotFoundHandlerRegistered(t *testing.T) {
|
||||
g.cfg.router.ServeHTTP(writer, &http.Request{Method: "GET", Host: "localhost", URL: &url.URL{Path: "/foo"}})
|
||||
assert.Equal(t, http.StatusNotFound, writer.Code)
|
||||
}
|
||||
|
||||
func TestServer_TimeoutHandlerBypassesSSE(t *testing.T) {
|
||||
handler := http.NewServeMux()
|
||||
handler.HandleFunc(eventStreamPath, func(w http.ResponseWriter, _ *http.Request) {
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := w.Write([]byte("stream-open"))
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
g, err := New(t.Context(),
|
||||
WithHTTPAddr("127.0.0.1:0"),
|
||||
WithRouter(handler),
|
||||
WithTimeout(5*time.Millisecond),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, eventStreamPath, nil)
|
||||
writer := httptest.NewRecorder()
|
||||
g.server.Handler.ServeHTTP(writer, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
assert.Equal(t, "stream-open", writer.Body.String())
|
||||
}
|
||||
|
||||
func TestServer_TimeoutHandlerStillAppliesToNonSSE(t *testing.T) {
|
||||
handler := http.NewServeMux()
|
||||
handler.HandleFunc("/foo", func(w http.ResponseWriter, _ *http.Request) {
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := w.Write([]byte("ok"))
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
g, err := New(t.Context(),
|
||||
WithHTTPAddr("127.0.0.1:0"),
|
||||
WithRouter(handler),
|
||||
WithTimeout(5*time.Millisecond),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/foo", nil)
|
||||
writer := httptest.NewRecorder()
|
||||
g.server.Handler.ServeHTTP(writer, req)
|
||||
|
||||
assert.Equal(t, http.StatusServiceUnavailable, writer.Code)
|
||||
assert.Equal(t, true, strings.Contains(writer.Body.String(), "request timed out"))
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"conversions_block_execution_test.go",
|
||||
"conversions_block_gloas_test.go",
|
||||
"conversions_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
|
||||
@@ -584,6 +584,13 @@ func (s *SignedBeaconBlockGloas) SigString() string {
|
||||
return s.Signature
|
||||
}
|
||||
|
||||
type BlockContentsGloas struct {
|
||||
Block *BeaconBlockGloas `json:"block"`
|
||||
ExecutionPayloadEnvelope *ExecutionPayloadEnvelope `json:"execution_payload_envelope"`
|
||||
KzgProofs []string `json:"kzg_proofs"`
|
||||
Blobs []string `json:"blobs"`
|
||||
}
|
||||
|
||||
type ExecutionPayloadEnvelope struct {
|
||||
Payload *ExecutionPayloadDeneb `json:"payload"`
|
||||
ExecutionRequests *ExecutionRequests `json:"execution_requests"`
|
||||
|
||||
@@ -2983,6 +2983,19 @@ func PayloadAttestationDataFromConsensus(d *eth.PayloadAttestationData) *Payload
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SignedBeaconBlockGloas) ToGeneric() (*eth.GenericSignedBeaconBlock, error) {
|
||||
if b == nil {
|
||||
return nil, errNilValue
|
||||
}
|
||||
signed, err := b.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ð.GenericSignedBeaconBlock{
|
||||
Block: ð.GenericSignedBeaconBlock_Gloas{Gloas: signed},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *SignedBeaconBlockGloas) ToConsensus() (*eth.SignedBeaconBlockGloas, error) {
|
||||
if b == nil {
|
||||
return nil, errNilValue
|
||||
@@ -3137,6 +3150,14 @@ func (b *BeaconBlockBodyGloas) ToConsensus() (*eth.BeaconBlockBodyGloas, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *BeaconBlockGloas) ToGeneric() (*eth.GenericBeaconBlock, error) {
|
||||
block, err := b.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert gloas block to consensus")
|
||||
}
|
||||
return ð.GenericBeaconBlock{Block: ð.GenericBeaconBlock_Gloas{Gloas: block}}, nil
|
||||
}
|
||||
|
||||
func (b *SignedExecutionPayloadBid) ToConsensus() (*eth.SignedExecutionPayloadBid, error) {
|
||||
if b == nil {
|
||||
return nil, errNilValue
|
||||
@@ -3284,25 +3305,113 @@ func (d *PayloadAttestationData) ToConsensus() (*eth.PayloadAttestationData, err
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SignedExecutionPayloadEnvelopeFromConsensus converts a proto envelope to the API struct.
|
||||
func SignedExecutionPayloadEnvelopeFromConsensus(e *eth.SignedExecutionPayloadEnvelope) (*SignedExecutionPayloadEnvelope, error) {
|
||||
payload, err := ExecutionPayloadDenebFromConsensus(e.Message.Payload)
|
||||
// ExecutionPayloadEnvelopeFromConsensus converts a proto envelope to the API struct.
|
||||
func ExecutionPayloadEnvelopeFromConsensus(e *eth.ExecutionPayloadEnvelope) (*ExecutionPayloadEnvelope, error) {
|
||||
payload, err := ExecutionPayloadDenebFromConsensus(e.Payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var requests *ExecutionRequests
|
||||
if e.Message.ExecutionRequests != nil {
|
||||
requests = ExecutionRequestsFromConsensus(e.Message.ExecutionRequests)
|
||||
if e.ExecutionRequests != nil {
|
||||
requests = ExecutionRequestsFromConsensus(e.ExecutionRequests)
|
||||
}
|
||||
return &ExecutionPayloadEnvelope{
|
||||
Payload: payload,
|
||||
ExecutionRequests: requests,
|
||||
BuilderIndex: fmt.Sprintf("%d", e.BuilderIndex),
|
||||
BeaconBlockRoot: hexutil.Encode(e.BeaconBlockRoot),
|
||||
Slot: fmt.Sprintf("%d", e.Slot),
|
||||
StateRoot: hexutil.Encode(e.StateRoot),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SignedExecutionPayloadEnvelopeFromConsensus converts a signed proto envelope to the API struct.
|
||||
func SignedExecutionPayloadEnvelopeFromConsensus(e *eth.SignedExecutionPayloadEnvelope) (*SignedExecutionPayloadEnvelope, error) {
|
||||
envelope, err := ExecutionPayloadEnvelopeFromConsensus(e.Message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SignedExecutionPayloadEnvelope{
|
||||
Message: &ExecutionPayloadEnvelope{
|
||||
Payload: payload,
|
||||
ExecutionRequests: requests,
|
||||
BuilderIndex: fmt.Sprintf("%d", e.Message.BuilderIndex),
|
||||
BeaconBlockRoot: hexutil.Encode(e.Message.BeaconBlockRoot),
|
||||
Slot: fmt.Sprintf("%d", e.Message.Slot),
|
||||
StateRoot: hexutil.Encode(e.Message.StateRoot),
|
||||
},
|
||||
Message: envelope,
|
||||
Signature: hexutil.Encode(e.Signature),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BlockContentsGloasFromConsensus converts a proto Gloas block and envelope to the API struct.
|
||||
func BlockContentsGloasFromConsensus(block *eth.BeaconBlockGloas, envelope *eth.ExecutionPayloadEnvelope) (*BlockContentsGloas, error) {
|
||||
b, err := BeaconBlockGloasFromConsensus(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
env, err := ExecutionPayloadEnvelopeFromConsensus(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BlockContentsGloas{
|
||||
Block: b,
|
||||
ExecutionPayloadEnvelope: env,
|
||||
KzgProofs: []string{}, // TODO: populate from blobs bundle
|
||||
Blobs: []string{}, // TODO: populate from blobs bundle
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToConsensus converts the API struct to a proto ExecutionPayloadEnvelope.
|
||||
func (e *ExecutionPayloadEnvelope) ToConsensus() (*eth.ExecutionPayloadEnvelope, error) {
|
||||
if e == nil {
|
||||
return nil, server.NewDecodeError(errNilValue, "ExecutionPayloadEnvelope")
|
||||
}
|
||||
payload, err := e.Payload.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Payload")
|
||||
}
|
||||
var requests *enginev1.ExecutionRequests
|
||||
if e.ExecutionRequests != nil {
|
||||
requests, err = e.ExecutionRequests.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "ExecutionRequests")
|
||||
}
|
||||
}
|
||||
builderIndex, err := strconv.ParseUint(e.BuilderIndex, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "BuilderIndex")
|
||||
}
|
||||
beaconBlockRoot, err := bytesutil.DecodeHexWithLength(e.BeaconBlockRoot, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "BeaconBlockRoot")
|
||||
}
|
||||
slot, err := strconv.ParseUint(e.Slot, 10, 64)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Slot")
|
||||
}
|
||||
stateRoot, err := bytesutil.DecodeHexWithLength(e.StateRoot, fieldparams.RootLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "StateRoot")
|
||||
}
|
||||
return ð.ExecutionPayloadEnvelope{
|
||||
Payload: payload,
|
||||
ExecutionRequests: requests,
|
||||
BuilderIndex: primitives.BuilderIndex(builderIndex),
|
||||
BeaconBlockRoot: beaconBlockRoot,
|
||||
Slot: primitives.Slot(slot),
|
||||
StateRoot: stateRoot,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToConsensus converts the API struct to a proto SignedExecutionPayloadEnvelope.
|
||||
func (e *SignedExecutionPayloadEnvelope) ToConsensus() (*eth.SignedExecutionPayloadEnvelope, error) {
|
||||
if e == nil {
|
||||
return nil, server.NewDecodeError(errNilValue, "SignedExecutionPayloadEnvelope")
|
||||
}
|
||||
msg, err := e.Message.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Message")
|
||||
}
|
||||
sig, err := bytesutil.DecodeHexWithLength(e.Signature, fieldparams.BLSSignatureLength)
|
||||
if err != nil {
|
||||
return nil, server.NewDecodeError(err, "Signature")
|
||||
}
|
||||
return ð.SignedExecutionPayloadEnvelope{
|
||||
Message: msg,
|
||||
Signature: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
67
api/server/structs/conversions_block_gloas_test.go
Normal file
67
api/server/structs/conversions_block_gloas_test.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package structs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
||||
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
func testEnvelopeProto() *eth.ExecutionPayloadEnvelope {
|
||||
return ð.ExecutionPayloadEnvelope{
|
||||
Payload: &enginev1.ExecutionPayloadDeneb{
|
||||
ParentHash: fillByteSlice(common.HashLength, 0xaa),
|
||||
FeeRecipient: fillByteSlice(20, 0xbb),
|
||||
StateRoot: fillByteSlice(32, 0xcc),
|
||||
ReceiptsRoot: fillByteSlice(32, 0xdd),
|
||||
LogsBloom: fillByteSlice(256, 0xee),
|
||||
PrevRandao: fillByteSlice(32, 0xff),
|
||||
BaseFeePerGas: fillByteSlice(32, 0x11),
|
||||
BlockHash: fillByteSlice(common.HashLength, 0x22),
|
||||
},
|
||||
ExecutionRequests: &enginev1.ExecutionRequests{},
|
||||
BuilderIndex: 7,
|
||||
BeaconBlockRoot: fillByteSlice(32, 0x33),
|
||||
Slot: 42,
|
||||
StateRoot: fillByteSlice(32, 0x44),
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecutionPayloadEnvelopeFromConsensus(t *testing.T) {
|
||||
env := testEnvelopeProto()
|
||||
result, err := ExecutionPayloadEnvelopeFromConsensus(env)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, result.Payload)
|
||||
require.Equal(t, hexutil.Encode(env.Payload.ParentHash), result.Payload.ParentHash)
|
||||
require.Equal(t, "7", result.BuilderIndex)
|
||||
require.Equal(t, hexutil.Encode(env.BeaconBlockRoot), result.BeaconBlockRoot)
|
||||
require.Equal(t, "42", result.Slot)
|
||||
require.Equal(t, hexutil.Encode(env.StateRoot), result.StateRoot)
|
||||
require.NotNil(t, result.ExecutionRequests)
|
||||
}
|
||||
|
||||
func TestExecutionPayloadEnvelopeFromConsensus_NilRequests(t *testing.T) {
|
||||
env := testEnvelopeProto()
|
||||
env.ExecutionRequests = nil
|
||||
result, err := ExecutionPayloadEnvelopeFromConsensus(env)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, (*ExecutionRequests)(nil), result.ExecutionRequests)
|
||||
}
|
||||
|
||||
func TestBlockContentsGloasFromConsensus(t *testing.T) {
|
||||
block := util.NewBeaconBlockGloas().Block
|
||||
env := testEnvelopeProto()
|
||||
|
||||
result, err := BlockContentsGloasFromConsensus(block, env)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, result.Block)
|
||||
require.NotNil(t, result.Block.Body)
|
||||
require.NotNil(t, result.ExecutionPayloadEnvelope)
|
||||
require.Equal(t, hexutil.Encode(env.BeaconBlockRoot), result.ExecutionPayloadEnvelope.BeaconBlockRoot)
|
||||
require.Equal(t, 0, len(result.KzgProofs))
|
||||
require.Equal(t, 0, len(result.Blobs))
|
||||
}
|
||||
@@ -95,6 +95,14 @@ type ProduceBlockV3Response struct {
|
||||
Data json.RawMessage `json:"data"` // represents the block values based on the version
|
||||
}
|
||||
|
||||
// ProduceBlockV4Response is a wrapper json object for the returned block from the ProduceBlockV4 endpoint
|
||||
type ProduceBlockV4Response struct {
|
||||
Version string `json:"version"`
|
||||
ConsensusBlockValue string `json:"consensus_block_value"`
|
||||
ExecutionPayloadIncluded bool `json:"execution_payload_included"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
type GetLivenessResponse struct {
|
||||
Data []*Liveness `json:"data"`
|
||||
}
|
||||
@@ -151,6 +159,11 @@ type ValidatorParticipation struct {
|
||||
PreviousEpochHeadAttestingGwei string `json:"previous_epoch_head_attesting_gwei"`
|
||||
}
|
||||
|
||||
type GetValidatorExecutionPayloadEnvelopeResponse struct {
|
||||
Version string `json:"version"`
|
||||
Data *ExecutionPayloadEnvelope `json:"data"`
|
||||
}
|
||||
|
||||
type ActiveSetChanges struct {
|
||||
Epoch string `json:"epoch"`
|
||||
ActivatedPublicKeys []string `json:"activated_public_keys"`
|
||||
|
||||
@@ -116,17 +116,32 @@ func CalculateStateRoot(
|
||||
rollback state.BeaconState,
|
||||
signed interfaces.ReadOnlySignedBeaconBlock,
|
||||
) ([32]byte, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "core.state.CalculateStateRoot")
|
||||
st, err := CalculatePostState(ctx, rollback, signed)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
return st.HashTreeRoot(ctx)
|
||||
}
|
||||
|
||||
// CalculatePostState returns the post-block state after processing the given
|
||||
// block on a copy of the input state. It is identical to CalculateStateRoot
|
||||
// but returns the full state instead of just its hash tree root.
|
||||
func CalculatePostState(
|
||||
ctx context.Context,
|
||||
rollback state.BeaconState,
|
||||
signed interfaces.ReadOnlySignedBeaconBlock,
|
||||
) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "core.state.CalculatePostState")
|
||||
defer span.End()
|
||||
if ctx.Err() != nil {
|
||||
tracing.AnnotateError(span, ctx.Err())
|
||||
return [32]byte{}, ctx.Err()
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
if rollback == nil || rollback.IsNil() {
|
||||
return [32]byte{}, errors.New("nil state")
|
||||
return nil, errors.New("nil state")
|
||||
}
|
||||
if signed == nil || signed.IsNil() || signed.Block().IsNil() {
|
||||
return [32]byte{}, errors.New("nil block")
|
||||
return nil, errors.New("nil block")
|
||||
}
|
||||
|
||||
// Copy state to avoid mutating the state reference.
|
||||
@@ -136,22 +151,22 @@ func CalculateStateRoot(
|
||||
var err error
|
||||
state, err = ProcessSlotsForBlock(ctx, state, signed.Block())
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not process slots")
|
||||
return nil, errors.Wrap(err, "could not process slots")
|
||||
}
|
||||
|
||||
// Execute per block transition.
|
||||
if features.Get().EnableProposerPreprocessing {
|
||||
state, err = processBlockForProposing(ctx, state, signed)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not process block for proposing")
|
||||
return nil, errors.Wrap(err, "could not process block for proposing")
|
||||
}
|
||||
} else {
|
||||
state, err = ProcessBlockForStateRoot(ctx, state, signed)
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not process block")
|
||||
return nil, errors.Wrap(err, "could not process block")
|
||||
}
|
||||
}
|
||||
return state.HashTreeRoot(ctx)
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// processBlockVerifySigs processes the block and verifies the signatures within it. Block signatures are not verified as this block is not yet signed.
|
||||
|
||||
@@ -138,24 +138,19 @@ func (s *Service) SyncCommitteeDuties(ctx context.Context, st state.BeaconState,
|
||||
nextSyncCommitteeFirstEpoch := currentSyncCommitteeFirstEpoch + params.BeaconConfig().EpochsPerSyncCommitteePeriod
|
||||
isCurrentCommittee := requestedEpoch < nextSyncCommitteeFirstEpoch
|
||||
|
||||
var committee [][]byte
|
||||
syncCommitteeFunc := st.NextSyncCommittee
|
||||
if isCurrentCommittee {
|
||||
sc, err := st.CurrentSyncCommittee()
|
||||
if err != nil {
|
||||
return nil, &RpcError{Err: errors.Wrap(err, "could not get sync committee"), Reason: Internal}
|
||||
}
|
||||
committee = sc.Pubkeys
|
||||
} else {
|
||||
sc, err := st.NextSyncCommittee()
|
||||
if err != nil {
|
||||
return nil, &RpcError{Err: errors.Wrap(err, "could not get sync committee"), Reason: Internal}
|
||||
}
|
||||
committee = sc.Pubkeys
|
||||
syncCommitteeFunc = st.CurrentSyncCommittee
|
||||
}
|
||||
|
||||
sc, err := syncCommitteeFunc()
|
||||
if err != nil {
|
||||
return nil, &RpcError{Err: errors.Wrap(err, "could not get sync committee"), Reason: Internal}
|
||||
}
|
||||
|
||||
// Build pubkey → positions map from committee pubkeys.
|
||||
committeePubkeys := make(map[[fieldparams.BLSPubkeyLength]byte][]uint64)
|
||||
for j, pk := range committee {
|
||||
for j, pk := range sc.Pubkeys {
|
||||
var pk48 [fieldparams.BLSPubkeyLength]byte
|
||||
copy(pk48[:], pk)
|
||||
committeePubkeys[pk48] = append(committeePubkeys[pk48], uint64(j))
|
||||
|
||||
@@ -393,6 +393,16 @@ func (s *Service) validatorEndpoints(
|
||||
handler: server.ProduceBlockV3,
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
{
|
||||
template: "/eth/v4/validator/blocks/{slot}",
|
||||
name: namespace + ".ProduceBlockV4",
|
||||
middleware: []middleware.Middleware{
|
||||
middleware.AcceptHeaderHandler([]string{api.JsonMediaType, api.OctetStreamMediaType}),
|
||||
middleware.AcceptEncodingHeaderHandler(),
|
||||
},
|
||||
handler: server.ProduceBlockV4,
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
{
|
||||
template: "/eth/v1/validator/beacon_committee_selections",
|
||||
name: namespace + ".BeaconCommitteeSelections",
|
||||
@@ -411,6 +421,15 @@ func (s *Service) validatorEndpoints(
|
||||
handler: server.SyncCommitteeSelections,
|
||||
methods: []string{http.MethodPost},
|
||||
},
|
||||
{
|
||||
template: "/eth/v1/validator/execution_payload_envelope/{slot}",
|
||||
name: namespace + ".ExecutionPayloadEnvelope",
|
||||
middleware: []middleware.Middleware{
|
||||
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
|
||||
},
|
||||
handler: server.ExecutionPayloadEnvelope,
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,7 +930,17 @@ func (s *Service) beaconEndpoints(
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
{
|
||||
template: "/eth/v2/beacon/execution_payload/bid",
|
||||
template: "/eth/v1/beacon/execution_payload_envelope",
|
||||
name: namespace + ".PublishExecutionPayloadEnvelope",
|
||||
middleware: []middleware.Middleware{
|
||||
middleware.ContentTypeHandler([]string{api.JsonMediaType}),
|
||||
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
|
||||
},
|
||||
handler: server.PublishExecutionPayloadEnvelope,
|
||||
methods: []string{http.MethodPost},
|
||||
},
|
||||
{
|
||||
template: "/eth/v1/beacon/execution_payload_bid",
|
||||
name: namespace + ".PublishSignedExecutionPayloadBid",
|
||||
middleware: []middleware.Middleware{
|
||||
middleware.ContentTypeHandler([]string{api.JsonMediaType, api.OctetStreamMediaType}),
|
||||
|
||||
@@ -34,7 +34,8 @@ func Test_endpoints(t *testing.T) {
|
||||
"/eth/v1/beacon/states/{state_id}/pending_consolidations": {http.MethodGet},
|
||||
"/eth/v1/beacon/states/{state_id}/proposer_lookahead": {http.MethodGet},
|
||||
"/eth/v1/beacon/execution_payload_envelope/{block_id}": {http.MethodGet},
|
||||
"/eth/v2/beacon/execution_payload/bid": {http.MethodPost},
|
||||
"/eth/v1/beacon/execution_payload_envelope": {http.MethodPost},
|
||||
"/eth/v1/beacon/execution_payload_bid": {http.MethodPost},
|
||||
"/eth/v1/beacon/headers": {http.MethodGet},
|
||||
"/eth/v1/beacon/headers/{block_id}": {http.MethodGet},
|
||||
"/eth/v2/beacon/blinded_blocks": {http.MethodPost},
|
||||
@@ -94,24 +95,26 @@ func Test_endpoints(t *testing.T) {
|
||||
}
|
||||
|
||||
validatorRoutes := map[string][]string{
|
||||
"/eth/v1/validator/duties/attester/{epoch}": {http.MethodPost},
|
||||
"/eth/v1/validator/duties/proposer/{epoch}": {http.MethodGet},
|
||||
"/eth/v2/validator/duties/proposer/{epoch}": {http.MethodGet},
|
||||
"/eth/v1/validator/duties/sync/{epoch}": {http.MethodPost},
|
||||
"/eth/v1/validator/duties/ptc/{epoch}": {http.MethodPost},
|
||||
"/eth/v3/validator/blocks/{slot}": {http.MethodGet},
|
||||
"/eth/v1/validator/attestation_data": {http.MethodGet},
|
||||
"/eth/v2/validator/aggregate_attestation": {http.MethodGet},
|
||||
"/eth/v2/validator/aggregate_and_proofs": {http.MethodPost},
|
||||
"/eth/v1/validator/beacon_committee_subscriptions": {http.MethodPost},
|
||||
"/eth/v1/validator/sync_committee_subscriptions": {http.MethodPost},
|
||||
"/eth/v1/validator/beacon_committee_selections": {http.MethodPost},
|
||||
"/eth/v1/validator/sync_committee_selections": {http.MethodPost},
|
||||
"/eth/v1/validator/sync_committee_contribution": {http.MethodGet},
|
||||
"/eth/v1/validator/contribution_and_proofs": {http.MethodPost},
|
||||
"/eth/v1/validator/prepare_beacon_proposer": {http.MethodPost},
|
||||
"/eth/v1/validator/register_validator": {http.MethodPost},
|
||||
"/eth/v1/validator/liveness/{epoch}": {http.MethodPost},
|
||||
"/eth/v1/validator/duties/attester/{epoch}": {http.MethodPost},
|
||||
"/eth/v1/validator/duties/proposer/{epoch}": {http.MethodGet},
|
||||
"/eth/v2/validator/duties/proposer/{epoch}": {http.MethodGet},
|
||||
"/eth/v1/validator/duties/sync/{epoch}": {http.MethodPost},
|
||||
"/eth/v1/validator/duties/ptc/{epoch}": {http.MethodPost},
|
||||
"/eth/v3/validator/blocks/{slot}": {http.MethodGet},
|
||||
"/eth/v4/validator/blocks/{slot}": {http.MethodGet},
|
||||
"/eth/v1/validator/attestation_data": {http.MethodGet},
|
||||
"/eth/v2/validator/aggregate_attestation": {http.MethodGet},
|
||||
"/eth/v2/validator/aggregate_and_proofs": {http.MethodPost},
|
||||
"/eth/v1/validator/beacon_committee_subscriptions": {http.MethodPost},
|
||||
"/eth/v1/validator/sync_committee_subscriptions": {http.MethodPost},
|
||||
"/eth/v1/validator/beacon_committee_selections": {http.MethodPost},
|
||||
"/eth/v1/validator/sync_committee_selections": {http.MethodPost},
|
||||
"/eth/v1/validator/execution_payload_envelope/{slot}": {http.MethodGet},
|
||||
"/eth/v1/validator/sync_committee_contribution": {http.MethodGet},
|
||||
"/eth/v1/validator/contribution_and_proofs": {http.MethodPost},
|
||||
"/eth/v1/validator/prepare_beacon_proposer": {http.MethodPost},
|
||||
"/eth/v1/validator/register_validator": {http.MethodPost},
|
||||
"/eth/v1/validator/liveness/{epoch}": {http.MethodPost},
|
||||
}
|
||||
|
||||
prysmBeaconRoutes := map[string][]string{
|
||||
|
||||
@@ -66,6 +66,8 @@ go_library(
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -134,7 +136,10 @@ go_test(
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@com_github_stretchr_testify//mock:go_default_library",
|
||||
"@org_golang_google_grpc//codes: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",
|
||||
"@org_uber_go_mock//gomock:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -643,6 +643,7 @@ func (s *Server) publishBlockSSZ(ctx context.Context, w http.ResponseWriter, r *
|
||||
}
|
||||
|
||||
var sszDecoders = map[string]blockDecoder{
|
||||
version.String(version.Gloas): decodeGloasSSZ,
|
||||
version.String(version.Fulu): decodeFuluSSZ,
|
||||
version.String(version.Electra): decodeElectraSSZ,
|
||||
version.String(version.Deneb): decodeDenebSSZ,
|
||||
@@ -660,6 +661,18 @@ func decodeSSZToGenericBlock(versionHeader string, body []byte) (*eth.GenericSig
|
||||
return nil, errors.New("body does not represent a valid block type")
|
||||
}
|
||||
|
||||
func decodeGloasSSZ(body []byte) (*eth.GenericSignedBeaconBlock, error) {
|
||||
gloasBlock := ð.SignedBeaconBlockGloas{}
|
||||
if err := gloasBlock.UnmarshalSSZ(body); err != nil {
|
||||
return nil, decodingError(
|
||||
version.String(version.Gloas), err,
|
||||
)
|
||||
}
|
||||
return ð.GenericSignedBeaconBlock{
|
||||
Block: ð.GenericSignedBeaconBlock_Gloas{Gloas: gloasBlock},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeFuluSSZ(body []byte) (*eth.GenericSignedBeaconBlock, error) {
|
||||
fuluBlock := ð.SignedBeaconBlockContentsFulu{}
|
||||
if err := fuluBlock.UnmarshalSSZ(body); err != nil {
|
||||
@@ -798,6 +811,7 @@ func (s *Server) publishBlock(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
}
|
||||
|
||||
var jsonDecoders = map[string]blockDecoder{
|
||||
version.String(version.Gloas): decodeGloasJSON,
|
||||
version.String(version.Fulu): decodeFuluJSON,
|
||||
version.String(version.Electra): decodeElectraJSON,
|
||||
version.String(version.Deneb): decodeDenebJSON,
|
||||
@@ -815,6 +829,13 @@ func decodeJSONToGenericBlock(versionHeader string, body []byte) (*eth.GenericSi
|
||||
return nil, fmt.Errorf("body does not represent a valid block type")
|
||||
}
|
||||
|
||||
func decodeGloasJSON(body []byte) (*eth.GenericSignedBeaconBlock, error) {
|
||||
return decodeGenericJSON[*structs.SignedBeaconBlockGloas](
|
||||
body,
|
||||
version.String(version.Gloas),
|
||||
)
|
||||
}
|
||||
|
||||
func decodeFuluJSON(body []byte) (*eth.GenericSignedBeaconBlock, error) {
|
||||
return decodeGenericJSON[*structs.SignedBeaconBlockContentsFulu](
|
||||
body,
|
||||
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// GetExecutionPayloadEnvelope retrieves a full execution payload envelope by beacon block root.
|
||||
@@ -81,6 +83,48 @@ func (s *Server) GetExecutionPayloadEnvelope(w http.ResponseWriter, r *http.Requ
|
||||
})
|
||||
}
|
||||
|
||||
// PublishExecutionPayloadEnvelope broadcasts a signed execution payload envelope.
|
||||
//
|
||||
// Endpoint: POST /eth/v1/beacon/execution_payload_envelope
|
||||
func (s *Server) PublishExecutionPayloadEnvelope(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.PublishExecutionPayloadEnvelope")
|
||||
defer span.End()
|
||||
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "could not read request body: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var jsonEnvelope structs.SignedExecutionPayloadEnvelope
|
||||
if err := json.Unmarshal(body, &jsonEnvelope); err != nil {
|
||||
httputil.HandleError(w, "could not decode request body: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
consensus, err := jsonEnvelope.ToConsensus()
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "invalid signed execution payload envelope: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := s.V1Alpha1ValidatorServer.PublishExecutionPayloadEnvelope(ctx, consensus); err != nil {
|
||||
if st, ok := status.FromError(err); ok {
|
||||
switch st.Code() {
|
||||
case codes.InvalidArgument:
|
||||
httputil.HandleError(w, st.Message(), http.StatusBadRequest)
|
||||
default:
|
||||
httputil.HandleError(w, st.Message(), http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
httputil.HandleError(w, "could not publish execution payload envelope: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
// PublishSignedExecutionPayloadBid broadcasts a signed execution payload bid to the P2P network.
|
||||
func (s *Server) PublishSignedExecutionPayloadBid(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.PublishSignedExecutionPayloadBid")
|
||||
|
||||
@@ -2,10 +2,12 @@ package beacon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
chainMock "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing"
|
||||
dbTest "github.com/OffchainLabs/prysm/v7/beacon-chain/db/testing"
|
||||
executiontesting "github.com/OffchainLabs/prysm/v7/beacon-chain/execution/testing"
|
||||
@@ -17,7 +19,12 @@ import (
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
mock2 "github.com/OffchainLabs/prysm/v7/testing/mock"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
func TestGetExecutionPayloadEnvelope_AcceptsSlotID(t *testing.T) {
|
||||
@@ -105,3 +112,84 @@ func TestGetExecutionPayloadEnvelope_BlockNotFound(t *testing.T) {
|
||||
require.Equal(t, http.StatusNotFound, w.Code)
|
||||
assert.Equal(t, true, bytes.Contains(w.Body.Bytes(), []byte("Block not found")))
|
||||
}
|
||||
|
||||
func testSignedEnvelope() *ethpb.SignedExecutionPayloadEnvelope {
|
||||
return ðpb.SignedExecutionPayloadEnvelope{
|
||||
Message: ðpb.ExecutionPayloadEnvelope{
|
||||
Payload: &enginev1.ExecutionPayloadDeneb{
|
||||
ParentHash: bytesutil.PadTo([]byte("parent"), 32),
|
||||
FeeRecipient: bytesutil.PadTo([]byte("fee"), 20),
|
||||
StateRoot: bytesutil.PadTo([]byte("state"), 32),
|
||||
ReceiptsRoot: bytesutil.PadTo([]byte("receipts"), 32),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: bytesutil.PadTo([]byte("randao"), 32),
|
||||
BaseFeePerGas: bytesutil.PadTo([]byte{1}, 32),
|
||||
BlockHash: bytesutil.PadTo([]byte("blockhash"), 32),
|
||||
Transactions: [][]byte{},
|
||||
Withdrawals: []*enginev1.Withdrawal{},
|
||||
},
|
||||
ExecutionRequests: &enginev1.ExecutionRequests{},
|
||||
BuilderIndex: primitives.BuilderIndex(42),
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("beacon-root"), 32),
|
||||
Slot: primitives.Slot(100),
|
||||
StateRoot: bytesutil.PadTo([]byte("envelope-state"), 32),
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("sig"), 96),
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishExecutionPayloadEnvelope_OK(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
signed := testSignedEnvelope()
|
||||
|
||||
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
|
||||
v1alpha1Server.EXPECT().PublishExecutionPayloadEnvelope(
|
||||
gomock.Any(), gomock.Any(),
|
||||
).Return(&emptypb.Empty{}, nil)
|
||||
|
||||
jsonEnvelope, err := structs.SignedExecutionPayloadEnvelopeFromConsensus(signed)
|
||||
require.NoError(t, err)
|
||||
body, err := json.Marshal(jsonEnvelope)
|
||||
require.NoError(t, err)
|
||||
|
||||
s := &Server{V1Alpha1ValidatorServer: v1alpha1Server}
|
||||
req := httptest.NewRequest(http.MethodPost, "/eth/v1/beacon/execution_payload_envelope", bytes.NewReader(body))
|
||||
w := httptest.NewRecorder()
|
||||
w.Body = &bytes.Buffer{}
|
||||
|
||||
s.PublishExecutionPayloadEnvelope(w, req)
|
||||
require.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
func TestPublishExecutionPayloadEnvelope_InvalidBody(t *testing.T) {
|
||||
s := &Server{}
|
||||
req := httptest.NewRequest(http.MethodPost, "/eth/v1/beacon/execution_payload_envelope", bytes.NewReader([]byte("not json")))
|
||||
w := httptest.NewRecorder()
|
||||
w.Body = &bytes.Buffer{}
|
||||
|
||||
s.PublishExecutionPayloadEnvelope(w, req)
|
||||
require.Equal(t, http.StatusBadRequest, w.Code)
|
||||
}
|
||||
|
||||
func TestPublishExecutionPayloadEnvelope_ServerError(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
|
||||
v1alpha1Server.EXPECT().PublishExecutionPayloadEnvelope(
|
||||
gomock.Any(), gomock.Any(),
|
||||
).Return(nil, status.Error(codes.Internal, "broadcast failed"))
|
||||
|
||||
signed := testSignedEnvelope()
|
||||
jsonEnvelope, err := structs.SignedExecutionPayloadEnvelopeFromConsensus(signed)
|
||||
require.NoError(t, err)
|
||||
body, err := json.Marshal(jsonEnvelope)
|
||||
require.NoError(t, err)
|
||||
|
||||
s := &Server{V1Alpha1ValidatorServer: v1alpha1Server}
|
||||
req := httptest.NewRequest(http.MethodPost, "/eth/v1/beacon/execution_payload_envelope", bytes.NewReader(body))
|
||||
w := httptest.NewRecorder()
|
||||
w.Body = &bytes.Buffer{}
|
||||
|
||||
s.PublishExecutionPayloadEnvelope(w, req)
|
||||
require.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api"
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
@@ -35,8 +34,7 @@ func (s *Server) Blobs(w http.ResponseWriter, r *http.Request) {
|
||||
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
segments := strings.Split(r.URL.Path, "/")
|
||||
blockId := segments[len(segments)-1]
|
||||
blockId := r.PathValue("block_id")
|
||||
|
||||
verifiedBlobs, rpcErr := s.Blocker.BlobSidecars(ctx, blockId, options.WithIndices(indices))
|
||||
if rpcErr != nil {
|
||||
@@ -131,8 +129,7 @@ func (s *Server) GetBlobs(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.GetBlobs")
|
||||
defer span.End()
|
||||
|
||||
segments := strings.Split(r.URL.Path, "/")
|
||||
blockId := segments[len(segments)-1]
|
||||
blockId := r.PathValue("block_id")
|
||||
|
||||
// Check if versioned_hashes parameter is provided
|
||||
versionedHashesStr := r.URL.Query()["versioned_hashes"]
|
||||
|
||||
@@ -64,6 +64,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("genesis", func(t *testing.T) {
|
||||
u := "http://foo.example/genesis"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "genesis")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{}
|
||||
@@ -78,6 +79,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("head", func(t *testing.T) {
|
||||
u := "http://foo.example/head"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -126,6 +128,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("finalized", func(t *testing.T) {
|
||||
u := "http://foo.example/finalized"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -150,6 +153,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("root", func(t *testing.T) {
|
||||
u := "http://foo.example/" + hexutil.Encode(blockRoot[:])
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", hexutil.Encode(blockRoot[:]))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -174,6 +178,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("slot", func(t *testing.T) {
|
||||
u := fmt.Sprintf("http://foo.example/%d", es)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -198,6 +203,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("slot not found", func(t *testing.T) {
|
||||
u := fmt.Sprintf("http://foo.example/%d", es-1)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es-1))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -215,6 +221,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("one blob only", func(t *testing.T) {
|
||||
u := fmt.Sprintf("http://foo.example/%d?indices=2", es)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -246,6 +253,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("no blobs returns an empty array", func(t *testing.T) {
|
||||
u := fmt.Sprintf("http://foo.example/%d", es)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -271,6 +279,7 @@ func TestBlobs(t *testing.T) {
|
||||
overLimit := params.BeaconConfig().MaxBlobsPerBlock(ds)
|
||||
u := fmt.Sprintf("http://foo.example/%d?indices=%d", es, overLimit)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{}
|
||||
@@ -285,6 +294,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("outside retention period returns 200 with what we have", func(t *testing.T) {
|
||||
u := fmt.Sprintf("http://foo.example/%d", es)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
moc := &mockChain.ChainService{FinalizedCheckPoint: ð.Checkpoint{Root: blockRoot[:]}, Block: denebBlock}
|
||||
@@ -315,6 +325,7 @@ func TestBlobs(t *testing.T) {
|
||||
|
||||
u := fmt.Sprintf("http://foo.example/%d", es+128)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es+128))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -345,6 +356,7 @@ func TestBlobs(t *testing.T) {
|
||||
|
||||
u := "http://foo.example/31"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "31")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -367,6 +379,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("malformed block ID", func(t *testing.T) {
|
||||
u := "http://foo.example/foo"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "foo")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{}
|
||||
@@ -381,6 +394,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("ssz", func(t *testing.T) {
|
||||
u := "http://foo.example/finalized?indices=0"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
request.Header.Add("Accept", "application/octet-stream")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -404,6 +418,7 @@ func TestBlobs(t *testing.T) {
|
||||
t.Run("ssz multiple blobs", func(t *testing.T) {
|
||||
u := "http://foo.example/finalized"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
request.Header.Add("Accept", "application/octet-stream")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -455,6 +470,7 @@ func TestBlobs_Electra(t *testing.T) {
|
||||
t.Run("max blobs for electra", func(t *testing.T) {
|
||||
u := fmt.Sprintf("http://foo.example/%d", es)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -487,6 +503,7 @@ func TestBlobs_Electra(t *testing.T) {
|
||||
limit := params.BeaconConfig().MaxBlobsPerBlock(es) - 1
|
||||
u := fmt.Sprintf("http://foo.example/%d?indices=%d", es, limit)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -519,6 +536,7 @@ func TestBlobs_Electra(t *testing.T) {
|
||||
overLimit := params.BeaconConfig().MaxBlobsPerBlock(es)
|
||||
u := fmt.Sprintf("http://foo.example/%d?indices=%d", es, overLimit)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", es))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{}
|
||||
@@ -617,6 +635,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("genesis", func(t *testing.T) {
|
||||
u := "http://foo.example/genesis"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "genesis")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{}
|
||||
@@ -631,6 +650,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("head", func(t *testing.T) {
|
||||
u := "http://foo.example/head"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -665,6 +685,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("finalized", func(t *testing.T) {
|
||||
u := "http://foo.example/finalized"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -688,6 +709,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("root", func(t *testing.T) {
|
||||
u := "http://foo.example/" + hexutil.Encode(blockRoot[:])
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", hexutil.Encode(blockRoot[:]))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -711,6 +733,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("slot", func(t *testing.T) {
|
||||
u := "http://foo.example/123"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "123")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -734,6 +757,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("slot not found", func(t *testing.T) {
|
||||
u := "http://foo.example/122"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "122")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -751,6 +775,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("no blobs returns an empty array", func(t *testing.T) {
|
||||
u := "http://foo.example/123"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "123")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -774,6 +799,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("outside retention period still returns 200 what we have in db ", func(t *testing.T) {
|
||||
u := "http://foo.example/123"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "123")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
moc := &mockChain.ChainService{FinalizedCheckPoint: ð.Checkpoint{Root: blockRoot[:]}, Block: denebBlock}
|
||||
@@ -803,6 +829,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
|
||||
u := "http://foo.example/333"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "333")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -832,6 +859,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
|
||||
u := "http://foo.example/31"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "31")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -853,6 +881,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("malformed block ID", func(t *testing.T) {
|
||||
u := "http://foo.example/foo"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "foo")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{}
|
||||
@@ -867,6 +896,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("ssz", func(t *testing.T) {
|
||||
u := "http://foo.example/finalized"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
request.Header.Add("Accept", "application/octet-stream")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -889,6 +919,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("ssz multiple blobs", func(t *testing.T) {
|
||||
u := "http://foo.example/finalized"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
request.Header.Add("Accept", "application/octet-stream")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -910,6 +941,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
t.Run("versioned_hashes invalid hex", func(t *testing.T) {
|
||||
u := "http://foo.example/finalized?versioned_hashes=invalidhex,invalid2hex"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -935,6 +967,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
shortHash := "0x1234567890abcdef1234567890abcdef"
|
||||
u := fmt.Sprintf("http://foo.example/finalized?versioned_hashes=%s", shortHash)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -961,6 +994,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
|
||||
u := fmt.Sprintf("http://foo.example/finalized?versioned_hashes=%s", hexutil.Encode(versionedHash[:]))
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -990,6 +1024,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
u := fmt.Sprintf("http://foo.example/finalized?versioned_hashes=%s&versioned_hashes=%s",
|
||||
hexutil.Encode(versionedHash1[:]), hexutil.Encode(versionedHash3[:]))
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "finalized")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -1026,6 +1061,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
|
||||
u := "http://foo.example/323"
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", "323")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.Blocker = &lookup.BeaconDbBlocker{
|
||||
@@ -1063,6 +1099,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
|
||||
u := fmt.Sprintf("http://foo.example/%d", fuluForkSlot)
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", fuluForkSlot))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
// Create an empty blob storage (won't be used but needs to be non-nil)
|
||||
@@ -1117,6 +1154,7 @@ func TestGetBlobs(t *testing.T) {
|
||||
hexutil.Encode(versionedHash1[:]),
|
||||
hexutil.Encode(versionedHash2[:]))
|
||||
request := httptest.NewRequest("GET", u, nil)
|
||||
request.SetPathValue("block_id", fmt.Sprintf("%d", fuluForkSlot2))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
// Create an empty blob storage (won't be used but needs to be non-nil)
|
||||
|
||||
@@ -258,8 +258,7 @@ func (s *Server) DataColumnSidecars(w http.ResponseWriter, r *http.Request) {
|
||||
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
segments := strings.Split(r.URL.Path, "/")
|
||||
blockId := segments[len(segments)-1]
|
||||
blockId := r.PathValue("block_id")
|
||||
|
||||
verifiedDataColumns, rpcErr := s.Blocker.DataColumns(ctx, blockId, indices)
|
||||
if rpcErr != nil {
|
||||
|
||||
@@ -647,6 +647,7 @@ func TestDataColumnSidecars(t *testing.T) {
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/debug/beacon/data_column_sidecars/head", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -682,6 +683,7 @@ func TestDataColumnSidecars(t *testing.T) {
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/debug/beacon/data_column_sidecars/head", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -718,6 +720,7 @@ func TestDataColumnSidecars(t *testing.T) {
|
||||
|
||||
// Test with invalid index (out of range)
|
||||
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/debug/beacon/data_column_sidecars/head?indices=9999", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -754,6 +757,7 @@ func TestDataColumnSidecars(t *testing.T) {
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/debug/beacon/data_column_sidecars/head", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -797,6 +801,7 @@ func TestDataColumnSidecars(t *testing.T) {
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/debug/beacon/data_column_sidecars/head", nil)
|
||||
request.SetPathValue("block_id", "head")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"net/http"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/altair"
|
||||
@@ -28,8 +27,7 @@ import (
|
||||
func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.BlockRewards")
|
||||
defer span.End()
|
||||
segments := strings.Split(r.URL.Path, "/")
|
||||
blockId := segments[len(segments)-1]
|
||||
blockId := r.PathValue("block_id")
|
||||
|
||||
blk, err := s.Blocker.Block(r.Context(), []byte(blockId))
|
||||
if !shared.WriteBlockFetchError(w, blk, err) {
|
||||
@@ -116,8 +114,7 @@ func (s *Server) AttestationRewards(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.SyncCommitteeRewards")
|
||||
defer span.End()
|
||||
segments := strings.Split(r.URL.Path, "/")
|
||||
blockId := segments[len(segments)-1]
|
||||
blockId := r.PathValue("block_id")
|
||||
|
||||
blk, err := s.Blocker.Block(r.Context(), []byte(blockId))
|
||||
if !shared.WriteBlockFetchError(w, blk, err) {
|
||||
@@ -199,8 +196,7 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (s *Server) attRewardsState(w http.ResponseWriter, r *http.Request) (state.BeaconState, bool) {
|
||||
segments := strings.Split(r.URL.Path, "/")
|
||||
requestedEpoch, err := strconv.ParseUint(segments[len(segments)-1], 10, 64)
|
||||
requestedEpoch, err := strconv.ParseUint(r.PathValue("epoch"), 10, 64)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not decode epoch: "+err.Error(), http.StatusBadRequest)
|
||||
return nil, false
|
||||
|
||||
@@ -268,6 +268,7 @@ func TestBlockRewards(t *testing.T) {
|
||||
}
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/0"
|
||||
request := httptest.NewRequest("GET", url, nil)
|
||||
request.SetPathValue("block_id", "0")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -298,6 +299,7 @@ func TestBlockRewards(t *testing.T) {
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/2"
|
||||
request := httptest.NewRequest("GET", url, nil)
|
||||
request.SetPathValue("block_id", "2")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -334,6 +336,7 @@ func TestBlockRewards(t *testing.T) {
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/2"
|
||||
request := httptest.NewRequest("GET", url, nil)
|
||||
request.SetPathValue("block_id", "2")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -370,6 +373,7 @@ func TestBlockRewards(t *testing.T) {
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/2"
|
||||
request := httptest.NewRequest("GET", url, nil)
|
||||
request.SetPathValue("block_id", "2")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -406,6 +410,7 @@ func TestBlockRewards(t *testing.T) {
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/2"
|
||||
request := httptest.NewRequest("GET", url, nil)
|
||||
request.SetPathValue("block_id", "2")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -442,6 +447,7 @@ func TestBlockRewards(t *testing.T) {
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/2"
|
||||
request := httptest.NewRequest("GET", url, nil)
|
||||
request.SetPathValue("block_id", "2")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -511,6 +517,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
t.Run("ideal rewards", func(t *testing.T) {
|
||||
url := "http://only.the.epoch.number.at.the.end.is.important/1"
|
||||
request := httptest.NewRequest("POST", url, nil)
|
||||
request.SetPathValue("epoch", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -540,6 +547,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("epoch", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -563,6 +571,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
t.Run("all vals", func(t *testing.T) {
|
||||
url := "http://only.the.epoch.number.at.the.end.is.important/1"
|
||||
request := httptest.NewRequest("POST", url, nil)
|
||||
request.SetPathValue("epoch", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -605,6 +614,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("epoch", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -643,6 +653,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("epoch", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -660,6 +671,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("epoch", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -681,6 +693,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("epoch", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -699,6 +712,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("epoch", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -712,6 +726,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
t.Run("phase 0", func(t *testing.T) {
|
||||
url := "http://only.the.epoch.number.at.the.end.is.important/0"
|
||||
request := httptest.NewRequest("POST", url, nil)
|
||||
request.SetPathValue("epoch", "0")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -725,6 +740,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
t.Run("invalid epoch", func(t *testing.T) {
|
||||
url := "http://only.the.epoch.number.at.the.end.is.important/foo"
|
||||
request := httptest.NewRequest("POST", url, nil)
|
||||
request.SetPathValue("epoch", "foo")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -738,6 +754,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
t.Run("previous epoch", func(t *testing.T) {
|
||||
url := "http://only.the.epoch.number.at.the.end.is.important/2"
|
||||
request := httptest.NewRequest("POST", url, nil)
|
||||
request.SetPathValue("epoch", "2")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -751,6 +768,7 @@ func TestAttestationRewards(t *testing.T) {
|
||||
t.Run("epoch overflow", func(t *testing.T) {
|
||||
url := "http://only.the.epoch.number.at.the.end.is.important/" + strconv.FormatUint(math.MaxUint64, 10)
|
||||
request := httptest.NewRequest("POST", url, nil)
|
||||
request.SetPathValue("epoch", strconv.FormatUint(math.MaxUint64, 10))
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -858,6 +876,7 @@ func TestSyncCommiteeRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("block_id", "32")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -885,6 +904,7 @@ func TestSyncCommiteeRewards(t *testing.T) {
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/32"
|
||||
request := httptest.NewRequest("POST", url, nil)
|
||||
request.SetPathValue("block_id", "32")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -916,6 +936,7 @@ func TestSyncCommiteeRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("block_id", "32")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -947,6 +968,7 @@ func TestSyncCommiteeRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("block_id", "32")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -977,6 +999,7 @@ func TestSyncCommiteeRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("block_id", "32")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -1004,6 +1027,7 @@ func TestSyncCommiteeRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("block_id", "32")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -1028,6 +1052,7 @@ func TestSyncCommiteeRewards(t *testing.T) {
|
||||
_, err = body.Write(valIds)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", url, &body)
|
||||
request.SetPathValue("block_id", "32")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -1047,6 +1072,7 @@ func TestSyncCommiteeRewards(t *testing.T) {
|
||||
|
||||
url := "http://only.the.slot.number.at.the.end.is.important/0"
|
||||
request := httptest.NewRequest("POST", url, nil)
|
||||
request.SetPathValue("block_id", "0")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ go_library(
|
||||
"//api/server/structs:go_default_library",
|
||||
"//beacon-chain/blockchain:go_default_library",
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
"//beacon-chain/sync:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
@@ -30,6 +31,7 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
"//network/httputil:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/rpc/lookup"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/stategen"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/network/httputil"
|
||||
@@ -14,7 +15,7 @@ import (
|
||||
// The argument error should be a result of fetching state.
|
||||
func WriteStateFetchError(w http.ResponseWriter, err error) {
|
||||
var stateNotFoundError *lookup.StateNotFoundError
|
||||
if errors.As(err, &stateNotFoundError) {
|
||||
if errors.As(err, &stateNotFoundError) || errors.Is(err, stategen.ErrNoDataForSlot) {
|
||||
httputil.HandleError(w, "State not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/rpc/lookup"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/stategen"
|
||||
"github.com/OffchainLabs/prysm/v7/network/httputil"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
"github.com/pkg/errors"
|
||||
@@ -31,6 +32,11 @@ func TestWriteStateFetchError(t *testing.T) {
|
||||
expectedMessage: "Invalid state ID",
|
||||
expectedCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
err: errors.Wrap(stategen.ErrNoDataForSlot, "no data for slot"),
|
||||
expectedMessage: "State not found",
|
||||
expectedCode: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
err: errors.New("state not found"),
|
||||
expectedMessage: "Could not get state",
|
||||
|
||||
@@ -5,7 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"handlers.go",
|
||||
"handlers_block.go",
|
||||
"handlers_gloas.go",
|
||||
"handlers_block_gloas.go",
|
||||
"log.go",
|
||||
"server.go",
|
||||
],
|
||||
@@ -49,6 +49,8 @@ go_library(
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
"@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -56,6 +58,7 @@ go_library(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"handlers_block_gloas_test.go",
|
||||
"handlers_block_test.go",
|
||||
"handlers_test.go",
|
||||
],
|
||||
@@ -88,6 +91,7 @@ go_test(
|
||||
"//crypto/bls/common:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//network/httputil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
|
||||
@@ -1189,9 +1189,28 @@ func (s *Server) GetSyncCommitteeDuties(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
startingEpoch := min(requestedEpoch, currentEpoch)
|
||||
currentCommitteeFirstEpoch, err := slots.SyncCommitteePeriodStartEpoch(currentEpoch)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get sync committee period start epoch: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
st, err := s.Stater.StateByEpoch(ctx, startingEpoch)
|
||||
requestedCommitteeFirstEpoch, err := slots.SyncCommitteePeriodStartEpoch(requestedEpoch)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get sync committee period start epoch: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Sync committee assignments are computed at the start of the sync committee period and don't change during the period.
|
||||
// - For the current period we use the current epoch to avoid expensive state replays.
|
||||
// - For the next period we also use the current epoch and later read NextSyncCommittee (known one period in advance) to avoid fetching a future state.
|
||||
// - For a past period we fall back to the first epoch of that period.
|
||||
targetEpoch := currentEpoch
|
||||
if requestedCommitteeFirstEpoch < currentCommitteeFirstEpoch {
|
||||
targetEpoch = requestedCommitteeFirstEpoch
|
||||
}
|
||||
|
||||
st, err := s.Stater.StateByEpoch(ctx, targetEpoch)
|
||||
if err != nil {
|
||||
shared.WriteStateFetchError(w, err)
|
||||
return
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api"
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
@@ -49,8 +48,7 @@ func (s *Server) ProduceBlockV3(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
segments := strings.Split(r.URL.Path, "/")
|
||||
rawSlot := segments[len(segments)-1]
|
||||
rawSlot := r.PathValue("slot")
|
||||
rawRandaoReveal := r.URL.Query().Get("randao_reveal")
|
||||
rawGraffiti := r.URL.Query().Get("graffiti")
|
||||
rawSkipRandaoVerification := r.URL.Query().Get("skip_randao_verification")
|
||||
|
||||
238
beacon-chain/rpc/eth/validator/handlers_block_gloas.go
Normal file
238
beacon-chain/rpc/eth/validator/handlers_block_gloas.go
Normal file
@@ -0,0 +1,238 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api"
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/rpc/eth/shared"
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls/common"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
|
||||
"github.com/OffchainLabs/prysm/v7/network/httputil"
|
||||
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
// ProduceBlockV4 requests a beacon node to produce a valid Gloas block.
|
||||
// When include_payload=true (default), the response includes the execution payload
|
||||
// envelope alongside the beacon block.
|
||||
// Endpoint: GET /eth/v4/validator/blocks/{slot}
|
||||
func (s *Server) ProduceBlockV4(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.ProduceBlockV4")
|
||||
defer span.End()
|
||||
|
||||
if shared.IsSyncing(ctx, w, s.SyncChecker, s.HeadFetcher, s.TimeFetcher, s.OptimisticModeFetcher) {
|
||||
return
|
||||
}
|
||||
|
||||
rawSlot := r.PathValue("slot")
|
||||
|
||||
slot, valid := shared.ValidateUint(w, "slot", rawSlot)
|
||||
if !valid {
|
||||
return
|
||||
}
|
||||
if slots.ToEpoch(primitives.Slot(slot)) < params.BeaconConfig().GloasForkEpoch {
|
||||
httputil.HandleError(w, "ProduceBlockV4 is only supported for Gloas and later forks", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rawRandaoReveal := r.URL.Query().Get("randao_reveal")
|
||||
rawGraffiti := r.URL.Query().Get("graffiti")
|
||||
rawSkipRandaoVerification := r.URL.Query().Get("skip_randao_verification")
|
||||
|
||||
var bbFactor *wrapperspb.UInt64Value
|
||||
rawBbFactor, bbValue, ok := shared.UintFromQuery(w, r, "builder_boost_factor", false)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if rawBbFactor != "" {
|
||||
bbFactor = &wrapperspb.UInt64Value{Value: bbValue}
|
||||
}
|
||||
|
||||
includePayload := true
|
||||
if raw := r.URL.Query().Get("include_payload"); raw == "false" {
|
||||
includePayload = false
|
||||
}
|
||||
|
||||
var randaoReveal []byte
|
||||
if rawSkipRandaoVerification == "true" {
|
||||
randaoReveal = common.InfiniteSignature[:]
|
||||
} else {
|
||||
rr, err := bytesutil.DecodeHexWithLength(rawRandaoReveal, fieldparams.BLSSignatureLength)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, errors.Wrap(err, "unable to decode randao reveal").Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
randaoReveal = rr
|
||||
}
|
||||
var graffiti []byte
|
||||
if rawGraffiti != "" {
|
||||
g, err := bytesutil.DecodeHexWithLength(rawGraffiti, 32)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, errors.Wrap(err, "unable to decode graffiti").Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
graffiti = g
|
||||
}
|
||||
|
||||
v1alpha1resp, err := s.V1Alpha1Server.GetBeaconBlock(ctx, ð.BlockRequest{
|
||||
Slot: primitives.Slot(slot),
|
||||
RandaoReveal: randaoReveal,
|
||||
Graffiti: graffiti,
|
||||
SkipMevBoost: false,
|
||||
BuilderBoostFactor: bbFactor,
|
||||
EagerPayloadStateRoot: includePayload,
|
||||
})
|
||||
if err != nil {
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
gloasBlock, ok := v1alpha1resp.Block.(*eth.GenericBeaconBlock_Gloas)
|
||||
if !ok {
|
||||
httputil.HandleError(w, fmt.Sprintf("expected Gloas block, got %T", v1alpha1resp.Block), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
consensusBlockValue, httpError := getConsensusBlockValue(ctx, s.BlockRewardFetcher, v1alpha1resp.Block)
|
||||
if httpError != nil {
|
||||
log.WithError(httpError).Debug("Failed to get consensus block value")
|
||||
consensusBlockValue = "0"
|
||||
}
|
||||
|
||||
w.Header().Set(api.VersionHeader, version.String(version.Gloas))
|
||||
w.Header().Set(api.ConsensusBlockValueHeader, consensusBlockValue)
|
||||
w.Header().Set(api.ExecutionPayloadIncludedHeader, fmt.Sprintf("%v", includePayload))
|
||||
|
||||
isSSZ := httputil.RespondWithSsz(r)
|
||||
|
||||
if includePayload {
|
||||
envelopeResp, err := s.V1Alpha1Server.GetExecutionPayloadEnvelope(ctx, ð.ExecutionPayloadEnvelopeRequest{
|
||||
Slot: primitives.Slot(slot),
|
||||
})
|
||||
if err != nil {
|
||||
httputil.HandleError(w, errors.Wrap(err, "could not get execution payload envelope").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if isSSZ {
|
||||
sszResp, err := (ð.BeaconBlockContentsGloas{
|
||||
Block: gloasBlock.Gloas,
|
||||
ExecutionPayloadEnvelope: envelopeResp.Envelope,
|
||||
}).MarshalSSZ()
|
||||
if err != nil {
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
httputil.WriteSsz(w, sszResp)
|
||||
return
|
||||
}
|
||||
|
||||
blockContents, err := structs.BlockContentsGloasFromConsensus(gloasBlock.Gloas, envelopeResp.Envelope)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, errors.Wrap(err, "could not convert block contents").Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
jsonBytes, err := json.Marshal(blockContents)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
httputil.WriteJson(w, &structs.ProduceBlockV4Response{
|
||||
Version: version.String(version.Gloas),
|
||||
ConsensusBlockValue: consensusBlockValue,
|
||||
ExecutionPayloadIncluded: true,
|
||||
Data: jsonBytes,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// include_payload=false: return only the beacon block.
|
||||
if isSSZ {
|
||||
sszResp, err := gloasBlock.Gloas.MarshalSSZ()
|
||||
if err != nil {
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
httputil.WriteSsz(w, sszResp)
|
||||
return
|
||||
}
|
||||
|
||||
block, err := structs.BeaconBlockGloasFromConsensus(gloasBlock.Gloas)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
jsonBytes, err := json.Marshal(block)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
httputil.WriteJson(w, &structs.ProduceBlockV4Response{
|
||||
Version: version.String(version.Gloas),
|
||||
ConsensusBlockValue: consensusBlockValue,
|
||||
ExecutionPayloadIncluded: false,
|
||||
Data: jsonBytes,
|
||||
})
|
||||
}
|
||||
|
||||
// ExecutionPayloadEnvelope retrieves a cached execution payload envelope.
|
||||
//
|
||||
// Endpoint: GET /eth/v1/validator/execution_payload_envelope/{slot}
|
||||
func (s *Server) ExecutionPayloadEnvelope(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.ExecutionPayloadEnvelope")
|
||||
defer span.End()
|
||||
|
||||
rawSlot := r.PathValue("slot")
|
||||
if rawSlot == "" {
|
||||
httputil.HandleError(w, "slot is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
slot, err := strconv.ParseUint(rawSlot, 10, 64)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "invalid slot: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := s.V1Alpha1Server.GetExecutionPayloadEnvelope(ctx, ð.ExecutionPayloadEnvelopeRequest{
|
||||
Slot: primitives.Slot(slot),
|
||||
})
|
||||
if err != nil {
|
||||
if st, ok := status.FromError(err); ok {
|
||||
switch st.Code() {
|
||||
case codes.NotFound:
|
||||
httputil.HandleError(w, st.Message(), http.StatusNotFound)
|
||||
case codes.InvalidArgument:
|
||||
httputil.HandleError(w, st.Message(), http.StatusBadRequest)
|
||||
default:
|
||||
httputil.HandleError(w, st.Message(), http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
httputil.HandleError(w, "could not get execution payload envelope: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
jsonEnvelope, err := structs.ExecutionPayloadEnvelopeFromConsensus(resp.Envelope)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "could not convert envelope to JSON: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set(api.VersionHeader, version.String(version.Gloas))
|
||||
httputil.WriteJson(w, &structs.GetValidatorExecutionPayloadEnvelopeResponse{
|
||||
Version: version.String(version.Gloas),
|
||||
Data: jsonEnvelope,
|
||||
})
|
||||
}
|
||||
235
beacon-chain/rpc/eth/validator/handlers_block_gloas_test.go
Normal file
235
beacon-chain/rpc/eth/validator/handlers_block_gloas_test.go
Normal file
@@ -0,0 +1,235 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api"
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
blockchainTesting "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing"
|
||||
rewardtesting "github.com/OffchainLabs/prysm/v7/beacon-chain/rpc/eth/rewards/testing"
|
||||
mockSync "github.com/OffchainLabs/prysm/v7/beacon-chain/sync/initial-sync/testing"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
||||
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
mock2 "github.com/OffchainLabs/prysm/v7/testing/mock"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
var (
|
||||
testRandao = "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
|
||||
testGraffiti = "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
|
||||
)
|
||||
|
||||
func testEnvelope() *eth.ExecutionPayloadEnvelope {
|
||||
return ð.ExecutionPayloadEnvelope{
|
||||
Payload: &enginev1.ExecutionPayloadDeneb{
|
||||
ParentHash: make([]byte, 32),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, 32),
|
||||
ReceiptsRoot: make([]byte, 32),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: make([]byte, 32),
|
||||
BaseFeePerGas: make([]byte, 32),
|
||||
BlockHash: make([]byte, 32),
|
||||
},
|
||||
BuilderIndex: 0,
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
StateRoot: make([]byte, 32),
|
||||
}
|
||||
}
|
||||
|
||||
func gloasGenericBlock() *eth.GenericBeaconBlock {
|
||||
return ð.GenericBeaconBlock{
|
||||
Block: ð.GenericBeaconBlock_Gloas{
|
||||
Gloas: util.NewBeaconBlockGloas().Block,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestProduceBlockV4_IncludePayloadTrue(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
|
||||
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), gomock.Any()).Return(gloasGenericBlock(), nil)
|
||||
v1alpha1Server.EXPECT().GetExecutionPayloadEnvelope(gomock.Any(), gomock.Any()).Return(
|
||||
ð.ExecutionPayloadEnvelopeResponse{Envelope: testEnvelope()}, nil,
|
||||
)
|
||||
|
||||
server := &Server{
|
||||
V1Alpha1Server: v1alpha1Server,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
OptimisticModeFetcher: &blockchainTesting.ChainService{},
|
||||
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: &structs.BlockRewards{Total: "10"}},
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v4/validator/blocks/1?randao_reveal=%s&graffiti=%s", testRandao, testGraffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV4(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
var resp structs.ProduceBlockV4Response
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp))
|
||||
assert.Equal(t, "gloas", resp.Version)
|
||||
assert.Equal(t, true, resp.ExecutionPayloadIncluded)
|
||||
assert.Equal(t, "10000000000", resp.ConsensusBlockValue)
|
||||
|
||||
var blockContents structs.BlockContentsGloas
|
||||
require.NoError(t, json.Unmarshal(resp.Data, &blockContents))
|
||||
assert.NotNil(t, blockContents.Block)
|
||||
assert.NotNil(t, blockContents.ExecutionPayloadEnvelope)
|
||||
|
||||
require.Equal(t, "gloas", writer.Header().Get(api.VersionHeader))
|
||||
require.Equal(t, "10000000000", writer.Header().Get(api.ConsensusBlockValueHeader))
|
||||
require.Equal(t, "true", writer.Header().Get(api.ExecutionPayloadIncludedHeader))
|
||||
}
|
||||
|
||||
func TestProduceBlockV4_IncludePayloadFalse(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
|
||||
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), gomock.Any()).Return(gloasGenericBlock(), nil)
|
||||
|
||||
server := &Server{
|
||||
V1Alpha1Server: v1alpha1Server,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
OptimisticModeFetcher: &blockchainTesting.ChainService{},
|
||||
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: &structs.BlockRewards{Total: "10"}},
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v4/validator/blocks/1?randao_reveal=%s&graffiti=%s&include_payload=false", testRandao, testGraffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV4(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
var resp structs.ProduceBlockV4Response
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp))
|
||||
assert.Equal(t, "gloas", resp.Version)
|
||||
assert.Equal(t, false, resp.ExecutionPayloadIncluded)
|
||||
|
||||
var block structs.BeaconBlockGloas
|
||||
require.NoError(t, json.Unmarshal(resp.Data, &block))
|
||||
assert.NotNil(t, block.Body)
|
||||
|
||||
require.Equal(t, "gloas", writer.Header().Get(api.VersionHeader))
|
||||
require.Equal(t, "false", writer.Header().Get(api.ExecutionPayloadIncludedHeader))
|
||||
}
|
||||
|
||||
func TestProduceBlockV4_PreGloasSlotRejected(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 100
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
|
||||
server := &Server{
|
||||
V1Alpha1Server: v1alpha1Server,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
OptimisticModeFetcher: &blockchainTesting.ChainService{},
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v4/validator/blocks/1?randao_reveal=%s&graffiti=%s", testRandao, testGraffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV4(writer, request)
|
||||
assert.Equal(t, http.StatusBadRequest, writer.Code)
|
||||
assert.StringContains(t, "only supported for Gloas", writer.Body.String())
|
||||
}
|
||||
|
||||
func TestProduceBlockV4_Syncing(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
chainService := &blockchainTesting.ChainService{}
|
||||
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
|
||||
server := &Server{
|
||||
V1Alpha1Server: v1alpha1Server,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: true},
|
||||
HeadFetcher: chainService,
|
||||
TimeFetcher: chainService,
|
||||
OptimisticModeFetcher: chainService,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v4/validator/blocks/1?randao_reveal=%s&graffiti=%s", testRandao, testGraffiti), nil)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV4(writer, request)
|
||||
assert.Equal(t, http.StatusServiceUnavailable, writer.Code)
|
||||
}
|
||||
|
||||
func TestProduceBlockV4_SSZ_IncludePayloadTrue(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
|
||||
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), gomock.Any()).Return(gloasGenericBlock(), nil)
|
||||
v1alpha1Server.EXPECT().GetExecutionPayloadEnvelope(gomock.Any(), gomock.Any()).Return(
|
||||
ð.ExecutionPayloadEnvelopeResponse{Envelope: testEnvelope()}, nil,
|
||||
)
|
||||
|
||||
server := &Server{
|
||||
V1Alpha1Server: v1alpha1Server,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
OptimisticModeFetcher: &blockchainTesting.ChainService{},
|
||||
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: &structs.BlockRewards{Total: "10"}},
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v4/validator/blocks/1?randao_reveal=%s&graffiti=%s", testRandao, testGraffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", "application/octet-stream")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV4(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
assert.Equal(t, "application/octet-stream", writer.Header().Get("Content-Type"))
|
||||
assert.Equal(t, true, writer.Body.Len() > 0)
|
||||
}
|
||||
|
||||
func TestProduceBlockV4_SSZ_IncludePayloadFalse(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
v1alpha1Server := mock2.NewMockBeaconNodeValidatorServer(ctrl)
|
||||
v1alpha1Server.EXPECT().GetBeaconBlock(gomock.Any(), gomock.Any()).Return(gloasGenericBlock(), nil)
|
||||
|
||||
server := &Server{
|
||||
V1Alpha1Server: v1alpha1Server,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
OptimisticModeFetcher: &blockchainTesting.ChainService{},
|
||||
BlockRewardFetcher: &rewardtesting.MockBlockRewardFetcher{Rewards: &structs.BlockRewards{Total: "10"}},
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v4/validator/blocks/1?randao_reveal=%s&graffiti=%s&include_payload=false", testRandao, testGraffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", "application/octet-stream")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV4(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
assert.Equal(t, "application/octet-stream", writer.Header().Get("Content-Type"))
|
||||
}
|
||||
@@ -57,6 +57,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
SyncChecker: syncChecker,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -93,6 +94,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -131,6 +133,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -169,6 +172,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -207,6 +211,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -245,6 +250,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -283,6 +289,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -321,6 +328,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -359,6 +367,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -397,6 +406,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -435,6 +445,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -473,6 +484,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -505,6 +517,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
SyncChecker: syncChecker,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v3/validator/blocks/asdfsad", nil)
|
||||
request.SetPathValue("slot", "asdfsad")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -518,6 +531,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
SyncChecker: syncChecker,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, "http://foo.example/eth/v3/validator/blocks/1?randao_reveal=0x213123", nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -566,6 +580,7 @@ func TestProduceBlockV3(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
server.ProduceBlockV3(writer, request)
|
||||
@@ -611,6 +626,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
SyncChecker: syncChecker,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -649,6 +665,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -691,6 +708,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -732,6 +750,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -773,6 +792,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -814,6 +834,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -855,6 +876,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -896,6 +918,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -937,6 +960,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -978,6 +1002,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -1019,6 +1044,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -1060,6 +1086,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
@@ -1103,6 +1130,7 @@ func TestProduceBlockV3SSZ(t *testing.T) {
|
||||
BlockRewardFetcher: rewardFetcher,
|
||||
}
|
||||
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://foo.example/eth/v3/validator/blocks/1?randao_reveal=%s&graffiti=%s", randao, graffiti), nil)
|
||||
request.SetPathValue("slot", "1")
|
||||
request.Header.Set("Accept", api.OctetStreamMediaType)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/network/httputil"
|
||||
)
|
||||
|
||||
// ProduceBlockV4 requests a beacon node to produce a valid Gloas block.
|
||||
//
|
||||
// TODO: Implement Gloas-specific block production.
|
||||
// Endpoint: GET /eth/v4/validator/blocks/{slot}
|
||||
func (s *Server) ProduceBlockV4(w http.ResponseWriter, r *http.Request) {
|
||||
httputil.HandleError(w, "ProduceBlockV4 not yet implemented", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// ExecutionPayloadEnvelope retrieves a cached execution payload envelope.
|
||||
//
|
||||
// TODO: Implement envelope retrieval from cache.
|
||||
// Endpoint: GET /eth/v1/validator/execution_payload_envelope/{slot}/{builder_index}
|
||||
func (s *Server) ExecutionPayloadEnvelope(w http.ResponseWriter, r *http.Request) {
|
||||
httputil.HandleError(w, "ExecutionPayloadEnvelope not yet implemented", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// PublishExecutionPayloadEnvelope broadcasts a signed execution payload envelope.
|
||||
//
|
||||
// TODO: Implement envelope validation and broadcast.
|
||||
// Endpoint: POST /eth/v1/beacon/execution_payload_envelope
|
||||
func (s *Server) PublishExecutionPayloadEnvelope(w http.ResponseWriter, r *http.Request) {
|
||||
httputil.HandleError(w, "PublishExecutionPayloadEnvelope not yet implemented", http.StatusNotImplemented)
|
||||
}
|
||||
@@ -3062,6 +3062,93 @@ func TestGetSyncCommitteeDuties(t *testing.T) {
|
||||
require.Equal(t, 1, len(duty.ValidatorSyncCommitteeIndices))
|
||||
assert.Equal(t, "1", duty.ValidatorSyncCommitteeIndices[0])
|
||||
})
|
||||
t.Run("past sync committee period", func(t *testing.T) {
|
||||
// Chain is two periods ahead, the request targets epoch 0 (a past period).
|
||||
// The handler must load the state at the requested period's start epoch and
|
||||
// use its CurrentSyncCommittee, NOT the current state's committee.
|
||||
pastEpochStartSlot := primitives.Slot(0)
|
||||
currentSlot := primitives.Slot(uint64(params.BeaconConfig().EpochsPerSyncCommitteePeriod) * 2 * uint64(params.BeaconConfig().SlotsPerEpoch))
|
||||
|
||||
pastSt, _ := util.DeterministicGenesisStateAltair(t, numVals)
|
||||
require.NoError(t, pastSt.SetSlot(pastEpochStartSlot))
|
||||
require.NoError(t, pastSt.SetGenesisTime(genesisTime))
|
||||
|
||||
pastVals := pastSt.Validators()
|
||||
pastCommittee := ðpbalpha.SyncCommittee{AggregatePubkey: make([]byte, 48)}
|
||||
|
||||
for i := range 5 {
|
||||
pastCommittee.Pubkeys = append(pastCommittee.Pubkeys, pastVals[i].PublicKey)
|
||||
}
|
||||
|
||||
require.NoError(t, pastSt.SetCurrentSyncCommittee(pastCommittee))
|
||||
|
||||
pastNextCommittee := ðpbalpha.SyncCommittee{AggregatePubkey: make([]byte, 48)}
|
||||
for i := 5; i < 10; i++ {
|
||||
pastNextCommittee.Pubkeys = append(pastNextCommittee.Pubkeys, pastVals[i].PublicKey)
|
||||
}
|
||||
|
||||
require.NoError(t, pastSt.SetNextSyncCommittee(pastNextCommittee))
|
||||
|
||||
// Current state has different sync committees so that if the handler used
|
||||
// the current state instead of the past state, assertions below would fail.
|
||||
currentSt, _ := util.DeterministicGenesisStateAltair(t, numVals)
|
||||
require.NoError(t, currentSt.SetSlot(currentSlot))
|
||||
require.NoError(t, currentSt.SetGenesisTime(genesisTime))
|
||||
|
||||
currentVals := currentSt.Validators()
|
||||
currentCommittee := ðpbalpha.SyncCommittee{AggregatePubkey: make([]byte, 48)}
|
||||
|
||||
for i := 5; i < 10; i++ {
|
||||
currentCommittee.Pubkeys = append(currentCommittee.Pubkeys, currentVals[i].PublicKey)
|
||||
}
|
||||
|
||||
require.NoError(t, currentSt.SetCurrentSyncCommittee(currentCommittee))
|
||||
|
||||
currentNextCommittee := ðpbalpha.SyncCommittee{AggregatePubkey: make([]byte, 48)}
|
||||
for i := range 5 {
|
||||
currentNextCommittee.Pubkeys = append(currentNextCommittee.Pubkeys, currentVals[i].PublicKey)
|
||||
}
|
||||
|
||||
require.NoError(t, currentSt.SetNextSyncCommittee(currentNextCommittee))
|
||||
|
||||
mockChainService := &mockChain.ChainService{Genesis: genesisTime, Slot: ¤tSlot, State: currentSt}
|
||||
s := &Server{
|
||||
Stater: &testutil.MockStater{StatesByEpoch: map[primitives.Epoch]state.BeaconState{
|
||||
0: pastSt,
|
||||
primitives.Epoch(uint64(params.BeaconConfig().EpochsPerSyncCommitteePeriod) * 2): currentSt,
|
||||
}},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
TimeFetcher: mockChainService,
|
||||
HeadFetcher: mockChainService,
|
||||
OptimisticModeFetcher: mockChainService,
|
||||
}
|
||||
|
||||
var body bytes.Buffer
|
||||
_, err := body.WriteString("[\"1\"]")
|
||||
require.NoError(t, err)
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://www.example.com/eth/v1/validator/duties/sync/{epoch}", &body)
|
||||
request.SetPathValue("epoch", "0")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetSyncCommitteeDuties(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
resp := &structs.GetSyncCommitteeDutiesResponse{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
require.Equal(t, 1, len(resp.Data))
|
||||
|
||||
duty := resp.Data[0]
|
||||
// Validator 1 is in pastSt's CurrentSyncCommittee at index 1. If the handler
|
||||
// had loaded currentSt instead, validator 1 would not appear in its
|
||||
// CurrentSyncCommittee and no duty would be returned.
|
||||
require.Equal(t, hexutil.Encode(pastVals[1].PublicKey), duty.Pubkey)
|
||||
require.Equal(t, "1", duty.ValidatorIndex)
|
||||
require.Equal(t, 1, len(duty.ValidatorSyncCommitteeIndices))
|
||||
require.Equal(t, "1", duty.ValidatorSyncCommitteeIndices[0])
|
||||
})
|
||||
|
||||
t.Run("epoch too far in the future", func(t *testing.T) {
|
||||
var body bytes.Buffer
|
||||
_, err := body.WriteString("[\"5\"]")
|
||||
|
||||
@@ -58,10 +58,12 @@ go_test(
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/dbval:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -140,13 +140,29 @@ func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.Beaco
|
||||
}
|
||||
case "finalized":
|
||||
checkpoint := p.ChainInfoFetcher.FinalizedCheckpt()
|
||||
s, err = p.StateGenService.StateByRoot(ctx, bytesutil.ToBytes32(checkpoint.Root))
|
||||
targetSlot, err := slots.EpochStart(checkpoint.Epoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get start slot")
|
||||
}
|
||||
// We use the stategen replayer to fetch the finalized state and then
|
||||
// replay it to the start slot of our checkpoint's epoch. The replayer
|
||||
// only ever accesses our canonical history, so the state retrieved will
|
||||
// always be the finalized state at that epoch.
|
||||
s, err = p.ReplayerBuilder.ReplayerForSlot(targetSlot).ReplayToSlot(ctx, targetSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get finalized state")
|
||||
}
|
||||
case "justified":
|
||||
checkpoint := p.ChainInfoFetcher.CurrentJustifiedCheckpt()
|
||||
s, err = p.StateGenService.StateByRoot(ctx, bytesutil.ToBytes32(checkpoint.Root))
|
||||
targetSlot, err := slots.EpochStart(checkpoint.Epoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get start slot")
|
||||
}
|
||||
// We use the stategen replayer to fetch the justified state and then
|
||||
// replay it to the start slot of our checkpoint's epoch. The replayer
|
||||
// only ever accesses our canonical history, so the state retrieved will
|
||||
// always be the justified state at that epoch.
|
||||
s, err = p.ReplayerBuilder.ReplayerForSlot(targetSlot).ReplayToSlot(ctx, targetSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get justified state")
|
||||
}
|
||||
@@ -275,8 +291,37 @@ func (p *BeaconDbStater) StateBySlot(ctx context.Context, target primitives.Slot
|
||||
return nil, errors.New("requested slot is in the future")
|
||||
}
|
||||
|
||||
if p.BeaconDB != nil {
|
||||
earliestSlot, err := p.BeaconDB.EarliestSlot(ctx)
|
||||
if err != nil && !errors.Is(err, db.ErrNotFound) {
|
||||
return nil, errors.Wrap(err, "could not determine state availability")
|
||||
}
|
||||
if err == nil && target > 0 && target < earliestSlot {
|
||||
return nil, &StateNotFoundError{
|
||||
message: fmt.Sprintf("requested slot %d is unavailable; earliest available slot is %d", target, earliestSlot),
|
||||
}
|
||||
}
|
||||
|
||||
backfillStatus, err := p.BeaconDB.BackfillStatus(ctx)
|
||||
if err != nil && !errors.Is(err, db.ErrNotFound) {
|
||||
return nil, errors.Wrap(err, "could not determine state availability")
|
||||
}
|
||||
if err == nil && backfillStatus != nil {
|
||||
if target > 0 && target < primitives.Slot(backfillStatus.LowSlot) {
|
||||
return nil, &StateNotFoundError{
|
||||
message: fmt.Sprintf("requested slot %d is unavailable; backfill starts at slot %d", target, backfillStatus.LowSlot),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
st, err := p.ReplayerBuilder.ReplayerForSlot(target).ReplayBlocks(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, stategen.ErrNoDataForSlot) {
|
||||
return nil, &StateNotFoundError{
|
||||
message: fmt.Sprintf("requested slot %d is unavailable; historical data not available", target),
|
||||
}
|
||||
}
|
||||
msg := fmt.Sprintf("error while replaying history to slot=%d", target)
|
||||
return nil, errors.Wrap(err, msg)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package lookup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -15,11 +16,13 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
"github.com/OffchainLabs/prysm/v7/proto/dbval"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestGetState(t *testing.T) {
|
||||
@@ -91,20 +94,20 @@ func TestGetState(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("finalized", func(t *testing.T) {
|
||||
// Use a block root distinct from the state root to verify
|
||||
// we look up by checkpoint root, not by state root.
|
||||
blockRoot := bytesutil.ToBytes32([]byte("finalized-block-root"))
|
||||
stateGen := mockstategen.NewService()
|
||||
stateGen.StatesByRoot[blockRoot] = newBeaconState
|
||||
replayer := mockstategen.NewReplayerBuilder()
|
||||
replayer.SetMockStateForSlot(newBeaconState, params.BeaconConfig().SlotsPerEpoch*10)
|
||||
stateGen.StatesByRoot[stateRoot] = newBeaconState
|
||||
|
||||
p := BeaconDbStater{
|
||||
ChainInfoFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: ðpb.Checkpoint{
|
||||
Root: blockRoot[:],
|
||||
Root: stateRoot[:],
|
||||
Epoch: 10,
|
||||
},
|
||||
},
|
||||
StateGenService: stateGen,
|
||||
ReplayerBuilder: replayer,
|
||||
}
|
||||
|
||||
s, err := p.State(ctx, []byte("finalized"))
|
||||
@@ -115,18 +118,20 @@ func TestGetState(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("justified", func(t *testing.T) {
|
||||
blockRoot := bytesutil.ToBytes32([]byte("justified-block-root"))
|
||||
stateGen := mockstategen.NewService()
|
||||
stateGen.StatesByRoot[blockRoot] = newBeaconState
|
||||
replayer := mockstategen.NewReplayerBuilder()
|
||||
replayer.SetMockStateForSlot(newBeaconState, params.BeaconConfig().SlotsPerEpoch*10)
|
||||
stateGen.StatesByRoot[stateRoot] = newBeaconState
|
||||
|
||||
p := BeaconDbStater{
|
||||
ChainInfoFetcher: &chainMock.ChainService{
|
||||
CurrentJustifiedCheckPoint: ðpb.Checkpoint{
|
||||
Root: blockRoot[:],
|
||||
Root: stateRoot[:],
|
||||
Epoch: 10,
|
||||
},
|
||||
},
|
||||
StateGenService: stateGen,
|
||||
ReplayerBuilder: replayer,
|
||||
}
|
||||
|
||||
s, err := p.State(ctx, []byte("justified"))
|
||||
@@ -443,6 +448,72 @@ func TestStateBySlot_AfterHeadSlot(t *testing.T) {
|
||||
assert.Equal(t, primitives.Slot(101), st.Slot())
|
||||
}
|
||||
|
||||
func TestStateBySlot_EarlierThanEarliestAvailableSlot(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
db := testDB.SetupDB(t)
|
||||
target := primitives.Slot(100)
|
||||
|
||||
genesisRoot := bytesutil.ToBytes32([]byte("genesis"))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot))
|
||||
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.ParentRoot = genesisRoot[:]
|
||||
b.Block.Slot = target + 2
|
||||
util.SaveBlock(t, ctx, db, b)
|
||||
|
||||
currentSlot := target + 3
|
||||
p := BeaconDbStater{
|
||||
BeaconDB: db,
|
||||
GenesisTimeFetcher: &chainMock.ChainService{Slot: ¤tSlot},
|
||||
}
|
||||
|
||||
_, err := p.StateBySlot(ctx, target)
|
||||
require.ErrorContains(t, fmt.Sprintf("earliest available slot is %d", b.Block.Slot), err)
|
||||
var stateNotFoundErr *StateNotFoundError
|
||||
require.Equal(t, true, errors.As(err, &stateNotFoundErr))
|
||||
}
|
||||
|
||||
func TestStateBySlot_BeforeBackfillLowSlot(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
db := testDB.SetupDB(t)
|
||||
target := primitives.Slot(100)
|
||||
|
||||
genesisRoot := bytesutil.ToBytes32([]byte("genesis"))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot))
|
||||
|
||||
lowSlot := target + 1
|
||||
require.NoError(t, db.SaveBackfillStatus(ctx, &dbval.BackfillStatus{LowSlot: uint64(lowSlot)}))
|
||||
|
||||
currentSlot := lowSlot + 1
|
||||
p := BeaconDbStater{
|
||||
BeaconDB: db,
|
||||
GenesisTimeFetcher: &chainMock.ChainService{Slot: ¤tSlot},
|
||||
}
|
||||
|
||||
_, err := p.StateBySlot(ctx, target)
|
||||
require.ErrorContains(t, fmt.Sprintf("backfill starts at slot %d", lowSlot), err)
|
||||
var stateNotFoundErr *StateNotFoundError
|
||||
require.Equal(t, true, errors.As(err, &stateNotFoundErr))
|
||||
}
|
||||
|
||||
func TestStateBySlot_ReplayNoDataForSlotReturnsNotFound(t *testing.T) {
|
||||
target := primitives.Slot(100)
|
||||
currentSlot := target + 1
|
||||
mock := &chainMock.ChainService{Slot: ¤tSlot}
|
||||
mockReplayer := mockstategen.NewReplayerBuilder()
|
||||
mockReplayer.SetMockSlotError(target, errors.Wrap(stategen.ErrNoDataForSlot, fmt.Sprintf("slot %d not in db due to checkpoint sync", target)))
|
||||
|
||||
p := BeaconDbStater{
|
||||
GenesisTimeFetcher: mock,
|
||||
ReplayerBuilder: mockReplayer,
|
||||
}
|
||||
|
||||
_, err := p.StateBySlot(t.Context(), target)
|
||||
require.ErrorContains(t, "historical data not available", err)
|
||||
var stateNotFoundErr *StateNotFoundError
|
||||
require.Equal(t, true, errors.As(err, &stateNotFoundErr))
|
||||
}
|
||||
|
||||
func TestStateByEpoch(t *testing.T) {
|
||||
ctx := t.Context()
|
||||
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p"
|
||||
@@ -105,8 +104,7 @@ func (s *Server) RemoveTrustedPeer(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := trace.StartSpan(r.Context(), "node.RemoveTrustedPeer")
|
||||
defer span.End()
|
||||
|
||||
segments := strings.Split(r.URL.Path, "/")
|
||||
id := segments[len(segments)-1]
|
||||
id := r.PathValue("peer_id")
|
||||
peerId, err := peer.Decode(id)
|
||||
if err != nil {
|
||||
errJson := &httputil.DefaultJsonError{
|
||||
|
||||
@@ -227,6 +227,7 @@ func TestRemoveTrustedPeer(t *testing.T) {
|
||||
|
||||
url := "http://anything.is.fine.but.last.is.important/16Uiu2HAm1n583t4huDMMqEUUBuQs6bLts21mxCfX3tiqu9JfHvRJ"
|
||||
request := httptest.NewRequest("DELETE", url, nil)
|
||||
request.SetPathValue("peer_id", "16Uiu2HAm1n583t4huDMMqEUUBuQs6bLts21mxCfX3tiqu9JfHvRJ")
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.RemoveTrustedPeer(writer, request)
|
||||
|
||||
@@ -111,7 +111,7 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
|
||||
builderBoostFactor = primitives.Gwei(req.BuilderBoostFactor.Value)
|
||||
}
|
||||
|
||||
resp, err := vs.BuildBlockParallel(ctx, sBlk, head, req.SkipMevBoost, builderBoostFactor)
|
||||
resp, err := vs.BuildBlockParallel(ctx, sBlk, head, req.SkipMevBoost, builderBoostFactor, req.EagerPayloadStateRoot)
|
||||
l := log.WithFields(logrus.Fields{
|
||||
"sinceSlotStartTime": time.Since(t),
|
||||
"validator": sBlk.Block().ProposerIndex(),
|
||||
@@ -202,7 +202,7 @@ func (vs *Server) getParentState(ctx context.Context, slot primitives.Slot) (sta
|
||||
return head, parentRoot, err
|
||||
}
|
||||
|
||||
func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.SignedBeaconBlock, head state.BeaconState, skipMevBoost bool, builderBoostFactor primitives.Gwei) (*ethpb.GenericBeaconBlock, error) {
|
||||
func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.SignedBeaconBlock, head state.BeaconState, skipMevBoost bool, builderBoostFactor primitives.Gwei, eagerPayloadStateRoot bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
// Build consensus fields in background
|
||||
var wg sync.WaitGroup
|
||||
wg.Go(func() {
|
||||
@@ -296,19 +296,29 @@ func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.Signed
|
||||
|
||||
wg.Wait()
|
||||
|
||||
sr, err := vs.computeStateRoot(ctx, sBlk)
|
||||
sr, postBlockState, err := vs.computePostBlockStateAndRoot(ctx, sBlk)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not compute state root: %v", err)
|
||||
}
|
||||
sBlk.SetStateRoot(sr)
|
||||
|
||||
// For Gloas self-build, cache the execution payload envelope now that the
|
||||
// block is fully built (state root set). The envelope needs the final block
|
||||
// HTR as BeaconBlockRoot and the post-payload state root as StateRoot.
|
||||
// For Gloas self-build, build and cache the execution payload envelope now
|
||||
// that the block is fully built (state root set). The envelope needs the
|
||||
// final block HTR as BeaconBlockRoot and the post-payload state root as
|
||||
// StateRoot.
|
||||
//
|
||||
// When a remote P2P bid was selected, the winning builder is responsible
|
||||
// for producing the envelope, so we must not cache a self-build one.
|
||||
//
|
||||
// When eagerPayloadStateRoot is true, the post-block state is passed so the
|
||||
// envelope StateRoot is computed immediately. Otherwise it is left zeroed
|
||||
// and computed lazily when GetExecutionPayloadEnvelope is called.
|
||||
if sBlk.Version() >= version.Gloas && selfBuildEnvelope {
|
||||
if err := vs.storeExecutionPayloadEnvelope(sBlk, local); err != nil {
|
||||
var envelopeState state.BeaconState
|
||||
if eagerPayloadStateRoot {
|
||||
envelopeState = postBlockState
|
||||
}
|
||||
if err := vs.storeExecutionPayloadEnvelope(ctx, sBlk, local, envelopeState); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not build execution payload envelope: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -645,9 +655,25 @@ func (vs *Server) GetFeeRecipientByPubKey(ctx context.Context, request *ethpb.Fe
|
||||
}, nil
|
||||
}
|
||||
|
||||
// computeStateRoot computes the state root after a block has been processed through a state transition and
|
||||
// returns it to the validator client.
|
||||
func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.SignedBeaconBlock) ([]byte, error) {
|
||||
// computePostBlockStateAndRoot computes the state root after a block has been processed through a state transition and
|
||||
// returns both the state root bytes and the full post-block state.
|
||||
func (vs *Server) computePostBlockStateAndRoot(ctx context.Context, block interfaces.SignedBeaconBlock) ([]byte, state.BeaconState, error) {
|
||||
st, err := vs.computePostBlockState(ctx, block)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root, err := st.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not compute state root")
|
||||
}
|
||||
log.WithField("beaconStateRoot", fmt.Sprintf("%#x", root)).Debugf("Computed state root")
|
||||
return root[:], st, nil
|
||||
}
|
||||
|
||||
// computePostBlockState computes the post-block state by running the state transition.
|
||||
// It uses the same logic as CalculateStateRoot (Copy, feature flags, slot processing)
|
||||
// but returns the full state instead of just its hash.
|
||||
func (vs *Server) computePostBlockState(ctx context.Context, block interfaces.SignedBeaconBlock) (state.BeaconState, error) {
|
||||
roblock, err := blocks.NewROBlockWithRoot(block, [32]byte{}) // root is not used
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create ROBlock")
|
||||
@@ -656,17 +682,11 @@ func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.SignedB
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not retrieve beacon state")
|
||||
}
|
||||
root, err := transition.CalculateStateRoot(
|
||||
ctx,
|
||||
beaconState,
|
||||
block,
|
||||
)
|
||||
st, err := transition.CalculatePostState(ctx, beaconState, block)
|
||||
if err != nil {
|
||||
return vs.handleStateRootError(ctx, block, err)
|
||||
return vs.handlePostBlockStateError(ctx, block, err)
|
||||
}
|
||||
|
||||
log.WithField("beaconStateRoot", fmt.Sprintf("%#x", root)).Debugf("Computed state root")
|
||||
return root[:], nil
|
||||
return st, nil
|
||||
}
|
||||
|
||||
type computeStateRootAttemptsKeyType string
|
||||
@@ -674,8 +694,8 @@ type computeStateRootAttemptsKeyType string
|
||||
const computeStateRootAttemptsKey = computeStateRootAttemptsKeyType("compute-state-root-attempts")
|
||||
const maxComputeStateRootAttempts = 3
|
||||
|
||||
// handleStateRootError retries block construction in some error cases.
|
||||
func (vs *Server) handleStateRootError(ctx context.Context, block interfaces.SignedBeaconBlock, err error) ([]byte, error) {
|
||||
// handlePostBlockStateError retries block construction in some error cases.
|
||||
func (vs *Server) handlePostBlockStateError(ctx context.Context, block interfaces.SignedBeaconBlock, err error) (state.BeaconState, error) {
|
||||
if ctx.Err() != nil {
|
||||
return nil, status.Errorf(codes.Canceled, "context error: %v", ctx.Err())
|
||||
}
|
||||
@@ -724,8 +744,8 @@ func (vs *Server) handleStateRootError(ctx context.Context, block interfaces.Sig
|
||||
} else {
|
||||
ctx = context.WithValue(ctx, computeStateRootAttemptsKey, v+1)
|
||||
}
|
||||
// recursive call to compute state root again
|
||||
return vs.computeStateRoot(ctx, block)
|
||||
// recursive call to compute post-block state again
|
||||
return vs.computePostBlockState(ctx, block)
|
||||
}
|
||||
|
||||
// Deprecated: The gRPC API will remain the default and fully supported through v8 (expected in 2026) but will be eventually removed in favor of REST API.
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
coregloas "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
consensusblocks "github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
@@ -24,13 +25,14 @@ import (
|
||||
)
|
||||
|
||||
// storeExecutionPayloadEnvelope creates and caches the execution payload envelope
|
||||
// after the block is fully built (state root set). The envelope is cached with a
|
||||
// zeroed state root; the actual post-payload state root is computed lazily in
|
||||
// GetExecutionPayloadEnvelope once the block has been submitted and the post-block
|
||||
// state is available via StateGen.
|
||||
// after the block is fully built (state root set). If postBlockState is non-nil,
|
||||
// the envelope state root is eagerly computed; otherwise it is left zeroed for
|
||||
// lazy computation by GetExecutionPayloadEnvelope.
|
||||
func (vs *Server) storeExecutionPayloadEnvelope(
|
||||
ctx context.Context,
|
||||
sBlk interfaces.SignedBeaconBlock,
|
||||
local *consensusblocks.GetPayloadResponse,
|
||||
postBlockState state.BeaconState,
|
||||
) error {
|
||||
blockRoot, err := sBlk.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
@@ -45,7 +47,26 @@ func (vs *Server) storeExecutionPayloadEnvelope(
|
||||
BuilderIndex: params.BeaconConfig().BuilderIndexSelfBuild,
|
||||
BeaconBlockRoot: blockRoot[:],
|
||||
Slot: sBlk.Block().Slot(),
|
||||
StateRoot: make([]byte, 32), // zeroed; computed lazily in GetExecutionPayloadEnvelope
|
||||
StateRoot: make([]byte, 32),
|
||||
}
|
||||
|
||||
// When postBlockState is provided, eagerly compute the post-payload state
|
||||
// root so the envelope is immediately usable by ProduceBlockV4.
|
||||
// Otherwise, leave the state root zeroed for lazy computation later.
|
||||
if postBlockState != nil {
|
||||
stateCopy := postBlockState.Copy()
|
||||
roEnvelope, err := consensusblocks.WrappedROExecutionPayloadEnvelope(envelope)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not wrap envelope")
|
||||
}
|
||||
if err := coregloas.ApplyExecutionPayload(ctx, stateCopy, roEnvelope); err != nil {
|
||||
return errors.Wrap(err, "could not apply execution payload for envelope state root")
|
||||
}
|
||||
stateRoot, err := stateCopy.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not compute post-payload state root")
|
||||
}
|
||||
envelope.StateRoot = stateRoot[:]
|
||||
}
|
||||
|
||||
// Precompute data column sidecars now (inside ProposeBeaconBlock) so the
|
||||
|
||||
@@ -17,6 +17,62 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
)
|
||||
|
||||
func testGloasBlock(t *testing.T) (*consensusblocks.GetPayloadResponse, interfaces.SignedBeaconBlock) {
|
||||
t.Helper()
|
||||
|
||||
payload := &enginev1.ExecutionPayloadDeneb{
|
||||
ParentHash: make([]byte, 32),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, 32),
|
||||
ReceiptsRoot: make([]byte, 32),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: make([]byte, 32),
|
||||
BaseFeePerGas: make([]byte, 32),
|
||||
BlockHash: make([]byte, 32),
|
||||
ExtraData: make([]byte, 0),
|
||||
}
|
||||
ed, err := consensusblocks.WrappedExecutionPayloadDeneb(payload)
|
||||
require.NoError(t, err)
|
||||
|
||||
local := &consensusblocks.GetPayloadResponse{
|
||||
ExecutionData: ed,
|
||||
Bid: big.NewInt(0),
|
||||
ExecutionRequests: &enginev1.ExecutionRequests{},
|
||||
}
|
||||
|
||||
sBlk, err := consensusblocks.NewSignedBeaconBlock(util.NewBeaconBlockGloas())
|
||||
require.NoError(t, err)
|
||||
|
||||
return local, sBlk
|
||||
}
|
||||
|
||||
func TestStoreExecutionPayloadEnvelope_NilState(t *testing.T) {
|
||||
local, sBlk := testGloasBlock(t)
|
||||
|
||||
vs := &Server{}
|
||||
err := vs.storeExecutionPayloadEnvelope(t.Context(), sBlk, local, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
envelope, found := vs.getExecutionPayloadEnvelope(sBlk.Block().Slot())
|
||||
require.Equal(t, true, found)
|
||||
require.NotNil(t, envelope.Payload)
|
||||
require.Equal(t, sBlk.Block().Slot(), envelope.Slot)
|
||||
require.DeepEqual(t, make([]byte, 32), envelope.StateRoot)
|
||||
}
|
||||
|
||||
func TestStoreExecutionPayloadEnvelope_WithState(t *testing.T) {
|
||||
local, sBlk := testGloasBlock(t)
|
||||
|
||||
vs := &Server{}
|
||||
st, err := util.NewBeaconStateGloas()
|
||||
require.NoError(t, err)
|
||||
|
||||
// The eager path is entered but ApplyExecutionPayload will fail because
|
||||
// the default test state doesn't satisfy all transition checks.
|
||||
err = vs.storeExecutionPayloadEnvelope(t.Context(), sBlk, local, st)
|
||||
require.ErrorContains(t, "could not apply execution payload for envelope state root", err)
|
||||
}
|
||||
|
||||
func TestExtractExecutionPayloadDeneb(t *testing.T) {
|
||||
payload := &enginev1.ExecutionPayloadDeneb{
|
||||
ParentHash: make([]byte, 32),
|
||||
|
||||
@@ -49,15 +49,26 @@ func (vs *Server) SubmitSignedProposerPreferences(
|
||||
)
|
||||
}
|
||||
|
||||
if slots.ToEpoch(proposalSlot) != currentEpoch+1 {
|
||||
proposalEpoch := slots.ToEpoch(proposalSlot)
|
||||
if proposalEpoch < currentEpoch || proposalEpoch > currentEpoch.Add(1) {
|
||||
return nil, status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
"signed proposer preferences proposal slot must be in the next epoch: slot %d currentEpoch %d",
|
||||
"signed proposer preferences proposal slot must be in the current or next epoch: slot %d currentEpoch %d",
|
||||
proposalSlot,
|
||||
currentEpoch,
|
||||
)
|
||||
}
|
||||
|
||||
currentSlot := vs.TimeFetcher.CurrentSlot()
|
||||
if proposalSlot <= currentSlot {
|
||||
return nil, status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
"signed proposer preferences proposal slot has already passed: proposalSlot %d currentSlot %d",
|
||||
proposalSlot,
|
||||
currentSlot,
|
||||
)
|
||||
}
|
||||
|
||||
if vs.ProposerPreferencesCache.Has(proposalSlot) {
|
||||
duplicate++
|
||||
continue
|
||||
|
||||
@@ -162,7 +162,7 @@ func TestSubmitSignedProposerPreferences_InvalidEpoch(t *testing.T) {
|
||||
ProposerPreferencesCache: cache.NewProposerPreferencesCache(),
|
||||
}
|
||||
|
||||
// Same epoch (current), not next epoch.
|
||||
// Current slot (already passed) should fail.
|
||||
req := ðpb.SubmitSignedProposerPreferencesRequest{
|
||||
SignedProposerPreferences: []*ethpb.SignedProposerPreferences{
|
||||
{
|
||||
@@ -177,12 +177,50 @@ func TestSubmitSignedProposerPreferences_InvalidEpoch(t *testing.T) {
|
||||
},
|
||||
}
|
||||
_, err := vs.SubmitSignedProposerPreferences(t.Context(), req)
|
||||
require.ErrorContains(t, "next epoch", err)
|
||||
require.ErrorContains(t, "already passed", err)
|
||||
|
||||
// Two epochs ahead.
|
||||
// Two epochs ahead should fail.
|
||||
req.SignedProposerPreferences[0].Message.ProposalSlot = currentSlot + primitives.Slot(2*params.BeaconConfig().SlotsPerEpoch)
|
||||
_, err = vs.SubmitSignedProposerPreferences(t.Context(), req)
|
||||
require.ErrorContains(t, "next epoch", err)
|
||||
require.ErrorContains(t, "current or next epoch", err)
|
||||
}
|
||||
|
||||
func TestSubmitSignedProposerPreferences_CurrentEpochFutureSlot(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 1
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
currentSlot := primitives.Slot(33)
|
||||
proposalSlot := currentSlot + 1 // future slot in current epoch
|
||||
chain := &chainMock.ChainService{Slot: ¤tSlot}
|
||||
p2p := &p2pmock.MockBroadcaster{}
|
||||
cache := cache.NewProposerPreferencesCache()
|
||||
vs := &Server{
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
TimeFetcher: chain,
|
||||
P2P: p2p,
|
||||
ProposerPreferencesCache: cache,
|
||||
}
|
||||
|
||||
req := ðpb.SubmitSignedProposerPreferencesRequest{
|
||||
SignedProposerPreferences: []*ethpb.SignedProposerPreferences{
|
||||
{
|
||||
Message: ðpb.ProposerPreferences{
|
||||
ProposalSlot: proposalSlot,
|
||||
ValidatorIndex: 2,
|
||||
FeeRecipient: make([]byte, 20),
|
||||
GasLimit: 30_000_000,
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := vs.SubmitSignedProposerPreferences(t.Context(), req)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, &emptypb.Empty{}, resp)
|
||||
assert.Equal(t, true, p2p.BroadcastCalled.Load())
|
||||
}
|
||||
|
||||
func TestSubmitSignedProposerPreferences_Syncing(t *testing.T) {
|
||||
|
||||
@@ -95,7 +95,7 @@ func TestServer_GetBeaconBlock_Phase0(t *testing.T) {
|
||||
|
||||
proposerServer := getProposerServer(ctx, db, beaconState, parentRoot[:])
|
||||
// Use a separate mock for BlockReceiver with an independent state copy.
|
||||
// This mirrors production where computeStateRoot calls StateByRoot (fresh from DB),
|
||||
// This mirrors production where computePostBlockStateAndRoot calls StateByRoot (fresh from DB),
|
||||
// not the same head state object mutated by the getSlashings goroutine.
|
||||
proposerServer.BlockReceiver = &mock.ChainService{
|
||||
State: beaconState.Copy(),
|
||||
@@ -1354,12 +1354,12 @@ func TestProposer_ComputeStateRoot_OK(t *testing.T) {
|
||||
|
||||
wsb, err := blocks.NewSignedBeaconBlock(req)
|
||||
require.NoError(t, err)
|
||||
_, err = proposerServer.computeStateRoot(t.Context(), wsb)
|
||||
_, _, err = proposerServer.computePostBlockStateAndRoot(t.Context(), wsb)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestHandleStateRootError_MaxAttemptsReached(t *testing.T) {
|
||||
// Test that handleStateRootError returns an error when max attempts is reached
|
||||
func TestHandlePostBlockStateError_MaxAttemptsReached(t *testing.T) {
|
||||
// Test that handlePostBlockStateError returns an error when max attempts is reached
|
||||
// instead of recursing infinitely.
|
||||
ctx := t.Context()
|
||||
vs := &Server{}
|
||||
@@ -1372,15 +1372,15 @@ func TestHandleStateRootError_MaxAttemptsReached(t *testing.T) {
|
||||
// Pre-seed the context with max attempts already reached
|
||||
ctx = context.WithValue(ctx, computeStateRootAttemptsKey, maxComputeStateRootAttempts)
|
||||
|
||||
// Call handleStateRootError with a retryable error
|
||||
_, err = vs.handleStateRootError(ctx, wsb, transition.ErrAttestationsSignatureInvalid)
|
||||
// Call handlePostBlockStateError with a retryable error
|
||||
_, err = vs.handlePostBlockStateError(ctx, wsb, transition.ErrAttestationsSignatureInvalid)
|
||||
|
||||
// Should return an error about max attempts instead of recursing
|
||||
require.ErrorContains(t, "attempted max compute state root attempts", err)
|
||||
}
|
||||
|
||||
func TestHandleStateRootError_IncrementsAttempts(t *testing.T) {
|
||||
// Test that handleStateRootError properly increments the attempts counter
|
||||
func TestHandlePostBlockStateError_IncrementsAttempts(t *testing.T) {
|
||||
// Test that handlePostBlockStateError properly increments the attempts counter
|
||||
// and eventually fails after max attempts.
|
||||
db := dbutil.SetupDB(t)
|
||||
ctx := t.Context()
|
||||
@@ -1403,10 +1403,10 @@ func TestHandleStateRootError_IncrementsAttempts(t *testing.T) {
|
||||
// Add a state for the parent root so StateByRoot succeeds
|
||||
require.NoError(t, stateGen.SaveState(ctx, parentRoot, beaconState))
|
||||
|
||||
// Call handleStateRootError with a retryable error - it will recurse
|
||||
// but eventually hit the max attempts limit since CalculateStateRoot
|
||||
// Call handlePostBlockStateError with a retryable error - it will recurse
|
||||
// but eventually hit the max attempts limit since CalculatePostState
|
||||
// will keep failing (no valid attestations, randao, etc.)
|
||||
_, err = vs.handleStateRootError(ctx, wsb, transition.ErrAttestationsSignatureInvalid)
|
||||
_, err = vs.handlePostBlockStateError(ctx, wsb, transition.ErrAttestationsSignatureInvalid)
|
||||
|
||||
// Should eventually fail - either with max attempts or another error
|
||||
require.NotNil(t, err)
|
||||
|
||||
@@ -22,6 +22,7 @@ func NewRegularSyncFuzz(opts ...Option) *Service {
|
||||
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
|
||||
seenPendingBlocks: make(map[[32]byte]bool),
|
||||
blkRootToPendingAtts: make(map[[32]byte][]any),
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
}
|
||||
r.rateLimiter = newRateLimiter(r.cfg.p2p)
|
||||
|
||||
|
||||
@@ -160,6 +160,7 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
||||
|
||||
// Process synchronously because it's likely that the next pending block depends on it.
|
||||
s.processPendingPayloadEnvelope(ctx, blkRoot)
|
||||
s.processPendingGloasColumns(blkRoot, b)
|
||||
blkRoots = append(blkRoots, blkRoot)
|
||||
|
||||
// Remove the processed block from the queue.
|
||||
|
||||
@@ -97,6 +97,11 @@ func (s *Service) requestAndSaveMissingDataColumnSidecars(blks []blocks.ROBlock)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process any gossip columns queued before the block arrived.
|
||||
for _, blk := range blks {
|
||||
s.processPendingGloasColumns(blk.Root(), blk)
|
||||
}
|
||||
|
||||
samplesPerSlot := params.BeaconConfig().SamplesPerSlot
|
||||
|
||||
custodyGroupCount, err := s.cfg.p2p.CustodyGroupCount(s.ctx)
|
||||
|
||||
@@ -160,6 +160,8 @@ type Service struct {
|
||||
seenBlobLock sync.RWMutex
|
||||
seenBlobCache *lru.Cache
|
||||
seenDataColumnCache *slotAwareCache
|
||||
pendingGloasColumnsLock sync.RWMutex
|
||||
pendingGloasColumns map[[32]byte]*pendingGloasEntry
|
||||
seenAggregatedAttestationLock sync.RWMutex
|
||||
seenAggregatedAttestationCache *lru.Cache
|
||||
seenUnAggregatedAttestationLock sync.RWMutex
|
||||
@@ -219,6 +221,7 @@ func NewService(ctx context.Context, opts ...Option) *Service {
|
||||
slotToPendingBlocks: gcache.New(pendingBlockExpTime /* exp time */, 0 /* disable janitor */),
|
||||
seenPendingBlocks: make(map[[32]byte]bool),
|
||||
blkRootToPendingAtts: make(map[[32]byte][]any),
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
dataColumnLogCh: make(chan dataColumnLogEntry, 1000),
|
||||
reconstructionRandGen: rand.NewGenerator(),
|
||||
payloadAttestationCache: &cache.PayloadAttestationCache{},
|
||||
@@ -329,6 +332,8 @@ func (s *Service) Start() {
|
||||
// Prune data column cache periodically on finalization.
|
||||
async.RunEvery(s.ctx, 30*time.Second, s.pruneDataColumnCache)
|
||||
|
||||
go s.prunePendingGloasColumns()
|
||||
|
||||
if !params.FuluEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -83,6 +83,8 @@ func (s *Service) beaconBlockSubscriber(ctx context.Context, msg proto.Message)
|
||||
|
||||
go s.processPendingPayloadEnvelope(s.ctx, root)
|
||||
|
||||
s.processPendingGloasColumns(root, signed)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,39 @@ package sync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/verification"
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"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/encoding/bytesutil"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/logging"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// maxPendingGloasRoots caps the number of distinct block roots in the pending queue.
|
||||
const maxPendingGloasRoots = 8
|
||||
|
||||
type pendingColumnEntry struct {
|
||||
sidecar *ethpb.DataColumnSidecarGloas
|
||||
peer peer.ID
|
||||
}
|
||||
|
||||
type pendingGloasEntry struct {
|
||||
slot primitives.Slot
|
||||
columns [fieldparams.NumberOfColumns]*pendingColumnEntry
|
||||
}
|
||||
|
||||
func (s *Service) validateDataColumnGloas(
|
||||
ctx context.Context,
|
||||
msg *pubsub.Message,
|
||||
@@ -26,8 +48,12 @@ func (s *Service) validateDataColumnGloas(
|
||||
// If not yet seen, a client MUST queue the sidecar for deferred validation and possible processing once
|
||||
// the block is received or retrieved.
|
||||
if s.cfg.chain == nil || !s.cfg.chain.HasBlock(ctx, roDataColumn.BlockRoot()) {
|
||||
// TODO: Queue the sidecar for deferred validation and possible processing once the
|
||||
// block is received or retrieved
|
||||
actualSubnet := peerdas.ComputeSubnetForDataColumnSidecar(roDataColumn.Index())
|
||||
expectedSubTopic := fmt.Sprintf(dataColumnSidecarSubTopic, actualSubnet)
|
||||
if msg.Topic == nil || !strings.Contains(*msg.Topic+"/", expectedSubTopic) {
|
||||
return blocks.VerifiedRODataColumn{}, errors.New("gloas data column on wrong subnet")
|
||||
}
|
||||
s.queuePendingGloasColumn(roDataColumn, peer.ID(msg.GetFrom()))
|
||||
return blocks.VerifiedRODataColumn{}, ignoreValidation(errors.New("gloas data column block not yet seen"))
|
||||
}
|
||||
|
||||
@@ -97,6 +123,160 @@ func (s *Service) setSeenDataColumnRootIndex(root [fieldparams.RootLength]byte,
|
||||
s.seenDataColumnCache.Add(slot, key, true)
|
||||
}
|
||||
|
||||
func (s *Service) queuePendingGloasColumn(roCol blocks.RODataColumn, pid peer.ID) {
|
||||
dc := roCol.DataColumnSidecarGloas()
|
||||
if dc == nil {
|
||||
return
|
||||
}
|
||||
idx := roCol.Index()
|
||||
if idx >= fieldparams.NumberOfColumns {
|
||||
return
|
||||
}
|
||||
|
||||
root := roCol.BlockRoot()
|
||||
slot := roCol.Slot()
|
||||
|
||||
s.pendingGloasColumnsLock.Lock()
|
||||
defer s.pendingGloasColumnsLock.Unlock()
|
||||
|
||||
entry := s.pendingGloasColumns[root]
|
||||
if entry == nil {
|
||||
if len(s.pendingGloasColumns) >= maxPendingGloasRoots {
|
||||
return
|
||||
}
|
||||
entry = &pendingGloasEntry{slot: slot}
|
||||
s.pendingGloasColumns[root] = entry
|
||||
}
|
||||
|
||||
if entry.columns[idx] != nil {
|
||||
return
|
||||
}
|
||||
entry.columns[idx] = &pendingColumnEntry{sidecar: dc, peer: pid}
|
||||
}
|
||||
|
||||
func (s *Service) processPendingGloasColumns(root [fieldparams.RootLength]byte, blk interfaces.ReadOnlySignedBeaconBlock) {
|
||||
if blk == nil || blk.IsNil() {
|
||||
return
|
||||
}
|
||||
|
||||
s.pendingGloasColumnsLock.Lock()
|
||||
entry := s.pendingGloasColumns[root]
|
||||
delete(s.pendingGloasColumns, root)
|
||||
s.pendingGloasColumnsLock.Unlock()
|
||||
|
||||
if entry == nil {
|
||||
return
|
||||
}
|
||||
|
||||
commitments, err := blk.Block().Body().BlobKzgCommitments()
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("root", fmt.Sprintf("%#x", root)).Warn("Failed to get bid commitments for pending Gloas columns")
|
||||
return
|
||||
}
|
||||
|
||||
// Count pending sidecars for pre-allocation.
|
||||
count := 0
|
||||
for _, pe := range entry.columns {
|
||||
if pe != nil {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
verified := make([]blocks.VerifiedRODataColumn, 0, count)
|
||||
var skipped int
|
||||
badPeers := make(map[peer.ID]bool)
|
||||
for _, pe := range entry.columns {
|
||||
if pe == nil {
|
||||
continue
|
||||
}
|
||||
roCol, err := blocks.NewRODataColumnGloasWithRoot(pe.sidecar, root)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("root", fmt.Sprintf("%#x", root)).Error("Failed to wrap pending Gloas column")
|
||||
skipped++
|
||||
continue
|
||||
}
|
||||
roCol.SetBidCommitments(commitments)
|
||||
|
||||
if s.hasSeenDataColumnRootIndex(root, roCol.Index()) {
|
||||
continue
|
||||
}
|
||||
|
||||
verifier := verification.NewGloasDataColumnVerifier(roCol, blk.Block(), verification.PendingGloasColumnRequirements)
|
||||
|
||||
if err := verifier.VerifyDataColumnSidecarSlotMatchesBlockGloas(); err != nil {
|
||||
skipped++
|
||||
badPeers[pe.peer] = true
|
||||
continue
|
||||
}
|
||||
if err := verifier.VerifyDataColumnSidecarGloas(); err != nil {
|
||||
skipped++
|
||||
badPeers[pe.peer] = true
|
||||
continue
|
||||
}
|
||||
if err := verifier.VerifyDataColumnSidecarKzgProofsGloas(); err != nil {
|
||||
skipped++
|
||||
badPeers[pe.peer] = true
|
||||
continue
|
||||
}
|
||||
|
||||
v, err := verifier.VerifiedRODataColumn()
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("root", fmt.Sprintf("%#x", root)).Error("Failed to get verified pending Gloas column")
|
||||
skipped++
|
||||
continue
|
||||
}
|
||||
v.SetBidCommitments(commitments)
|
||||
|
||||
s.setSeenDataColumnRootIndex(root, v.Index(), v.Slot())
|
||||
verified = append(verified, v)
|
||||
}
|
||||
|
||||
for pid := range badPeers {
|
||||
s.cfg.p2p.Peers().Scorers().BadResponsesScorer().Increment(pid)
|
||||
}
|
||||
|
||||
if len(verified) > 0 {
|
||||
if err := s.cfg.dataColumnStorage.Save(verified); err != nil {
|
||||
log.WithError(err).WithField("root", fmt.Sprintf("%#x", root)).Warn("Failed to save pending Gloas columns")
|
||||
return
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"root": fmt.Sprintf("%#x", root),
|
||||
"count": len(verified),
|
||||
"skipped": skipped,
|
||||
"slot": entry.slot,
|
||||
}).Debug("Processed pending Gloas data columns")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) hasPendingGloasColumns(root [fieldparams.RootLength]byte) bool {
|
||||
s.pendingGloasColumnsLock.RLock()
|
||||
defer s.pendingGloasColumnsLock.RUnlock()
|
||||
_, ok := s.pendingGloasColumns[root]
|
||||
return ok
|
||||
}
|
||||
|
||||
// prunePendingGloasColumns removes stale entries every slot.
|
||||
func (s *Service) prunePendingGloasColumns() {
|
||||
slotTicker := slots.NewSlotTicker(s.cfg.clock.GenesisTime(), params.BeaconConfig().SecondsPerSlot)
|
||||
defer slotTicker.Done()
|
||||
for {
|
||||
select {
|
||||
case currentSlot := <-slotTicker.C():
|
||||
s.pendingGloasColumnsLock.Lock()
|
||||
for r, e := range s.pendingGloasColumns {
|
||||
if e.slot+1 < currentSlot {
|
||||
delete(s.pendingGloasColumns, r)
|
||||
}
|
||||
}
|
||||
s.pendingGloasColumnsLock.Unlock()
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func computeRootIndexCacheKey(root [fieldparams.RootLength]byte, index uint64) string {
|
||||
key := make([]byte, 0, fieldparams.RootLength+32)
|
||||
key = append(key, root[:]...)
|
||||
|
||||
@@ -10,12 +10,14 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/kzg"
|
||||
mock "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/testing"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/db/filesystem"
|
||||
dbtest "github.com/OffchainLabs/prysm/v7/beacon-chain/db/testing"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p"
|
||||
p2ptest "github.com/OffchainLabs/prysm/v7/beacon-chain/p2p/testing"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/startup"
|
||||
mockSync "github.com/OffchainLabs/prysm/v7/beacon-chain/sync/initial-sync/testing"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/verification"
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
@@ -25,9 +27,48 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
pb "github.com/libp2p/go-libp2p-pubsub/pb"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
)
|
||||
|
||||
func gloasFixture(t *testing.T) (*ethpb.DataColumnSidecarGloas, interfaces.ReadOnlySignedBeaconBlock) {
|
||||
t.Helper()
|
||||
|
||||
roBlock, roSidecars, _ := util.GenerateTestFuluBlockWithSidecars(t, 1, util.WithSlot(1))
|
||||
require.Equal(t, true, len(roSidecars) > 0)
|
||||
|
||||
base := roSidecars[0]
|
||||
bid := util.GenerateTestSignedExecutionPayloadBid(base.Slot())
|
||||
comms, err := roBlock.Block().Body().BlobKzgCommitments()
|
||||
require.NoError(t, err)
|
||||
bid.Message.BlobKzgCommitments = bytesutil.SafeCopy2dBytes(comms)
|
||||
|
||||
pb := util.NewBeaconBlockGloas()
|
||||
pb.Block.Slot = base.Slot()
|
||||
pb.Block.ProposerIndex = roBlock.Block().ProposerIndex()
|
||||
parentRoot := roBlock.Block().ParentRoot()
|
||||
pb.Block.ParentRoot = parentRoot[:]
|
||||
stateRoot := roBlock.Block().StateRoot()
|
||||
pb.Block.StateRoot = stateRoot[:]
|
||||
pb.Block.Body.SignedExecutionPayloadBid = bid
|
||||
|
||||
signedBlock, err := blocks.NewSignedBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
|
||||
blockRoot, err := signedBlock.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
sidecar := ðpb.DataColumnSidecarGloas{
|
||||
Index: base.Index(),
|
||||
Column: bytesutil.SafeCopy2dBytes(base.Column()),
|
||||
KzgProofs: bytesutil.SafeCopy2dBytes(base.KzgProofs()),
|
||||
Slot: base.Slot(),
|
||||
BeaconBlockRoot: blockRoot[:],
|
||||
}
|
||||
|
||||
return sidecar, signedBlock
|
||||
}
|
||||
|
||||
func TestValidateDataColumnGloas(t *testing.T) {
|
||||
err := kzg.Start()
|
||||
require.NoError(t, err)
|
||||
@@ -50,6 +91,7 @@ func TestValidateDataColumnGloas(t *testing.T) {
|
||||
ctx: ctx,
|
||||
newColumnsVerifier: newDataColumnsVerifier,
|
||||
seenDataColumnCache: newSlotAwareCache(seenDataColumnSize),
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
@@ -67,44 +109,6 @@ func TestValidateDataColumnGloas(t *testing.T) {
|
||||
return service, message
|
||||
}
|
||||
|
||||
gloasFixture := func(t *testing.T) (*ethpb.DataColumnSidecarGloas, interfaces.ReadOnlySignedBeaconBlock) {
|
||||
t.Helper()
|
||||
|
||||
roBlock, roSidecars, _ := util.GenerateTestFuluBlockWithSidecars(t, 1, util.WithSlot(1))
|
||||
require.Equal(t, true, len(roSidecars) > 0)
|
||||
|
||||
base := roSidecars[0]
|
||||
bid := util.GenerateTestSignedExecutionPayloadBid(base.Slot())
|
||||
comms, err := roBlock.Block().Body().BlobKzgCommitments()
|
||||
require.NoError(t, err)
|
||||
bid.Message.BlobKzgCommitments = bytesutil.SafeCopy2dBytes(comms)
|
||||
|
||||
pb := util.NewBeaconBlockGloas()
|
||||
pb.Block.Slot = base.Slot()
|
||||
pb.Block.ProposerIndex = roBlock.Block().ProposerIndex()
|
||||
parentRoot := roBlock.Block().ParentRoot()
|
||||
pb.Block.ParentRoot = parentRoot[:]
|
||||
stateRoot := roBlock.Block().StateRoot()
|
||||
pb.Block.StateRoot = stateRoot[:]
|
||||
pb.Block.Body.SignedExecutionPayloadBid = bid
|
||||
|
||||
signedBlock, err := blocks.NewSignedBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
|
||||
blockRoot, err := signedBlock.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
sidecar := ðpb.DataColumnSidecarGloas{
|
||||
Index: base.Index(),
|
||||
Column: bytesutil.SafeCopy2dBytes(base.Column()),
|
||||
KzgProofs: bytesutil.SafeCopy2dBytes(base.KzgProofs()),
|
||||
Slot: base.Slot(),
|
||||
BeaconBlockRoot: blockRoot[:],
|
||||
}
|
||||
|
||||
return sidecar, signedBlock
|
||||
}
|
||||
|
||||
t.Run("ignores unseen block", func(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig()
|
||||
@@ -186,3 +190,268 @@ func TestValidateDataColumnGloas(t *testing.T) {
|
||||
require.ErrorContains(t, "slot does not match block slot", err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPendingGloasColumns(t *testing.T) {
|
||||
clock := startup.NewClock(time.Now(), [32]byte{})
|
||||
|
||||
t.Run("queue and retrieve", func(t *testing.T) {
|
||||
s := &Service{
|
||||
cfg: &config{clock: clock},
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
}
|
||||
root := [32]byte{0xaa}
|
||||
dc := ðpb.DataColumnSidecarGloas{
|
||||
Index: 5,
|
||||
Slot: clock.CurrentSlot(),
|
||||
BeaconBlockRoot: root[:],
|
||||
Column: [][]byte{make([]byte, 2048)},
|
||||
KzgProofs: [][]byte{make([]byte, 48)},
|
||||
}
|
||||
roCol, err := blocks.NewRODataColumnGloasWithRoot(dc, root)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.queuePendingGloasColumn(roCol, "peer1")
|
||||
require.Equal(t, true, s.hasPendingGloasColumns(root))
|
||||
|
||||
entry := s.pendingGloasColumns[root]
|
||||
require.NotNil(t, entry)
|
||||
require.NotNil(t, entry.columns[5])
|
||||
require.Equal(t, peer.ID("peer1"), entry.columns[5].peer)
|
||||
})
|
||||
|
||||
t.Run("dedup by index", func(t *testing.T) {
|
||||
s := &Service{
|
||||
cfg: &config{clock: clock},
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
}
|
||||
root := [32]byte{0xbb}
|
||||
dc := ðpb.DataColumnSidecarGloas{
|
||||
Index: 10,
|
||||
Slot: clock.CurrentSlot(),
|
||||
BeaconBlockRoot: root[:],
|
||||
Column: [][]byte{make([]byte, 2048)},
|
||||
KzgProofs: [][]byte{make([]byte, 48)},
|
||||
}
|
||||
roCol, err := blocks.NewRODataColumnGloasWithRoot(dc, root)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.queuePendingGloasColumn(roCol, "peer1")
|
||||
s.queuePendingGloasColumn(roCol, "peer2")
|
||||
require.Equal(t, peer.ID("peer1"), s.pendingGloasColumns[root].columns[10].peer)
|
||||
})
|
||||
|
||||
t.Run("nil block is no-op", func(t *testing.T) {
|
||||
s := &Service{
|
||||
cfg: &config{clock: clock},
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
}
|
||||
root := [32]byte{0xcc}
|
||||
s.pendingGloasColumns[root] = &pendingGloasEntry{slot: clock.CurrentSlot()}
|
||||
|
||||
s.processPendingGloasColumns(root, nil)
|
||||
// Entry should remain because the block was nil.
|
||||
require.Equal(t, true, s.hasPendingGloasColumns(root))
|
||||
})
|
||||
|
||||
t.Run("index out of bounds rejected", func(t *testing.T) {
|
||||
s := &Service{
|
||||
cfg: &config{clock: clock},
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
}
|
||||
root := [32]byte{0xee}
|
||||
dc := ðpb.DataColumnSidecarGloas{
|
||||
Index: fieldparams.NumberOfColumns + 1,
|
||||
Slot: clock.CurrentSlot(),
|
||||
BeaconBlockRoot: root[:],
|
||||
Column: [][]byte{make([]byte, 2048)},
|
||||
KzgProofs: [][]byte{make([]byte, 48)},
|
||||
}
|
||||
roCol, err := blocks.NewRODataColumnGloasWithRoot(dc, root)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.queuePendingGloasColumn(roCol, "peer1")
|
||||
require.Equal(t, false, s.hasPendingGloasColumns(root))
|
||||
})
|
||||
|
||||
t.Run("map capped at maxPendingGloasRoots", func(t *testing.T) {
|
||||
s := &Service{
|
||||
cfg: &config{clock: clock},
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
}
|
||||
// Fill up to the cap.
|
||||
for i := range maxPendingGloasRoots {
|
||||
root := [32]byte{byte(i)}
|
||||
dc := ðpb.DataColumnSidecarGloas{
|
||||
Index: 0,
|
||||
Slot: clock.CurrentSlot(),
|
||||
BeaconBlockRoot: root[:],
|
||||
Column: [][]byte{make([]byte, 2048)},
|
||||
KzgProofs: [][]byte{make([]byte, 48)},
|
||||
}
|
||||
roCol, err := blocks.NewRODataColumnGloasWithRoot(dc, root)
|
||||
require.NoError(t, err)
|
||||
s.queuePendingGloasColumn(roCol, "peer1")
|
||||
}
|
||||
require.Equal(t, maxPendingGloasRoots, len(s.pendingGloasColumns))
|
||||
|
||||
// One more should be dropped.
|
||||
overflowRoot := [32]byte{0xff}
|
||||
dc := ðpb.DataColumnSidecarGloas{
|
||||
Index: 0,
|
||||
Slot: clock.CurrentSlot(),
|
||||
BeaconBlockRoot: overflowRoot[:],
|
||||
Column: [][]byte{make([]byte, 2048)},
|
||||
KzgProofs: [][]byte{make([]byte, 48)},
|
||||
}
|
||||
roCol, err := blocks.NewRODataColumnGloasWithRoot(dc, overflowRoot)
|
||||
require.NoError(t, err)
|
||||
s.queuePendingGloasColumn(roCol, "peer1")
|
||||
require.Equal(t, false, s.hasPendingGloasColumns(overflowRoot))
|
||||
|
||||
// Adding to an existing root should still work.
|
||||
existingRoot := [32]byte{0x00}
|
||||
dc2 := ðpb.DataColumnSidecarGloas{
|
||||
Index: 1,
|
||||
Slot: clock.CurrentSlot(),
|
||||
BeaconBlockRoot: existingRoot[:],
|
||||
Column: [][]byte{make([]byte, 2048)},
|
||||
KzgProofs: [][]byte{make([]byte, 48)},
|
||||
}
|
||||
roCol2, err := blocks.NewRODataColumnGloasWithRoot(dc2, existingRoot)
|
||||
require.NoError(t, err)
|
||||
s.queuePendingGloasColumn(roCol2, "peer1")
|
||||
require.NotNil(t, s.pendingGloasColumns[existingRoot].columns[1])
|
||||
})
|
||||
|
||||
t.Run("process verifies and saves valid columns", func(t *testing.T) {
|
||||
err := kzg.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.FuluForkEpoch = 0
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
p := p2ptest.NewTestP2P(t)
|
||||
dcs := filesystem.NewEphemeralDataColumnStorage(t)
|
||||
|
||||
sidecar, signedBlock := gloasFixture(t)
|
||||
blockRoot, err := signedBlock.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
s := &Service{
|
||||
cfg: &config{
|
||||
p2p: p,
|
||||
clock: clock,
|
||||
dataColumnStorage: dcs,
|
||||
},
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
seenDataColumnCache: newSlotAwareCache(seenDataColumnSize),
|
||||
}
|
||||
|
||||
// Queue the sidecar.
|
||||
roCol, err := blocks.NewRODataColumnGloasWithRoot(sidecar, blockRoot)
|
||||
require.NoError(t, err)
|
||||
s.queuePendingGloasColumn(roCol, "peer1")
|
||||
require.Equal(t, true, s.hasPendingGloasColumns(blockRoot))
|
||||
|
||||
// Process with the block.
|
||||
s.processPendingGloasColumns(blockRoot, signedBlock)
|
||||
require.Equal(t, false, s.hasPendingGloasColumns(blockRoot))
|
||||
|
||||
// Column should be marked as seen.
|
||||
require.Equal(t, true, s.hasSeenDataColumnRootIndex(blockRoot, sidecar.Index))
|
||||
})
|
||||
|
||||
t.Run("process downscores bad peer for slot mismatch", func(t *testing.T) {
|
||||
err := kzg.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.FuluForkEpoch = 0
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
p := p2ptest.NewTestP2P(t)
|
||||
dcs := filesystem.NewEphemeralDataColumnStorage(t)
|
||||
|
||||
sidecar, signedBlock := gloasFixture(t)
|
||||
blockRoot, err := signedBlock.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Mismatch the slot.
|
||||
sidecar.Slot = sidecar.Slot + 10
|
||||
|
||||
s := &Service{
|
||||
cfg: &config{
|
||||
p2p: p,
|
||||
clock: clock,
|
||||
dataColumnStorage: dcs,
|
||||
},
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
seenDataColumnCache: newSlotAwareCache(seenDataColumnSize),
|
||||
}
|
||||
|
||||
roCol, err := blocks.NewRODataColumnGloasWithRoot(sidecar, blockRoot)
|
||||
require.NoError(t, err)
|
||||
s.queuePendingGloasColumn(roCol, "badpeer")
|
||||
|
||||
s.processPendingGloasColumns(blockRoot, signedBlock)
|
||||
require.Equal(t, false, s.hasPendingGloasColumns(blockRoot))
|
||||
// Column should NOT be marked as seen (it was invalid).
|
||||
require.Equal(t, false, s.hasSeenDataColumnRootIndex(blockRoot, sidecar.Index))
|
||||
})
|
||||
|
||||
t.Run("no entry is no-op", func(t *testing.T) {
|
||||
p := p2ptest.NewTestP2P(t)
|
||||
s := &Service{
|
||||
cfg: &config{
|
||||
p2p: p,
|
||||
clock: clock,
|
||||
},
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
seenDataColumnCache: newSlotAwareCache(seenDataColumnSize),
|
||||
}
|
||||
root := [32]byte{0xdd}
|
||||
pb := util.NewBeaconBlockGloas()
|
||||
blk, err := blocks.NewSignedBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
// Should not panic.
|
||||
s.processPendingGloasColumns(root, blk)
|
||||
})
|
||||
|
||||
t.Run("prune keeps current and next slot", func(t *testing.T) {
|
||||
s := &Service{
|
||||
cfg: &config{clock: clock},
|
||||
pendingGloasColumns: make(map[[32]byte]*pendingGloasEntry),
|
||||
}
|
||||
currentSlot := clock.CurrentSlot()
|
||||
if currentSlot < 3 {
|
||||
t.Skip("need slot >= 3")
|
||||
}
|
||||
|
||||
staleRoot := [32]byte{0x01}
|
||||
currentRoot := [32]byte{0x02}
|
||||
prevRoot := [32]byte{0x03}
|
||||
|
||||
s.pendingGloasColumns[staleRoot] = &pendingGloasEntry{slot: currentSlot - 3}
|
||||
s.pendingGloasColumns[currentRoot] = &pendingGloasEntry{slot: currentSlot}
|
||||
s.pendingGloasColumns[prevRoot] = &pendingGloasEntry{slot: currentSlot - 1}
|
||||
|
||||
// Simulate what the ticker does.
|
||||
s.pendingGloasColumnsLock.Lock()
|
||||
for r, e := range s.pendingGloasColumns {
|
||||
if e.slot+1 < currentSlot {
|
||||
delete(s.pendingGloasColumns, r)
|
||||
}
|
||||
}
|
||||
s.pendingGloasColumnsLock.Unlock()
|
||||
|
||||
// Stale should be pruned, current and prev should remain.
|
||||
require.Equal(t, false, s.hasPendingGloasColumns(staleRoot))
|
||||
require.Equal(t, true, s.hasPendingGloasColumns(currentRoot))
|
||||
require.Equal(t, true, s.hasPendingGloasColumns(prevRoot))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package sync
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/p2p"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/verification"
|
||||
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
|
||||
@@ -44,14 +45,26 @@ func (s *Service) validateSignedProposerPreferencesGossip(ctx context.Context, p
|
||||
if err != nil {
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
headRoot, err := s.cfg.chain.HeadRoot(ctx)
|
||||
if err != nil {
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
// HeadStateReadOnly returns the current head state as stored, which may still
|
||||
// be on the previous slot or epoch until the next block arrives. Advance it to
|
||||
// the wall-clock slot so current-epoch proposer preferences are validated
|
||||
// against the same epoch/ProposerLookahead view used elsewhere.
|
||||
st, err = transition.ProcessSlotsIfNeeded(ctx, st, headRoot, s.cfg.clock.CurrentSlot())
|
||||
if err != nil {
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
|
||||
v := s.newSignedProposerPreferencesVerifier(signedPreferences, verification.SignedProposerPreferencesGossipRequirements)
|
||||
// [IGNORE] preferences.proposal_slot is in the next epoch.
|
||||
if err := v.VerifyNextEpoch(st); err != nil {
|
||||
// [IGNORE] preferences.proposal_slot is in the current or next epoch and has not already passed.
|
||||
if err := v.VerifyCurrentOrNextEpoch(st); err != nil {
|
||||
return pubsub.ValidationIgnore, err
|
||||
}
|
||||
// [REJECT] preferences.validator_index is present at the correct slot in the
|
||||
// next epoch's portion of state.proposer_lookahead.
|
||||
// current or next epoch's portion of state.proposer_lookahead.
|
||||
if err := v.VerifyValidProposalSlot(st); err != nil {
|
||||
return pubsub.ValidationReject, err
|
||||
}
|
||||
|
||||
@@ -58,8 +58,8 @@ func TestValidateSignedProposerPreferencesGossip_ErrorPathsWithMock(t *testing.T
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "not next epoch",
|
||||
verifier: mockSignedProposerPreferencesVerifier{errNextEpoch: errors.New("wrong epoch")},
|
||||
name: "not current or next epoch",
|
||||
verifier: mockSignedProposerPreferencesVerifier{errCurrentOrNextEpoch: errors.New("wrong epoch")},
|
||||
result: pubsub.ValidationIgnore,
|
||||
wantError: true,
|
||||
},
|
||||
@@ -134,22 +134,26 @@ func TestSignedProposerPreferencesSubscriber_HappyPath(t *testing.T) {
|
||||
}
|
||||
|
||||
type mockSignedProposerPreferencesVerifier struct {
|
||||
errNextEpoch error
|
||||
errValidProposalSlot error
|
||||
errSignature error
|
||||
errCurrentOrNextEpoch error
|
||||
errValidProposalSlot error
|
||||
errSignature error
|
||||
lastStateSlot primitives.Slot
|
||||
}
|
||||
|
||||
var _ verification.SignedProposerPreferencesVerifier = &mockSignedProposerPreferencesVerifier{}
|
||||
|
||||
func (m *mockSignedProposerPreferencesVerifier) VerifyNextEpoch(state.ReadOnlyBeaconState) error {
|
||||
return m.errNextEpoch
|
||||
func (m *mockSignedProposerPreferencesVerifier) VerifyCurrentOrNextEpoch(st state.ReadOnlyBeaconState) error {
|
||||
m.lastStateSlot = st.Slot()
|
||||
return m.errCurrentOrNextEpoch
|
||||
}
|
||||
|
||||
func (m *mockSignedProposerPreferencesVerifier) VerifyValidProposalSlot(state.ReadOnlyBeaconState) error {
|
||||
func (m *mockSignedProposerPreferencesVerifier) VerifyValidProposalSlot(st state.ReadOnlyBeaconState) error {
|
||||
m.lastStateSlot = st.Slot()
|
||||
return m.errValidProposalSlot
|
||||
}
|
||||
|
||||
func (m *mockSignedProposerPreferencesVerifier) VerifySignature(state.ReadOnlyBeaconState) error {
|
||||
func (m *mockSignedProposerPreferencesVerifier) VerifySignature(st state.ReadOnlyBeaconState) error {
|
||||
m.lastStateSlot = st.Slot()
|
||||
return m.errSignature
|
||||
}
|
||||
|
||||
@@ -162,6 +166,36 @@ func testNewSignedProposerPreferencesVerifier(m mockSignedProposerPreferencesVer
|
||||
}
|
||||
}
|
||||
|
||||
func testNewSignedProposerPreferencesVerifierCapture(slot *primitives.Slot) verification.NewSignedProposerPreferencesVerifier {
|
||||
return func(*ethpb.SignedProposerPreferences, []verification.Requirement) verification.SignedProposerPreferencesVerifier {
|
||||
return &mockSignedProposerPreferencesVerifierWithCapture{slot: slot}
|
||||
}
|
||||
}
|
||||
|
||||
type mockSignedProposerPreferencesVerifierWithCapture struct {
|
||||
slot *primitives.Slot
|
||||
}
|
||||
|
||||
var _ verification.SignedProposerPreferencesVerifier = &mockSignedProposerPreferencesVerifierWithCapture{}
|
||||
|
||||
func (m *mockSignedProposerPreferencesVerifierWithCapture) VerifyCurrentOrNextEpoch(st state.ReadOnlyBeaconState) error {
|
||||
*m.slot = st.Slot()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockSignedProposerPreferencesVerifierWithCapture) VerifyValidProposalSlot(st state.ReadOnlyBeaconState) error {
|
||||
*m.slot = st.Slot()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockSignedProposerPreferencesVerifierWithCapture) VerifySignature(st state.ReadOnlyBeaconState) error {
|
||||
*m.slot = st.Slot()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*mockSignedProposerPreferencesVerifierWithCapture) SatisfyRequirement(verification.Requirement) {
|
||||
}
|
||||
|
||||
func setupSignedProposerPreferencesService(t *testing.T) (*Service, *pubsub.Message, *ethpb.SignedProposerPreferences) {
|
||||
t.Helper()
|
||||
|
||||
@@ -194,6 +228,28 @@ func setupSignedProposerPreferencesService(t *testing.T) (*Service, *pubsub.Mess
|
||||
return s, msg, signedPreferences
|
||||
}
|
||||
|
||||
func TestValidateSignedProposerPreferencesGossip_AdvancesHeadStateToCurrentSlot(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s, _, signedPreferences := setupSignedProposerPreferencesService(t)
|
||||
|
||||
chainService, ok := s.cfg.chain.(*mock.ChainService)
|
||||
require.Equal(t, true, ok)
|
||||
st, _ := util.DeterministicGenesisStateFulu(t, 64)
|
||||
require.NoError(t, st.SetSlot(31))
|
||||
chainService.State = st
|
||||
currentSlot := primitives.Slot(32)
|
||||
s.cfg.clock = startup.NewClock(s.cfg.chain.GenesisTime(), s.cfg.chain.GenesisValidatorsRoot(), startup.WithSlotAsNow(currentSlot))
|
||||
msg := signedProposerPreferencesToPubsub(t, s, s.cfg.p2p, signedPreferences)
|
||||
|
||||
var verifiedSlot primitives.Slot
|
||||
s.newSignedProposerPreferencesVerifier = testNewSignedProposerPreferencesVerifierCapture(&verifiedSlot)
|
||||
|
||||
result, err := s.validateSignedProposerPreferencesGossip(ctx, "", msg)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, pubsub.ValidationAccept, result)
|
||||
require.Equal(t, currentSlot, verifiedSlot)
|
||||
}
|
||||
|
||||
func signedProposerPreferencesToPubsub(t *testing.T, s *Service, p p2p.P2P, preferences *ethpb.SignedProposerPreferences) *pubsub.Message {
|
||||
t.Helper()
|
||||
|
||||
|
||||
@@ -21,6 +21,13 @@ var GossipDataColumnSidecarRequirementsGloas = []Requirement{
|
||||
RequireNotSeenGloas,
|
||||
}
|
||||
|
||||
// PendingGloasColumnRequirements defines the requirements for columns queued before their block arrived.
|
||||
var PendingGloasColumnRequirements = []Requirement{
|
||||
RequireSlotMatchesBlockGloas,
|
||||
RequireValidFieldsGloas,
|
||||
RequireSidecarKzgProofVerifiedGloas,
|
||||
}
|
||||
|
||||
type ROGloasDataColumnVerifier struct {
|
||||
sidecar blocks.RODataColumn
|
||||
block interfaces.ReadOnlyBeaconBlock
|
||||
|
||||
@@ -85,7 +85,7 @@ type NewPayloadAttestationMsgVerifier func(pa payloadattestation.ROMessage, reqs
|
||||
|
||||
// SignedProposerPreferencesVerifier defines the methods implemented by the signed proposer preferences verifier.
|
||||
type SignedProposerPreferencesVerifier interface {
|
||||
VerifyNextEpoch(state.ReadOnlyBeaconState) error
|
||||
VerifyCurrentOrNextEpoch(state.ReadOnlyBeaconState) error
|
||||
VerifyValidProposalSlot(state.ReadOnlyBeaconState) error
|
||||
VerifySignature(state.ReadOnlyBeaconState) error
|
||||
SatisfyRequirement(Requirement)
|
||||
|
||||
@@ -49,7 +49,7 @@ const (
|
||||
RequireBidSignatureValid
|
||||
|
||||
// Signed proposer preferences specific.
|
||||
RequireProposerPreferencesNextEpoch
|
||||
RequireProposerPreferencesCurrentOrNextEpoch
|
||||
RequireProposerPreferencesProposalSlotValid
|
||||
RequireProposerPreferencesSignatureValid
|
||||
)
|
||||
|
||||
@@ -83,8 +83,8 @@ func (r Requirement) String() string {
|
||||
return "RequireBidBuilderCanCover"
|
||||
case RequireBidSignatureValid:
|
||||
return "RequireBidSignatureValid"
|
||||
case RequireProposerPreferencesNextEpoch:
|
||||
return "RequireProposerPreferencesNextEpoch"
|
||||
case RequireProposerPreferencesCurrentOrNextEpoch:
|
||||
return "RequireProposerPreferencesCurrentOrNextEpoch"
|
||||
case RequireProposerPreferencesProposalSlotValid:
|
||||
return "RequireProposerPreferencesProposalSlotValid"
|
||||
case RequireProposerPreferencesSignatureValid:
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"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/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
"github.com/pkg/errors"
|
||||
@@ -14,14 +15,15 @@ import (
|
||||
// SignedProposerPreferencesGossipRequirements is the requirement list for gossip
|
||||
// signed proposer preferences.
|
||||
var SignedProposerPreferencesGossipRequirements = requirementList([]Requirement{
|
||||
RequireProposerPreferencesNextEpoch,
|
||||
RequireProposerPreferencesCurrentOrNextEpoch,
|
||||
RequireProposerPreferencesProposalSlotValid,
|
||||
RequireProposerPreferencesSignatureValid,
|
||||
})
|
||||
|
||||
var (
|
||||
ErrProposerPreferencesNotNextEpoch = errors.New("proposer preferences proposal slot is not in the next epoch")
|
||||
ErrProposerPreferencesInvalidProposalSlot = errors.New("proposer preferences validator is not assigned to the proposal slot")
|
||||
ErrProposerPreferencesNotCurrentOrNextEpoch = errors.New("proposer preferences proposal slot is not in the current or next epoch")
|
||||
ErrProposerPreferencesSlotAlreadyPassed = errors.New("proposer preferences proposal slot has already passed")
|
||||
ErrProposerPreferencesInvalidProposalSlot = errors.New("proposer preferences validator is not assigned to the proposal slot")
|
||||
)
|
||||
|
||||
var _ SignedProposerPreferencesVerifier = &ProposerPreferencesVerifier{}
|
||||
@@ -33,17 +35,25 @@ type ProposerPreferencesVerifier struct {
|
||||
p *ethpb.SignedProposerPreferences
|
||||
}
|
||||
|
||||
// VerifyNextEpoch verifies the proposal slot is in the next epoch relative to
|
||||
// the state epoch, keeping it consistent with the ProposerLookahead index.
|
||||
func (v *ProposerPreferencesVerifier) VerifyNextEpoch(st state.ReadOnlyBeaconState) (err error) {
|
||||
defer v.record(RequireProposerPreferencesNextEpoch, &err)
|
||||
// VerifyCurrentOrNextEpoch verifies the proposal slot is in the current or next
|
||||
// epoch relative to the state epoch and has not already passed.
|
||||
func (v *ProposerPreferencesVerifier) VerifyCurrentOrNextEpoch(st state.ReadOnlyBeaconState) (err error) {
|
||||
defer v.record(RequireProposerPreferencesCurrentOrNextEpoch, &err)
|
||||
|
||||
msg := v.message()
|
||||
stateEpoch := slots.ToEpoch(st.Slot())
|
||||
currentSlot := st.Slot()
|
||||
if v.clock != nil && v.clock.CurrentSlot() > currentSlot {
|
||||
currentSlot = v.clock.CurrentSlot()
|
||||
}
|
||||
currentEpoch := slots.ToEpoch(currentSlot)
|
||||
proposalEpoch := slots.ToEpoch(msg.ProposalSlot)
|
||||
if proposalEpoch != stateEpoch.Add(1) {
|
||||
return fmt.Errorf("%w: proposal epoch %d, state epoch %d",
|
||||
ErrProposerPreferencesNotNextEpoch, proposalEpoch, stateEpoch)
|
||||
if proposalEpoch < currentEpoch || proposalEpoch > currentEpoch.Add(1) {
|
||||
return fmt.Errorf("%w: proposal epoch %d, current epoch %d",
|
||||
ErrProposerPreferencesNotCurrentOrNextEpoch, proposalEpoch, currentEpoch)
|
||||
}
|
||||
if msg.ProposalSlot <= currentSlot {
|
||||
return fmt.Errorf("%w: proposal slot %d <= current slot %d",
|
||||
ErrProposerPreferencesSlotAlreadyPassed, msg.ProposalSlot, currentSlot)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -59,7 +69,9 @@ func (v *ProposerPreferencesVerifier) VerifyValidProposalSlot(st state.ReadOnlyB
|
||||
return errors.Wrap(err, "failed to get proposer lookahead")
|
||||
}
|
||||
|
||||
slotIndex := params.BeaconConfig().SlotsPerEpoch + (msg.ProposalSlot % params.BeaconConfig().SlotsPerEpoch)
|
||||
currentEpoch := slots.ToEpoch(st.Slot())
|
||||
proposalEpoch := slots.ToEpoch(msg.ProposalSlot)
|
||||
slotIndex := primitives.Slot(proposalEpoch.Sub(uint64(currentEpoch)))*params.BeaconConfig().SlotsPerEpoch + (msg.ProposalSlot % params.BeaconConfig().SlotsPerEpoch)
|
||||
if uint64(len(lookahead)) <= uint64(slotIndex) {
|
||||
return fmt.Errorf("%w: proposer lookahead index %d out of bounds", ErrProposerPreferencesInvalidProposalSlot, slotIndex)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@ package verification
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/startup"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
@@ -15,15 +17,36 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
)
|
||||
|
||||
func TestProposerPreferencesVerifier_VerifyNextEpoch(t *testing.T) {
|
||||
func TestProposerPreferencesVerifier_VerifyCurrentOrNextEpoch(t *testing.T) {
|
||||
// Next epoch future slot is accepted.
|
||||
st, _, signed := newSignedProposerPreferencesState(t, 31, 40, 0)
|
||||
verifier := &ProposerPreferencesVerifier{sharedResources: &sharedResources{clock: testClockAtSlotForProposerPreferences(t, st.Slot())}, results: newResults(RequireProposerPreferencesCurrentOrNextEpoch), p: signed}
|
||||
require.NoError(t, verifier.VerifyCurrentOrNextEpoch(st))
|
||||
|
||||
verifier := &ProposerPreferencesVerifier{sharedResources: &sharedResources{}, results: newResults(RequireProposerPreferencesNextEpoch), p: signed}
|
||||
require.NoError(t, verifier.VerifyNextEpoch(st))
|
||||
// Current epoch future slot is accepted.
|
||||
signed.Message.ProposalSlot = st.Slot() + 1
|
||||
verifier = &ProposerPreferencesVerifier{sharedResources: &sharedResources{clock: testClockAtSlotForProposerPreferences(t, st.Slot())}, results: newResults(RequireProposerPreferencesCurrentOrNextEpoch), p: signed}
|
||||
require.NoError(t, verifier.VerifyCurrentOrNextEpoch(st))
|
||||
|
||||
// Current slot (already passed) is rejected.
|
||||
signed.Message.ProposalSlot = st.Slot()
|
||||
verifier = &ProposerPreferencesVerifier{sharedResources: &sharedResources{}, results: newResults(RequireProposerPreferencesNextEpoch), p: signed}
|
||||
require.ErrorIs(t, verifier.VerifyNextEpoch(st), ErrProposerPreferencesNotNextEpoch)
|
||||
verifier = &ProposerPreferencesVerifier{sharedResources: &sharedResources{clock: testClockAtSlotForProposerPreferences(t, st.Slot())}, results: newResults(RequireProposerPreferencesCurrentOrNextEpoch), p: signed}
|
||||
require.ErrorIs(t, verifier.VerifyCurrentOrNextEpoch(st), ErrProposerPreferencesSlotAlreadyPassed)
|
||||
|
||||
// Same-epoch future slot with more room.
|
||||
st2, _, signed2 := newSignedProposerPreferencesState(t, 24, 28, 0)
|
||||
verifier = &ProposerPreferencesVerifier{sharedResources: &sharedResources{clock: testClockAtSlotForProposerPreferences(t, st2.Slot())}, results: newResults(RequireProposerPreferencesCurrentOrNextEpoch), p: signed2}
|
||||
require.NoError(t, verifier.VerifyCurrentOrNextEpoch(st2))
|
||||
}
|
||||
|
||||
func TestProposerPreferencesVerifier_VerifyCurrentOrNextEpoch_UsesClockWhenStateLags(t *testing.T) {
|
||||
st, _, signed := newSignedProposerPreferencesState(t, 31, 32, 0)
|
||||
verifier := &ProposerPreferencesVerifier{
|
||||
sharedResources: &sharedResources{clock: testClockAtSlotForProposerPreferences(t, 32)},
|
||||
results: newResults(RequireProposerPreferencesCurrentOrNextEpoch),
|
||||
p: signed,
|
||||
}
|
||||
require.ErrorIs(t, verifier.VerifyCurrentOrNextEpoch(st), ErrProposerPreferencesSlotAlreadyPassed)
|
||||
}
|
||||
|
||||
func TestProposerPreferencesVerifier_VerifyValidProposalSlot(t *testing.T) {
|
||||
@@ -107,7 +130,9 @@ func newSignedProposerPreferencesState(t *testing.T, currentSlot, proposalSlot p
|
||||
|
||||
lookaheadSize := int(uint64(params.BeaconConfig().MinSeedLookahead+1) * uint64(params.BeaconConfig().SlotsPerEpoch))
|
||||
lookahead := make([]primitives.ValidatorIndex, lookaheadSize)
|
||||
index := params.BeaconConfig().SlotsPerEpoch + (proposalSlot % params.BeaconConfig().SlotsPerEpoch)
|
||||
currentEpoch := slots.ToEpoch(currentSlot)
|
||||
proposalEpoch := slots.ToEpoch(proposalSlot)
|
||||
index := primitives.Slot(proposalEpoch-currentEpoch)*params.BeaconConfig().SlotsPerEpoch + (proposalSlot % params.BeaconConfig().SlotsPerEpoch)
|
||||
lookahead[index] = validatorIndex
|
||||
require.NoError(t, st.SetProposerLookahead(lookahead))
|
||||
|
||||
@@ -135,3 +160,12 @@ func signProposerPreferencesWithConfigFork(t *testing.T, sk bls.SecretKey, prefe
|
||||
require.NoError(t, err)
|
||||
return sig
|
||||
}
|
||||
|
||||
func testClockAtSlotForProposerPreferences(t *testing.T, slot primitives.Slot) *startup.Clock {
|
||||
t.Helper()
|
||||
|
||||
genesis := time.Unix(1_700_000_000, 0)
|
||||
now, err := slots.StartTime(genesis, slot)
|
||||
require.NoError(t, err)
|
||||
return startup.NewClock(genesis, [32]byte{}, startup.WithNower(func() time.Time { return now }))
|
||||
}
|
||||
|
||||
3
changelog/alizfara112_fix-event-subscription-timeout.md
Normal file
3
changelog/alizfara112_fix-event-subscription-timeout.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- Prevent `/eth/v1/events` subscriptions from timing out under the global HTTP timeout handler.
|
||||
3
changelog/barnabasbusa_fix-minimal-max-builders-sweep.md
Normal file
3
changelog/barnabasbusa_fix-minimal-max-builders-sweep.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- Fixed `MaxBuildersPerWithdrawalsSweep` in the minimal preset to match the consensus-specs minimal gloas preset value of `16`.
|
||||
3
changelog/james-prysm_calculate-post-state.md
Normal file
3
changelog/james-prysm_calculate-post-state.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Ignored
|
||||
|
||||
- refactors calculate state root and breaks up into calculate post state function.
|
||||
4
changelog/james-prysm_execution-payload-envelope-rest.md
Normal file
4
changelog/james-prysm_execution-payload-envelope-rest.md
Normal file
@@ -0,0 +1,4 @@
|
||||
### Added
|
||||
|
||||
- GET /eth/v1/validator/execution_payload_envelope/{slot} endpoint
|
||||
- POST /eth/v1/beacon/execution_payload_envelope endpoint
|
||||
3
changelog/james-prysm_fix-payload-bid-path.md
Normal file
3
changelog/james-prysm_fix-payload-bid-path.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- changed POST incorrect endpoint /eth/v2/beacon/execution_payload/bid to /eth/v1/beacon/execution_payload_bid
|
||||
3
changelog/james-prysm_get-block-v4.md
Normal file
3
changelog/james-prysm_get-block-v4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- GET /eth/v4/validator/blocks/{slot}
|
||||
3
changelog/james-prysm_reverse-checkpont-api-change.md
Normal file
3
changelog/james-prysm_reverse-checkpont-api-change.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Ignored
|
||||
|
||||
- reverses pr#16635.
|
||||
3
changelog/james-prysm_same-epoch-proposer-preferences.md
Normal file
3
changelog/james-prysm_same-epoch-proposer-preferences.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- allow and send same epoch proposer preferences from https://github.com/ethereum/consensus-specs/pull/5035.
|
||||
3
changelog/james-prysm_validator-block-v4.md
Normal file
3
changelog/james-prysm_validator-block-v4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- added validator client call to blocks v4 and payload envelope endpoints post gloas.
|
||||
3
changelog/manu-pubkey-cache-map-mutex.md
Normal file
3
changelog/manu-pubkey-cache-map-mutex.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- Replace LRU cache with map+mutex for BLS public key cache.
|
||||
3
changelog/manu_sync_committee_duties_state_replay.md
Normal file
3
changelog/manu_sync_committee_duties_state_replay.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- `GetSyncCommitteeDuties` now fetches the state at the current epoch for current and next-period requests to avoid expensive state replays.
|
||||
@@ -1,2 +0,0 @@
|
||||
### Fixed
|
||||
- Fixed finalized and justified state endpoint to not advance the slot.
|
||||
3
changelog/rupam-04_issue-16191.md
Normal file
3
changelog/rupam-04_issue-16191.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- Prevent replays and return 404 for Beacon-API requests that ask for pre checkpoint sync state
|
||||
3
changelog/terence_gloas-pending-columns-queue.md
Normal file
3
changelog/terence_gloas-pending-columns-queue.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- Queue Gloas data column sidecars that arrive before their block for deferred validation, with per-index deduplication, slot-based pruning, and peer downscoring on verification failure.
|
||||
@@ -80,6 +80,7 @@ func MinimalSpecConfig() *BeaconChainConfig {
|
||||
minimalConfig.MaxWithdrawalsPerPayload = 4
|
||||
minimalConfig.MaxBlsToExecutionChanges = 16
|
||||
minimalConfig.MaxValidatorsPerWithdrawalsSweep = 16
|
||||
minimalConfig.MaxBuildersPerWithdrawalsSweep = 16
|
||||
|
||||
// Signature domains
|
||||
minimalConfig.DomainBeaconProposer = bytesutil.ToBytes4(bytesutil.Bytes4(0))
|
||||
|
||||
@@ -18,7 +18,6 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = select({
|
||||
"@io_bazel_rules_go//go/platform:android_amd64": [
|
||||
"//cache/nonblocking:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
@@ -27,7 +26,6 @@ go_library(
|
||||
"@com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:android_arm64": [
|
||||
"//cache/nonblocking:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
@@ -36,7 +34,6 @@ go_library(
|
||||
"@com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:darwin_amd64": [
|
||||
"//cache/nonblocking:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
@@ -45,7 +42,6 @@ go_library(
|
||||
"@com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:darwin_arm64": [
|
||||
"//cache/nonblocking:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
@@ -54,7 +50,6 @@ go_library(
|
||||
"@com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:ios_amd64": [
|
||||
"//cache/nonblocking:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
@@ -63,7 +58,6 @@ go_library(
|
||||
"@com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:ios_arm64": [
|
||||
"//cache/nonblocking:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
@@ -72,7 +66,6 @@ go_library(
|
||||
"@com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"//cache/nonblocking:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
@@ -81,7 +74,6 @@ go_library(
|
||||
"@com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:linux_arm64": [
|
||||
"//cache/nonblocking:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
@@ -90,7 +82,6 @@ go_library(
|
||||
"@com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||
"//cache/nonblocking:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
@@ -109,7 +100,6 @@ go_test(
|
||||
"public_key_test.go",
|
||||
"secret_key_test.go",
|
||||
"signature_test.go",
|
||||
"test_helper_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = select({
|
||||
|
||||
@@ -3,11 +3,8 @@
|
||||
package blst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/cache/nonblocking"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls/common"
|
||||
blst "github.com/supranational/blst/bindings/go"
|
||||
)
|
||||
|
||||
@@ -18,10 +15,4 @@ func init() {
|
||||
maxProcs = 1
|
||||
}
|
||||
blst.SetMaxProcs(maxProcs)
|
||||
onEvict := func(_ [48]byte, _ common.PublicKey) {}
|
||||
keysCache, err := nonblocking.NewLRU(maxKeys, onEvict)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Could not initiate public keys cache: %v", err))
|
||||
}
|
||||
pubkeyCache = keysCache
|
||||
}
|
||||
|
||||
@@ -4,16 +4,37 @@ package blst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/cache/nonblocking"
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls/common"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var maxKeys = 2_000_000
|
||||
var pubkeyCache *nonblocking.LRU[[48]byte, common.PublicKey]
|
||||
var pubkeyCache = &pubkeyCacheMap{
|
||||
items: make(map[[fieldparams.BLSPubkeyLength]byte]common.PublicKey),
|
||||
}
|
||||
|
||||
type pubkeyCacheMap struct {
|
||||
mu sync.RWMutex
|
||||
items map[[fieldparams.BLSPubkeyLength]byte]common.PublicKey
|
||||
}
|
||||
|
||||
func (c *pubkeyCacheMap) pubkey(key [fieldparams.BLSPubkeyLength]byte) (common.PublicKey, bool) {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
v, ok := c.items[key]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (c *pubkeyCacheMap) setPubkey(key [fieldparams.BLSPubkeyLength]byte, value common.PublicKey) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
c.items[key] = value
|
||||
}
|
||||
|
||||
// PublicKey used in the BLS signature scheme.
|
||||
type PublicKey struct {
|
||||
@@ -30,7 +51,7 @@ func publicKeyFromBytes(pubKey []byte, cacheCopy bool) (common.PublicKey, error)
|
||||
return nil, fmt.Errorf("public key must be %d bytes", params.BeaconConfig().BLSPubkeyLength)
|
||||
}
|
||||
newKey := (*[fieldparams.BLSPubkeyLength]byte)(pubKey)
|
||||
if cv, ok := pubkeyCache.Get(*newKey); ok {
|
||||
if cv, ok := pubkeyCache.pubkey(*newKey); ok {
|
||||
if cacheCopy {
|
||||
return cv.Copy(), nil
|
||||
}
|
||||
@@ -48,8 +69,7 @@ func publicKeyFromBytes(pubKey []byte, cacheCopy bool) (common.PublicKey, error)
|
||||
}
|
||||
pubKeyObj := &PublicKey{p: p}
|
||||
copiedKey := pubKeyObj.Copy()
|
||||
cacheKey := *newKey
|
||||
pubkeyCache.Add(cacheKey, copiedKey)
|
||||
pubkeyCache.setPubkey(*newKey, copiedKey)
|
||||
return pubKeyObj, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -162,27 +162,3 @@ func TestPublicKeysEmpty(t *testing.T) {
|
||||
_, err := blst.AggregatePublicKeys(pubs)
|
||||
require.ErrorContains(t, "nil or empty public keys", err)
|
||||
}
|
||||
|
||||
func BenchmarkPublicKeyFromBytes(b *testing.B) {
|
||||
priv, err := blst.RandKey()
|
||||
require.NoError(b, err)
|
||||
pubkey := priv.PublicKey()
|
||||
pubkeyBytes := pubkey.Marshal()
|
||||
|
||||
b.Run("cache on", func(b *testing.B) {
|
||||
blst.EnableCaches()
|
||||
for b.Loop() {
|
||||
_, err := blst.PublicKeyFromBytes(pubkeyBytes)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("cache off", func(b *testing.B) {
|
||||
blst.DisableCaches()
|
||||
for b.Loop() {
|
||||
_, err := blst.PublicKeyFromBytes(pubkeyBytes)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package blst
|
||||
|
||||
// Note: These functions are for tests to access private globals, such as pubkeyCache.
|
||||
|
||||
// DisableCaches sets the cache sizes to 0.
|
||||
func DisableCaches() {
|
||||
pubkeyCache.Resize(0)
|
||||
}
|
||||
|
||||
// EnableCaches sets the cache sizes to the default values.
|
||||
func EnableCaches() {
|
||||
pubkeyCache.Resize(maxKeys)
|
||||
}
|
||||
@@ -212,6 +212,7 @@ ssz_gloas_objs = [
|
||||
"SignedBlindedExecutionPayloadEnvelope",
|
||||
"SignedExecutionPayloadEnvelope",
|
||||
"BeaconBlockGloas",
|
||||
"BeaconBlockContentsGloas",
|
||||
"SignedBeaconBlockGloas",
|
||||
"BeaconStateGloas",
|
||||
]
|
||||
|
||||
586
proto/prysm/v1alpha1/gloas.pb.go
generated
586
proto/prysm/v1alpha1/gloas.pb.go
generated
@@ -1261,6 +1261,74 @@ func (x *PTCs) GetValidatorIndices() []github_com_OffchainLabs_prysm_v7_consensu
|
||||
return []github_com_OffchainLabs_prysm_v7_consensus_types_primitives.ValidatorIndex(nil)
|
||||
}
|
||||
|
||||
type BeaconBlockContentsGloas struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Block *BeaconBlockGloas `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"`
|
||||
ExecutionPayloadEnvelope *ExecutionPayloadEnvelope `protobuf:"bytes,2,opt,name=execution_payload_envelope,json=executionPayloadEnvelope,proto3" json:"execution_payload_envelope,omitempty"`
|
||||
KzgProofs [][]byte `protobuf:"bytes,3,rep,name=kzg_proofs,json=kzgProofs,proto3" json:"kzg_proofs,omitempty" ssz-max:"4096" ssz-size:"?,48"`
|
||||
Blobs [][]byte `protobuf:"bytes,4,rep,name=blobs,proto3" json:"blobs,omitempty" ssz-max:"4096" ssz-size:"?,131072"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *BeaconBlockContentsGloas) Reset() {
|
||||
*x = BeaconBlockContentsGloas{}
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BeaconBlockContentsGloas) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BeaconBlockContentsGloas) ProtoMessage() {}
|
||||
|
||||
func (x *BeaconBlockContentsGloas) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[13]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BeaconBlockContentsGloas.ProtoReflect.Descriptor instead.
|
||||
func (*BeaconBlockContentsGloas) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
func (x *BeaconBlockContentsGloas) GetBlock() *BeaconBlockGloas {
|
||||
if x != nil {
|
||||
return x.Block
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconBlockContentsGloas) GetExecutionPayloadEnvelope() *ExecutionPayloadEnvelope {
|
||||
if x != nil {
|
||||
return x.ExecutionPayloadEnvelope
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconBlockContentsGloas) GetKzgProofs() [][]byte {
|
||||
if x != nil {
|
||||
return x.KzgProofs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconBlockContentsGloas) GetBlobs() [][]byte {
|
||||
if x != nil {
|
||||
return x.Blobs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type BuilderPendingPayment struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Weight github_com_OffchainLabs_prysm_v7_consensus_types_primitives.Gwei `protobuf:"varint,1,opt,name=weight,proto3" json:"weight,omitempty" cast-type:"github.com/OffchainLabs/prysm/v7/consensus-types/primitives.Gwei"`
|
||||
@@ -1271,7 +1339,7 @@ type BuilderPendingPayment struct {
|
||||
|
||||
func (x *BuilderPendingPayment) Reset() {
|
||||
*x = BuilderPendingPayment{}
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[13]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1283,7 +1351,7 @@ func (x *BuilderPendingPayment) String() string {
|
||||
func (*BuilderPendingPayment) ProtoMessage() {}
|
||||
|
||||
func (x *BuilderPendingPayment) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[13]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[14]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1296,7 +1364,7 @@ func (x *BuilderPendingPayment) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use BuilderPendingPayment.ProtoReflect.Descriptor instead.
|
||||
func (*BuilderPendingPayment) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{13}
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
func (x *BuilderPendingPayment) GetWeight() github_com_OffchainLabs_prysm_v7_consensus_types_primitives.Gwei {
|
||||
@@ -1324,7 +1392,7 @@ type BuilderPendingWithdrawal struct {
|
||||
|
||||
func (x *BuilderPendingWithdrawal) Reset() {
|
||||
*x = BuilderPendingWithdrawal{}
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[14]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1336,7 +1404,7 @@ func (x *BuilderPendingWithdrawal) String() string {
|
||||
func (*BuilderPendingWithdrawal) ProtoMessage() {}
|
||||
|
||||
func (x *BuilderPendingWithdrawal) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[14]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[15]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1349,7 +1417,7 @@ func (x *BuilderPendingWithdrawal) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use BuilderPendingWithdrawal.ProtoReflect.Descriptor instead.
|
||||
func (*BuilderPendingWithdrawal) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{14}
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *BuilderPendingWithdrawal) GetFeeRecipient() []byte {
|
||||
@@ -1386,7 +1454,7 @@ type DataColumnSidecarGloas struct {
|
||||
|
||||
func (x *DataColumnSidecarGloas) Reset() {
|
||||
*x = DataColumnSidecarGloas{}
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[15]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1398,7 +1466,7 @@ func (x *DataColumnSidecarGloas) String() string {
|
||||
func (*DataColumnSidecarGloas) ProtoMessage() {}
|
||||
|
||||
func (x *DataColumnSidecarGloas) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[15]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[16]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1411,7 +1479,7 @@ func (x *DataColumnSidecarGloas) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use DataColumnSidecarGloas.ProtoReflect.Descriptor instead.
|
||||
func (*DataColumnSidecarGloas) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{15}
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
func (x *DataColumnSidecarGloas) GetIndex() uint64 {
|
||||
@@ -1463,7 +1531,7 @@ type ExecutionPayloadEnvelope struct {
|
||||
|
||||
func (x *ExecutionPayloadEnvelope) Reset() {
|
||||
*x = ExecutionPayloadEnvelope{}
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[16]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1475,7 +1543,7 @@ func (x *ExecutionPayloadEnvelope) String() string {
|
||||
func (*ExecutionPayloadEnvelope) ProtoMessage() {}
|
||||
|
||||
func (x *ExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[16]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[17]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1488,7 +1556,7 @@ func (x *ExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ExecutionPayloadEnvelope.ProtoReflect.Descriptor instead.
|
||||
func (*ExecutionPayloadEnvelope) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{16}
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{17}
|
||||
}
|
||||
|
||||
func (x *ExecutionPayloadEnvelope) GetPayload() *v1.ExecutionPayloadDeneb {
|
||||
@@ -1543,7 +1611,7 @@ type SignedExecutionPayloadEnvelope struct {
|
||||
|
||||
func (x *SignedExecutionPayloadEnvelope) Reset() {
|
||||
*x = SignedExecutionPayloadEnvelope{}
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[17]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[18]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1555,7 +1623,7 @@ func (x *SignedExecutionPayloadEnvelope) String() string {
|
||||
func (*SignedExecutionPayloadEnvelope) ProtoMessage() {}
|
||||
|
||||
func (x *SignedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[17]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[18]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1568,7 +1636,7 @@ func (x *SignedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use SignedExecutionPayloadEnvelope.ProtoReflect.Descriptor instead.
|
||||
func (*SignedExecutionPayloadEnvelope) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{17}
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{18}
|
||||
}
|
||||
|
||||
func (x *SignedExecutionPayloadEnvelope) GetMessage() *ExecutionPayloadEnvelope {
|
||||
@@ -1600,7 +1668,7 @@ type BlindedExecutionPayloadEnvelope struct {
|
||||
|
||||
func (x *BlindedExecutionPayloadEnvelope) Reset() {
|
||||
*x = BlindedExecutionPayloadEnvelope{}
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[18]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[19]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1612,7 +1680,7 @@ func (x *BlindedExecutionPayloadEnvelope) String() string {
|
||||
func (*BlindedExecutionPayloadEnvelope) ProtoMessage() {}
|
||||
|
||||
func (x *BlindedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[18]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[19]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1625,7 +1693,7 @@ func (x *BlindedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use BlindedExecutionPayloadEnvelope.ProtoReflect.Descriptor instead.
|
||||
func (*BlindedExecutionPayloadEnvelope) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{18}
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{19}
|
||||
}
|
||||
|
||||
func (x *BlindedExecutionPayloadEnvelope) GetBlockHash() []byte {
|
||||
@@ -1687,7 +1755,7 @@ type SignedBlindedExecutionPayloadEnvelope struct {
|
||||
|
||||
func (x *SignedBlindedExecutionPayloadEnvelope) Reset() {
|
||||
*x = SignedBlindedExecutionPayloadEnvelope{}
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[19]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[20]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1699,7 +1767,7 @@ func (x *SignedBlindedExecutionPayloadEnvelope) String() string {
|
||||
func (*SignedBlindedExecutionPayloadEnvelope) ProtoMessage() {}
|
||||
|
||||
func (x *SignedBlindedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[19]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[20]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1712,7 +1780,7 @@ func (x *SignedBlindedExecutionPayloadEnvelope) ProtoReflect() protoreflect.Mess
|
||||
|
||||
// Deprecated: Use SignedBlindedExecutionPayloadEnvelope.ProtoReflect.Descriptor instead.
|
||||
func (*SignedBlindedExecutionPayloadEnvelope) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{19}
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{20}
|
||||
}
|
||||
|
||||
func (x *SignedBlindedExecutionPayloadEnvelope) GetMessage() *BlindedExecutionPayloadEnvelope {
|
||||
@@ -1743,7 +1811,7 @@ type Builder struct {
|
||||
|
||||
func (x *Builder) Reset() {
|
||||
*x = Builder{}
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[20]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[21]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -1755,7 +1823,7 @@ func (x *Builder) String() string {
|
||||
func (*Builder) ProtoMessage() {}
|
||||
|
||||
func (x *Builder) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[20]
|
||||
mi := &file_proto_prysm_v1alpha1_gloas_proto_msgTypes[21]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -1768,7 +1836,7 @@ func (x *Builder) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Builder.ProtoReflect.Descriptor instead.
|
||||
func (*Builder) Descriptor() ([]byte, []int) {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{20}
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP(), []int{21}
|
||||
}
|
||||
|
||||
func (x *Builder) GetPubkey() []byte {
|
||||
@@ -2341,168 +2409,187 @@ var file_proto_prysm_v1alpha1_gloas_proto_rawDesc = []byte{
|
||||
0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x69,
|
||||
0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x8a, 0xb5, 0x18, 0x03, 0x35, 0x31,
|
||||
0x32, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x64, 0x69,
|
||||
0x63, 0x65, 0x73, 0x22, 0xc6, 0x01, 0x0a, 0x15, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x50,
|
||||
0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x5c, 0x0a,
|
||||
0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82,
|
||||
0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66,
|
||||
0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d,
|
||||
0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79,
|
||||
0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x47,
|
||||
0x77, 0x65, 0x69, 0x52, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x4f, 0x0a, 0x0a, 0x77,
|
||||
0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x2f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76,
|
||||
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x50,
|
||||
0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c,
|
||||
0x52, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x22, 0x98, 0x02, 0x0a,
|
||||
0x18, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x57,
|
||||
0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x12, 0x2b, 0x0a, 0x0d, 0x66, 0x65, 0x65,
|
||||
0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
|
||||
0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x0c, 0x66, 0x65, 0x65, 0x52, 0x65, 0x63,
|
||||
0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x5c, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c,
|
||||
0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69,
|
||||
0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x47, 0x77, 0x65, 0x69, 0x52, 0x06, 0x61, 0x6d,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x12, 0x71, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f,
|
||||
0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4c, 0x82, 0xb5, 0x18,
|
||||
0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63,
|
||||
0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76,
|
||||
0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65,
|
||||
0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x69,
|
||||
0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64,
|
||||
0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x99, 0x02, 0x0a, 0x16, 0x44, 0x61, 0x74, 0x61,
|
||||
0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x53, 0x69, 0x64, 0x65, 0x63, 0x61, 0x72, 0x47, 0x6c, 0x6f,
|
||||
0x61, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x04, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2a, 0x0a, 0x06, 0x63, 0x6f, 0x6c, 0x75,
|
||||
0x6d, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x12, 0x8a, 0xb5, 0x18, 0x06, 0x3f, 0x2c,
|
||||
0x32, 0x30, 0x34, 0x38, 0x92, 0xb5, 0x18, 0x04, 0x34, 0x30, 0x39, 0x36, 0x52, 0x06, 0x63, 0x6f,
|
||||
0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x2f, 0x0a, 0x0a, 0x6b, 0x7a, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x6f,
|
||||
0x66, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x10, 0x8a, 0xb5, 0x18, 0x04, 0x3f, 0x2c,
|
||||
0x34, 0x38, 0x92, 0xb5, 0x18, 0x04, 0x34, 0x30, 0x39, 0x36, 0x52, 0x09, 0x6b, 0x7a, 0x67, 0x50,
|
||||
0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x58, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x65, 0x73, 0x22, 0xa5, 0x02, 0x0a, 0x18, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x47, 0x6c, 0x6f, 0x61, 0x73,
|
||||
0x12, 0x3d, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x27, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76,
|
||||
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x47, 0x6c, 0x6f, 0x61, 0x73, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12,
|
||||
0x6d, 0x0a, 0x1a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x79,
|
||||
0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65,
|
||||
0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63,
|
||||
0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65,
|
||||
0x6c, 0x6f, 0x70, 0x65, 0x52, 0x18, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50,
|
||||
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x2f,
|
||||
0x0a, 0x0a, 0x6b, 0x7a, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x18, 0x03, 0x20, 0x03,
|
||||
0x28, 0x0c, 0x42, 0x10, 0x8a, 0xb5, 0x18, 0x04, 0x3f, 0x2c, 0x34, 0x38, 0x92, 0xb5, 0x18, 0x04,
|
||||
0x34, 0x30, 0x39, 0x36, 0x52, 0x09, 0x6b, 0x7a, 0x67, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12,
|
||||
0x2a, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x14,
|
||||
0x8a, 0xb5, 0x18, 0x08, 0x3f, 0x2c, 0x31, 0x33, 0x31, 0x30, 0x37, 0x32, 0x92, 0xb5, 0x18, 0x04,
|
||||
0x34, 0x30, 0x39, 0x36, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x22, 0xc6, 0x01, 0x0a, 0x15,
|
||||
0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61,
|
||||
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x5c, 0x0a, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61,
|
||||
0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d,
|
||||
0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x47, 0x77, 0x65, 0x69, 0x52, 0x06, 0x77, 0x65, 0x69,
|
||||
0x67, 0x68, 0x74, 0x12, 0x4f, 0x0a, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61,
|
||||
0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65,
|
||||
0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e,
|
||||
0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x57, 0x69,
|
||||
0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72,
|
||||
0x61, 0x77, 0x61, 0x6c, 0x22, 0x98, 0x02, 0x0a, 0x18, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72,
|
||||
0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61,
|
||||
0x6c, 0x12, 0x2b, 0x0a, 0x0d, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65,
|
||||
0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30,
|
||||
0x52, 0x0c, 0x66, 0x65, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x5c,
|
||||
0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44,
|
||||
0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f,
|
||||
0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73,
|
||||
0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74,
|
||||
0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e,
|
||||
0x47, 0x77, 0x65, 0x69, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x71, 0x0a, 0x0d,
|
||||
0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x04, 0x42, 0x4c, 0x82, 0xb5, 0x18, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73,
|
||||
0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e,
|
||||
0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74,
|
||||
0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12,
|
||||
0x32, 0x0a, 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
|
||||
0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02,
|
||||
0x33, 0x32, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52,
|
||||
0x6f, 0x6f, 0x74, 0x22, 0xdd, 0x03, 0x0a, 0x18, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65,
|
||||
0x12, 0x43, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x29, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67,
|
||||
0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x44, 0x65, 0x6e, 0x65, 0x62, 0x52, 0x07, 0x70, 0x61,
|
||||
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x54, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x25, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67,
|
||||
0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x71, 0x0a, 0x0d, 0x62,
|
||||
0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x04, 0x42, 0x4c, 0x82, 0xb5, 0x18, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f,
|
||||
0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73,
|
||||
0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69,
|
||||
0x76, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78,
|
||||
0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x32,
|
||||
0x0a, 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72,
|
||||
0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33,
|
||||
0x32, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f,
|
||||
0x6f, 0x74, 0x12, 0x58, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04,
|
||||
0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72,
|
||||
0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73,
|
||||
0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65,
|
||||
0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12, 0x25, 0x0a, 0x0a,
|
||||
0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c,
|
||||
0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52,
|
||||
0x6f, 0x6f, 0x74, 0x22, 0x91, 0x01, 0x0a, 0x1e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x78,
|
||||
0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e,
|
||||
0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x49, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65,
|
||||
0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e,
|
||||
0x69, 0x76, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65,
|
||||
0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22,
|
||||
0x99, 0x02, 0x0a, 0x16, 0x44, 0x61, 0x74, 0x61, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x53, 0x69,
|
||||
0x64, 0x65, 0x63, 0x61, 0x72, 0x47, 0x6c, 0x6f, 0x61, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e,
|
||||
0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78,
|
||||
0x12, 0x2a, 0x0a, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c,
|
||||
0x42, 0x12, 0x8a, 0xb5, 0x18, 0x06, 0x3f, 0x2c, 0x32, 0x30, 0x34, 0x38, 0x92, 0xb5, 0x18, 0x04,
|
||||
0x34, 0x30, 0x39, 0x36, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x2f, 0x0a, 0x0a,
|
||||
0x6b, 0x7a, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c,
|
||||
0x42, 0x10, 0x8a, 0xb5, 0x18, 0x04, 0x3f, 0x2c, 0x34, 0x38, 0x92, 0xb5, 0x18, 0x04, 0x34, 0x30,
|
||||
0x39, 0x36, 0x52, 0x09, 0x6b, 0x7a, 0x67, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x58, 0x0a,
|
||||
0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18,
|
||||
0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63,
|
||||
0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76,
|
||||
0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65,
|
||||
0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f,
|
||||
0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12, 0x32, 0x0a, 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f,
|
||||
0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63,
|
||||
0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0xdd, 0x03, 0x0a, 0x18,
|
||||
0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
|
||||
0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69,
|
||||
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xfa, 0x03, 0x0a, 0x1f, 0x42, 0x6c, 0x69, 0x6e,
|
||||
0x64, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c,
|
||||
0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0a, 0x62,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42,
|
||||
0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61,
|
||||
0x73, 0x68, 0x12, 0x54, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25,
|
||||
0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x71, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c,
|
||||
0x64, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42,
|
||||
0x4c, 0x82, 0xb5, 0x18, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79,
|
||||
0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d,
|
||||
0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73,
|
||||
0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0c, 0x62,
|
||||
0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x32, 0x0a, 0x11, 0x62,
|
||||
0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f,
|
||||
0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x12,
|
||||
0x58, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82,
|
||||
0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66,
|
||||
0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d,
|
||||
0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79,
|
||||
0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53,
|
||||
0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x74, 0x61,
|
||||
0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a,
|
||||
0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74,
|
||||
0x12, 0x32, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18,
|
||||
0x02, 0x33, 0x32, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
|
||||
0x48, 0x61, 0x73, 0x68, 0x22, 0x9f, 0x01, 0x0a, 0x25, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42,
|
||||
0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50,
|
||||
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x50,
|
||||
0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x36, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76,
|
||||
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x45,
|
||||
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45,
|
||||
0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, 0x67,
|
||||
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xc1, 0x03, 0x0a, 0x07, 0x42, 0x75, 0x69, 0x6c, 0x64,
|
||||
0x65, 0x72, 0x12, 0x1e, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x34, 0x38, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b,
|
||||
0x65, 0x79, 0x12, 0x1f, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x42, 0x05, 0x8a, 0xb5, 0x18, 0x01, 0x31, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06,
|
||||
0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x5e, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61,
|
||||
0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f,
|
||||
0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f,
|
||||
0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x47, 0x77, 0x65, 0x69, 0x52,
|
||||
0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x6a, 0x0a, 0x0d, 0x64, 0x65, 0x70, 0x6f,
|
||||
0x73, 0x69, 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42,
|
||||
0x45, 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79,
|
||||
0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d,
|
||||
0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73,
|
||||
0x2e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x45,
|
||||
0x70, 0x6f, 0x63, 0x68, 0x12, 0x74, 0x0a, 0x12, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04,
|
||||
0x42, 0x45, 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72,
|
||||
0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73,
|
||||
0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65,
|
||||
0x73, 0x2e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x11, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61,
|
||||
0x77, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69,
|
||||
0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x43, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c,
|
||||
0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x65, 0x74, 0x68, 0x65,
|
||||
0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45,
|
||||
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x44,
|
||||
0x65, 0x6e, 0x65, 0x62, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x54, 0x0a,
|
||||
0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x65, 0x74, 0x68, 0x65,
|
||||
0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45,
|
||||
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73,
|
||||
0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x73, 0x12, 0x71, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69,
|
||||
0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4c, 0x82, 0xb5, 0x18, 0x48,
|
||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68,
|
||||
0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37,
|
||||
0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73,
|
||||
0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c,
|
||||
0x64, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65,
|
||||
0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x32, 0x0a, 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e,
|
||||
0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f,
|
||||
0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x58, 0x0a, 0x04, 0x73, 0x6c,
|
||||
0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69,
|
||||
0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70,
|
||||
0x68, 0x61, 0x31, 0x3b, 0x65, 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70,
|
||||
0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04,
|
||||
0x73, 0x6c, 0x6f, 0x74, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f,
|
||||
0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32,
|
||||
0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x22, 0x91, 0x01, 0x0a, 0x1e,
|
||||
0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50,
|
||||
0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x49,
|
||||
0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x2f, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76,
|
||||
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65,
|
||||
0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67,
|
||||
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5,
|
||||
0x18, 0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22,
|
||||
0xfa, 0x03, 0x0a, 0x1f, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c,
|
||||
0x6f, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73,
|
||||
0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52,
|
||||
0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x54, 0x0a, 0x12, 0x65, 0x78,
|
||||
0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75,
|
||||
0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x78, 0x65, 0x63,
|
||||
0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x11, 0x65,
|
||||
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73,
|
||||
0x12, 0x71, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65,
|
||||
0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4c, 0x82, 0xb5, 0x18, 0x48, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e,
|
||||
0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72,
|
||||
0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72,
|
||||
0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x49, 0x6e,
|
||||
0x64, 0x65, 0x78, 0x12, 0x32, 0x0a, 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06,
|
||||
0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x58, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61,
|
||||
0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d,
|
||||
0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f,
|
||||
0x74, 0x12, 0x25, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18,
|
||||
0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x09, 0x73,
|
||||
0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x32, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x65,
|
||||
0x6e, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0f, 0x70, 0x61, 0x72,
|
||||
0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x9f, 0x01, 0x0a,
|
||||
0x25, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x45, 0x78,
|
||||
0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e,
|
||||
0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x50, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65,
|
||||
0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e,
|
||||
0x42, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x64, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52,
|
||||
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e,
|
||||
0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18,
|
||||
0x02, 0x39, 0x36, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xc1,
|
||||
0x03, 0x0a, 0x07, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x06, 0x70, 0x75,
|
||||
0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02,
|
||||
0x34, 0x38, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x07, 0x76, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x05, 0x8a, 0xb5, 0x18,
|
||||
0x01, 0x31, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x11, 0x65,
|
||||
0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x32, 0x30, 0x52, 0x10,
|
||||
0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
|
||||
0x12, 0x5e, 0x0a, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x04, 0x42, 0x44, 0x82, 0xb5, 0x18, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70,
|
||||
0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75,
|
||||
0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76,
|
||||
0x65, 0x73, 0x2e, 0x47, 0x77, 0x65, 0x69, 0x52, 0x07, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x12, 0x6a, 0x0a, 0x0d, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63,
|
||||
0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x45, 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74,
|
||||
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e,
|
||||
0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72,
|
||||
0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x0c,
|
||||
0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x74, 0x0a, 0x12,
|
||||
0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x70, 0x6f,
|
||||
0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x42, 0x45, 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69,
|
||||
0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x63,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70,
|
||||
0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52,
|
||||
0x11, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x70, 0x6f,
|
||||
0x63, 0x68, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x4f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72,
|
||||
0x79, 0x73, 0x6d, 0x2f, 0x76, 0x37, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x79,
|
||||
0x73, 0x6d, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x65, 0x74, 0x68, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -2517,7 +2604,7 @@ func file_proto_prysm_v1alpha1_gloas_proto_rawDescGZIP() []byte {
|
||||
return file_proto_prysm_v1alpha1_gloas_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proto_prysm_v1alpha1_gloas_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
|
||||
var file_proto_prysm_v1alpha1_gloas_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
|
||||
var file_proto_prysm_v1alpha1_gloas_proto_goTypes = []any{
|
||||
(*ExecutionPayloadBid)(nil), // 0: ethereum.eth.v1alpha1.ExecutionPayloadBid
|
||||
(*SignedExecutionPayloadBid)(nil), // 1: ethereum.eth.v1alpha1.SignedExecutionPayloadBid
|
||||
@@ -2532,34 +2619,35 @@ var file_proto_prysm_v1alpha1_gloas_proto_goTypes = []any{
|
||||
(*SignedBeaconBlockGloas)(nil), // 10: ethereum.eth.v1alpha1.SignedBeaconBlockGloas
|
||||
(*BeaconStateGloas)(nil), // 11: ethereum.eth.v1alpha1.BeaconStateGloas
|
||||
(*PTCs)(nil), // 12: ethereum.eth.v1alpha1.PTCs
|
||||
(*BuilderPendingPayment)(nil), // 13: ethereum.eth.v1alpha1.BuilderPendingPayment
|
||||
(*BuilderPendingWithdrawal)(nil), // 14: ethereum.eth.v1alpha1.BuilderPendingWithdrawal
|
||||
(*DataColumnSidecarGloas)(nil), // 15: ethereum.eth.v1alpha1.DataColumnSidecarGloas
|
||||
(*ExecutionPayloadEnvelope)(nil), // 16: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope
|
||||
(*SignedExecutionPayloadEnvelope)(nil), // 17: ethereum.eth.v1alpha1.SignedExecutionPayloadEnvelope
|
||||
(*BlindedExecutionPayloadEnvelope)(nil), // 18: ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope
|
||||
(*SignedBlindedExecutionPayloadEnvelope)(nil), // 19: ethereum.eth.v1alpha1.SignedBlindedExecutionPayloadEnvelope
|
||||
(*Builder)(nil), // 20: ethereum.eth.v1alpha1.Builder
|
||||
(*Eth1Data)(nil), // 21: ethereum.eth.v1alpha1.Eth1Data
|
||||
(*ProposerSlashing)(nil), // 22: ethereum.eth.v1alpha1.ProposerSlashing
|
||||
(*AttesterSlashingElectra)(nil), // 23: ethereum.eth.v1alpha1.AttesterSlashingElectra
|
||||
(*AttestationElectra)(nil), // 24: ethereum.eth.v1alpha1.AttestationElectra
|
||||
(*Deposit)(nil), // 25: ethereum.eth.v1alpha1.Deposit
|
||||
(*SignedVoluntaryExit)(nil), // 26: ethereum.eth.v1alpha1.SignedVoluntaryExit
|
||||
(*SyncAggregate)(nil), // 27: ethereum.eth.v1alpha1.SyncAggregate
|
||||
(*SignedBLSToExecutionChange)(nil), // 28: ethereum.eth.v1alpha1.SignedBLSToExecutionChange
|
||||
(*Fork)(nil), // 29: ethereum.eth.v1alpha1.Fork
|
||||
(*BeaconBlockHeader)(nil), // 30: ethereum.eth.v1alpha1.BeaconBlockHeader
|
||||
(*Validator)(nil), // 31: ethereum.eth.v1alpha1.Validator
|
||||
(*Checkpoint)(nil), // 32: ethereum.eth.v1alpha1.Checkpoint
|
||||
(*SyncCommittee)(nil), // 33: ethereum.eth.v1alpha1.SyncCommittee
|
||||
(*HistoricalSummary)(nil), // 34: ethereum.eth.v1alpha1.HistoricalSummary
|
||||
(*PendingDeposit)(nil), // 35: ethereum.eth.v1alpha1.PendingDeposit
|
||||
(*PendingPartialWithdrawal)(nil), // 36: ethereum.eth.v1alpha1.PendingPartialWithdrawal
|
||||
(*PendingConsolidation)(nil), // 37: ethereum.eth.v1alpha1.PendingConsolidation
|
||||
(*v1.Withdrawal)(nil), // 38: ethereum.engine.v1.Withdrawal
|
||||
(*v1.ExecutionPayloadDeneb)(nil), // 39: ethereum.engine.v1.ExecutionPayloadDeneb
|
||||
(*v1.ExecutionRequests)(nil), // 40: ethereum.engine.v1.ExecutionRequests
|
||||
(*BeaconBlockContentsGloas)(nil), // 13: ethereum.eth.v1alpha1.BeaconBlockContentsGloas
|
||||
(*BuilderPendingPayment)(nil), // 14: ethereum.eth.v1alpha1.BuilderPendingPayment
|
||||
(*BuilderPendingWithdrawal)(nil), // 15: ethereum.eth.v1alpha1.BuilderPendingWithdrawal
|
||||
(*DataColumnSidecarGloas)(nil), // 16: ethereum.eth.v1alpha1.DataColumnSidecarGloas
|
||||
(*ExecutionPayloadEnvelope)(nil), // 17: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope
|
||||
(*SignedExecutionPayloadEnvelope)(nil), // 18: ethereum.eth.v1alpha1.SignedExecutionPayloadEnvelope
|
||||
(*BlindedExecutionPayloadEnvelope)(nil), // 19: ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope
|
||||
(*SignedBlindedExecutionPayloadEnvelope)(nil), // 20: ethereum.eth.v1alpha1.SignedBlindedExecutionPayloadEnvelope
|
||||
(*Builder)(nil), // 21: ethereum.eth.v1alpha1.Builder
|
||||
(*Eth1Data)(nil), // 22: ethereum.eth.v1alpha1.Eth1Data
|
||||
(*ProposerSlashing)(nil), // 23: ethereum.eth.v1alpha1.ProposerSlashing
|
||||
(*AttesterSlashingElectra)(nil), // 24: ethereum.eth.v1alpha1.AttesterSlashingElectra
|
||||
(*AttestationElectra)(nil), // 25: ethereum.eth.v1alpha1.AttestationElectra
|
||||
(*Deposit)(nil), // 26: ethereum.eth.v1alpha1.Deposit
|
||||
(*SignedVoluntaryExit)(nil), // 27: ethereum.eth.v1alpha1.SignedVoluntaryExit
|
||||
(*SyncAggregate)(nil), // 28: ethereum.eth.v1alpha1.SyncAggregate
|
||||
(*SignedBLSToExecutionChange)(nil), // 29: ethereum.eth.v1alpha1.SignedBLSToExecutionChange
|
||||
(*Fork)(nil), // 30: ethereum.eth.v1alpha1.Fork
|
||||
(*BeaconBlockHeader)(nil), // 31: ethereum.eth.v1alpha1.BeaconBlockHeader
|
||||
(*Validator)(nil), // 32: ethereum.eth.v1alpha1.Validator
|
||||
(*Checkpoint)(nil), // 33: ethereum.eth.v1alpha1.Checkpoint
|
||||
(*SyncCommittee)(nil), // 34: ethereum.eth.v1alpha1.SyncCommittee
|
||||
(*HistoricalSummary)(nil), // 35: ethereum.eth.v1alpha1.HistoricalSummary
|
||||
(*PendingDeposit)(nil), // 36: ethereum.eth.v1alpha1.PendingDeposit
|
||||
(*PendingPartialWithdrawal)(nil), // 37: ethereum.eth.v1alpha1.PendingPartialWithdrawal
|
||||
(*PendingConsolidation)(nil), // 38: ethereum.eth.v1alpha1.PendingConsolidation
|
||||
(*v1.Withdrawal)(nil), // 39: ethereum.engine.v1.Withdrawal
|
||||
(*v1.ExecutionPayloadDeneb)(nil), // 40: ethereum.engine.v1.ExecutionPayloadDeneb
|
||||
(*v1.ExecutionRequests)(nil), // 41: ethereum.engine.v1.ExecutionRequests
|
||||
}
|
||||
var file_proto_prysm_v1alpha1_gloas_proto_depIdxs = []int32{
|
||||
0, // 0: ethereum.eth.v1alpha1.SignedExecutionPayloadBid.message:type_name -> ethereum.eth.v1alpha1.ExecutionPayloadBid
|
||||
@@ -2568,48 +2656,50 @@ var file_proto_prysm_v1alpha1_gloas_proto_depIdxs = []int32{
|
||||
5, // 3: ethereum.eth.v1alpha1.PayloadAttestation.data:type_name -> ethereum.eth.v1alpha1.PayloadAttestationData
|
||||
5, // 4: ethereum.eth.v1alpha1.PayloadAttestationMessage.data:type_name -> ethereum.eth.v1alpha1.PayloadAttestationData
|
||||
9, // 5: ethereum.eth.v1alpha1.BeaconBlockGloas.body:type_name -> ethereum.eth.v1alpha1.BeaconBlockBodyGloas
|
||||
21, // 6: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data
|
||||
22, // 7: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing
|
||||
23, // 8: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashingElectra
|
||||
24, // 9: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.attestations:type_name -> ethereum.eth.v1alpha1.AttestationElectra
|
||||
25, // 10: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.deposits:type_name -> ethereum.eth.v1alpha1.Deposit
|
||||
26, // 11: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit
|
||||
27, // 12: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.sync_aggregate:type_name -> ethereum.eth.v1alpha1.SyncAggregate
|
||||
28, // 13: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.bls_to_execution_changes:type_name -> ethereum.eth.v1alpha1.SignedBLSToExecutionChange
|
||||
22, // 6: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data
|
||||
23, // 7: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.proposer_slashings:type_name -> ethereum.eth.v1alpha1.ProposerSlashing
|
||||
24, // 8: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.attester_slashings:type_name -> ethereum.eth.v1alpha1.AttesterSlashingElectra
|
||||
25, // 9: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.attestations:type_name -> ethereum.eth.v1alpha1.AttestationElectra
|
||||
26, // 10: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.deposits:type_name -> ethereum.eth.v1alpha1.Deposit
|
||||
27, // 11: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.voluntary_exits:type_name -> ethereum.eth.v1alpha1.SignedVoluntaryExit
|
||||
28, // 12: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.sync_aggregate:type_name -> ethereum.eth.v1alpha1.SyncAggregate
|
||||
29, // 13: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.bls_to_execution_changes:type_name -> ethereum.eth.v1alpha1.SignedBLSToExecutionChange
|
||||
1, // 14: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.signed_execution_payload_bid:type_name -> ethereum.eth.v1alpha1.SignedExecutionPayloadBid
|
||||
6, // 15: ethereum.eth.v1alpha1.BeaconBlockBodyGloas.payload_attestations:type_name -> ethereum.eth.v1alpha1.PayloadAttestation
|
||||
8, // 16: ethereum.eth.v1alpha1.SignedBeaconBlockGloas.block:type_name -> ethereum.eth.v1alpha1.BeaconBlockGloas
|
||||
29, // 17: ethereum.eth.v1alpha1.BeaconStateGloas.fork:type_name -> ethereum.eth.v1alpha1.Fork
|
||||
30, // 18: ethereum.eth.v1alpha1.BeaconStateGloas.latest_block_header:type_name -> ethereum.eth.v1alpha1.BeaconBlockHeader
|
||||
21, // 19: ethereum.eth.v1alpha1.BeaconStateGloas.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data
|
||||
21, // 20: ethereum.eth.v1alpha1.BeaconStateGloas.eth1_data_votes:type_name -> ethereum.eth.v1alpha1.Eth1Data
|
||||
31, // 21: ethereum.eth.v1alpha1.BeaconStateGloas.validators:type_name -> ethereum.eth.v1alpha1.Validator
|
||||
32, // 22: ethereum.eth.v1alpha1.BeaconStateGloas.previous_justified_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint
|
||||
32, // 23: ethereum.eth.v1alpha1.BeaconStateGloas.current_justified_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint
|
||||
32, // 24: ethereum.eth.v1alpha1.BeaconStateGloas.finalized_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint
|
||||
33, // 25: ethereum.eth.v1alpha1.BeaconStateGloas.current_sync_committee:type_name -> ethereum.eth.v1alpha1.SyncCommittee
|
||||
33, // 26: ethereum.eth.v1alpha1.BeaconStateGloas.next_sync_committee:type_name -> ethereum.eth.v1alpha1.SyncCommittee
|
||||
30, // 17: ethereum.eth.v1alpha1.BeaconStateGloas.fork:type_name -> ethereum.eth.v1alpha1.Fork
|
||||
31, // 18: ethereum.eth.v1alpha1.BeaconStateGloas.latest_block_header:type_name -> ethereum.eth.v1alpha1.BeaconBlockHeader
|
||||
22, // 19: ethereum.eth.v1alpha1.BeaconStateGloas.eth1_data:type_name -> ethereum.eth.v1alpha1.Eth1Data
|
||||
22, // 20: ethereum.eth.v1alpha1.BeaconStateGloas.eth1_data_votes:type_name -> ethereum.eth.v1alpha1.Eth1Data
|
||||
32, // 21: ethereum.eth.v1alpha1.BeaconStateGloas.validators:type_name -> ethereum.eth.v1alpha1.Validator
|
||||
33, // 22: ethereum.eth.v1alpha1.BeaconStateGloas.previous_justified_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint
|
||||
33, // 23: ethereum.eth.v1alpha1.BeaconStateGloas.current_justified_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint
|
||||
33, // 24: ethereum.eth.v1alpha1.BeaconStateGloas.finalized_checkpoint:type_name -> ethereum.eth.v1alpha1.Checkpoint
|
||||
34, // 25: ethereum.eth.v1alpha1.BeaconStateGloas.current_sync_committee:type_name -> ethereum.eth.v1alpha1.SyncCommittee
|
||||
34, // 26: ethereum.eth.v1alpha1.BeaconStateGloas.next_sync_committee:type_name -> ethereum.eth.v1alpha1.SyncCommittee
|
||||
0, // 27: ethereum.eth.v1alpha1.BeaconStateGloas.latest_execution_payload_bid:type_name -> ethereum.eth.v1alpha1.ExecutionPayloadBid
|
||||
34, // 28: ethereum.eth.v1alpha1.BeaconStateGloas.historical_summaries:type_name -> ethereum.eth.v1alpha1.HistoricalSummary
|
||||
35, // 29: ethereum.eth.v1alpha1.BeaconStateGloas.pending_deposits:type_name -> ethereum.eth.v1alpha1.PendingDeposit
|
||||
36, // 30: ethereum.eth.v1alpha1.BeaconStateGloas.pending_partial_withdrawals:type_name -> ethereum.eth.v1alpha1.PendingPartialWithdrawal
|
||||
37, // 31: ethereum.eth.v1alpha1.BeaconStateGloas.pending_consolidations:type_name -> ethereum.eth.v1alpha1.PendingConsolidation
|
||||
20, // 32: ethereum.eth.v1alpha1.BeaconStateGloas.builders:type_name -> ethereum.eth.v1alpha1.Builder
|
||||
13, // 33: ethereum.eth.v1alpha1.BeaconStateGloas.builder_pending_payments:type_name -> ethereum.eth.v1alpha1.BuilderPendingPayment
|
||||
14, // 34: ethereum.eth.v1alpha1.BeaconStateGloas.builder_pending_withdrawals:type_name -> ethereum.eth.v1alpha1.BuilderPendingWithdrawal
|
||||
38, // 35: ethereum.eth.v1alpha1.BeaconStateGloas.payload_expected_withdrawals:type_name -> ethereum.engine.v1.Withdrawal
|
||||
35, // 28: ethereum.eth.v1alpha1.BeaconStateGloas.historical_summaries:type_name -> ethereum.eth.v1alpha1.HistoricalSummary
|
||||
36, // 29: ethereum.eth.v1alpha1.BeaconStateGloas.pending_deposits:type_name -> ethereum.eth.v1alpha1.PendingDeposit
|
||||
37, // 30: ethereum.eth.v1alpha1.BeaconStateGloas.pending_partial_withdrawals:type_name -> ethereum.eth.v1alpha1.PendingPartialWithdrawal
|
||||
38, // 31: ethereum.eth.v1alpha1.BeaconStateGloas.pending_consolidations:type_name -> ethereum.eth.v1alpha1.PendingConsolidation
|
||||
21, // 32: ethereum.eth.v1alpha1.BeaconStateGloas.builders:type_name -> ethereum.eth.v1alpha1.Builder
|
||||
14, // 33: ethereum.eth.v1alpha1.BeaconStateGloas.builder_pending_payments:type_name -> ethereum.eth.v1alpha1.BuilderPendingPayment
|
||||
15, // 34: ethereum.eth.v1alpha1.BeaconStateGloas.builder_pending_withdrawals:type_name -> ethereum.eth.v1alpha1.BuilderPendingWithdrawal
|
||||
39, // 35: ethereum.eth.v1alpha1.BeaconStateGloas.payload_expected_withdrawals:type_name -> ethereum.engine.v1.Withdrawal
|
||||
12, // 36: ethereum.eth.v1alpha1.BeaconStateGloas.ptc_window:type_name -> ethereum.eth.v1alpha1.PTCs
|
||||
14, // 37: ethereum.eth.v1alpha1.BuilderPendingPayment.withdrawal:type_name -> ethereum.eth.v1alpha1.BuilderPendingWithdrawal
|
||||
39, // 38: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope.payload:type_name -> ethereum.engine.v1.ExecutionPayloadDeneb
|
||||
40, // 39: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope.execution_requests:type_name -> ethereum.engine.v1.ExecutionRequests
|
||||
16, // 40: ethereum.eth.v1alpha1.SignedExecutionPayloadEnvelope.message:type_name -> ethereum.eth.v1alpha1.ExecutionPayloadEnvelope
|
||||
40, // 41: ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope.execution_requests:type_name -> ethereum.engine.v1.ExecutionRequests
|
||||
18, // 42: ethereum.eth.v1alpha1.SignedBlindedExecutionPayloadEnvelope.message:type_name -> ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope
|
||||
43, // [43:43] is the sub-list for method output_type
|
||||
43, // [43:43] is the sub-list for method input_type
|
||||
43, // [43:43] is the sub-list for extension type_name
|
||||
43, // [43:43] is the sub-list for extension extendee
|
||||
0, // [0:43] is the sub-list for field type_name
|
||||
8, // 37: ethereum.eth.v1alpha1.BeaconBlockContentsGloas.block:type_name -> ethereum.eth.v1alpha1.BeaconBlockGloas
|
||||
17, // 38: ethereum.eth.v1alpha1.BeaconBlockContentsGloas.execution_payload_envelope:type_name -> ethereum.eth.v1alpha1.ExecutionPayloadEnvelope
|
||||
15, // 39: ethereum.eth.v1alpha1.BuilderPendingPayment.withdrawal:type_name -> ethereum.eth.v1alpha1.BuilderPendingWithdrawal
|
||||
40, // 40: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope.payload:type_name -> ethereum.engine.v1.ExecutionPayloadDeneb
|
||||
41, // 41: ethereum.eth.v1alpha1.ExecutionPayloadEnvelope.execution_requests:type_name -> ethereum.engine.v1.ExecutionRequests
|
||||
17, // 42: ethereum.eth.v1alpha1.SignedExecutionPayloadEnvelope.message:type_name -> ethereum.eth.v1alpha1.ExecutionPayloadEnvelope
|
||||
41, // 43: ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope.execution_requests:type_name -> ethereum.engine.v1.ExecutionRequests
|
||||
19, // 44: ethereum.eth.v1alpha1.SignedBlindedExecutionPayloadEnvelope.message:type_name -> ethereum.eth.v1alpha1.BlindedExecutionPayloadEnvelope
|
||||
45, // [45:45] is the sub-list for method output_type
|
||||
45, // [45:45] is the sub-list for method input_type
|
||||
45, // [45:45] is the sub-list for extension type_name
|
||||
45, // [45:45] is the sub-list for extension extendee
|
||||
0, // [0:45] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proto_prysm_v1alpha1_gloas_proto_init() }
|
||||
@@ -2627,7 +2717,7 @@ func file_proto_prysm_v1alpha1_gloas_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proto_prysm_v1alpha1_gloas_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 21,
|
||||
NumMessages: 22,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -398,6 +398,22 @@ message PTCs {
|
||||
];
|
||||
}
|
||||
|
||||
// BeaconBlockContentsGloas bundles a Gloas beacon block with the execution
|
||||
// payload envelope and associated blob data. This is used for block production
|
||||
// when include_payload=true.
|
||||
message BeaconBlockContentsGloas {
|
||||
BeaconBlockGloas block = 1;
|
||||
ExecutionPayloadEnvelope execution_payload_envelope = 2;
|
||||
repeated bytes kzg_proofs = 3 [
|
||||
(ethereum.eth.ext.ssz_size) = "?,48",
|
||||
(ethereum.eth.ext.ssz_max) = "max_blob_commitments.size"
|
||||
];
|
||||
repeated bytes blobs = 4 [
|
||||
(ethereum.eth.ext.ssz_size) = "?,blob.size",
|
||||
(ethereum.eth.ext.ssz_max) = "max_blob_commitments.size"
|
||||
];
|
||||
}
|
||||
|
||||
// BuilderPendingPayment represents a pending payment to a builder.
|
||||
//
|
||||
// Spec:
|
||||
|
||||
@@ -3206,6 +3206,254 @@ func (p *PTCs) HashTreeRootWith(hh *ssz.Hasher) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalSSZ ssz marshals the BeaconBlockContentsGloas object
|
||||
func (b *BeaconBlockContentsGloas) MarshalSSZ() ([]byte, error) {
|
||||
return ssz.MarshalSSZ(b)
|
||||
}
|
||||
|
||||
// MarshalSSZTo ssz marshals the BeaconBlockContentsGloas object to a target array
|
||||
func (b *BeaconBlockContentsGloas) MarshalSSZTo(buf []byte) (dst []byte, err error) {
|
||||
dst = buf
|
||||
offset := int(16)
|
||||
|
||||
// Offset (0) 'Block'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
if b.Block == nil {
|
||||
b.Block = new(BeaconBlockGloas)
|
||||
}
|
||||
offset += b.Block.SizeSSZ()
|
||||
|
||||
// Offset (1) 'ExecutionPayloadEnvelope'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
if b.ExecutionPayloadEnvelope == nil {
|
||||
b.ExecutionPayloadEnvelope = new(ExecutionPayloadEnvelope)
|
||||
}
|
||||
offset += b.ExecutionPayloadEnvelope.SizeSSZ()
|
||||
|
||||
// Offset (2) 'KzgProofs'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
offset += len(b.KzgProofs) * 48
|
||||
|
||||
// Offset (3) 'Blobs'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
offset += len(b.Blobs) * 131072
|
||||
|
||||
// Field (0) 'Block'
|
||||
if dst, err = b.Block.MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Field (1) 'ExecutionPayloadEnvelope'
|
||||
if dst, err = b.ExecutionPayloadEnvelope.MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Field (2) 'KzgProofs'
|
||||
if size := len(b.KzgProofs); size > 4096 {
|
||||
err = ssz.ErrListTooBigFn("--.KzgProofs", size, 4096)
|
||||
return
|
||||
}
|
||||
for ii := 0; ii < len(b.KzgProofs); ii++ {
|
||||
if size := len(b.KzgProofs[ii]); size != 48 {
|
||||
err = ssz.ErrBytesLengthFn("--.KzgProofs[ii]", size, 48)
|
||||
return
|
||||
}
|
||||
dst = append(dst, b.KzgProofs[ii]...)
|
||||
}
|
||||
|
||||
// Field (3) 'Blobs'
|
||||
if size := len(b.Blobs); size > 4096 {
|
||||
err = ssz.ErrListTooBigFn("--.Blobs", size, 4096)
|
||||
return
|
||||
}
|
||||
for ii := 0; ii < len(b.Blobs); ii++ {
|
||||
if size := len(b.Blobs[ii]); size != 131072 {
|
||||
err = ssz.ErrBytesLengthFn("--.Blobs[ii]", size, 131072)
|
||||
return
|
||||
}
|
||||
dst = append(dst, b.Blobs[ii]...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalSSZ ssz unmarshals the BeaconBlockContentsGloas object
|
||||
func (b *BeaconBlockContentsGloas) UnmarshalSSZ(buf []byte) error {
|
||||
var err error
|
||||
size := uint64(len(buf))
|
||||
if size < 16 {
|
||||
return ssz.ErrSize
|
||||
}
|
||||
|
||||
tail := buf
|
||||
var o0, o1, o2, o3 uint64
|
||||
|
||||
// Offset (0) 'Block'
|
||||
if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
if o0 != 16 {
|
||||
return ssz.ErrInvalidVariableOffset
|
||||
}
|
||||
|
||||
// Offset (1) 'ExecutionPayloadEnvelope'
|
||||
if o1 = ssz.ReadOffset(buf[4:8]); o1 > size || o0 > o1 {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
// Offset (2) 'KzgProofs'
|
||||
if o2 = ssz.ReadOffset(buf[8:12]); o2 > size || o1 > o2 {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
// Offset (3) 'Blobs'
|
||||
if o3 = ssz.ReadOffset(buf[12:16]); o3 > size || o2 > o3 {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
// Field (0) 'Block'
|
||||
{
|
||||
buf = tail[o0:o1]
|
||||
if b.Block == nil {
|
||||
b.Block = new(BeaconBlockGloas)
|
||||
}
|
||||
if err = b.Block.UnmarshalSSZ(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Field (1) 'ExecutionPayloadEnvelope'
|
||||
{
|
||||
buf = tail[o1:o2]
|
||||
if b.ExecutionPayloadEnvelope == nil {
|
||||
b.ExecutionPayloadEnvelope = new(ExecutionPayloadEnvelope)
|
||||
}
|
||||
if err = b.ExecutionPayloadEnvelope.UnmarshalSSZ(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Field (2) 'KzgProofs'
|
||||
{
|
||||
buf = tail[o2:o3]
|
||||
num, err := ssz.DivideInt2(len(buf), 48, 4096)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.KzgProofs = make([][]byte, num)
|
||||
for ii := 0; ii < num; ii++ {
|
||||
if cap(b.KzgProofs[ii]) == 0 {
|
||||
b.KzgProofs[ii] = make([]byte, 0, len(buf[ii*48:(ii+1)*48]))
|
||||
}
|
||||
b.KzgProofs[ii] = append(b.KzgProofs[ii], buf[ii*48:(ii+1)*48]...)
|
||||
}
|
||||
}
|
||||
|
||||
// Field (3) 'Blobs'
|
||||
{
|
||||
buf = tail[o3:]
|
||||
num, err := ssz.DivideInt2(len(buf), 131072, 4096)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.Blobs = make([][]byte, num)
|
||||
for ii := 0; ii < num; ii++ {
|
||||
if cap(b.Blobs[ii]) == 0 {
|
||||
b.Blobs[ii] = make([]byte, 0, len(buf[ii*131072:(ii+1)*131072]))
|
||||
}
|
||||
b.Blobs[ii] = append(b.Blobs[ii], buf[ii*131072:(ii+1)*131072]...)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SizeSSZ returns the ssz encoded size in bytes for the BeaconBlockContentsGloas object
|
||||
func (b *BeaconBlockContentsGloas) SizeSSZ() (size int) {
|
||||
size = 16
|
||||
|
||||
// Field (0) 'Block'
|
||||
if b.Block == nil {
|
||||
b.Block = new(BeaconBlockGloas)
|
||||
}
|
||||
size += b.Block.SizeSSZ()
|
||||
|
||||
// Field (1) 'ExecutionPayloadEnvelope'
|
||||
if b.ExecutionPayloadEnvelope == nil {
|
||||
b.ExecutionPayloadEnvelope = new(ExecutionPayloadEnvelope)
|
||||
}
|
||||
size += b.ExecutionPayloadEnvelope.SizeSSZ()
|
||||
|
||||
// Field (2) 'KzgProofs'
|
||||
size += len(b.KzgProofs) * 48
|
||||
|
||||
// Field (3) 'Blobs'
|
||||
size += len(b.Blobs) * 131072
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// HashTreeRoot ssz hashes the BeaconBlockContentsGloas object
|
||||
func (b *BeaconBlockContentsGloas) HashTreeRoot() ([32]byte, error) {
|
||||
return ssz.HashWithDefaultHasher(b)
|
||||
}
|
||||
|
||||
// HashTreeRootWith ssz hashes the BeaconBlockContentsGloas object with a hasher
|
||||
func (b *BeaconBlockContentsGloas) HashTreeRootWith(hh *ssz.Hasher) (err error) {
|
||||
indx := hh.Index()
|
||||
|
||||
// Field (0) 'Block'
|
||||
if err = b.Block.HashTreeRootWith(hh); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Field (1) 'ExecutionPayloadEnvelope'
|
||||
if err = b.ExecutionPayloadEnvelope.HashTreeRootWith(hh); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Field (2) 'KzgProofs'
|
||||
{
|
||||
if size := len(b.KzgProofs); size > 4096 {
|
||||
err = ssz.ErrListTooBigFn("--.KzgProofs", size, 4096)
|
||||
return
|
||||
}
|
||||
subIndx := hh.Index()
|
||||
for _, i := range b.KzgProofs {
|
||||
if len(i) != 48 {
|
||||
err = ssz.ErrBytesLength
|
||||
return
|
||||
}
|
||||
hh.PutBytes(i)
|
||||
}
|
||||
|
||||
numItems := uint64(len(b.KzgProofs))
|
||||
hh.MerkleizeWithMixin(subIndx, numItems, 4096)
|
||||
}
|
||||
|
||||
// Field (3) 'Blobs'
|
||||
{
|
||||
if size := len(b.Blobs); size > 4096 {
|
||||
err = ssz.ErrListTooBigFn("--.Blobs", size, 4096)
|
||||
return
|
||||
}
|
||||
subIndx := hh.Index()
|
||||
for _, i := range b.Blobs {
|
||||
if len(i) != 131072 {
|
||||
err = ssz.ErrBytesLength
|
||||
return
|
||||
}
|
||||
hh.PutBytes(i)
|
||||
}
|
||||
|
||||
numItems := uint64(len(b.Blobs))
|
||||
hh.MerkleizeWithMixin(subIndx, numItems, 4096)
|
||||
}
|
||||
|
||||
hh.Merkleize(indx)
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalSSZ ssz marshals the BuilderPendingPayment object
|
||||
func (b *BuilderPendingPayment) MarshalSSZ() ([]byte, error) {
|
||||
return ssz.MarshalSSZ(b)
|
||||
|
||||
1789
proto/prysm/v1alpha1/validator.pb.go
generated
1789
proto/prysm/v1alpha1/validator.pb.go
generated
File diff suppressed because it is too large
Load Diff
@@ -961,6 +961,12 @@ message BlockRequest {
|
||||
// Percentage multiplier to apply to the builder's payload value when choosing
|
||||
// between a builder payload header and payload from the paired execution node
|
||||
google.protobuf.UInt64Value builder_boost_factor = 5;
|
||||
|
||||
// When true, eagerly compute the post-payload state root in the envelope
|
||||
// during block production. Used by the V4 produce-block endpoint when
|
||||
// include_payload=true so the envelope is immediately available with a
|
||||
// populated state root.
|
||||
bool eager_payload_state_root = 6;
|
||||
}
|
||||
|
||||
message ProposeResponse {
|
||||
|
||||
@@ -990,7 +990,7 @@
|
||||
- name: compute_new_state_root#phase0
|
||||
sources:
|
||||
- file: beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go
|
||||
search: func (vs *Server) computeStateRoot(
|
||||
search: func (vs *Server) computePostBlockStateAndRoot(
|
||||
spec: |
|
||||
<spec fn="compute_new_state_root" fork="phase0" hash="ad3c03b7">
|
||||
def compute_new_state_root(state: BeaconState, block: BeaconBlock) -> Root:
|
||||
|
||||
@@ -89,6 +89,7 @@ go_test(
|
||||
"domain_data_test.go",
|
||||
"doppelganger_test.go",
|
||||
"duties_test.go",
|
||||
"execution_payload_envelope_test.go",
|
||||
"genesis_test.go",
|
||||
"get_beacon_block_test.go",
|
||||
"index_test.go",
|
||||
|
||||
@@ -1,28 +1,51 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"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"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// TODO: Implement Gloas beacon API client methods.
|
||||
|
||||
// getExecutionPayloadEnvelope retrieves the execution payload envelope for the given slot.
|
||||
func (c *beaconApiValidatorClient) getExecutionPayloadEnvelope(
|
||||
ctx context.Context,
|
||||
slot primitives.Slot,
|
||||
) (*ethpb.ExecutionPayloadEnvelope, error) {
|
||||
return nil, errors.New("getExecutionPayloadEnvelope not yet implemented")
|
||||
endpoint := fmt.Sprintf("/eth/v1/validator/execution_payload_envelope/%d", slot)
|
||||
var resp structs.GetValidatorExecutionPayloadEnvelopeResponse
|
||||
if err := c.handler.Get(ctx, endpoint, &resp); err != nil {
|
||||
return nil, errors.Wrap(err, "could not get execution payload envelope")
|
||||
}
|
||||
if resp.Data == nil {
|
||||
return nil, errors.New("execution payload envelope data is nil")
|
||||
}
|
||||
envelope, err := resp.Data.ToConsensus()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert execution payload envelope to consensus")
|
||||
}
|
||||
return envelope, nil
|
||||
}
|
||||
|
||||
// publishExecutionPayloadEnvelope broadcasts a signed execution payload envelope.
|
||||
func (c *beaconApiValidatorClient) publishExecutionPayloadEnvelope(
|
||||
ctx context.Context,
|
||||
envelope *ethpb.SignedExecutionPayloadEnvelope,
|
||||
) (*empty.Empty, error) {
|
||||
return nil, errors.New("publishExecutionPayloadEnvelope not yet implemented")
|
||||
jsonEnvelope, err := structs.SignedExecutionPayloadEnvelopeFromConsensus(envelope)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert envelope to JSON")
|
||||
}
|
||||
body, err := json.Marshal(jsonEnvelope)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not marshal envelope")
|
||||
}
|
||||
if err := c.handler.Post(ctx, "/eth/v1/beacon/execution_payload_envelope", nil, bytes.NewBuffer(body), nil); err != nil {
|
||||
return nil, errors.Wrap(err, "could not publish execution payload envelope")
|
||||
}
|
||||
return &empty.Empty{}, nil
|
||||
}
|
||||
|
||||
170
validator/client/beacon-api/execution_payload_envelope_test.go
Normal file
170
validator/client/beacon-api/execution_payload_envelope_test.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package beacon_api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/validator/client/beacon-api/mock"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func testProtoEnvelope() *ethpb.ExecutionPayloadEnvelope {
|
||||
return ðpb.ExecutionPayloadEnvelope{
|
||||
Payload: &enginev1.ExecutionPayloadDeneb{
|
||||
ParentHash: bytesutil.PadTo([]byte("parent"), 32),
|
||||
FeeRecipient: bytesutil.PadTo([]byte("fee"), 20),
|
||||
StateRoot: bytesutil.PadTo([]byte("state"), 32),
|
||||
ReceiptsRoot: bytesutil.PadTo([]byte("receipts"), 32),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: bytesutil.PadTo([]byte("randao"), 32),
|
||||
BaseFeePerGas: bytesutil.PadTo([]byte{1}, 32),
|
||||
BlockHash: bytesutil.PadTo([]byte("blockhash"), 32),
|
||||
Transactions: [][]byte{},
|
||||
Withdrawals: []*enginev1.Withdrawal{},
|
||||
},
|
||||
ExecutionRequests: &enginev1.ExecutionRequests{},
|
||||
BuilderIndex: primitives.BuilderIndex(42),
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("beacon-root"), 32),
|
||||
Slot: primitives.Slot(100),
|
||||
StateRoot: bytesutil.PadTo([]byte("envelope-state"), 32),
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetExecutionPayloadEnvelope_Valid(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
envelope := testProtoEnvelope()
|
||||
jsonEnvelope, err := structs.ExecutionPayloadEnvelopeFromConsensus(envelope)
|
||||
require.NoError(t, err)
|
||||
|
||||
handler := mock.NewMockJsonRestHandler(ctrl)
|
||||
handler.EXPECT().Get(
|
||||
gomock.Any(),
|
||||
"/eth/v1/validator/execution_payload_envelope/100",
|
||||
gomock.Any(),
|
||||
).SetArg(
|
||||
2,
|
||||
structs.GetValidatorExecutionPayloadEnvelopeResponse{
|
||||
Version: "gloas",
|
||||
Data: jsonEnvelope,
|
||||
},
|
||||
).Return(nil)
|
||||
|
||||
client := &beaconApiValidatorClient{handler: handler}
|
||||
resp, err := client.getExecutionPayloadEnvelope(t.Context(), 100)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
assert.Equal(t, primitives.BuilderIndex(42), resp.BuilderIndex)
|
||||
assert.Equal(t, primitives.Slot(100), resp.Slot)
|
||||
assert.DeepEqual(t, envelope.BeaconBlockRoot, resp.BeaconBlockRoot)
|
||||
}
|
||||
|
||||
func TestGetExecutionPayloadEnvelope_Error(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
handler := mock.NewMockJsonRestHandler(ctrl)
|
||||
handler.EXPECT().Get(
|
||||
gomock.Any(), gomock.Any(), gomock.Any(),
|
||||
).Return(errors.New("not found"))
|
||||
|
||||
client := &beaconApiValidatorClient{handler: handler}
|
||||
_, err := client.getExecutionPayloadEnvelope(t.Context(), 999)
|
||||
assert.ErrorContains(t, "not found", err)
|
||||
}
|
||||
|
||||
func TestGetExecutionPayloadEnvelope_NilData(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
handler := mock.NewMockJsonRestHandler(ctrl)
|
||||
handler.EXPECT().Get(
|
||||
gomock.Any(), gomock.Any(), gomock.Any(),
|
||||
).SetArg(
|
||||
2,
|
||||
structs.GetValidatorExecutionPayloadEnvelopeResponse{
|
||||
Version: "gloas",
|
||||
Data: nil,
|
||||
},
|
||||
).Return(nil)
|
||||
|
||||
client := &beaconApiValidatorClient{handler: handler}
|
||||
_, err := client.getExecutionPayloadEnvelope(t.Context(), 100)
|
||||
assert.ErrorContains(t, "execution payload envelope data is nil", err)
|
||||
}
|
||||
|
||||
func TestPublishExecutionPayloadEnvelope_Valid(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
envelope := testProtoEnvelope()
|
||||
signed := ðpb.SignedExecutionPayloadEnvelope{
|
||||
Message: envelope,
|
||||
Signature: bytesutil.PadTo([]byte("sig"), 96),
|
||||
}
|
||||
|
||||
jsonEnvelope, err := structs.SignedExecutionPayloadEnvelopeFromConsensus(signed)
|
||||
require.NoError(t, err)
|
||||
expectedBody, err := json.Marshal(jsonEnvelope)
|
||||
require.NoError(t, err)
|
||||
|
||||
handler := mock.NewMockJsonRestHandler(ctrl)
|
||||
handler.EXPECT().Post(
|
||||
gomock.Any(),
|
||||
"/eth/v1/beacon/execution_payload_envelope",
|
||||
nil,
|
||||
bytes.NewBuffer(expectedBody),
|
||||
nil,
|
||||
).Return(nil)
|
||||
|
||||
client := &beaconApiValidatorClient{handler: handler}
|
||||
resp, err := client.publishExecutionPayloadEnvelope(t.Context(), signed)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
}
|
||||
|
||||
func TestPublishExecutionPayloadEnvelope_Error(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
envelope := testProtoEnvelope()
|
||||
signed := ðpb.SignedExecutionPayloadEnvelope{
|
||||
Message: envelope,
|
||||
Signature: bytesutil.PadTo([]byte("sig"), 96),
|
||||
}
|
||||
|
||||
handler := mock.NewMockJsonRestHandler(ctrl)
|
||||
handler.EXPECT().Post(
|
||||
gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(),
|
||||
).Return(errors.New("server error"))
|
||||
|
||||
client := &beaconApiValidatorClient{handler: handler}
|
||||
_, err := client.publishExecutionPayloadEnvelope(t.Context(), signed)
|
||||
assert.ErrorContains(t, "server error", err)
|
||||
}
|
||||
|
||||
func TestEnvelopeRoundTrip(t *testing.T) {
|
||||
envelope := testProtoEnvelope()
|
||||
jsonEnvelope, err := structs.ExecutionPayloadEnvelopeFromConsensus(envelope)
|
||||
require.NoError(t, err)
|
||||
|
||||
roundTripped, err := jsonEnvelope.ToConsensus()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, envelope.BuilderIndex, roundTripped.BuilderIndex)
|
||||
assert.Equal(t, envelope.Slot, roundTripped.Slot)
|
||||
assert.DeepEqual(t, envelope.BeaconBlockRoot, roundTripped.BeaconBlockRoot)
|
||||
assert.DeepEqual(t, envelope.StateRoot, roundTripped.StateRoot)
|
||||
assert.Equal(t, hexutil.Encode(envelope.Payload.BlockHash), hexutil.Encode(roundTripped.Payload.BlockHash))
|
||||
}
|
||||
@@ -12,9 +12,11 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/api"
|
||||
"github.com/OffchainLabs/prysm/v7/api/apiutil"
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -25,6 +27,11 @@ func (c *beaconApiValidatorClient) beaconBlock(ctx context.Context, slot primiti
|
||||
if len(graffiti) > 0 {
|
||||
queryParams.Add("graffiti", hexutil.Encode(graffiti))
|
||||
}
|
||||
|
||||
if slots.ToEpoch(slot) >= params.BeaconConfig().GloasForkEpoch {
|
||||
return c.beaconBlockV4(ctx, slot, queryParams)
|
||||
}
|
||||
|
||||
queryUrl := apiutil.BuildURL(fmt.Sprintf("/eth/v3/validator/blocks/%d", slot), queryParams)
|
||||
data, header, err := c.handler.GetSSZ(ctx, queryUrl)
|
||||
if err != nil {
|
||||
@@ -55,6 +62,58 @@ func (c *beaconApiValidatorClient) beaconBlock(ctx context.Context, slot primiti
|
||||
}
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) beaconBlockV4(ctx context.Context, slot primitives.Slot, queryParams neturl.Values) (*ethpb.GenericBeaconBlock, error) {
|
||||
queryUrl := apiutil.BuildURL(fmt.Sprintf("/eth/v4/validator/blocks/%d", slot), queryParams)
|
||||
data, header, err := c.handler.GetSSZ(ctx, queryUrl)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get v4 beacon block")
|
||||
}
|
||||
|
||||
if strings.Contains(header.Get("Content-Type"), api.OctetStreamMediaType) {
|
||||
payloadIncluded := header.Get(api.ExecutionPayloadIncludedHeader) == "true"
|
||||
if payloadIncluded {
|
||||
contents := ðpb.BeaconBlockContentsGloas{}
|
||||
if err := contents.UnmarshalSSZ(data); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal gloas block contents SSZ")
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Gloas{Gloas: contents.Block}}, nil
|
||||
}
|
||||
block := ðpb.BeaconBlockGloas{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to unmarshal gloas block SSZ")
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Gloas{Gloas: block}}, nil
|
||||
}
|
||||
|
||||
resp := structs.ProduceBlockV4Response{}
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to decode v4 response body for %s", queryUrl)
|
||||
}
|
||||
if resp.ExecutionPayloadIncluded {
|
||||
contents := &structs.BlockContentsGloas{}
|
||||
if err := json.Unmarshal(resp.Data, contents); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to decode gloas block contents")
|
||||
}
|
||||
if contents.Block == nil {
|
||||
return nil, errors.New("gloas block contents has nil block")
|
||||
}
|
||||
blk, err := contents.Block.ToGeneric()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert gloas block contents to generic")
|
||||
}
|
||||
return blk, nil
|
||||
}
|
||||
block := &structs.BeaconBlockGloas{}
|
||||
if err := json.Unmarshal(resp.Data, block); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to decode gloas block")
|
||||
}
|
||||
blk, err := block.ToGeneric()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not convert gloas block to generic")
|
||||
}
|
||||
return blk, nil
|
||||
}
|
||||
|
||||
// sszBlockCodec defines SSZ unmarshalers for a fork's block and blinded block types.
|
||||
type sszBlockCodec struct {
|
||||
unmarshalBlock func([]byte) (*ethpb.GenericBeaconBlock, error)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api"
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
@@ -1346,3 +1347,198 @@ func TestGetBeaconBlock_BlindedElectraValid(t *testing.T) {
|
||||
|
||||
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
|
||||
}
|
||||
|
||||
func setupGloasConfig(t *testing.T) {
|
||||
t.Helper()
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
}
|
||||
|
||||
func TestGetBeaconBlock_GloasValid_JSON_WithPayload(t *testing.T) {
|
||||
setupGloasConfig(t)
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
proto := testhelpers.GenerateProtoGloasBeaconBlock()
|
||||
block := testhelpers.GenerateJsonGloasBeaconBlock()
|
||||
|
||||
blockContents := &structs.BlockContentsGloas{
|
||||
Block: block,
|
||||
ExecutionPayloadEnvelope: nil,
|
||||
KzgProofs: []string{},
|
||||
Blobs: []string{},
|
||||
}
|
||||
dataBytes, err := json.Marshal(blockContents)
|
||||
require.NoError(t, err)
|
||||
|
||||
const slot = primitives.Slot(1)
|
||||
randaoReveal := []byte{2}
|
||||
graffiti := []byte{3}
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
b, err := json.Marshal(structs.ProduceBlockV4Response{
|
||||
Version: "gloas",
|
||||
ConsensusBlockValue: "0",
|
||||
ExecutionPayloadIncluded: true,
|
||||
Data: dataBytes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
handler := mock.NewMockHandler(ctrl)
|
||||
handler.EXPECT().GetSSZ(
|
||||
gomock.Any(),
|
||||
fmt.Sprintf("/eth/v4/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)),
|
||||
).Return(
|
||||
b,
|
||||
http.Header{"Content-Type": []string{"application/json"}},
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{handler: handler}
|
||||
beaconBlock, err := validatorClient.beaconBlock(ctx, slot, randaoReveal, graffiti)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedBeaconBlock := ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Gloas{
|
||||
Gloas: proto,
|
||||
},
|
||||
}
|
||||
|
||||
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
|
||||
}
|
||||
|
||||
func TestGetBeaconBlock_GloasValid_JSON_WithoutPayload(t *testing.T) {
|
||||
setupGloasConfig(t)
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
proto := testhelpers.GenerateProtoGloasBeaconBlock()
|
||||
block := testhelpers.GenerateJsonGloasBeaconBlock()
|
||||
dataBytes, err := json.Marshal(block)
|
||||
require.NoError(t, err)
|
||||
|
||||
const slot = primitives.Slot(1)
|
||||
randaoReveal := []byte{2}
|
||||
graffiti := []byte{3}
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
b, err := json.Marshal(structs.ProduceBlockV4Response{
|
||||
Version: "gloas",
|
||||
ConsensusBlockValue: "0",
|
||||
ExecutionPayloadIncluded: false,
|
||||
Data: dataBytes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
handler := mock.NewMockHandler(ctrl)
|
||||
handler.EXPECT().GetSSZ(
|
||||
gomock.Any(),
|
||||
fmt.Sprintf("/eth/v4/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)),
|
||||
).Return(
|
||||
b,
|
||||
http.Header{"Content-Type": []string{"application/json"}},
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{handler: handler}
|
||||
beaconBlock, err := validatorClient.beaconBlock(ctx, slot, randaoReveal, graffiti)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedBeaconBlock := ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Gloas{
|
||||
Gloas: proto,
|
||||
},
|
||||
}
|
||||
|
||||
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
|
||||
}
|
||||
|
||||
func TestGetBeaconBlock_GloasValid_SSZ_WithPayload(t *testing.T) {
|
||||
setupGloasConfig(t)
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
proto := testhelpers.GenerateProtoGloasBeaconBlock()
|
||||
contents := ðpb.BeaconBlockContentsGloas{
|
||||
Block: proto,
|
||||
ExecutionPayloadEnvelope: testhelpers.GenerateProtoExecutionPayloadEnvelope(),
|
||||
}
|
||||
sszBytes, err := contents.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
const slot = primitives.Slot(1)
|
||||
randaoReveal := []byte{2}
|
||||
graffiti := []byte{3}
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
handler := mock.NewMockHandler(ctrl)
|
||||
handler.EXPECT().GetSSZ(
|
||||
gomock.Any(),
|
||||
fmt.Sprintf("/eth/v4/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)),
|
||||
).Return(
|
||||
sszBytes,
|
||||
http.Header{
|
||||
"Content-Type": []string{api.OctetStreamMediaType},
|
||||
api.VersionHeader: []string{"gloas"},
|
||||
api.ExecutionPayloadIncludedHeader: []string{"true"},
|
||||
},
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{handler: handler}
|
||||
beaconBlock, err := validatorClient.beaconBlock(ctx, slot, randaoReveal, graffiti)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedBeaconBlock := ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Gloas{
|
||||
Gloas: proto,
|
||||
},
|
||||
}
|
||||
|
||||
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
|
||||
}
|
||||
|
||||
func TestGetBeaconBlock_GloasValid_SSZ_WithoutPayload(t *testing.T) {
|
||||
setupGloasConfig(t)
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
proto := testhelpers.GenerateProtoGloasBeaconBlock()
|
||||
sszBytes, err := proto.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
|
||||
const slot = primitives.Slot(1)
|
||||
randaoReveal := []byte{2}
|
||||
graffiti := []byte{3}
|
||||
|
||||
ctx := t.Context()
|
||||
|
||||
handler := mock.NewMockHandler(ctrl)
|
||||
handler.EXPECT().GetSSZ(
|
||||
gomock.Any(),
|
||||
fmt.Sprintf("/eth/v4/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)),
|
||||
).Return(
|
||||
sszBytes,
|
||||
http.Header{
|
||||
"Content-Type": []string{api.OctetStreamMediaType},
|
||||
api.VersionHeader: []string{"gloas"},
|
||||
api.ExecutionPayloadIncludedHeader: []string{"false"},
|
||||
},
|
||||
nil,
|
||||
).Times(1)
|
||||
|
||||
validatorClient := &beaconApiValidatorClient{handler: handler}
|
||||
beaconBlock, err := validatorClient.beaconBlock(ctx, slot, randaoReveal, graffiti)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedBeaconBlock := ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Gloas{
|
||||
Gloas: proto,
|
||||
},
|
||||
}
|
||||
|
||||
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
|
||||
}
|
||||
|
||||
@@ -144,6 +144,14 @@ func (c *beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *e
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
case *ethpb.GenericSignedBeaconBlock_Gloas:
|
||||
res, err = buildBlockResult("gloas", false, blockType.Gloas, blockType.Gloas.Block, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockGloasFromConsensus(blockType.Gloas)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert gloas beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported block type %T", in.Block)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ go_library(
|
||||
"deneb_beacon_block_test_helpers.go",
|
||||
"electra_beacon_block_test_helpers.go",
|
||||
"fulu_beacon_block_test_helpers.go",
|
||||
"gloas_beacon_block_test_helpers.go",
|
||||
"phase0_beacon_block_test_helpers.go",
|
||||
"test_helpers.go",
|
||||
],
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
package test_helpers
|
||||
|
||||
import (
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
func GenerateProtoGloasBeaconBlock() *ethpb.BeaconBlockGloas {
|
||||
return ðpb.BeaconBlockGloas{
|
||||
Slot: 1,
|
||||
ProposerIndex: 2,
|
||||
ParentRoot: FillByteSlice(32, 3),
|
||||
StateRoot: FillByteSlice(32, 4),
|
||||
Body: ðpb.BeaconBlockBodyGloas{
|
||||
RandaoReveal: FillByteSlice(96, 5),
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: FillByteSlice(32, 6),
|
||||
DepositCount: 7,
|
||||
BlockHash: FillByteSlice(32, 8),
|
||||
},
|
||||
Graffiti: FillByteSlice(32, 9),
|
||||
ProposerSlashings: []*ethpb.ProposerSlashing{
|
||||
{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 10,
|
||||
ProposerIndex: 11,
|
||||
ParentRoot: FillByteSlice(32, 12),
|
||||
StateRoot: FillByteSlice(32, 13),
|
||||
BodyRoot: FillByteSlice(32, 14),
|
||||
},
|
||||
Signature: FillByteSlice(96, 15),
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 16,
|
||||
ProposerIndex: 17,
|
||||
ParentRoot: FillByteSlice(32, 18),
|
||||
StateRoot: FillByteSlice(32, 19),
|
||||
BodyRoot: FillByteSlice(32, 20),
|
||||
},
|
||||
Signature: FillByteSlice(96, 21),
|
||||
},
|
||||
},
|
||||
},
|
||||
AttesterSlashings: []*ethpb.AttesterSlashingElectra{},
|
||||
Attestations: []*ethpb.AttestationElectra{},
|
||||
Deposits: []*ethpb.Deposit{},
|
||||
VoluntaryExits: []*ethpb.SignedVoluntaryExit{},
|
||||
SyncAggregate: ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: FillByteSlice(64, 100),
|
||||
SyncCommitteeSignature: FillByteSlice(96, 101),
|
||||
},
|
||||
BlsToExecutionChanges: []*ethpb.SignedBLSToExecutionChange{},
|
||||
SignedExecutionPayloadBid: ðpb.SignedExecutionPayloadBid{
|
||||
Message: ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: FillByteSlice(32, 110),
|
||||
ParentBlockRoot: FillByteSlice(32, 111),
|
||||
BlockHash: FillByteSlice(32, 112),
|
||||
PrevRandao: FillByteSlice(32, 113),
|
||||
FeeRecipient: FillByteSlice(20, 114),
|
||||
GasLimit: 120,
|
||||
BuilderIndex: 121,
|
||||
Slot: 1,
|
||||
Value: 123,
|
||||
ExecutionPayment: 124,
|
||||
BlobKzgCommitments: [][]byte{},
|
||||
},
|
||||
Signature: FillByteSlice(96, 130),
|
||||
},
|
||||
PayloadAttestations: []*ethpb.PayloadAttestation{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateJsonGloasBeaconBlock() *structs.BeaconBlockGloas {
|
||||
return &structs.BeaconBlockGloas{
|
||||
Slot: "1",
|
||||
ProposerIndex: "2",
|
||||
ParentRoot: hexutil.Encode(FillByteSlice(32, 3)),
|
||||
StateRoot: hexutil.Encode(FillByteSlice(32, 4)),
|
||||
Body: &structs.BeaconBlockBodyGloas{
|
||||
RandaoReveal: hexutil.Encode(FillByteSlice(96, 5)),
|
||||
Eth1Data: &structs.Eth1Data{
|
||||
DepositRoot: hexutil.Encode(FillByteSlice(32, 6)),
|
||||
DepositCount: "7",
|
||||
BlockHash: hexutil.Encode(FillByteSlice(32, 8)),
|
||||
},
|
||||
Graffiti: hexutil.Encode(FillByteSlice(32, 9)),
|
||||
ProposerSlashings: []*structs.ProposerSlashing{
|
||||
{
|
||||
SignedHeader1: &structs.SignedBeaconBlockHeader{
|
||||
Message: &structs.BeaconBlockHeader{
|
||||
Slot: "10",
|
||||
ProposerIndex: "11",
|
||||
ParentRoot: hexutil.Encode(FillByteSlice(32, 12)),
|
||||
StateRoot: hexutil.Encode(FillByteSlice(32, 13)),
|
||||
BodyRoot: hexutil.Encode(FillByteSlice(32, 14)),
|
||||
},
|
||||
Signature: hexutil.Encode(FillByteSlice(96, 15)),
|
||||
},
|
||||
SignedHeader2: &structs.SignedBeaconBlockHeader{
|
||||
Message: &structs.BeaconBlockHeader{
|
||||
Slot: "16",
|
||||
ProposerIndex: "17",
|
||||
ParentRoot: hexutil.Encode(FillByteSlice(32, 18)),
|
||||
StateRoot: hexutil.Encode(FillByteSlice(32, 19)),
|
||||
BodyRoot: hexutil.Encode(FillByteSlice(32, 20)),
|
||||
},
|
||||
Signature: hexutil.Encode(FillByteSlice(96, 21)),
|
||||
},
|
||||
},
|
||||
},
|
||||
AttesterSlashings: []*structs.AttesterSlashingElectra{},
|
||||
Attestations: []*structs.AttestationElectra{},
|
||||
Deposits: []*structs.Deposit{},
|
||||
VoluntaryExits: []*structs.SignedVoluntaryExit{},
|
||||
SyncAggregate: &structs.SyncAggregate{
|
||||
SyncCommitteeBits: hexutil.Encode(FillByteSlice(64, 100)),
|
||||
SyncCommitteeSignature: hexutil.Encode(FillByteSlice(96, 101)),
|
||||
},
|
||||
BLSToExecutionChanges: []*structs.SignedBLSToExecutionChange{},
|
||||
SignedExecutionPayloadBid: &structs.SignedExecutionPayloadBid{
|
||||
Message: &structs.ExecutionPayloadBid{
|
||||
ParentBlockHash: hexutil.Encode(FillByteSlice(32, 110)),
|
||||
ParentBlockRoot: hexutil.Encode(FillByteSlice(32, 111)),
|
||||
BlockHash: hexutil.Encode(FillByteSlice(32, 112)),
|
||||
PrevRandao: hexutil.Encode(FillByteSlice(32, 113)),
|
||||
FeeRecipient: hexutil.Encode(FillByteSlice(20, 114)),
|
||||
GasLimit: "120",
|
||||
BuilderIndex: "121",
|
||||
Slot: "1",
|
||||
Value: "123",
|
||||
ExecutionPayment: "124",
|
||||
BlobKzgCommitments: []string{},
|
||||
},
|
||||
Signature: hexutil.Encode(FillByteSlice(96, 130)),
|
||||
},
|
||||
PayloadAttestations: []*structs.PayloadAttestation{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateProtoExecutionPayloadEnvelope() *ethpb.ExecutionPayloadEnvelope {
|
||||
return ðpb.ExecutionPayloadEnvelope{
|
||||
Payload: &enginev1.ExecutionPayloadDeneb{
|
||||
ParentHash: FillByteSlice(32, 200),
|
||||
FeeRecipient: FillByteSlice(20, 201),
|
||||
StateRoot: FillByteSlice(32, 202),
|
||||
ReceiptsRoot: FillByteSlice(32, 203),
|
||||
LogsBloom: FillByteSlice(256, 204),
|
||||
PrevRandao: FillByteSlice(32, 205),
|
||||
BaseFeePerGas: FillByteSlice(32, 206),
|
||||
BlockHash: FillByteSlice(32, 207),
|
||||
ExtraData: make([]byte, 0),
|
||||
},
|
||||
ExecutionRequests: &enginev1.ExecutionRequests{},
|
||||
BuilderIndex: 121,
|
||||
BeaconBlockRoot: FillByteSlice(32, 210),
|
||||
Slot: 1,
|
||||
StateRoot: FillByteSlice(32, 211),
|
||||
}
|
||||
}
|
||||
@@ -223,6 +223,7 @@ func (v *ValidatorService) Start() {
|
||||
emitAccountMetrics: v.emitAccountMetrics,
|
||||
enableAPI: v.enableAPI,
|
||||
duties: &dutyStore{},
|
||||
submittedPrefSlots: make(map[primitives.Slot]bool),
|
||||
distributed: v.distributed,
|
||||
disableDutiesPolling: v.disableDutiesPolling,
|
||||
accountsChangedChannel: make(chan [][fieldparams.BLSPubkeyLength]byte, 1),
|
||||
|
||||
@@ -89,6 +89,7 @@ type validator struct {
|
||||
interopKeysConfig *local.InteropKeymanagerConfig
|
||||
duties *dutyStore
|
||||
signedValidatorRegistrations map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1
|
||||
submittedPrefSlots map[primitives.Slot]bool
|
||||
proposerSettings *proposer.Settings
|
||||
web3SignerConfig *remoteweb3signer.SetupConfig
|
||||
startBalances map[[fieldparams.BLSPubkeyLength]byte]uint64
|
||||
@@ -1027,7 +1028,15 @@ func (v *validator) buildProposerSettingsRequests(
|
||||
}
|
||||
|
||||
// buildProposerPreferences creates signed proposer preferences for validators
|
||||
// that have proposer slots in the next epoch.
|
||||
// that have proposer slots in the current epoch (future slots) or next epoch.
|
||||
//
|
||||
// Current-epoch preferences are submitted after the first slot of the epoch
|
||||
// (slot 0 is skipped to avoid stale state after epoch transition). If the
|
||||
// validator client starts mid-epoch, preferences are submitted for all
|
||||
// remaining future slots in the epoch.
|
||||
// Next-epoch preferences are submitted at or after mid-epoch to ensure beacon
|
||||
// nodes have processed the epoch transition.
|
||||
// Already-submitted slots are tracked to avoid duplicate signing and RPC calls.
|
||||
func (v *validator) buildProposerPreferences(
|
||||
ctx context.Context,
|
||||
km keymanager.IKeymanager,
|
||||
@@ -1038,27 +1047,23 @@ func (v *validator) buildProposerPreferences(
|
||||
if currentEpoch+1 < gloasEpoch {
|
||||
return nil
|
||||
}
|
||||
// Send once per epoch at mid-epoch so beacon nodes have processed the
|
||||
// epoch transition and updated their ProposerLookahead.
|
||||
|
||||
epochStart, err := slots.EpochStart(currentEpoch)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
midEpoch := epochStart + params.BeaconConfig().SlotsPerEpoch/2
|
||||
if slot != midEpoch {
|
||||
return nil
|
||||
|
||||
for s := range v.submittedPrefSlots {
|
||||
if s < epochStart {
|
||||
delete(v.submittedPrefSlots, s)
|
||||
}
|
||||
}
|
||||
|
||||
v.dutiesLock.RLock()
|
||||
defer v.dutiesLock.RUnlock()
|
||||
|
||||
if !v.duties.IsInitialized() {
|
||||
log.Debug("Duties not yet initialized, skipping proposer preferences")
|
||||
return nil
|
||||
}
|
||||
|
||||
nextDuties := v.duties.NextEpochDuties()
|
||||
if len(nextDuties) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1066,55 +1071,99 @@ func (v *validator) buildProposerPreferences(
|
||||
var signedPrefs []*ethpb.SignedProposerPreferences
|
||||
var sigFailCount int
|
||||
|
||||
for pk, duty := range nextDuties {
|
||||
if len(duty.ProposerSlots) == 0 {
|
||||
continue
|
||||
}
|
||||
if duty.Status != ethpb.ValidatorStatus_ACTIVE && duty.Status != ethpb.ValidatorStatus_EXITING {
|
||||
continue
|
||||
}
|
||||
|
||||
feeRecipient := common.HexToAddress(params.BeaconConfig().EthBurnAddressHex)
|
||||
gasLimit := params.BeaconConfig().DefaultBuilderGasLimit
|
||||
|
||||
if ps != nil && ps.DefaultConfig != nil {
|
||||
if ps.DefaultConfig.FeeRecipientConfig != nil {
|
||||
feeRecipient = ps.DefaultConfig.FeeRecipientConfig.FeeRecipient
|
||||
}
|
||||
if ps.DefaultConfig.BuilderConfig != nil && ps.DefaultConfig.BuilderConfig.Enabled {
|
||||
gasLimit = uint64(ps.DefaultConfig.BuilderConfig.GasLimit)
|
||||
}
|
||||
}
|
||||
if ps != nil && ps.ProposeConfig != nil {
|
||||
if config, ok := ps.ProposeConfig[pk]; ok && config != nil {
|
||||
if config.FeeRecipientConfig != nil {
|
||||
feeRecipient = config.FeeRecipientConfig.FeeRecipient
|
||||
}
|
||||
if config.BuilderConfig != nil && config.BuilderConfig.Enabled {
|
||||
gasLimit = uint64(config.BuilderConfig.GasLimit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, proposalSlot := range duty.ProposerSlots {
|
||||
pref := ðpb.ProposerPreferences{
|
||||
ProposalSlot: proposalSlot,
|
||||
ValidatorIndex: duty.ValidatorIndex,
|
||||
FeeRecipient: feeRecipient[:],
|
||||
GasLimit: gasLimit,
|
||||
}
|
||||
|
||||
signedPref, err := v.signProposerPreferences(ctx, km, pk, pref)
|
||||
if err != nil {
|
||||
sigFailCount++
|
||||
processDuties := func(duties map[pubkey]*ethpb.ValidatorDuty, isNextEpoch bool) {
|
||||
for pk, duty := range duties {
|
||||
if len(duty.ProposerSlots) == 0 {
|
||||
continue
|
||||
}
|
||||
signedPrefs = append(signedPrefs, signedPref)
|
||||
if duty.Status != ethpb.ValidatorStatus_ACTIVE && duty.Status != ethpb.ValidatorStatus_EXITING {
|
||||
continue
|
||||
}
|
||||
|
||||
feeRecipient := common.HexToAddress(params.BeaconConfig().EthBurnAddressHex)
|
||||
gasLimit := params.BeaconConfig().DefaultBuilderGasLimit
|
||||
if ps != nil && ps.DefaultConfig != nil {
|
||||
if ps.DefaultConfig.FeeRecipientConfig != nil {
|
||||
feeRecipient = ps.DefaultConfig.FeeRecipientConfig.FeeRecipient
|
||||
}
|
||||
if ps.DefaultConfig.BuilderConfig != nil && ps.DefaultConfig.BuilderConfig.Enabled {
|
||||
gasLimit = uint64(ps.DefaultConfig.BuilderConfig.GasLimit)
|
||||
}
|
||||
}
|
||||
if ps != nil && ps.ProposeConfig != nil {
|
||||
if config, ok := ps.ProposeConfig[pk]; ok && config != nil {
|
||||
if config.FeeRecipientConfig != nil {
|
||||
feeRecipient = config.FeeRecipientConfig.FeeRecipient
|
||||
}
|
||||
if config.BuilderConfig != nil && config.BuilderConfig.Enabled {
|
||||
gasLimit = uint64(config.BuilderConfig.GasLimit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, proposalSlot := range duty.ProposerSlots {
|
||||
if v.submittedPrefSlots[proposalSlot] {
|
||||
continue
|
||||
}
|
||||
// Skip slots that have passed or are too close. Preferences are
|
||||
// submitted at mid-slot, so the proposer needs to be at least 1
|
||||
// full slot away for the beacon node to receive them in time.
|
||||
if !isNextEpoch && proposalSlot <= slot+1 {
|
||||
continue
|
||||
}
|
||||
|
||||
pref := ðpb.ProposerPreferences{
|
||||
ProposalSlot: proposalSlot,
|
||||
ValidatorIndex: duty.ValidatorIndex,
|
||||
FeeRecipient: feeRecipient[:],
|
||||
GasLimit: gasLimit,
|
||||
}
|
||||
signedPref, err := v.signProposerPreferences(ctx, km, pk, pref)
|
||||
if err != nil {
|
||||
sigFailCount++
|
||||
continue
|
||||
}
|
||||
signedPrefs = append(signedPrefs, signedPref)
|
||||
v.submittedPrefSlots[proposalSlot] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentDuties := v.duties.CurrentEpochDuties()
|
||||
nextDuties := v.duties.NextEpochDuties()
|
||||
|
||||
var currentProposerCount, nextProposerCount int
|
||||
for _, d := range currentDuties {
|
||||
currentProposerCount += len(d.ProposerSlots)
|
||||
}
|
||||
for _, d := range nextDuties {
|
||||
nextProposerCount += len(d.ProposerSlots)
|
||||
}
|
||||
|
||||
// Current-epoch: submit after first slot of epoch to avoid stale state.
|
||||
// Only post-gloas — current-epoch prefs before gloas would be rejected.
|
||||
if currentEpoch >= gloasEpoch && slot > epochStart {
|
||||
processDuties(currentDuties, false)
|
||||
}
|
||||
|
||||
// Next-epoch: submit at or after mid-epoch.
|
||||
if slot >= midEpoch {
|
||||
processDuties(nextDuties, true)
|
||||
}
|
||||
|
||||
if sigFailCount > 0 {
|
||||
log.WithField("count", sigFailCount).Warn("Failed to sign proposer preferences")
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": slot,
|
||||
"epoch": currentEpoch,
|
||||
"epochStart": epochStart,
|
||||
"midEpoch": midEpoch,
|
||||
"currentProposerSlots": currentProposerCount,
|
||||
"nextProposerSlots": nextProposerCount,
|
||||
"prefsBuilt": len(signedPrefs),
|
||||
"alreadySubmitted": len(v.submittedPrefSlots),
|
||||
}).Debug("Build proposer preferences result")
|
||||
return signedPrefs
|
||||
}
|
||||
|
||||
|
||||
@@ -2157,7 +2157,8 @@ func TestValidator_buildProposerPreferences(t *testing.T) {
|
||||
index: 1,
|
||||
},
|
||||
},
|
||||
duties: &dutyStore{},
|
||||
duties: &dutyStore{},
|
||||
submittedPrefSlots: make(map[primitives.Slot]bool),
|
||||
}
|
||||
|
||||
t.Run("pre-gloas returns nil", func(t *testing.T) {
|
||||
@@ -2185,6 +2186,7 @@ func TestValidator_buildProposerPreferences(t *testing.T) {
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
@@ -2212,6 +2214,7 @@ func TestValidator_buildProposerPreferences(t *testing.T) {
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
@@ -2252,6 +2255,7 @@ func TestValidator_buildProposerPreferences(t *testing.T) {
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
@@ -2281,6 +2285,7 @@ func TestValidator_buildProposerPreferences(t *testing.T) {
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
@@ -2314,6 +2319,7 @@ func TestValidator_buildProposerPreferences(t *testing.T) {
|
||||
slot2 := params.BeaconConfig().SlotsPerEpoch + 5
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
@@ -2348,6 +2354,7 @@ func TestValidator_buildProposerPreferences(t *testing.T) {
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
@@ -2400,6 +2407,7 @@ func TestValidator_buildProposerPreferences(t *testing.T) {
|
||||
}
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
@@ -2437,6 +2445,237 @@ func TestValidator_buildProposerPreferences(t *testing.T) {
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("current epoch proposer slot included", func(t *testing.T) {
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
currentEpochSlot := primitives.Slot(3)
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ProposerSlots: []primitives.Slot{currentEpochSlot},
|
||||
},
|
||||
},
|
||||
NextEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Slot 1 (past epoch start) allows current-epoch preferences.
|
||||
prefs := v.buildProposerPreferences(t.Context(), km, 1)
|
||||
require.Equal(t, 1, len(prefs))
|
||||
require.Equal(t, currentEpochSlot, prefs[0].Message.ProposalSlot)
|
||||
})
|
||||
|
||||
t.Run("both current and next epoch proposer slots included", func(t *testing.T) {
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
// Current-epoch slot must be after midEpoch so it's still in the future.
|
||||
currentEpochSlot := midEpochSlot + 3
|
||||
nextEpochSlot := params.BeaconConfig().SlotsPerEpoch + 2
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ProposerSlots: []primitives.Slot{currentEpochSlot},
|
||||
},
|
||||
},
|
||||
NextEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ProposerSlots: []primitives.Slot{nextEpochSlot},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// At mid-epoch, both current and next epoch preferences are eligible.
|
||||
prefs := v.buildProposerPreferences(t.Context(), km, midEpochSlot)
|
||||
require.Equal(t, 2, len(prefs))
|
||||
|
||||
gotSlots := []primitives.Slot{prefs[0].Message.ProposalSlot, prefs[1].Message.ProposalSlot}
|
||||
slices.Sort(gotSlots)
|
||||
require.Equal(t, currentEpochSlot, gotSlots[0])
|
||||
require.Equal(t, nextEpochSlot, gotSlots[1])
|
||||
})
|
||||
|
||||
t.Run("epoch start skips current epoch preferences", func(t *testing.T) {
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ProposerSlots: []primitives.Slot{3},
|
||||
},
|
||||
},
|
||||
NextEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Slot 0 (epoch start) skips current-epoch preferences.
|
||||
prefs := v.buildProposerPreferences(t.Context(), km, 0)
|
||||
require.Equal(t, 0, len(prefs))
|
||||
})
|
||||
|
||||
t.Run("second call deduplicates already submitted slots", func(t *testing.T) {
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ProposerSlots: []primitives.Slot{5},
|
||||
},
|
||||
},
|
||||
NextEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
prefs := v.buildProposerPreferences(t.Context(), km, 1)
|
||||
require.Equal(t, 1, len(prefs))
|
||||
|
||||
// Second call returns nothing — slot already submitted.
|
||||
prefs = v.buildProposerPreferences(t.Context(), km, 2)
|
||||
require.Equal(t, 0, len(prefs))
|
||||
})
|
||||
|
||||
t.Run("new validator added after initial submission", func(t *testing.T) {
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
kp2 := randKeypair(t)
|
||||
require.NoError(t, km.add(kp2))
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ProposerSlots: []primitives.Slot{5},
|
||||
},
|
||||
},
|
||||
NextEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
prefs := v.buildProposerPreferences(t.Context(), km, 1)
|
||||
require.Equal(t, 1, len(prefs))
|
||||
|
||||
// Simulate new validator added with a different proposal slot.
|
||||
v.pubkeyToStatus[kp2.pub] = &validatorStatus{
|
||||
publicKey: kp2.pub[:],
|
||||
status: ðpb.ValidatorStatusResponse{Status: ethpb.ValidatorStatus_ACTIVE},
|
||||
index: 2,
|
||||
}
|
||||
v.duties = &dutyStore{}
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ProposerSlots: []primitives.Slot{5},
|
||||
},
|
||||
{
|
||||
PublicKey: kp2.pub[:],
|
||||
ValidatorIndex: 2,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ProposerSlots: []primitives.Slot{7},
|
||||
},
|
||||
},
|
||||
NextEpochDuties: []*ethpb.ValidatorDuty{},
|
||||
})
|
||||
|
||||
// Only the new validator's slot is submitted.
|
||||
prefs = v.buildProposerPreferences(t.Context(), km, 2)
|
||||
require.Equal(t, 1, len(prefs))
|
||||
require.Equal(t, primitives.Slot(7), prefs[0].Message.ProposalSlot)
|
||||
|
||||
delete(v.pubkeyToStatus, kp2.pub)
|
||||
delete(km.keysMap, kp2.pub)
|
||||
})
|
||||
|
||||
t.Run("next epoch before mid-epoch returns nil", func(t *testing.T) {
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.GloasForkEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
v.duties = &dutyStore{}
|
||||
v.submittedPrefSlots = make(map[primitives.Slot]bool)
|
||||
v.duties.SetFromCombinedDutiesResponse(ðpb.ValidatorDutiesContainer{
|
||||
CurrentEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
},
|
||||
},
|
||||
NextEpochDuties: []*ethpb.ValidatorDuty{
|
||||
{
|
||||
PublicKey: kp.pub[:],
|
||||
ValidatorIndex: 1,
|
||||
Status: ethpb.ValidatorStatus_ACTIVE,
|
||||
ProposerSlots: []primitives.Slot{nextEpochProposerSlot},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Slot 1 is before mid-epoch, next-epoch prefs should not be sent.
|
||||
prefs := v.buildProposerPreferences(t.Context(), km, 1)
|
||||
require.Equal(t, 0, len(prefs))
|
||||
})
|
||||
}
|
||||
|
||||
func TestValidator_buildSignedRegReqs_DefaultConfigDisabled(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user