mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-04-19 03:01:06 -04:00
Edit to validator self build for gloas (#16366)
This commit is contained in:
@@ -393,7 +393,6 @@ func (c *grpcValidatorClient) EnsureReady(ctx context.Context) bool {
|
||||
}
|
||||
|
||||
// Gloas Fork Methods
|
||||
|
||||
func (c *grpcValidatorClient) GetExecutionPayloadEnvelope(ctx context.Context, slot primitives.Slot, builderIndex primitives.BuilderIndex) (*ethpb.ExecutionPayloadEnvelope, error) {
|
||||
req := ðpb.ExecutionPayloadEnvelopeRequest{
|
||||
Slot: slot,
|
||||
|
||||
@@ -177,29 +177,9 @@ func (v *validator) ProposeBlock(ctx context.Context, slot primitives.Slot, pubK
|
||||
return
|
||||
}
|
||||
|
||||
// For Gloas, retrieve, sign, and publish the execution payload envelope after
|
||||
// broadcasting the block. The envelope's state root is lazily computed by the
|
||||
// beacon node using the post-block state, so the block must be submitted first.
|
||||
if blk.Version() >= version.Gloas {
|
||||
envelope, err := v.getExecutionPayloadEnvelope(ctx, slot, b)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get execution payload envelope")
|
||||
if v.emitAccountMetrics {
|
||||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc()
|
||||
}
|
||||
return
|
||||
}
|
||||
signedEnvelope, err := v.signExecutionPayloadEnvelope(ctx, pubKey, slot, envelope)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to sign execution payload envelope")
|
||||
if v.emitAccountMetrics {
|
||||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc()
|
||||
}
|
||||
return
|
||||
}
|
||||
if _, err := v.validatorClient.PublishExecutionPayloadEnvelope(ctx, signedEnvelope); err != nil {
|
||||
log.WithError(err).Error("Failed to publish execution payload envelope")
|
||||
}
|
||||
if err := v.proposeSelfBuildEnvelope(ctx, slot, pubKey, blk); err != nil {
|
||||
log.WithError(err).Error("Failed to propose self-build envelope")
|
||||
return
|
||||
}
|
||||
|
||||
span.SetAttributes(
|
||||
|
||||
@@ -6,38 +6,18 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// getExecutionPayloadEnvelope retrieves the execution payload envelope from the
|
||||
// beacon node for the given block's builder index and slot.
|
||||
func (v *validator) getExecutionPayloadEnvelope(
|
||||
ctx context.Context,
|
||||
slot primitives.Slot,
|
||||
b *ethpb.GenericBeaconBlock,
|
||||
) (*ethpb.ExecutionPayloadEnvelope, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.getExecutionPayloadEnvelope")
|
||||
defer span.End()
|
||||
|
||||
gloasBlock := b.GetGloas()
|
||||
if gloasBlock == nil {
|
||||
return nil, errors.New("expected Gloas block but got nil")
|
||||
}
|
||||
if gloasBlock.Body == nil || gloasBlock.Body.SignedExecutionPayloadBid == nil || gloasBlock.Body.SignedExecutionPayloadBid.Message == nil {
|
||||
return nil, errors.New("block missing signed execution payload bid")
|
||||
}
|
||||
builderIndex := gloasBlock.Body.SignedExecutionPayloadBid.Message.BuilderIndex
|
||||
|
||||
return v.validatorClient.GetExecutionPayloadEnvelope(ctx, slot, builderIndex)
|
||||
}
|
||||
|
||||
// signExecutionPayloadEnvelope signs the execution payload envelope using the
|
||||
// builder's key. The envelope is signed with DomainBeaconBuilder since it is
|
||||
// proposer's key. The envelope is signed with DomainBeaconBuilder since it is
|
||||
// a builder artifact — even in the self-build case where the proposer acts as
|
||||
// their own builder.
|
||||
func (v *validator) signExecutionPayloadEnvelope(
|
||||
@@ -82,3 +62,41 @@ func (v *validator) signExecutionPayloadEnvelope(
|
||||
Signature: sig.Marshal(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *validator) proposeSelfBuildEnvelope(
|
||||
ctx context.Context,
|
||||
slot primitives.Slot,
|
||||
pubKey [fieldparams.BLSPubkeyLength]byte,
|
||||
blk interfaces.SignedBeaconBlock,
|
||||
) error {
|
||||
if blk.Version() < version.Gloas {
|
||||
return nil
|
||||
}
|
||||
|
||||
bid, err := blk.Block().Body().SignedExecutionPayloadBid()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bid == nil || bid.Message == nil {
|
||||
return errors.New("no execution payload bid found in block body")
|
||||
}
|
||||
if bid.Message.BuilderIndex != params.BeaconConfig().BuilderIndexSelfBuild {
|
||||
return nil
|
||||
}
|
||||
|
||||
envelope, err := v.validatorClient.GetExecutionPayloadEnvelope(ctx, slot, params.BeaconConfig().BuilderIndexSelfBuild)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get execution payload envelope for self-build")
|
||||
}
|
||||
|
||||
signedEnvelope, err := v.signExecutionPayloadEnvelope(ctx, pubKey, slot, envelope)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not sign execution payload envelope")
|
||||
}
|
||||
|
||||
if _, err := v.validatorClient.PublishExecutionPayloadEnvelope(ctx, signedEnvelope); err != nil {
|
||||
return errors.Wrap(err, "failed to publish execution payload envelope")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
consensusblocks "github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
||||
@@ -18,6 +20,26 @@ import (
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
func signedGloasBlock(t *testing.T, slot primitives.Slot, builderIndex primitives.BuilderIndex) interfaces.SignedBeaconBlock {
|
||||
t.Helper()
|
||||
|
||||
blk := util.NewBeaconBlockGloas()
|
||||
blk.Block.Slot = slot
|
||||
if blk.Block.Body == nil {
|
||||
blk.Block.Body = ðpb.BeaconBlockBodyGloas{}
|
||||
}
|
||||
blk.Block.Body.SignedExecutionPayloadBid = ðpb.SignedExecutionPayloadBid{
|
||||
Message: ðpb.ExecutionPayloadBid{
|
||||
BuilderIndex: builderIndex,
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
}
|
||||
|
||||
signed, err := consensusblocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
return signed
|
||||
}
|
||||
|
||||
func testExecutionPayloadEnvelope(slot primitives.Slot, builderIndex primitives.BuilderIndex) *ethpb.ExecutionPayloadEnvelope {
|
||||
return ðpb.ExecutionPayloadEnvelope{
|
||||
Payload: &enginev1.ExecutionPayloadDeneb{
|
||||
@@ -39,12 +61,12 @@ func testExecutionPayloadEnvelope(slot primitives.Slot, builderIndex primitives.
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecutionPayloadEnvelope(t *testing.T) {
|
||||
validator, m, _, finish := setup(t, false)
|
||||
func TestProposeSelfBuildEnvelope(t *testing.T) {
|
||||
validator, m, validatorKey, finish := setup(t, false)
|
||||
defer finish()
|
||||
|
||||
slot := primitives.Slot(100)
|
||||
builderIndex := primitives.BuilderIndex(42)
|
||||
builderIndex := params.BeaconConfig().BuilderIndexSelfBuild
|
||||
|
||||
expectedEnvelope := testExecutionPayloadEnvelope(slot, builderIndex)
|
||||
|
||||
@@ -52,80 +74,59 @@ func TestExecutionPayloadEnvelope(t *testing.T) {
|
||||
GetExecutionPayloadEnvelope(gomock.Any(), slot, builderIndex).
|
||||
Return(expectedEnvelope, nil)
|
||||
|
||||
b := ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Gloas{
|
||||
Gloas: ðpb.BeaconBlockGloas{
|
||||
Slot: slot,
|
||||
Body: ðpb.BeaconBlockBodyGloas{
|
||||
SignedExecutionPayloadBid: ðpb.SignedExecutionPayloadBid{
|
||||
Message: ðpb.ExecutionPayloadBid{
|
||||
BuilderIndex: builderIndex,
|
||||
},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
builderDomain := make([]byte, 32)
|
||||
copy(builderDomain, params.BeaconConfig().DomainBeaconBuilder[:])
|
||||
m.validatorClient.EXPECT().
|
||||
DomainData(gomock.Any(), gomock.Any()).
|
||||
Return(ðpb.DomainResponse{SignatureDomain: builderDomain}, nil)
|
||||
|
||||
envelope, err := validator.getExecutionPayloadEnvelope(t.Context(), slot, b)
|
||||
m.validatorClient.EXPECT().
|
||||
PublishExecutionPayloadEnvelope(gomock.Any(), gomock.AssignableToTypeOf(ðpb.SignedExecutionPayloadEnvelope{})).
|
||||
Return(&emptypb.Empty{}, nil)
|
||||
|
||||
signedBlock := signedGloasBlock(t, slot, builderIndex)
|
||||
|
||||
var pubKey [fieldparams.BLSPubkeyLength]byte
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
err := validator.proposeSelfBuildEnvelope(t.Context(), slot, pubKey, signedBlock)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, expectedEnvelope, envelope)
|
||||
}
|
||||
|
||||
func TestExecutionPayloadEnvelope_NilBlock(t *testing.T) {
|
||||
func TestProposeSelfBuildEnvelope_MissingBid(t *testing.T) {
|
||||
validator, _, _, finish := setup(t, false)
|
||||
defer finish()
|
||||
|
||||
b := ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Gloas{},
|
||||
blk := util.NewBeaconBlockGloas()
|
||||
blk.Block.Slot = 1
|
||||
if blk.Block.Body == nil {
|
||||
blk.Block.Body = ðpb.BeaconBlockBodyGloas{}
|
||||
}
|
||||
blk.Block.Body.SignedExecutionPayloadBid = nil
|
||||
|
||||
_, err := validator.getExecutionPayloadEnvelope(t.Context(), 1, b)
|
||||
require.ErrorContains(t, "expected Gloas block but got nil", err)
|
||||
signedBlock, err := consensusblocks.NewSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
|
||||
var pubKey [fieldparams.BLSPubkeyLength]byte
|
||||
err = validator.proposeSelfBuildEnvelope(t.Context(), 1, pubKey, signedBlock)
|
||||
require.ErrorContains(t, "no execution payload bid found in block body", err)
|
||||
}
|
||||
|
||||
func TestExecutionPayloadEnvelope_MissingBid(t *testing.T) {
|
||||
validator, _, _, finish := setup(t, false)
|
||||
defer finish()
|
||||
|
||||
b := ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Gloas{
|
||||
Gloas: ðpb.BeaconBlockGloas{
|
||||
Slot: 1,
|
||||
Body: ðpb.BeaconBlockBodyGloas{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_, err := validator.getExecutionPayloadEnvelope(t.Context(), 1, b)
|
||||
require.ErrorContains(t, "block missing signed execution payload bid", err)
|
||||
}
|
||||
|
||||
func TestExecutionPayloadEnvelope_ClientError(t *testing.T) {
|
||||
validator, m, _, finish := setup(t, false)
|
||||
func TestProposeSelfBuildEnvelope_ClientError(t *testing.T) {
|
||||
validator, m, validatorKey, finish := setup(t, false)
|
||||
defer finish()
|
||||
|
||||
m.validatorClient.EXPECT().
|
||||
GetExecutionPayloadEnvelope(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
Return(nil, errors.New("connection refused"))
|
||||
|
||||
b := ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Gloas{
|
||||
Gloas: ðpb.BeaconBlockGloas{
|
||||
Slot: 1,
|
||||
Body: ðpb.BeaconBlockBodyGloas{
|
||||
SignedExecutionPayloadBid: ðpb.SignedExecutionPayloadBid{
|
||||
Message: ðpb.ExecutionPayloadBid{BuilderIndex: 1},
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
signedBlock := signedGloasBlock(t, 1, params.BeaconConfig().BuilderIndexSelfBuild)
|
||||
|
||||
_, err := validator.getExecutionPayloadEnvelope(t.Context(), 1, b)
|
||||
require.ErrorContains(t, "connection refused", err)
|
||||
var pubKey [fieldparams.BLSPubkeyLength]byte
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
err := validator.proposeSelfBuildEnvelope(t.Context(), 1, pubKey, signedBlock)
|
||||
require.ErrorContains(t, "failed to get execution payload envelope for self-build", err)
|
||||
}
|
||||
|
||||
func TestSignExecutionPayloadEnvelope(t *testing.T) {
|
||||
@@ -250,7 +251,17 @@ func TestProposeBlock_Gloas_EnvelopeAfterBlock(t *testing.T) {
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
blk := util.NewBeaconBlockGloas()
|
||||
builderIndex := blk.Block.Body.SignedExecutionPayloadBid.Message.BuilderIndex
|
||||
builderIndex := params.BeaconConfig().BuilderIndexSelfBuild
|
||||
if blk.Block.Body == nil {
|
||||
blk.Block.Body = ðpb.BeaconBlockBodyGloas{}
|
||||
}
|
||||
if blk.Block.Body.SignedExecutionPayloadBid == nil {
|
||||
blk.Block.Body.SignedExecutionPayloadBid = ðpb.SignedExecutionPayloadBid{}
|
||||
}
|
||||
if blk.Block.Body.SignedExecutionPayloadBid.Message == nil {
|
||||
blk.Block.Body.SignedExecutionPayloadBid.Message = ðpb.ExecutionPayloadBid{}
|
||||
}
|
||||
blk.Block.Body.SignedExecutionPayloadBid.Message.BuilderIndex = builderIndex
|
||||
|
||||
gloasBlock := ðpb.GenericBeaconBlock{
|
||||
Block: ðpb.GenericBeaconBlock_Gloas{
|
||||
|
||||
Reference in New Issue
Block a user