prysm-pulse/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_phase0.go
terence tsao a80b1c252a
Refactor rpc proposer into smaller files (#9796)
* Refactor rpc proposer into smaller files

* Update BUILD.bazel

* Fix test

* Update BUILD.bazel
2021-10-18 11:35:32 -05:00

174 lines
5.9 KiB
Go

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 := &ethpb.BeaconBlock{
Slot: req.Slot,
ParentRoot: blkData.ParentRoot,
StateRoot: stateRoot,
ProposerIndex: blkData.ProposerIdx,
Body: &ethpb.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(
&ethpb.SignedBeaconBlock{Block: blk, Signature: make([]byte, 96)},
),
)
if err != nil {
interop.WriteBlockToDisk(wrapper.WrappedPhase0SignedBeaconBlock(&ethpb.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
}