diff --git a/beacon-chain/execution/testing/BUILD.bazel b/beacon-chain/execution/testing/BUILD.bazel index ce490c70769f..bd5ec6a4e1d9 100644 --- a/beacon-chain/execution/testing/BUILD.bazel +++ b/beacon-chain/execution/testing/BUILD.bazel @@ -21,6 +21,7 @@ go_library( "//consensus-types/blocks:go_default_library", "//consensus-types/interfaces:go_default_library", "//consensus-types/payload-attribute:go_default_library", + "//consensus-types/primitives:go_default_library", "//encoding/bytesutil:go_default_library", "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", diff --git a/beacon-chain/execution/testing/mock_engine_client.go b/beacon-chain/execution/testing/mock_engine_client.go index ff14e5d91e62..436f0f93f6fd 100644 --- a/beacon-chain/execution/testing/mock_engine_client.go +++ b/beacon-chain/execution/testing/mock_engine_client.go @@ -12,6 +12,7 @@ import ( "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute" + types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" ) @@ -53,8 +54,12 @@ func (e *EngineClient) ForkchoiceUpdated( } // GetPayload -- -func (e *EngineClient) GetPayload(_ context.Context, _ [8]byte) (*pb.ExecutionPayload, error) { - return e.ExecutionPayload, e.ErrGetPayload +func (e *EngineClient) GetPayload(_ context.Context, _ [8]byte, slot types.Slot) (interfaces.ExecutionData, error) { + p, err := blocks.WrappedExecutionPayload(e.ExecutionPayload) + if err != nil { + return nil, err + } + return p, e.ErrGetPayload } func (e *EngineClient) GetPayloadV2(_ context.Context, _ [8]byte) (*pb.ExecutionPayloadCapella, error) { diff --git a/beacon-chain/rpc/eth/validator/validator.go b/beacon-chain/rpc/eth/validator/validator.go index bd40911ac1e0..7902f601ec37 100644 --- a/beacon-chain/rpc/eth/validator/validator.go +++ b/beacon-chain/rpc/eth/validator/validator.go @@ -488,16 +488,9 @@ func (vs *Server) ProduceBlindedBlock(ctx context.Context, req *ethpbv1.ProduceB if optimistic { return nil, status.Errorf(codes.Unavailable, "The node is currently optimistic and cannot serve validators") } - altairBlk, err := vs.V1Alpha1Server.BuildAltairBeaconBlock(ctx, v1alpha1req) + b, err := vs.V1Alpha1Server.GetBeaconBlock(ctx, v1alpha1req) if err != nil { - return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err) - } - ok, b, err := vs.V1Alpha1Server.GetAndBuildBlindBlock(ctx, altairBlk) - if err != nil { - return nil, status.Errorf(codes.Internal, "Could not prepare blind beacon block: %v", err) - } - if !ok { - return nil, status.Error(codes.Unavailable, "Builder is not available due to miss-config or circuit breaker") + return nil, err } blk, err := migration.V1Alpha1BeaconBlockBlindedBellatrixToV2Blinded(b.GetBlindedBellatrix()) if err != nil { diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel b/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel index ddf3d83b3ece..8c630ad62f3c 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/BUILD.bazel @@ -16,7 +16,6 @@ go_library( "proposer_deposits.go", "proposer_eth1data.go", "proposer_execution_payload.go", - "proposer_phase0.go", "proposer_sync_aggregate.go", "server.go", "status.go", diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go index f5e58502a7ef..411a4336a7bf 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go @@ -12,10 +12,15 @@ import ( emptypb "github.com/golang/protobuf/ptypes/empty" "github.com/pkg/errors" "github.com/prysmaticlabs/prysm/v3/beacon-chain/builder" + blocks2 "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed" blockfeed "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/feed/block" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition" + v "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/validators" "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/kv" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/state" + fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" "github.com/prysmaticlabs/prysm/v3/config/params" "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" @@ -41,25 +46,241 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) ( ctx, span := trace.StartSpan(ctx, "ProposerServer.GetBeaconBlock") defer span.End() span.AddAttributes(trace.Int64Attribute("slot", int64(req.Slot))) - if slots.ToEpoch(req.Slot) < params.BeaconConfig().AltairForkEpoch { - blk, err := vs.getPhase0BeaconBlock(ctx, req) + + // A syncing validator should not produce a block. + if vs.SyncChecker.Syncing() { + return nil, status.Error(codes.Unavailable, "Syncing to latest head, not ready to respond") + } + + // An optimistic validator MUST NOT produce a block (i.e., sign across the DOMAIN_BEACON_PROPOSER domain). + if err := vs.optimisticStatus(ctx); err != nil { + return nil, status.Errorf(codes.Unavailable, "Validator is not ready to propose: %v", err) + } + + blk, sBlk, err := emptyBlockToSign(req.Slot) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not prepare block: %v", err) + } + + parentRoot, err := vs.HeadFetcher.HeadRoot(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get head root: %v", err) + } + head, err := vs.HeadFetcher.HeadState(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) + } + head, err = transition.ProcessSlotsUsingNextSlotCache(ctx, head, parentRoot, req.Slot) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not process slots up to %d: %v", req.Slot, err) + } + + // Set slot, graffiti, randao reveal, and parent root. + blk.SetSlot(req.Slot) + blk.Body().SetGraffiti(req.Graffiti) + blk.Body().SetRandaoReveal(req.RandaoReveal) + blk.SetParentRoot(parentRoot) + + // Set eth1 data. + eth1Data, err := vs.eth1DataMajorityVote(ctx, head) + if err != nil { + log.WithError(err).Error("Could not get eth1data") + } else { + blk.Body().SetEth1Data(eth1Data) + + // Set deposit and attestation. + deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data) // TODO: split attestations and deposits if err != nil { - return nil, status.Errorf(codes.Internal, "Could not fetch phase0 beacon block: %v", err) + log.WithError(err).Error("Could not pack deposits and attestations") + } else { + blk.Body().SetDeposits(deposits) + blk.Body().SetAttestations(atts) } - return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Phase0{Phase0: blk}}, nil - } else if slots.ToEpoch(req.Slot) < params.BeaconConfig().BellatrixForkEpoch { - blk, err := vs.getAltairBeaconBlock(ctx, req) + } + + // Set proposer index + idx, err := helpers.BeaconProposerIndex(ctx, head) + if err != nil { + return nil, fmt.Errorf("could not calculate proposer index %v", err) + } + blk.SetProposerIndex(idx) + + // Set slashings + validProposerSlashings, validAttSlashings := vs.getSlashings(ctx, head) + blk.Body().SetProposerSlashings(validProposerSlashings) + blk.Body().SetAttesterSlashings(validAttSlashings) + + // Set exits + blk.Body().SetVoluntaryExits(vs.getExits(head, req)) + + // Set sync aggregate. New in Altair. + if req.Slot > 0 && slots.ToEpoch(req.Slot) >= params.BeaconConfig().AltairForkEpoch { + syncAggregate, err := vs.getSyncAggregate(ctx, req.Slot-1, bytesutil.ToBytes32(parentRoot)) if err != nil { - return nil, status.Errorf(codes.Internal, "Could not fetch Altair beacon block: %v", err) + log.WithError(err).Error("Could not get sync aggregate") + } else { + if err := blk.Body().SetSyncAggregate(syncAggregate); err != nil { + log.WithError(err).Error("Could not set sync aggregate") + if err := blk.Body().SetSyncAggregate(ðpb.SyncAggregate{ + SyncCommitteeBits: make([]byte, params.BeaconConfig().SyncCommitteeSize), + SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength), + }); err != nil { + return nil, status.Errorf(codes.Internal, "Could not set default sync aggregate: %v", err) + } + } } - return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Altair{Altair: blk}}, nil } - // An optimistic validator MUST NOT produce a block (i.e., sign across the DOMAIN_BEACON_PROPOSER domain). - if err := vs.optimisticStatus(ctx); err != nil { - return nil, err + // Set execution data. New in Bellatrix + if slots.ToEpoch(req.Slot) >= params.BeaconConfig().BellatrixForkEpoch { + fallBackToLocal := true + canUseBuilder, err := vs.canUseBuilder(ctx, req.Slot, idx) + if err != nil { + log.WithError(err).Warn("Proposer: failed to check if builder can be used") + } else if canUseBuilder { + h, err := vs.getPayloadHeaderFromBuilder(ctx, req.Slot, idx) + if err != nil { + log.WithError(err).Warn("Proposer: failed to get payload header from builder") + } else { + blk.SetBlinded(true) + if err := blk.Body().SetExecution(h); err != nil { + log.WithError(err).Warn("Proposer: failed to set execution payload") + } else { + fallBackToLocal = false + } + } + } + if fallBackToLocal { + executionData, err := vs.getExecutionPayload(ctx, req.Slot, idx, bytesutil.ToBytes32(parentRoot), head) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get execution payload: %v", err) + } + if err := blk.Body().SetExecution(executionData); err != nil { + return nil, status.Errorf(codes.Internal, "Could not set execution payload: %v", err) + } + } + } + + // Set bls to execution change. New in Capella + if slots.ToEpoch(req.Slot) >= params.BeaconConfig().CapellaForkEpoch { + changes, err := vs.BLSChangesPool.BLSToExecChangesForInclusion(head) + if err != nil { + log.WithError(err).Error("Could not get bls to execution changes") + } else { + if err := blk.Body().SetBLSToExecutionChanges(changes); err != nil { + log.WithError(err).Error("Could not set bls to execution changes") + } + } + } + + if err := sBlk.SetBlock(blk); err != nil { + return nil, status.Errorf(codes.Internal, "Could not set block: %v", err) + } + sr, err := vs.computeStateRoot(ctx, sBlk) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not compute state root: %v", err) + } + blk.SetStateRoot(sr) + + pb, err := blk.Proto() + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not convert block to proto: %v", err) + } + if slots.ToEpoch(req.Slot) >= params.BeaconConfig().CapellaForkEpoch { + return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Capella{Capella: pb.(*ethpb.BeaconBlockCapella)}}, nil + } else if slots.ToEpoch(req.Slot) >= params.BeaconConfig().BellatrixForkEpoch { + return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Bellatrix{Bellatrix: pb.(*ethpb.BeaconBlockBellatrix)}}, nil + } else if slots.ToEpoch(req.Slot) >= params.BeaconConfig().AltairForkEpoch { + return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Altair{Altair: pb.(*ethpb.BeaconBlockAltair)}}, nil + } + return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Phase0{Phase0: pb.(*ethpb.BeaconBlock)}}, nil +} + +func (vs *Server) getExits(head state.BeaconState, req *ethpb.BlockRequest) []*ethpb.SignedVoluntaryExit { + exits := vs.ExitPool.PendingExits(head, req.Slot, false /*noLimit*/) + validExits := make([]*ethpb.SignedVoluntaryExit, 0, len(exits)) + for _, exit := range exits { + val, err := head.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex) + if err != nil { + log.WithError(err).Warn("Proposer: invalid exit") + continue + } + if err := blocks2.VerifyExitAndSignature(val, head.Slot(), head.Fork(), exit, head.GenesisValidatorsRoot()); err != nil { + log.WithError(err).Warn("Proposer: invalid exit") + continue + } + validExits = append(validExits, exit) + } + return validExits +} + +func (vs *Server) getSlashings(ctx context.Context, head state.BeaconState) ([]*ethpb.ProposerSlashing, []*ethpb.AttesterSlashing) { + proposerSlashings := vs.SlashingsPool.PendingProposerSlashings(ctx, head, false /*noLimit*/) + validProposerSlashings := make([]*ethpb.ProposerSlashing, 0, len(proposerSlashings)) + for _, slashing := range proposerSlashings { + _, err := blocks2.ProcessProposerSlashing(ctx, head, slashing, v.SlashValidator) + if err != nil { + log.WithError(err).Warn("Proposer: invalid proposer slashing") + continue + } + validProposerSlashings = append(validProposerSlashings, slashing) + } + attSlashings := vs.SlashingsPool.PendingAttesterSlashings(ctx, head, false /*noLimit*/) + validAttSlashings := make([]*ethpb.AttesterSlashing, 0, len(attSlashings)) + for _, slashing := range attSlashings { + _, err := blocks2.ProcessAttesterSlashing(ctx, head, slashing, v.SlashValidator) + if err != nil { + log.WithError(err).Warn("Proposer: invalid attester slashing") + continue + } + validAttSlashings = append(validAttSlashings, slashing) + } + return validProposerSlashings, validAttSlashings +} + +func emptyBlockToSign(slot types.Slot) (interfaces.BeaconBlock, interfaces.SignedBeaconBlock, error) { + var blk interfaces.BeaconBlock + var sBlk interfaces.SignedBeaconBlock + var err error + switch { + case slots.ToEpoch(slot) < params.BeaconConfig().AltairForkEpoch: + blk, err = blocks.NewBeaconBlock(ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}) + if err != nil { + return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err) + } + sBlk, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}) + if err != nil { + return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err) + } + case slots.ToEpoch(slot) < params.BeaconConfig().BellatrixForkEpoch: + blk, err = blocks.NewBeaconBlock(ðpb.BeaconBlockAltair{Body: ðpb.BeaconBlockBodyAltair{}}) + if err != nil { + return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err) + } + sBlk, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockAltair{Block: ðpb.BeaconBlockAltair{Body: ðpb.BeaconBlockBodyAltair{}}}) + if err != nil { + return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err) + } + case slots.ToEpoch(slot) < params.BeaconConfig().CapellaForkEpoch: + blk, err = blocks.NewBeaconBlock(ðpb.BeaconBlockBellatrix{Body: ðpb.BeaconBlockBodyBellatrix{}}) + if err != nil { + return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err) + } + sBlk, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: ðpb.BeaconBlockBellatrix{Body: ðpb.BeaconBlockBodyBellatrix{}}}) + if err != nil { + return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err) + } + default: + blk, err = blocks.NewBeaconBlock(ðpb.BeaconBlockCapella{Body: ðpb.BeaconBlockBodyCapella{}}) + if err != nil { + return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err) + } + sBlk, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockCapella{Block: ðpb.BeaconBlockCapella{Body: ðpb.BeaconBlockBodyCapella{}}}) + if err != nil { + return nil, nil, status.Errorf(codes.Internal, "Could not initialize block for proposal: %v", err) + } } - return vs.getBellatrixBeaconBlock(ctx, req) + return blk, sBlk, err } // ProposeBeaconBlock is called by a proposer during its assigned slot to create a block in an attempt diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_altair.go b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_altair.go index bb17e192c318..0c767101c5bb 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_altair.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_altair.go @@ -2,11 +2,8 @@ package validator import ( "context" - "fmt" - "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop" "github.com/prysmaticlabs/prysm/v3/config/params" - "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v3/crypto/bls" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" @@ -15,62 +12,6 @@ import ( "go.opencensus.io/trace" ) -func buildAltairBeaconBlockFromBlockData(blkData *blockData) *ethpb.BeaconBlockAltair { - // Use zero hash as stub for state root to compute later. - stateRoot := params.BeaconConfig().ZeroHash[:] - - return ðpb.BeaconBlockAltair{ - Slot: blkData.Slot, - ParentRoot: blkData.ParentRoot, - StateRoot: stateRoot, - ProposerIndex: blkData.ProposerIdx, - Body: ðpb.BeaconBlockBodyAltair{ - Eth1Data: blkData.Eth1Data, - Deposits: blkData.Deposits, - Attestations: blkData.Attestations, - RandaoReveal: blkData.RandaoReveal, - ProposerSlashings: blkData.ProposerSlashings, - AttesterSlashings: blkData.AttesterSlashings, - VoluntaryExits: blkData.VoluntaryExits, - Graffiti: blkData.Graffiti[:], - SyncAggregate: blkData.SyncAggregate, - }, - } -} - -func (vs *Server) BuildAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) { - ctx, span := trace.StartSpan(ctx, "ProposerServer.BuildAltairBeaconBlock") - defer span.End() - blkData, err := vs.buildPhase0BlockData(ctx, req) - if err != nil { - return nil, fmt.Errorf("could not build block data: %v", err) - } - return buildAltairBeaconBlockFromBlockData(blkData), nil -} - -func (vs *Server) getAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) { - ctx, span := trace.StartSpan(ctx, "ProposerServer.getAltairBeaconBlock") - defer span.End() - blk, err := vs.BuildAltairBeaconBlock(ctx, req) - if err != nil { - return nil, fmt.Errorf("could not build block data: %v", err) - } - // Compute state root with the newly constructed block. - wsb, err := blocks.NewSignedBeaconBlock( - ðpb.SignedBeaconBlockAltair{Block: blk, Signature: make([]byte, 96)}, - ) - if err != nil { - return nil, err - } - stateRoot, err := vs.computeStateRoot(ctx, wsb) - if err != nil { - interop.WriteBlockToDisk(wsb, true /*failed*/) - return nil, fmt.Errorf("could not compute state root: %v", err) - } - blk.StateRoot = stateRoot - return blk, nil -} - // getSyncAggregate retrieves the sync contributions from the pool to construct the sync aggregate object. // The contributions are filtered based on matching of the input root and slot then profitability. func (vs *Server) getSyncAggregate(ctx context.Context, slot types.Slot, root [32]byte) (*ethpb.SyncAggregate, error) { diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go index 4781ad205e65..83551e96c934 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_bellatrix.go @@ -12,8 +12,6 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing" - "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition" - "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop" "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/kv" "github.com/prysmaticlabs/prysm/v3/config/params" consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" @@ -39,134 +37,20 @@ var builderGetPayloadMissCount = promauto.NewCounter(prometheus.CounterOpts{ // block request. This value is known as `BUILDER_PROPOSAL_DELAY_TOLERANCE` in builder spec. const blockBuilderTimeout = 1 * time.Second -func (vs *Server) getBlockFromBuilder(ctx context.Context, altairBlk *ethpb.BeaconBlockAltair) ( - *ethpb.GenericBeaconBlock, error) { - registered, err := vs.validatorRegistered(ctx, altairBlk.ProposerIndex) - if registered && err == nil { - builderReady, b, err := vs.GetAndBuildBlindBlock(ctx, altairBlk) - if err != nil { - // In the event of an error, the node should fall back to default execution engine for building block. - builderGetPayloadMissCount.Inc() - return nil, err - } else if builderReady { - return b, nil - } - } else if err != nil { - return nil, err - } - return nil, errors.New("validator is not registered") -} - -func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) { - blkData, err := vs.buildPhase0BlockData(ctx, req) - if err != nil { - return nil, err - } - - // If the validator was not registered then we computed already an execution payload - if !req.SkipMevBoost && blkData.ExecutionPayload == nil && blkData.ExecutionPayloadV2 == nil { - altairBlk := buildAltairBeaconBlockFromBlockData(blkData) - b, err := vs.getBlockFromBuilder(ctx, altairBlk) - if err == nil { - return b, nil - } - log.WithError(err).Error("falling back to local execution") - - head, err := vs.HeadFetcher.HeadState(ctx) - if err != nil { - return nil, fmt.Errorf("could not get head state %v", err) - } - - head, err = transition.ProcessSlotsUsingNextSlotCache(ctx, head, blkData.ParentRoot, req.Slot) - if err != nil { - return nil, fmt.Errorf("could not advance slots to calculate proposer index: %v", err) - } - - e, err := vs.getExecutionPayload(ctx, req.Slot, blkData.ProposerIdx, bytesutil.ToBytes32(blkData.ParentRoot), head) - if err != nil { - return nil, errors.Wrap(err, "could not get execution payload") - } - p, err := e.PbV1() - if err != nil { - return nil, errors.Wrap(err, "could not get execution payload") - } - blkData.ExecutionPayload = p - } - - var wsb interfaces.SignedBeaconBlock - if slots.ToEpoch(req.Slot) < params.BeaconConfig().CapellaForkEpoch { - blk := ðpb.BeaconBlockBellatrix{ - Slot: blkData.Slot, - ProposerIndex: blkData.ProposerIdx, - ParentRoot: blkData.ParentRoot, - StateRoot: params.BeaconConfig().ZeroHash[:], - Body: ðpb.BeaconBlockBodyBellatrix{ - RandaoReveal: blkData.RandaoReveal, - Eth1Data: blkData.Eth1Data, - Graffiti: blkData.Graffiti[:], - ProposerSlashings: blkData.ProposerSlashings, - AttesterSlashings: blkData.AttesterSlashings, - Attestations: blkData.Attestations, - Deposits: blkData.Deposits, - VoluntaryExits: blkData.VoluntaryExits, - SyncAggregate: blkData.SyncAggregate, - ExecutionPayload: blkData.ExecutionPayload, - }, - } - // Compute state root with the newly constructed block. - wsb, err = consensusblocks.NewSignedBeaconBlock( - ðpb.SignedBeaconBlockBellatrix{Block: blk, Signature: make([]byte, 96)}, - ) - if err != nil { - return nil, err - } - } else { - blk := ðpb.BeaconBlockCapella{ - Slot: blkData.Slot, - ProposerIndex: blkData.ProposerIdx, - ParentRoot: blkData.ParentRoot, - StateRoot: params.BeaconConfig().ZeroHash[:], - Body: ðpb.BeaconBlockBodyCapella{ - RandaoReveal: blkData.RandaoReveal, - Eth1Data: blkData.Eth1Data, - Graffiti: blkData.Graffiti[:], - ProposerSlashings: blkData.ProposerSlashings, - AttesterSlashings: blkData.AttesterSlashings, - Attestations: blkData.Attestations, - Deposits: blkData.Deposits, - VoluntaryExits: blkData.VoluntaryExits, - SyncAggregate: blkData.SyncAggregate, - ExecutionPayload: blkData.ExecutionPayloadV2, - BlsToExecutionChanges: blkData.BlsToExecutionChanges, - }, - } - // Compute state root with the newly constructed block. - wsb, err = consensusblocks.NewSignedBeaconBlock( - ðpb.SignedBeaconBlockCapella{Block: blk, Signature: make([]byte, 96)}, - ) - if err != nil { - return nil, err - } - } - stateRoot, err := vs.computeStateRoot(ctx, wsb) - if err != nil { - interop.WriteBlockToDisk(wsb, true /*failed*/) - return nil, fmt.Errorf("could not compute state root: %v", err) - } - wsb.Block().SetStateRoot(stateRoot) - pb, err := wsb.Block().Proto() +func (vs *Server) canUseBuilder(ctx context.Context, slot types.Slot, idx types.ValidatorIndex) (bool, error) { + registered, err := vs.validatorRegistered(ctx, idx) if err != nil { - return nil, errors.Wrap(err, "could not unmarshal block") + return false, err } - if slots.ToEpoch(req.Slot) < params.BeaconConfig().CapellaForkEpoch { - return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Bellatrix{Bellatrix: pb.(*ethpb.BeaconBlockBellatrix)}}, nil + if !registered { + return false, nil } - return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Capella{Capella: pb.(*ethpb.BeaconBlockCapella)}}, nil + return vs.circuitBreakBuilder(slot) } // This function retrieves the payload header given the slot number and the validator index. // It's a no-op if the latest head block is not versioned bellatrix. -func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Slot, idx types.ValidatorIndex) (*enginev1.ExecutionPayloadHeader, error) { +func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Slot, idx types.ValidatorIndex) (interfaces.ExecutionData, error) { b, err := vs.HeadFetcher.HeadBlock(ctx) if err != nil { return nil, err @@ -226,48 +110,8 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Sl "builderPubKey": fmt.Sprintf("%#x", bid.Message.Pubkey), "blockHash": fmt.Sprintf("%#x", bid.Message.Header.BlockHash), }).Info("Received header with bid") - return bid.Message.Header, nil -} -// This function constructs the builder block given the input altair block and the header. It returns a generic beacon block for signing -func (vs *Server) buildBlindBlock(ctx context.Context, b *ethpb.BeaconBlockAltair, h *enginev1.ExecutionPayloadHeader) (*ethpb.GenericBeaconBlock, error) { - if b == nil || b.Body == nil { - return nil, errors.New("nil block") - } - if h == nil { - return nil, errors.New("nil header") - } - - blk := ðpb.BlindedBeaconBlockBellatrix{ - Slot: b.Slot, - ProposerIndex: b.ProposerIndex, - ParentRoot: b.ParentRoot, - StateRoot: params.BeaconConfig().ZeroHash[:], - Body: ðpb.BlindedBeaconBlockBodyBellatrix{ - RandaoReveal: b.Body.RandaoReveal, - Eth1Data: b.Body.Eth1Data, - Graffiti: b.Body.Graffiti, - ProposerSlashings: b.Body.ProposerSlashings, - AttesterSlashings: b.Body.AttesterSlashings, - Attestations: b.Body.Attestations, - Deposits: b.Body.Deposits, - VoluntaryExits: b.Body.VoluntaryExits, - SyncAggregate: b.Body.SyncAggregate, - ExecutionPayloadHeader: h, - }, - } - wsb, err := consensusblocks.NewSignedBeaconBlock( - ðpb.SignedBlindedBeaconBlockBellatrix{Block: blk, Signature: make([]byte, 96)}, - ) - if err != nil { - return nil, err - } - stateRoot, err := vs.computeStateRoot(ctx, wsb) - if err != nil { - return nil, errors.Wrap(err, "could not compute state root") - } - blk.StateRoot = stateRoot - return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedBellatrix{BlindedBellatrix: blk}}, nil + return coreBlock.WrappedExecutionPayloadHeader(bid.Message.Header) } // This function retrieves the full payload block using the input blind block. This input must be versioned as @@ -381,24 +225,6 @@ func (vs *Server) unblindBuilderBlock(ctx context.Context, b interfaces.SignedBe return wb, nil } -// readyForBuilder returns true if builder is allowed to be used. Builder is only allowed to be use after the -// first finalized checkpt has been execution-enabled. -func (vs *Server) readyForBuilder(ctx context.Context) (bool, error) { - cp := vs.FinalizationFetcher.FinalizedCheckpt() - // Checkpoint root is zero means we are still at genesis epoch. - if bytesutil.ToBytes32(cp.Root) == params.BeaconConfig().ZeroHash { - return false, nil - } - b, err := vs.BeaconDB.Block(ctx, bytesutil.ToBytes32(cp.Root)) - if err != nil { - return false, err - } - if err = coreBlock.BeaconBlockIsNil(b); err != nil { - return false, err - } - return blocks.IsExecutionBlock(b.Block().Body()) -} - // circuitBreakBuilder returns true if the builder is not allowed to be used due to circuit breaker conditions. func (vs *Server) circuitBreakBuilder(s types.Slot) (bool, error) { if vs.ForkFetcher == nil || vs.ForkFetcher.ForkChoicer() == nil { @@ -447,50 +273,6 @@ func (vs *Server) circuitBreakBuilder(s types.Slot) (bool, error) { return false, nil } -// GetAndBuildBlindBlock builds blind block from builder network. Returns a boolean status, built block and error. -// If the status is false that means builder the header block is disallowed. -// This routine is time limited by `blockBuilderTimeout`. -func (vs *Server) GetAndBuildBlindBlock(ctx context.Context, b *ethpb.BeaconBlockAltair) (bool, *ethpb.GenericBeaconBlock, error) { - // No op. Builder is not defined. User did not specify a user URL. We should use local EE. - if vs.BlockBuilder == nil || !vs.BlockBuilder.Configured() { - return false, nil, nil - } - ctx, cancel := context.WithTimeout(ctx, blockBuilderTimeout) - defer cancel() - // Does the protocol allow for builder at this current moment. Builder is only allowed post merge after finalization. - ready, err := vs.readyForBuilder(ctx) - if err != nil { - return false, nil, errors.Wrap(err, "could not determine if builder is ready") - } - if !ready { - return false, nil, nil - } - - circuitBreak, err := vs.circuitBreakBuilder(b.Slot) - if err != nil { - return false, nil, errors.Wrap(err, "could not determine if builder circuit breaker condition") - } - if circuitBreak { - return false, nil, nil - } - - h, err := vs.getPayloadHeaderFromBuilder(ctx, b.Slot, b.ProposerIndex) - if err != nil { - return false, nil, errors.Wrap(err, "could not get payload header") - } - log.WithFields(logrus.Fields{ - "blockHash": fmt.Sprintf("%#x", h.BlockHash), - "feeRecipient": fmt.Sprintf("%#x", h.FeeRecipient), - "gasUsed": h.GasUsed, - "slot": b.Slot, - }).Info("Retrieved header from builder") - gb, err := vs.buildBlindBlock(ctx, b, h) - if err != nil { - return false, nil, errors.Wrap(err, "could not combine altair block with payload header") - } - return true, gb, nil -} - // validatorRegistered returns true if validator with index `id` was previously registered in the database. func (vs *Server) validatorRegistered(ctx context.Context, id types.ValidatorIndex) (bool, error) { if vs.BeaconDB == nil { @@ -510,7 +292,7 @@ func (vs *Server) validatorRegistered(ctx context.Context, id types.ValidatorInd func (vs *Server) validateBuilderSignature(bid *ethpb.SignedBuilderBid) error { d, err := signing.ComputeDomain(params.BeaconConfig().DomainApplicationBuilder, nil, /* fork version */ - nil /* genesis val root */) + nil /* genesis val root */) if err != nil { return err } diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_phase0.go b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_phase0.go deleted file mode 100644 index 948b5f69f862..000000000000 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_phase0.go +++ /dev/null @@ -1,220 +0,0 @@ -package validator - -import ( - "context" - "fmt" - - "github.com/pkg/errors" - "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks" - "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers" - "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition" - "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop" - v "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/validators" - "github.com/prysmaticlabs/prysm/v3/config/params" - consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" - types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" - "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" - enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" - ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" - "github.com/prysmaticlabs/prysm/v3/time/slots" - "go.opencensus.io/trace" -) - -// blockData required to create a beacon block. -type blockData struct { - Slot types.Slot - ParentRoot []byte - Graffiti [32]byte - ProposerIdx types.ValidatorIndex - Eth1Data *ethpb.Eth1Data - Deposits []*ethpb.Deposit - Attestations []*ethpb.Attestation - RandaoReveal []byte - ProposerSlashings []*ethpb.ProposerSlashing - AttesterSlashings []*ethpb.AttesterSlashing - VoluntaryExits []*ethpb.SignedVoluntaryExit - SyncAggregate *ethpb.SyncAggregate - ExecutionPayload *enginev1.ExecutionPayload - ExecutionPayloadV2 *enginev1.ExecutionPayloadCapella - BlsToExecutionChanges []*ethpb.SignedBLSToExecutionChange -} - -func (vs *Server) getPhase0BeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlock, error) { - ctx, span := trace.StartSpan(ctx, "ProposerServer.getPhase0BeaconBlock") - defer span.End() - blkData, err := vs.buildPhase0BlockData(ctx, req) - if err != nil { - return nil, fmt.Errorf("could not build block data: %v", err) - } - - // Use zero hash as stub for state root to compute later. - stateRoot := params.BeaconConfig().ZeroHash[:] - - blk := ðpb.BeaconBlock{ - Slot: blkData.Slot, - ParentRoot: blkData.ParentRoot, - StateRoot: stateRoot, - ProposerIndex: blkData.ProposerIdx, - Body: ðpb.BeaconBlockBody{ - Eth1Data: blkData.Eth1Data, - Deposits: blkData.Deposits, - Attestations: blkData.Attestations, - RandaoReveal: blkData.RandaoReveal, - ProposerSlashings: blkData.ProposerSlashings, - AttesterSlashings: blkData.AttesterSlashings, - VoluntaryExits: blkData.VoluntaryExits, - Graffiti: blkData.Graffiti[:], - }, - } - - // Compute state root with the newly constructed block. - wsb, err := consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlock{Block: blk, Signature: make([]byte, 96)}) - if err != nil { - return nil, err - } - stateRoot, err = vs.computeStateRoot(ctx, wsb) - if err != nil { - interop.WriteBlockToDisk(wsb, true /*failed*/) - return nil, errors.Wrap(err, "could not compute state root") - } - blk.StateRoot = stateRoot - return blk, nil -} - -// Build data required for creating a new beacon block, so this method can be shared across forks. -func (vs *Server) buildPhase0BlockData(ctx context.Context, req *ethpb.BlockRequest) (*blockData, error) { - ctx, span := trace.StartSpan(ctx, "ProposerServer.buildPhase0BlockData") - defer span.End() - - if vs.SyncChecker.Syncing() { - return nil, fmt.Errorf("syncing to latest head, not ready to respond") - } - - if err := vs.HeadUpdater.UpdateHead(ctx); err != nil { - log.WithError(err).Error("Could not process attestations and update head") - } - - // Retrieve the parent block as the current head of the canonical chain. - parentRoot, err := vs.HeadFetcher.HeadRoot(ctx) - if err != nil { - return nil, fmt.Errorf("could not retrieve head root: %v", err) - } - - head, err := vs.HeadFetcher.HeadState(ctx) - if err != nil { - return nil, fmt.Errorf("could not get head state %v", err) - } - - head, err = transition.ProcessSlotsUsingNextSlotCache(ctx, head, parentRoot, req.Slot) - if err != nil { - return nil, fmt.Errorf("could not advance slots to calculate proposer index: %v", err) - } - - eth1Data, err := vs.eth1DataMajorityVote(ctx, head) - if err != nil { - return nil, fmt.Errorf("could not get ETH1 data: %v", err) - } - - deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data) - if err != nil { - return nil, err - } - - graffiti := bytesutil.ToBytes32(req.Graffiti) - - // Calculate new proposer index. - idx, err := helpers.BeaconProposerIndex(ctx, head) - if err != nil { - return nil, fmt.Errorf("could not calculate proposer index %v", err) - } - - proposerSlashings := vs.SlashingsPool.PendingProposerSlashings(ctx, head, false /*noLimit*/) - validProposerSlashings := make([]*ethpb.ProposerSlashing, 0, len(proposerSlashings)) - for _, slashing := range proposerSlashings { - _, err := blocks.ProcessProposerSlashing(ctx, head, slashing, v.SlashValidator) - if err != nil { - log.WithError(err).Warn("Proposer: invalid proposer slashing") - continue - } - validProposerSlashings = append(validProposerSlashings, slashing) - } - - attSlashings := vs.SlashingsPool.PendingAttesterSlashings(ctx, head, false /*noLimit*/) - validAttSlashings := make([]*ethpb.AttesterSlashing, 0, len(attSlashings)) - for _, slashing := range attSlashings { - _, err := blocks.ProcessAttesterSlashing(ctx, head, slashing, v.SlashValidator) - if err != nil { - log.WithError(err).Warn("Proposer: invalid attester slashing") - continue - } - validAttSlashings = append(validAttSlashings, slashing) - } - exits := vs.ExitPool.PendingExits(head, req.Slot, false /*noLimit*/) - validExits := make([]*ethpb.SignedVoluntaryExit, 0, len(exits)) - for _, exit := range exits { - val, err := head.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex) - if err != nil { - log.WithError(err).Warn("Proposer: invalid exit") - continue - } - if err := blocks.VerifyExitAndSignature(val, head.Slot(), head.Fork(), exit, head.GenesisValidatorsRoot()); err != nil { - log.WithError(err).Warn("Proposer: invalid exit") - continue - } - validExits = append(validExits, exit) - } - - blk := &blockData{ - Slot: req.Slot, - ParentRoot: parentRoot, - Graffiti: graffiti, - ProposerIdx: idx, - Eth1Data: eth1Data, - Deposits: deposits, - Attestations: atts, - RandaoReveal: req.RandaoReveal, - ProposerSlashings: validProposerSlashings, - AttesterSlashings: validAttSlashings, - VoluntaryExits: validExits, - } - - if slots.ToEpoch(req.Slot) >= params.BeaconConfig().AltairForkEpoch { - syncAggregate, err := vs.getSyncAggregate(ctx, req.Slot-1, bytesutil.ToBytes32(parentRoot)) - if err != nil { - return nil, errors.Wrap(err, "could not compute the sync aggregate") - } - - blk.SyncAggregate = syncAggregate - } - - if slots.ToEpoch(req.Slot) >= params.BeaconConfig().BellatrixForkEpoch { - // We request the execution payload only if the validator is not registered with a relayer - registered, err := vs.validatorRegistered(ctx, idx) - if !registered || err != nil { - executionData, err := vs.getExecutionPayload(ctx, req.Slot, idx, bytesutil.ToBytes32(parentRoot), head) - if err != nil { - return nil, errors.Wrap(err, "could not get execution payload") - } - if slots.ToEpoch(req.Slot) >= params.BeaconConfig().CapellaForkEpoch { - p, err := executionData.PbV2() - if err != nil { - return nil, errors.Wrap(err, "could not get execution payload v2") - } - blk.ExecutionPayloadV2 = p - changes, err := vs.BLSChangesPool.BLSToExecChangesForInclusion(head) - if err != nil { - return nil, errors.Wrap(err, "could not pack BLSToExecutionChanges") - } - blk.BlsToExecutionChanges = changes - } else { - p, err := executionData.PbV1() - if err != nil { - return nil, errors.Wrap(err, "could not get execution payload v2") - } - blk.ExecutionPayload = p - } - } - } - - return blk, nil -} diff --git a/consensus-types/blocks/getters.go b/consensus-types/blocks/getters.go index e5cc18aced84..2bfc22024487 100644 --- a/consensus-types/blocks/getters.go +++ b/consensus-types/blocks/getters.go @@ -29,11 +29,63 @@ func (b *SignedBeaconBlock) Signature() [field_params.BLSSignatureLength]byte { return b.signature } +// SetSignature sets the signature of the signed beacon block. +func (b *SignedBeaconBlock) SetSignature(sig []byte) { + copy(b.signature[:], sig) +} + // Block returns the underlying beacon block object. func (b *SignedBeaconBlock) Block() interfaces.BeaconBlock { return b.block } +// SetBlock sets the underlying beacon block object. +func (b *SignedBeaconBlock) SetBlock(blk interfaces.BeaconBlock) error { + copied, err := blk.Copy() + if err != nil { + return err + } + b.block.slot = copied.Slot() + b.block.parentRoot = copied.ParentRoot() + b.block.stateRoot = copied.StateRoot() + b.block.stateRoot = copied.StateRoot() + b.block.proposerIndex = copied.ProposerIndex() + b.block.body.randaoReveal = copied.Body().RandaoReveal() + b.block.body.eth1Data = copied.Body().Eth1Data() + b.block.body.graffiti = copied.Body().Graffiti() + b.block.body.proposerSlashings = copied.Body().ProposerSlashings() + b.block.body.attesterSlashings = copied.Body().AttesterSlashings() + b.block.body.attestations = copied.Body().Attestations() + b.block.body.deposits = copied.Body().Deposits() + b.block.body.voluntaryExits = copied.Body().VoluntaryExits() + if b.version >= version.Altair { + syncAggregate, err := copied.Body().SyncAggregate() + if err != nil { + return err + } + b.block.body.syncAggregate = syncAggregate + } + if b.version >= version.Bellatrix { + executionData, err := copied.Body().Execution() + if err != nil { + return err + } + if b.block.body.isBlinded { + b.block.body.executionPayloadHeader = executionData + } else { + b.block.body.executionPayload = executionData + } + } + if b.version >= version.Capella { + changes, err := copied.Body().BLSToExecutionChanges() + if err != nil { + return err + } + b.block.body.blsToExecutionChanges = changes + } + return nil +} + // IsNil checks if the underlying beacon block is nil. func (b *SignedBeaconBlock) IsNil() bool { return b == nil || b.block.IsNil() @@ -458,16 +510,34 @@ func (b *BeaconBlock) Slot() types.Slot { return b.slot } +// SetSlot sets the respective slot of the block. +// This function is not thread safe, it is only used during block creation. +func (b *BeaconBlock) SetSlot(slot types.Slot) { + b.slot = slot +} + // ProposerIndex returns the proposer index of the beacon block. func (b *BeaconBlock) ProposerIndex() types.ValidatorIndex { return b.proposerIndex } +// SetProposerIndex sets the proposer index of the beacon block. +// This function is not thread safe, it is only used during block creation. +func (b *BeaconBlock) SetProposerIndex(proposerIndex types.ValidatorIndex) { + b.proposerIndex = proposerIndex +} + // ParentRoot returns the parent root of beacon block. func (b *BeaconBlock) ParentRoot() [field_params.RootLength]byte { return b.parentRoot } +// SetParentRoot sets the parent root of beacon block. +// This function is not thread safe, it is only used during block creation. +func (b *BeaconBlock) SetParentRoot(parentRoot []byte) { + copy(b.parentRoot[:], parentRoot) +} + // StateRoot returns the state root of the beacon block. func (b *BeaconBlock) StateRoot() [field_params.RootLength]byte { return b.stateRoot @@ -495,6 +565,11 @@ func (b *BeaconBlock) IsBlinded() bool { return b.body.isBlinded } +// SetBlinded sets the blinded flag of the beacon block. +func (b *BeaconBlock) SetBlinded(blinded bool) { + b.body.isBlinded = blinded +} + // Version of the underlying protobuf object. func (b *BeaconBlock) Version() int { return b.version @@ -738,6 +813,41 @@ func (b *BeaconBlock) AsSignRequestObject() (validatorpb.SignRequestObject, erro } } +func (b *BeaconBlock) Copy() (interfaces.BeaconBlock, error) { + if b == nil { + return nil, nil + } + + pb, err := b.Proto() + if err != nil { + return nil, err + } + switch b.version { + case version.Phase0: + cp := eth.CopyBeaconBlock(pb.(*eth.BeaconBlock)) + return initBlockFromProtoPhase0(cp) + case version.Altair: + cp := eth.CopyBeaconBlockAltair(pb.(*eth.BeaconBlockAltair)) + return initBlockFromProtoAltair(cp) + case version.Bellatrix: + if b.IsBlinded() { + cp := eth.CopyBlindedBeaconBlockBellatrix(pb.(*eth.BlindedBeaconBlockBellatrix)) + return initBlindedBlockFromProtoBellatrix(cp) + } + cp := eth.CopyBeaconBlockBellatrix(pb.(*eth.BeaconBlockBellatrix)) + return initBlockFromProtoBellatrix(cp) + case version.Capella: + if b.IsBlinded() { + cp := eth.CopyBlindedBeaconBlockCapella(pb.(*eth.BlindedBeaconBlockCapella)) + return initBlindedBlockFromProtoCapella(cp) + } + cp := eth.CopyBeaconBlockCapella(pb.(*eth.BeaconBlockCapella)) + return initBlockFromProtoCapella(cp) + default: + return nil, errIncorrectBlockVersion + } +} + // IsNil checks if the block body is nil. func (b *BeaconBlockBody) IsNil() bool { return b == nil @@ -748,41 +858,81 @@ func (b *BeaconBlockBody) RandaoReveal() [field_params.BLSSignatureLength]byte { return b.randaoReveal } +// SetRandaoReveal sets the randao reveal in the block body. +func (b *BeaconBlockBody) SetRandaoReveal(r []byte) { + copy(b.randaoReveal[:], r) +} + // Eth1Data returns the eth1 data in the block. func (b *BeaconBlockBody) Eth1Data() *eth.Eth1Data { return b.eth1Data } +// SetEth1Data sets the eth1 data in the block. +func (b *BeaconBlockBody) SetEth1Data(e *eth.Eth1Data) { + b.eth1Data = eth.CopyETH1Data(e) +} + // Graffiti returns the graffiti in the block. func (b *BeaconBlockBody) Graffiti() [field_params.RootLength]byte { return b.graffiti } +// SetGraffiti sets the graffiti in the block. +func (b *BeaconBlockBody) SetGraffiti(g []byte) { + copy(b.graffiti[:], g) +} + // ProposerSlashings returns the proposer slashings in the block. func (b *BeaconBlockBody) ProposerSlashings() []*eth.ProposerSlashing { return b.proposerSlashings } +// SetProposerSlashings sets the proposer slashings in the block. +func (b *BeaconBlockBody) SetProposerSlashings(p []*eth.ProposerSlashing) { + b.proposerSlashings = eth.CopyProposerSlashings(p) +} + // AttesterSlashings returns the attester slashings in the block. func (b *BeaconBlockBody) AttesterSlashings() []*eth.AttesterSlashing { return b.attesterSlashings } +// SetAttesterSlashings sets the attester slashings in the block. +func (b *BeaconBlockBody) SetAttesterSlashings(a []*eth.AttesterSlashing) { + b.attesterSlashings = eth.CopyAttesterSlashings(a) +} + // Attestations returns the stored attestations in the block. func (b *BeaconBlockBody) Attestations() []*eth.Attestation { return b.attestations } +// SetAttestations sets the attestations in the block. +func (b *BeaconBlockBody) SetAttestations(a []*eth.Attestation) { + b.attestations = eth.CopyAttestations(a) +} + // Deposits returns the stored deposits in the block. func (b *BeaconBlockBody) Deposits() []*eth.Deposit { return b.deposits } +// SetDeposits sets the deposits in the block. +func (b *BeaconBlockBody) SetDeposits(d []*eth.Deposit) { + b.deposits = eth.CopyDeposits(d) +} + // VoluntaryExits returns the voluntary exits in the block. func (b *BeaconBlockBody) VoluntaryExits() []*eth.SignedVoluntaryExit { return b.voluntaryExits } +// SetVoluntaryExits sets the voluntary exits in the block. +func (b *BeaconBlockBody) SetVoluntaryExits(v []*eth.SignedVoluntaryExit) { + b.voluntaryExits = eth.CopySignedVoluntaryExits(v) +} + // SyncAggregate returns the sync aggregate in the block. func (b *BeaconBlockBody) SyncAggregate() (*eth.SyncAggregate, error) { if b.version == version.Phase0 { @@ -791,6 +941,15 @@ func (b *BeaconBlockBody) SyncAggregate() (*eth.SyncAggregate, error) { return b.syncAggregate, nil } +// SetSyncAggregate sets the sync aggregate in the block. +func (b *BeaconBlockBody) SetSyncAggregate(s *eth.SyncAggregate) error { + if b.version == version.Phase0 { + return ErrNotSupported("SyncAggregate", b.version) + } + b.syncAggregate = eth.CopySyncAggregate(s) + return nil +} + // Execution returns the execution payload of the block body. func (b *BeaconBlockBody) Execution() (interfaces.ExecutionData, error) { switch b.version { @@ -843,6 +1002,19 @@ func (b *BeaconBlockBody) Execution() (interfaces.ExecutionData, error) { } } +// SetExecution sets the execution payload of the block body. +func (b *BeaconBlockBody) SetExecution(e interfaces.ExecutionData) error { + if b.version == version.Phase0 || b.version == version.Altair { + return ErrNotSupported("Execution", b.version) + } + if b.isBlinded { + b.executionPayloadHeader = e // TODO: Copy? + return nil + } + b.executionPayload = e + return nil +} + func (b *BeaconBlockBody) BLSToExecutionChanges() ([]*eth.SignedBLSToExecutionChange, error) { if b.version < version.Capella { return nil, ErrNotSupported("BLSToExecutionChanges", b.version) @@ -850,6 +1022,15 @@ func (b *BeaconBlockBody) BLSToExecutionChanges() ([]*eth.SignedBLSToExecutionCh return b.blsToExecutionChanges, nil } +// SetBLSToExecutionChanges sets the BLS to execution changes in the block. +func (b *BeaconBlockBody) SetBLSToExecutionChanges(blsToExecutionChanges []*eth.SignedBLSToExecutionChange) error { + if b.version < version.Capella { + return ErrNotSupported("BLSToExecutionChanges", b.version) + } + b.blsToExecutionChanges = eth.CopyBLSToExecutionChanges(blsToExecutionChanges) + return nil +} + // HashTreeRoot returns the ssz root of the block body. func (b *BeaconBlockBody) HashTreeRoot() ([field_params.RootLength]byte, error) { pb, err := b.Proto() diff --git a/consensus-types/interfaces/beacon_block.go b/consensus-types/interfaces/beacon_block.go index 258a2c4b797b..99c787dbb548 100644 --- a/consensus-types/interfaces/beacon_block.go +++ b/consensus-types/interfaces/beacon_block.go @@ -14,7 +14,9 @@ import ( // a signed beacon block. type SignedBeaconBlock interface { Block() BeaconBlock + SetBlock(BeaconBlock) error Signature() [field_params.BLSSignatureLength]byte + SetSignature(sig []byte) IsNil() bool Copy() (SignedBeaconBlock, error) Proto() (proto.Message, error) @@ -37,13 +39,17 @@ type SignedBeaconBlock interface { // employed by an object that is a beacon block. type BeaconBlock interface { Slot() types.Slot + SetSlot(slot types.Slot) ProposerIndex() types.ValidatorIndex + SetProposerIndex(idx types.ValidatorIndex) ParentRoot() [field_params.RootLength]byte + SetParentRoot([]byte) StateRoot() [field_params.RootLength]byte SetStateRoot([]byte) Body() BeaconBlockBody IsNil() bool IsBlinded() bool + SetBlinded(bool) HashTreeRoot() ([field_params.RootLength]byte, error) Proto() (proto.Message, error) ssz.Marshaler @@ -51,25 +57,37 @@ type BeaconBlock interface { ssz.HashRoot Version() int AsSignRequestObject() (validatorpb.SignRequestObject, error) + Copy() (BeaconBlock, error) } // BeaconBlockBody describes the method set employed by an object // that is a beacon block body. type BeaconBlockBody interface { RandaoReveal() [field_params.BLSSignatureLength]byte + SetRandaoReveal([]byte) Eth1Data() *ethpb.Eth1Data + SetEth1Data(*ethpb.Eth1Data) Graffiti() [field_params.RootLength]byte + SetGraffiti([]byte) ProposerSlashings() []*ethpb.ProposerSlashing + SetProposerSlashings([]*ethpb.ProposerSlashing) AttesterSlashings() []*ethpb.AttesterSlashing + SetAttesterSlashings([]*ethpb.AttesterSlashing) Attestations() []*ethpb.Attestation + SetAttestations([]*ethpb.Attestation) Deposits() []*ethpb.Deposit + SetDeposits([]*ethpb.Deposit) VoluntaryExits() []*ethpb.SignedVoluntaryExit + SetVoluntaryExits([]*ethpb.SignedVoluntaryExit) SyncAggregate() (*ethpb.SyncAggregate, error) + SetSyncAggregate(*ethpb.SyncAggregate) error IsNil() bool HashTreeRoot() ([field_params.RootLength]byte, error) Proto() (proto.Message, error) Execution() (ExecutionData, error) + SetExecution(ExecutionData) error BLSToExecutionChanges() ([]*ethpb.SignedBLSToExecutionChange, error) + SetBLSToExecutionChanges([]*ethpb.SignedBLSToExecutionChange) error } // ExecutionData represents execution layer information that is contained diff --git a/consensus-types/mock/block.go b/consensus-types/mock/block.go index 2761ac22372e..a54cc89b7f66 100644 --- a/consensus-types/mock/block.go +++ b/consensus-types/mock/block.go @@ -94,6 +94,14 @@ func (SignedBeaconBlock) Header() (*eth.SignedBeaconBlockHeader, error) { panic("implement me") } +func (SignedBeaconBlock) SetBlock(_ interfaces.BeaconBlock) error { + panic("implement me") +} + +func (SignedBeaconBlock) SetSignature(_ []byte) { + panic("implement me") +} + type BeaconBlock struct { Htr [field_params.RootLength]byte HtrErr error @@ -165,6 +173,30 @@ func (BeaconBlock) Version() int { panic("implement me") } +func (BeaconBlock) ToBlinded() (interfaces.BeaconBlock, error) { + panic("implement me") +} + +func (BeaconBlock) SetSlot(_ types.Slot) { + panic("implement me") +} + +func (BeaconBlock) SetProposerIndex(_ types.ValidatorIndex) { + panic("implement me") +} + +func (BeaconBlock) SetParentRoot(_ []byte) { + panic("implement me") +} + +func (BeaconBlock) SetBlinded(_ bool) { + panic("implement me") +} + +func (BeaconBlock) Copy() (interfaces.BeaconBlock, error) { + panic("implement me") +} + type BeaconBlockBody struct{} func (BeaconBlockBody) RandaoReveal() [field_params.BLSSignatureLength]byte { @@ -227,6 +259,50 @@ func (b *BeaconBlock) SetStateRoot(root []byte) { panic("implement me") } +func (b *BeaconBlockBody) SetRandaoReveal([]byte) { + panic("implement me") +} + +func (b *BeaconBlockBody) SetEth1Data(*eth.Eth1Data) { + panic("implement me") +} + +func (b *BeaconBlockBody) SetGraffiti([]byte) { + panic("implement me") +} + +func (b *BeaconBlockBody) SetProposerSlashings([]*eth.ProposerSlashing) { + panic("implement me") +} + +func (b *BeaconBlockBody) SetAttesterSlashings([]*eth.AttesterSlashing) { + panic("implement me") +} + +func (b *BeaconBlockBody) SetAttestations([]*eth.Attestation) { + panic("implement me") +} + +func (b *BeaconBlockBody) SetDeposits([]*eth.Deposit) { + panic("implement me") +} + +func (b *BeaconBlockBody) SetVoluntaryExits([]*eth.SignedVoluntaryExit) { + panic("implement me") +} + +func (b *BeaconBlockBody) SetSyncAggregate(*eth.SyncAggregate) error { + panic("implement me") +} + +func (b *BeaconBlockBody) SetExecution(interfaces.ExecutionData) error { + panic("implement me") +} + +func (b *BeaconBlockBody) SetBLSToExecutionChanges([]*eth.SignedBLSToExecutionChange) error { + panic("implement me") +} + var _ interfaces.SignedBeaconBlock = &SignedBeaconBlock{} var _ interfaces.BeaconBlock = &BeaconBlock{} var _ interfaces.BeaconBlockBody = &BeaconBlockBody{} diff --git a/testing/spectest/shared/common/forkchoice/service.go b/testing/spectest/shared/common/forkchoice/service.go index 1e7a0467305d..980de9c7916f 100644 --- a/testing/spectest/shared/common/forkchoice/service.go +++ b/testing/spectest/shared/common/forkchoice/service.go @@ -20,6 +20,7 @@ import ( "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute" + types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" @@ -78,13 +79,13 @@ type engineMock struct { payloadStatus error } -func (m *engineMock) GetPayload(context.Context, [8]byte) (*pb.ExecutionPayload, error) { +func (m *engineMock) GetPayload(context.Context, [8]byte, types.Slot) (interfaces.ExecutionData, error) { return nil, nil } func (m *engineMock) GetPayloadV2(context.Context, [8]byte) (*pb.ExecutionPayloadCapella, error) { return nil, nil } -func (m *engineMock) ForkchoiceUpdated(context.Context, *pb.ForkchoiceState, *pb.PayloadAttributes) (*pb.PayloadIDBytes, []byte, error) { +func (m *engineMock) ForkchoiceUpdated(context.Context, *pb.ForkchoiceState, payloadattribute.Attributer) (*pb.PayloadIDBytes, []byte, error) { return nil, m.latestValidHash, m.payloadStatus } func (m *engineMock) ForkchoiceUpdatedV2(context.Context, *pb.ForkchoiceState, *pb.PayloadAttributesV2) (*pb.PayloadIDBytes, []byte, error) {