package validator import ( "context" "fmt" types "github.com/prysmaticlabs/eth2-types" "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/core/transition" "github.com/prysmaticlabs/prysm/beacon-chain/core/transition/interop" v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" "github.com/prysmaticlabs/prysm/config/features" "github.com/prysmaticlabs/prysm/config/params" "github.com/prysmaticlabs/prysm/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper" "go.opencensus.io/trace" ) // blockData required to create a beacon block. type blockData struct { ParentRoot []byte Graffiti [32]byte ProposerIdx types.ValidatorIndex Eth1Data *ethpb.Eth1Data Deposits []*ethpb.Deposit Attestations []*ethpb.Attestation ProposerSlashings []*ethpb.ProposerSlashing AttesterSlashings []*ethpb.AttesterSlashing VoluntaryExits []*ethpb.SignedVoluntaryExit } 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: req.Slot, ParentRoot: blkData.ParentRoot, StateRoot: stateRoot, ProposerIndex: blkData.ProposerIdx, Body: ðpb.BeaconBlockBody{ Eth1Data: blkData.Eth1Data, Deposits: blkData.Deposits, Attestations: blkData.Attestations, RandaoReveal: req.RandaoReveal, ProposerSlashings: blkData.ProposerSlashings, AttesterSlashings: blkData.AttesterSlashings, VoluntaryExits: blkData.VoluntaryExits, Graffiti: blkData.Graffiti[:], }, } // Compute state root with the newly constructed block. stateRoot, err = vs.computeStateRoot( ctx, wrapper.WrappedPhase0SignedBeaconBlock( ðpb.SignedBeaconBlock{Block: blk, Signature: make([]byte, 96)}, ), ) if err != nil { interop.WriteBlockToDisk(wrapper.WrappedPhase0SignedBeaconBlock(ðpb.SignedBeaconBlock{Block: blk}), true /*failed*/) return nil, fmt.Errorf("could not compute state root: %v", err) } 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") } // 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) } if features.Get().EnableNextSlotStateCache { 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) } } else { head, err = transition.ProcessSlots(ctx, head, req.Slot) if err != nil { return nil, fmt.Errorf("could not advance slot 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.GenesisValidatorRoot()); err != nil { log.WithError(err).Warn("Proposer: invalid exit") continue } validExits = append(validExits, exit) } return &blockData{ ParentRoot: parentRoot, Graffiti: graffiti, ProposerIdx: idx, Eth1Data: eth1Data, Deposits: deposits, Attestations: atts, ProposerSlashings: validProposerSlashings, AttesterSlashings: validAttSlashings, VoluntaryExits: validExits, }, nil }