diff --git a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go index 4234f791f1..11dc45de45 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go +++ b/beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" "strings" + "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -18,6 +19,8 @@ import ( "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/kv" + "github.com/prysmaticlabs/prysm/v4/beacon-chain/state" + "github.com/prysmaticlabs/prysm/v4/config/features" "github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" @@ -82,25 +85,6 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) ( sBlk.SetRandaoReveal(req.RandaoReveal) sBlk.SetParentRoot(parentRoot[:]) - // Set eth1 data. - eth1Data, err := vs.eth1DataMajorityVote(ctx, head) - if err != nil { - eth1Data = ðpb.Eth1Data{DepositRoot: params.BeaconConfig().ZeroHash[:], BlockHash: params.BeaconConfig().ZeroHash[:]} - log.WithError(err).Error("Could not get eth1data") - } - sBlk.SetEth1Data(eth1Data) - - // Set deposit and attestation. - deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data) // TODO: split attestations and deposits - if err != nil { - sBlk.SetDeposits([]*ethpb.Deposit{}) - sBlk.SetAttestations([]*ethpb.Attestation{}) - log.WithError(err).Error("Could not pack deposits and attestations") - } else { - sBlk.SetDeposits(deposits) - sBlk.SetAttestations(atts) - } - // Set proposer index. idx, err := helpers.BeaconProposerIndex(ctx, head) if err != nil { @@ -108,25 +92,50 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) ( } sBlk.SetProposerIndex(idx) - // Set slashings. - validProposerSlashings, validAttSlashings := vs.getSlashings(ctx, head) - sBlk.SetProposerSlashings(validProposerSlashings) - sBlk.SetAttesterSlashings(validAttSlashings) + if features.Get().BuildBlockParallel { + if err := vs.BuildBlockParallel(ctx, sBlk, head); err != nil { + return nil, errors.Wrap(err, "could not build block in parallel") + } + } else { + // Set eth1 data. + eth1Data, err := vs.eth1DataMajorityVote(ctx, head) + if err != nil { + eth1Data = ðpb.Eth1Data{DepositRoot: params.BeaconConfig().ZeroHash[:], BlockHash: params.BeaconConfig().ZeroHash[:]} + log.WithError(err).Error("Could not get eth1data") + } + sBlk.SetEth1Data(eth1Data) - // Set exits. - sBlk.SetVoluntaryExits(vs.getExits(head, req.Slot)) + // Set deposit and attestation. + deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data) // TODO: split attestations and deposits + if err != nil { + sBlk.SetDeposits([]*ethpb.Deposit{}) + sBlk.SetAttestations([]*ethpb.Attestation{}) + log.WithError(err).Error("Could not pack deposits and attestations") + } else { + sBlk.SetDeposits(deposits) + sBlk.SetAttestations(atts) + } - // Set sync aggregate. New in Altair. - vs.setSyncAggregate(ctx, sBlk) + // Set slashings. + validProposerSlashings, validAttSlashings := vs.getSlashings(ctx, head) + sBlk.SetProposerSlashings(validProposerSlashings) + sBlk.SetAttesterSlashings(validAttSlashings) - // Set execution data. New in Bellatrix. - if err := vs.setExecutionData(ctx, sBlk, head); err != nil { - return nil, status.Errorf(codes.Internal, "Could not set execution data: %v", err) + // Set exits. + sBlk.SetVoluntaryExits(vs.getExits(head, req.Slot)) + + // Set sync aggregate. New in Altair. + vs.setSyncAggregate(ctx, sBlk) + + // Set execution data. New in Bellatrix. + if err := vs.setExecutionData(ctx, sBlk, head); err != nil { + return nil, status.Errorf(codes.Internal, "Could not set execution data: %v", err) + } + + // Set bls to execution change. New in Capella. + vs.setBlsToExecData(sBlk, head) } - // Set bls to execution change. New in Capella. - vs.setBlsToExecData(sBlk, head) - sr, err := vs.computeStateRoot(ctx, sBlk) if err != nil { return nil, status.Errorf(codes.Internal, "Could not compute state root: %v", err) @@ -155,6 +164,56 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) ( return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Phase0{Phase0: pb.(*ethpb.BeaconBlock)}}, nil } +func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.SignedBeaconBlock, head state.BeaconState) error { + // Build consensus fields in background + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + + // Set eth1 data. + eth1Data, err := vs.eth1DataMajorityVote(ctx, head) + if err != nil { + eth1Data = ðpb.Eth1Data{DepositRoot: params.BeaconConfig().ZeroHash[:], BlockHash: params.BeaconConfig().ZeroHash[:]} + log.WithError(err).Error("Could not get eth1data") + } + sBlk.SetEth1Data(eth1Data) + + // Set deposit and attestation. + deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data) // TODO: split attestations and deposits + if err != nil { + sBlk.SetDeposits([]*ethpb.Deposit{}) + sBlk.SetAttestations([]*ethpb.Attestation{}) + log.WithError(err).Error("Could not pack deposits and attestations") + } else { + sBlk.SetDeposits(deposits) + sBlk.SetAttestations(atts) + } + + // Set slashings. + validProposerSlashings, validAttSlashings := vs.getSlashings(ctx, head) + sBlk.SetProposerSlashings(validProposerSlashings) + sBlk.SetAttesterSlashings(validAttSlashings) + + // Set exits. + sBlk.SetVoluntaryExits(vs.getExits(head, sBlk.Block().Slot())) + + // Set sync aggregate. New in Altair. + vs.setSyncAggregate(ctx, sBlk) + + // Set bls to execution change. New in Capella. + vs.setBlsToExecData(sBlk, head) + }() + + if err := vs.setExecutionData(ctx, sBlk, head); err != nil { + return status.Errorf(codes.Internal, "Could not set execution data: %v", err) + } + + wg.Wait() // Wait until block is built via consensus and execution fields. + + return nil +} + // ProposeBeaconBlock is called by a proposer during its assigned slot to create a block in an attempt // to get it processed by the beacon node as the canonical head. func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) { diff --git a/config/features/config.go b/config/features/config.go index b0889cb8ac..907e1b08a0 100644 --- a/config/features/config.go +++ b/config/features/config.go @@ -67,6 +67,8 @@ type Flags struct { PrepareAllPayloads bool // PrepareAllPayloads informs the engine to prepare a block on every slot. + BuildBlockParallel bool // BuildBlockParallel builds beacon block for proposer in parallel. + // KeystoreImportDebounceInterval specifies the time duration the validator waits to reload new keys if they have // changed on disk. This feature is for advanced use cases only. KeystoreImportDebounceInterval time.Duration @@ -212,6 +214,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error { logEnabled(prepareAllPayloads) cfg.PrepareAllPayloads = true } + if ctx.IsSet(buildBlockParallel.Name) { + logEnabled(buildBlockParallel) + cfg.BuildBlockParallel = true + } Init(cfg) return nil } diff --git a/config/features/flags.go b/config/features/flags.go index 862dc4234b..4ebe55416c 100644 --- a/config/features/flags.go +++ b/config/features/flags.go @@ -118,6 +118,10 @@ var ( Name: "prepare-all-payloads", Usage: "Informs the engine to prepare all local payloads. Useful for relayers and builders", } + buildBlockParallel = &cli.BoolFlag{ + Name: "build-block-parallel", + Usage: "Builds a beacon block in parallel for consensus and execution. It results in faster block construction time", + } ) // devModeFlags holds list of flags that are set when development mode is on. @@ -164,6 +168,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c enableVerboseSigVerification, enableOptionalEngineMethods, prepareAllPayloads, + buildBlockParallel, }...)...) // E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E.