Proposer: better handling of blobs bundle (#12956)

* Proposer better handling of blobs bundle

* Reset bundles after conversion

* Reset earlier

* Proposer better handling of blobs bundle

* Reset bundles after conversion

* Reset earlier

* Fix conflict

* use correct blindBlobsBundle

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
terencechain
2023-10-16 09:41:24 -07:00
committed by GitHub
parent 58cdb29ef3
commit 2f378a045a
7 changed files with 158 additions and 157 deletions

View File

@@ -44,6 +44,12 @@ const (
eth1dataTimeout = 2 * time.Second
)
// blindBlobsBundle holds the KZG commitments and other relevant sidecar data for a builder's beacon block.
var blindBlobsBundle *enginev1.BlindedBlobsBundle
// fullBlobsBundle holds the KZG commitments and other relevant sidecar data for a local beacon block.
var fullBlobsBundle *enginev1.BlobsBundle
// GetBeaconBlock is called by a proposer during its assigned slot to request a block to sign
// by passing in the slot and the signed randao reveal of the slot.
func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) {
@@ -106,10 +112,7 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
}
sBlk.SetProposerIndex(idx)
var blobBundle *enginev1.BlobsBundle
var blindBlobBundle *enginev1.BlindedBlobsBundle
blindBlobBundle, blobBundle, err = vs.BuildBlockParallel(ctx, sBlk, head, req.SkipMevBoost)
if err != nil {
if err = vs.BuildBlockParallel(ctx, sBlk, head, false); err != nil {
return nil, errors.Wrap(err, "could not build block in parallel")
}
@@ -119,11 +122,14 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
}
sBlk.SetStateRoot(sr)
fullBlobs, err := blobsBundleToSidecars(blobBundle, sBlk.Block())
fullBlobs, err := blobsBundleToSidecars(fullBlobsBundle, sBlk.Block())
fullBlobsBundle = nil // Reset full blobs bundle after use.
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not convert blobs bundle to sidecar: %v", err)
}
blindBlobs, err := blindBlobsBundleToSidecars(blindBlobBundle, sBlk.Block())
blindBlobs, err := blindBlobsBundleToSidecars(blindBlobsBundle, sBlk.Block())
blindBlobsBundle = nil // Reset blind blobs bundle after use.
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not convert blind blobs bundle to sidecar: %v", err)
}
@@ -137,7 +143,7 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
return vs.constructGenericBeaconBlock(sBlk, blindBlobs, fullBlobs)
}
func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.SignedBeaconBlock, head state.BeaconState, skipMevBoost bool) (*enginev1.BlindedBlobsBundle, *enginev1.BlobsBundle, error) {
func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.SignedBeaconBlock, head state.BeaconState, skipMevBoost bool) error {
// Build consensus fields in background
var wg sync.WaitGroup
wg.Add(1)
@@ -178,17 +184,16 @@ func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.Signed
vs.setBlsToExecData(sBlk, head)
}()
localPayload, blobsBundle, overrideBuilder, err := vs.getLocalPayloadAndBlobs(ctx, sBlk.Block(), head)
localPayload, overrideBuilder, err := vs.getLocalPayloadAndBlobs(ctx, sBlk.Block(), head)
if err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not get local payload: %v", err)
return status.Errorf(codes.Internal, "Could not get local payload: %v", err)
}
// There's no reason to try to get a builder bid if local override is true.
var builderPayload interfaces.ExecutionData
var blindBlobsBundle *enginev1.BlindedBlobsBundle
overrideBuilder = overrideBuilder || skipMevBoost // Skip using mev-boost if requested by the caller.
if !overrideBuilder {
builderPayload, blindBlobsBundle, err = vs.getBuilderPayloadAndBlobs(ctx, sBlk.Block().Slot(), sBlk.Block().ProposerIndex())
builderPayload, err = vs.getBuilderPayloadAndBlobs(ctx, sBlk.Block().Slot(), sBlk.Block().ProposerIndex())
if err != nil {
builderGetPayloadMissCount.Inc()
log.WithError(err).Error("Could not get builder payload")
@@ -196,16 +201,12 @@ func (vs *Server) BuildBlockParallel(ctx context.Context, sBlk interfaces.Signed
}
if err := setExecutionData(ctx, sBlk, localPayload, builderPayload); err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not set execution data: %v", err)
}
if err := setKzgCommitments(sBlk, blobsBundle, blindBlobsBundle); err != nil {
return nil, nil, status.Errorf(codes.Internal, "Could not set kzg commitment: %v", err)
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 blindBlobsBundle, blobsBundle, nil
return nil
}
// ProposeBeaconBlock is called by a proposer during its assigned slot to create a block in an attempt

View File

@@ -20,7 +20,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/encoding/ssz"
"github.com/prysmaticlabs/prysm/v4/monitoring/tracing"
"github.com/prysmaticlabs/prysm/v4/network/forks"
enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/time/slots"
"github.com/sirupsen/logrus"
@@ -57,7 +56,7 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
// Use local payload if builder payload is nil.
if builderPayload == nil {
return blk.SetExecution(localPayload)
return setLocalExecution(blk, localPayload)
}
switch {
@@ -70,14 +69,14 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
builderValueGwei, err := builderPayload.ValueInGwei()
if err != nil {
log.WithError(err).Warn("Proposer: failed to get builder payload value") // Default to local if can't get builder value.
return blk.SetExecution(localPayload)
return setLocalExecution(blk, localPayload)
}
withdrawalsMatched, err := matchingWithdrawalsRoot(localPayload, builderPayload)
if err != nil {
tracing.AnnotateError(span, err)
log.WithError(err).Warn("Proposer: failed to match withdrawals root")
return blk.SetExecution(localPayload)
return setLocalExecution(blk, localPayload)
}
// Use builder payload if the following in true:
@@ -88,10 +87,10 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
// If we can't get the builder value, just use local block.
if higherValueBuilder && withdrawalsMatched { // Builder value is higher and withdrawals match.
blk.SetBlinded(true)
if err := blk.SetExecution(builderPayload); err != nil {
if err := setBuilderExecution(blk, builderPayload); err != nil {
log.WithError(err).Warn("Proposer: failed to set builder payload")
blk.SetBlinded(false)
return blk.SetExecution(localPayload)
return setLocalExecution(blk, localPayload)
} else {
return nil
}
@@ -109,13 +108,13 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
trace.Int64Attribute("localBoostPercentage", int64(boost)), // lint:ignore uintcast -- This is OK for tracing.
trace.Int64Attribute("builderGweiValue", int64(builderValueGwei)), // lint:ignore uintcast -- This is OK for tracing.
)
return blk.SetExecution(localPayload)
return setLocalExecution(blk, localPayload)
default: // Bellatrix case.
blk.SetBlinded(true)
if err := blk.SetExecution(builderPayload); err != nil {
if err := setBuilderExecution(blk, builderPayload); err != nil {
log.WithError(err).Warn("Proposer: failed to set builder payload")
blk.SetBlinded(false)
return blk.SetExecution(localPayload)
return setLocalExecution(blk, localPayload)
} else {
return nil
}
@@ -124,26 +123,26 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
// 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 primitives.Slot, idx primitives.ValidatorIndex) (interfaces.ExecutionData, *enginev1.BlindedBlobsBundle, error) {
func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot primitives.Slot, idx primitives.ValidatorIndex) (interfaces.ExecutionData, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.getPayloadHeaderFromBuilder")
defer span.End()
if slots.ToEpoch(slot) < params.BeaconConfig().BellatrixForkEpoch {
return nil, nil, errors.New("can't get payload header from builder before bellatrix epoch")
return nil, errors.New("can't get payload header from builder before bellatrix epoch")
}
b, err := vs.HeadFetcher.HeadBlock(ctx)
if err != nil {
return nil, nil, err
return nil, err
}
h, err := b.Block().Body().Execution()
if err != nil {
return nil, nil, errors.Wrap(err, "failed to get execution header")
return nil, errors.Wrap(err, "failed to get execution header")
}
pk, err := vs.HeadFetcher.HeadValidatorIndexToPublicKey(ctx, idx)
if err != nil {
return nil, nil, err
return nil, err
}
ctx, cancel := context.WithTimeout(ctx, blockBuilderTimeout)
@@ -151,72 +150,71 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot primitiv
signedBid, err := vs.BlockBuilder.GetHeader(ctx, slot, bytesutil.ToBytes32(h.BlockHash()), pk)
if err != nil {
return nil, nil, err
return nil, err
}
if signedBid.IsNil() {
return nil, nil, errors.New("builder returned nil bid")
return nil, errors.New("builder returned nil bid")
}
fork, err := forks.Fork(slots.ToEpoch(slot))
if err != nil {
return nil, nil, errors.Wrap(err, "unable to get fork information")
return nil, errors.Wrap(err, "unable to get fork information")
}
forkName, ok := params.BeaconConfig().ForkVersionNames[bytesutil.ToBytes4(fork.CurrentVersion)]
if !ok {
return nil, nil, errors.New("unable to find current fork in schedule")
return nil, errors.New("unable to find current fork in schedule")
}
if !strings.EqualFold(version.String(signedBid.Version()), forkName) {
return nil, nil, fmt.Errorf("builder bid response version: %d is different from head block version: %d for epoch %d", signedBid.Version(), b.Version(), slots.ToEpoch(slot))
return nil, fmt.Errorf("builder bid response version: %d is different from head block version: %d for epoch %d", signedBid.Version(), b.Version(), slots.ToEpoch(slot))
}
bid, err := signedBid.Message()
if err != nil {
return nil, nil, errors.Wrap(err, "could not get bid")
return nil, errors.Wrap(err, "could not get bid")
}
if bid.IsNil() {
return nil, nil, errors.New("builder returned nil bid")
return nil, errors.New("builder returned nil bid")
}
v := bytesutil.LittleEndianBytesToBigInt(bid.Value())
if v.String() == "0" {
return nil, nil, errors.New("builder returned header with 0 bid amount")
return nil, errors.New("builder returned header with 0 bid amount")
}
header, err := bid.Header()
if err != nil {
return nil, nil, errors.Wrap(err, "could not get bid header")
return nil, errors.Wrap(err, "could not get bid header")
}
txRoot, err := header.TransactionsRoot()
if err != nil {
return nil, nil, errors.Wrap(err, "could not get transaction root")
return nil, errors.Wrap(err, "could not get transaction root")
}
if bytesutil.ToBytes32(txRoot) == emptyTransactionsRoot {
return nil, nil, errors.New("builder returned header with an empty tx root")
return nil, errors.New("builder returned header with an empty tx root")
}
if !bytes.Equal(header.ParentHash(), h.BlockHash()) {
return nil, nil, fmt.Errorf("incorrect parent hash %#x != %#x", header.ParentHash(), h.BlockHash())
return nil, fmt.Errorf("incorrect parent hash %#x != %#x", header.ParentHash(), h.BlockHash())
}
t, err := slots.ToTime(uint64(vs.TimeFetcher.GenesisTime().Unix()), slot)
if err != nil {
return nil, nil, err
return nil, err
}
if header.Timestamp() != uint64(t.Unix()) {
return nil, nil, fmt.Errorf("incorrect timestamp %d != %d", header.Timestamp(), uint64(t.Unix()))
return nil, fmt.Errorf("incorrect timestamp %d != %d", header.Timestamp(), uint64(t.Unix()))
}
if err := validateBuilderSignature(signedBid); err != nil {
return nil, nil, errors.Wrap(err, "could not validate builder signature")
return nil, errors.Wrap(err, "could not validate builder signature")
}
var bundle *enginev1.BlindedBlobsBundle
if bid.Version() >= version.Deneb {
bundle, err = bid.BlindedBlobsBundle()
blindBlobsBundle, err = bid.BlindedBlobsBundle()
if err != nil {
return nil, nil, errors.Wrap(err, "could not get blinded blobs bundle")
return nil, errors.Wrap(err, "could not get blinded blobs bundle")
}
if bundle != nil {
log.WithField("blindBlobCount", len(bundle.BlobRoots))
if blindBlobsBundle != nil {
log.WithField("blindBlobCount", len(blindBlobsBundle.BlobRoots))
}
}
@@ -235,7 +233,7 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot primitiv
trace.StringAttribute("blockHash", fmt.Sprintf("%#x", header.BlockHash())),
)
return header, bundle, nil
return header, nil
}
// Validates builder signature and returns an error if the signature is invalid.
@@ -282,3 +280,59 @@ func matchingWithdrawalsRoot(local, builder interfaces.ExecutionData) (bool, err
}
return true, nil
}
// setLocalExecution sets the execution context for a local beacon block.
// It delegates to setExecution for the actual work.
func setLocalExecution(blk interfaces.SignedBeaconBlock, execution interfaces.ExecutionData) error {
var kzgCommitments [][]byte
if fullBlobsBundle != nil {
kzgCommitments = fullBlobsBundle.KzgCommitments
}
return setExecution(blk, execution, false, kzgCommitments)
}
// setBuilderExecution sets the execution context for a builder's beacon block.
// It delegates to setExecution for the actual work.
func setBuilderExecution(blk interfaces.SignedBeaconBlock, execution interfaces.ExecutionData) error {
var kzgCommitments [][]byte
if blindBlobsBundle != nil {
kzgCommitments = blindBlobsBundle.KzgCommitments
}
return setExecution(blk, execution, true, kzgCommitments)
}
// setExecution sets the execution context for a beacon block. It also sets KZG commitments based on the block version.
// The function is designed to be flexible and handle both local and builder executions.
func setExecution(blk interfaces.SignedBeaconBlock, execution interfaces.ExecutionData, isBlinded bool, kzgCommitments [][]byte) error {
if execution == nil {
return errors.New("execution is nil")
}
// Set the blinded status of the block
blk.SetBlinded(isBlinded)
// Set the execution data for the block
errMessage := "failed to set local execution"
if isBlinded {
errMessage = "failed to set builder execution"
}
if err := blk.SetExecution(execution); err != nil {
return errors.Wrap(err, errMessage)
}
// If the block version is below Deneb, no further actions are needed
if blk.Version() < version.Deneb {
return nil
}
// Set the KZG commitments for the block
errMessage = "failed to set local kzg commitments"
if isBlinded {
errMessage = "failed to set builder kzg commitments"
}
if err := blk.SetBlobKzgCommitments(kzgCommitments); err != nil {
return errors.Wrap(err, errMessage)
}
return nil
}

View File

@@ -78,9 +78,9 @@ func TestServer_setExecutionData(t *testing.T) {
blk, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockCapella())
require.NoError(t, err)
b := blk.Block()
localPayload, _, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
localPayload, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
require.NoError(t, err)
builderPayload, _, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
builderPayload, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
require.NoError(t, err)
require.NoError(t, setExecutionData(context.Background(), blk, localPayload, builderPayload))
e, err := blk.Block().Body().Execution()
@@ -137,9 +137,9 @@ func TestServer_setExecutionData(t *testing.T) {
vs.HeadFetcher = chain
b := blk.Block()
localPayload, _, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
localPayload, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
require.NoError(t, err)
builderPayload, _, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
builderPayload, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
require.NoError(t, err)
require.NoError(t, setExecutionData(context.Background(), blk, localPayload, builderPayload))
e, err := blk.Block().Body().Execution()
@@ -199,9 +199,9 @@ func TestServer_setExecutionData(t *testing.T) {
vs.HeadFetcher = chain
b := blk.Block()
localPayload, _, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
localPayload, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
require.NoError(t, err)
builderPayload, _, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
builderPayload, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
require.NoError(t, err)
require.NoError(t, setExecutionData(context.Background(), blk, localPayload, builderPayload))
e, err := blk.Block().Body().Execution()
@@ -213,9 +213,9 @@ func TestServer_setExecutionData(t *testing.T) {
require.NoError(t, err)
vs.ExecutionEngineCaller = &powtesting.EngineClient{PayloadIDBytes: id, ExecutionPayloadCapella: &v1.ExecutionPayloadCapella{BlockNumber: 3}, BlockValue: 2}
b := blk.Block()
localPayload, _, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
localPayload, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
require.NoError(t, err)
builderPayload, _, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
builderPayload, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
require.NoError(t, err)
require.NoError(t, setExecutionData(context.Background(), blk, localPayload, builderPayload))
e, err := blk.Block().Body().Execution()
@@ -233,9 +233,9 @@ func TestServer_setExecutionData(t *testing.T) {
require.NoError(t, err)
vs.ExecutionEngineCaller = &powtesting.EngineClient{PayloadIDBytes: id, ExecutionPayloadCapella: &v1.ExecutionPayloadCapella{BlockNumber: 3}, BlockValue: 1}
b := blk.Block()
localPayload, _, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
localPayload, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
require.NoError(t, err)
builderPayload, _, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
builderPayload, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
require.NoError(t, err)
require.NoError(t, setExecutionData(context.Background(), blk, localPayload, builderPayload))
e, err := blk.Block().Body().Execution()
@@ -254,9 +254,9 @@ func TestServer_setExecutionData(t *testing.T) {
}
vs.ExecutionEngineCaller = &powtesting.EngineClient{PayloadIDBytes: id, ExecutionPayloadCapella: &v1.ExecutionPayloadCapella{BlockNumber: 4}, BlockValue: 0}
b := blk.Block()
localPayload, _, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
localPayload, _, err := vs.getLocalPayloadAndBlobs(ctx, b, capellaTransitionState)
require.NoError(t, err)
builderPayload, _, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
builderPayload, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
require.ErrorIs(t, consensus_types.ErrNilObjectWrapped, err) // Builder returns fault. Use local block
require.NoError(t, setExecutionData(context.Background(), blk, localPayload, builderPayload))
e, err := blk.Block().Body().Execution()
@@ -285,10 +285,10 @@ func TestServer_setExecutionData(t *testing.T) {
ExecutionPayloadDeneb: &v1.ExecutionPayloadDeneb{BlockNumber: 4},
BlockValue: 0}
blk.SetSlot(primitives.Slot(params.BeaconConfig().DenebForkEpoch) * params.BeaconConfig().SlotsPerEpoch)
localPayload, bb, _, err := vs.getLocalPayloadAndBlobs(ctx, blk.Block(), capellaTransitionState)
localPayload, _, err := vs.getLocalPayloadAndBlobs(ctx, blk.Block(), capellaTransitionState)
require.NoError(t, err)
require.Equal(t, uint64(4), localPayload.BlockNumber())
require.DeepEqual(t, bb, blobsBundle)
require.DeepEqual(t, fullBlobsBundle, blobsBundle)
})
t.Run("Can get builder payload and blobs in Deneb", func(t *testing.T) {
cfg := params.BeaconConfig().Copy()
@@ -360,10 +360,10 @@ func TestServer_setExecutionData(t *testing.T) {
require.NoError(t, err)
blk.SetSlot(primitives.Slot(params.BeaconConfig().DenebForkEpoch) * params.BeaconConfig().SlotsPerEpoch)
require.NoError(t, err)
builderPayload, bb, err := vs.getBuilderPayloadAndBlobs(ctx, blk.Block().Slot(), blk.Block().ProposerIndex())
builderPayload, err := vs.getBuilderPayloadAndBlobs(ctx, blk.Block().Slot(), blk.Block().ProposerIndex())
require.NoError(t, err)
require.Equal(t, bid.Header.BlockNumber, builderPayload.BlockNumber()) // header should be the same from block
require.DeepEqual(t, bb, bid.BlindedBlobsBundle) // blind blobs should be the same from block
require.DeepEqual(t, blindBlobsBundle, bid.BlindedBlobsBundle) // blind blobs should be the same from block
})
}
func TestServer_getPayloadHeader(t *testing.T) {
@@ -581,7 +581,7 @@ func TestServer_getPayloadHeader(t *testing.T) {
}}
hb, err := vs.HeadFetcher.HeadBlock(context.Background())
require.NoError(t, err)
h, _, err := vs.getPayloadHeaderFromBuilder(context.Background(), hb.Block().Slot(), 0)
h, err := vs.getPayloadHeaderFromBuilder(context.Background(), hb.Block().Slot(), 0)
if tc.err != "" {
require.ErrorContains(t, tc.err, err)
} else {

View File

@@ -1,39 +1,12 @@
package validator
import (
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/time/slots"
)
// setKzgCommitments sets the KZG commitment on the block.
// Return early if the block version is older than deneb or block slot has not passed deneb epoch.
// Depends on the blk is blind or not, set the KZG commitment from the corresponding bundle.
func setKzgCommitments(blk interfaces.SignedBeaconBlock, bundle *enginev1.BlobsBundle, blindBundle *enginev1.BlindedBlobsBundle) error {
if blk.Version() < version.Deneb {
return nil
}
slot := blk.Block().Slot()
if slots.ToEpoch(slot) < params.BeaconConfig().DenebForkEpoch {
return nil
}
if blk.IsBlinded() {
if blindBundle == nil {
return nil
}
return blk.SetBlobKzgCommitments(blindBundle.KzgCommitments)
}
if bundle == nil {
return nil
}
return blk.SetBlobKzgCommitments(bundle.KzgCommitments)
}
// coverts a blobs bundle to a sidecar format.
func blobsBundleToSidecars(bundle *enginev1.BlobsBundle, blk interfaces.ReadOnlyBeaconBlock) ([]*ethpb.BlobSidecar, error) {
if blk.Version() < version.Deneb {

View File

@@ -3,7 +3,6 @@ package validator
import (
"testing"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
@@ -11,36 +10,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/testing/util"
)
func Test_setKzgCommitments(t *testing.T) {
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
require.NoError(t, setKzgCommitments(b, nil, nil))
b, err = blocks.NewSignedBeaconBlock(util.NewBeaconBlockDeneb())
require.NoError(t, err)
require.NoError(t, setKzgCommitments(b, nil, nil))
cfg := params.BeaconConfig().Copy()
cfg.DenebForkEpoch = 0
params.OverrideBeaconConfig(cfg)
kcs := [][]byte{[]byte("kzg"), []byte("kzg1"), []byte("kzg2")}
bundle := &enginev1.BlobsBundle{KzgCommitments: kcs}
bkcs := [][]byte{[]byte("bkzg"), []byte("bkzg1"), []byte("bkzg2")}
blindBundle := &enginev1.BlindedBlobsBundle{KzgCommitments: bkcs}
require.NoError(t, setKzgCommitments(b, bundle, blindBundle))
got, err := b.Block().Body().BlobKzgCommitments()
require.NoError(t, err)
require.DeepEqual(t, got, kcs)
b, err = blocks.NewSignedBeaconBlock(util.NewBeaconBlockDeneb())
require.NoError(t, err)
b.SetBlinded(true)
require.NoError(t, setKzgCommitments(b, bundle, blindBundle))
got, err = b.Block().Body().BlobKzgCommitments()
require.NoError(t, err)
require.DeepEqual(t, got, bkcs)
}
func Test_blobsBundleToSidecars(t *testing.T) {
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockDeneb())
require.NoError(t, err)

View File

@@ -43,12 +43,12 @@ var (
// This returns the local execution payload of a given slot. The function has full awareness of pre and post merge.
// It also returns the blobs bundle.
func (vs *Server) getLocalPayloadAndBlobs(ctx context.Context, blk interfaces.ReadOnlyBeaconBlock, st state.BeaconState) (interfaces.ExecutionData, *enginev1.BlobsBundle, bool, error) {
func (vs *Server) getLocalPayloadAndBlobs(ctx context.Context, blk interfaces.ReadOnlyBeaconBlock, st state.BeaconState) (interfaces.ExecutionData, bool, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.getLocalPayload")
defer span.End()
if blk.Version() < version.Bellatrix {
return nil, nil, false, nil
return nil, false, nil
}
slot := blk.Slot()
@@ -73,21 +73,23 @@ func (vs *Server) getLocalPayloadAndBlobs(ctx context.Context, blk interfaces.Re
"Please refer to our documentation for instructions")
}
default:
return nil, nil, false, errors.Wrap(err, "could not get fee recipient in db")
return nil, false, errors.Wrap(err, "could not get fee recipient in db")
}
if ok && proposerID == vIdx && payloadId != [8]byte{} { // Payload ID is cache hit. Return the cached payload ID.
var pid [8]byte
copy(pid[:], payloadId[:])
payloadIDCacheHit.Inc()
payload, blobsBundle, overrideBuilder, err := vs.ExecutionEngineCaller.GetPayload(ctx, pid, slot)
var payload interfaces.ExecutionData
var overrideBuilder bool
payload, fullBlobsBundle, overrideBuilder, err = vs.ExecutionEngineCaller.GetPayload(ctx, pid, slot)
switch {
case err == nil:
warnIfFeeRecipientDiffers(payload, feeRecipient)
return payload, blobsBundle, overrideBuilder, nil
return payload, overrideBuilder, nil
case errors.Is(err, context.DeadlineExceeded):
default:
return nil, nil, false, errors.Wrap(err, "could not get cached payload from execution client")
return nil, false, errors.Wrap(err, "could not get cached payload from execution client")
}
}
@@ -96,17 +98,17 @@ func (vs *Server) getLocalPayloadAndBlobs(ctx context.Context, blk interfaces.Re
case errors.Is(err, errActivationNotReached) || errors.Is(err, errNoTerminalBlockHash):
p, err := consensusblocks.WrappedExecutionPayload(emptyPayload())
if err != nil {
return nil, nil, false, err
return nil, false, err
}
return p, nil, false, nil
return p, false, nil
case err != nil:
return nil, nil, false, err
return nil, false, err
}
payloadIDCacheMiss.Inc()
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
if err != nil {
return nil, nil, false, err
return nil, false, err
}
finalizedBlockHash := [32]byte{}
@@ -125,14 +127,14 @@ func (vs *Server) getLocalPayloadAndBlobs(ctx context.Context, blk interfaces.Re
t, err := slots.ToTime(st.GenesisTime(), slot)
if err != nil {
return nil, nil, false, err
return nil, false, err
}
var attr payloadattribute.Attributer
switch st.Version() {
case version.Deneb:
withdrawals, err := st.ExpectedWithdrawals()
if err != nil {
return nil, nil, false, err
return nil, false, err
}
attr, err = payloadattribute.New(&enginev1.PayloadAttributesV3{
Timestamp: uint64(t.Unix()),
@@ -142,12 +144,12 @@ func (vs *Server) getLocalPayloadAndBlobs(ctx context.Context, blk interfaces.Re
ParentBeaconBlockRoot: headRoot[:],
})
if err != nil {
return nil, nil, false, err
return nil, false, err
}
case version.Capella:
withdrawals, err := st.ExpectedWithdrawals()
if err != nil {
return nil, nil, false, err
return nil, false, err
}
attr, err = payloadattribute.New(&enginev1.PayloadAttributesV2{
Timestamp: uint64(t.Unix()),
@@ -156,7 +158,7 @@ func (vs *Server) getLocalPayloadAndBlobs(ctx context.Context, blk interfaces.Re
Withdrawals: withdrawals,
})
if err != nil {
return nil, nil, false, err
return nil, false, err
}
case version.Bellatrix:
attr, err = payloadattribute.New(&enginev1.PayloadAttributes{
@@ -165,24 +167,26 @@ func (vs *Server) getLocalPayloadAndBlobs(ctx context.Context, blk interfaces.Re
SuggestedFeeRecipient: feeRecipient.Bytes(),
})
if err != nil {
return nil, nil, false, err
return nil, false, err
}
default:
return nil, nil, false, errors.New("unknown beacon state version")
return nil, false, errors.New("unknown beacon state version")
}
payloadID, _, err := vs.ExecutionEngineCaller.ForkchoiceUpdated(ctx, f, attr)
if err != nil {
return nil, nil, false, errors.Wrap(err, "could not prepare payload")
return nil, false, errors.Wrap(err, "could not prepare payload")
}
if payloadID == nil {
return nil, nil, false, fmt.Errorf("nil payload with block hash: %#x", parentHash)
return nil, false, fmt.Errorf("nil payload with block hash: %#x", parentHash)
}
payload, blobsBundle, overrideBuilder, err := vs.ExecutionEngineCaller.GetPayload(ctx, *payloadID, slot)
var payload interfaces.ExecutionData
var overrideBuilder bool
payload, fullBlobsBundle, overrideBuilder, err = vs.ExecutionEngineCaller.GetPayload(ctx, *payloadID, slot)
if err != nil {
return nil, nil, false, err
return nil, false, err
}
warnIfFeeRecipientDiffers(payload, feeRecipient)
return payload, blobsBundle, overrideBuilder, nil
return payload, overrideBuilder, nil
}
// warnIfFeeRecipientDiffers logs a warning if the fee recipient in the included payload does not
@@ -231,20 +235,20 @@ func (vs *Server) getTerminalBlockHashIfExists(ctx context.Context, transitionTi
func (vs *Server) getBuilderPayloadAndBlobs(ctx context.Context,
slot primitives.Slot,
vIdx primitives.ValidatorIndex) (interfaces.ExecutionData, *enginev1.BlindedBlobsBundle, error) {
vIdx primitives.ValidatorIndex) (interfaces.ExecutionData, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.getBuilderPayloadAndBlobs")
defer span.End()
if slots.ToEpoch(slot) < params.BeaconConfig().BellatrixForkEpoch {
return nil, nil, nil
return nil, nil
}
canUseBuilder, err := vs.canUseBuilder(ctx, slot, vIdx)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to check if we can use the builder")
return nil, errors.Wrap(err, "failed to check if we can use the builder")
}
span.AddAttributes(trace.BoolAttribute("canUseBuilder", canUseBuilder))
if !canUseBuilder {
return nil, nil, nil
return nil, nil
}
return vs.getPayloadHeaderFromBuilder(ctx, slot, vIdx)

View File

@@ -159,7 +159,7 @@ func TestServer_getExecutionPayload(t *testing.T) {
b, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err)
var gotOverride bool
_, _, gotOverride, err = vs.getLocalPayloadAndBlobs(context.Background(), b.Block(), tt.st)
_, gotOverride, err = vs.getLocalPayloadAndBlobs(context.Background(), b.Block(), tt.st)
if tt.errString != "" {
require.ErrorContains(t, tt.errString, err)
} else {
@@ -202,7 +202,7 @@ func TestServer_getExecutionPayloadContextTimeout(t *testing.T) {
blk.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
b, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err)
_, _, _, err = vs.getLocalPayloadAndBlobs(context.Background(), b.Block(), nonTransitionSt)
_, _, err = vs.getLocalPayloadAndBlobs(context.Background(), b.Block(), nonTransitionSt)
require.NoError(t, err)
}
@@ -254,7 +254,7 @@ func TestServer_getExecutionPayload_UnexpectedFeeRecipient(t *testing.T) {
blk.Block.ParentRoot = bytesutil.PadTo([]byte{}, 32)
b, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err)
gotPayload, _, _, err := vs.getLocalPayloadAndBlobs(context.Background(), b.Block(), transitionSt)
gotPayload, _, err := vs.getLocalPayloadAndBlobs(context.Background(), b.Block(), transitionSt)
require.NoError(t, err)
require.NotNil(t, gotPayload)
@@ -266,7 +266,7 @@ func TestServer_getExecutionPayload_UnexpectedFeeRecipient(t *testing.T) {
payload.FeeRecipient = evilRecipientAddress[:]
vs.ProposerSlotIndexCache = cache.NewProposerPayloadIDsCache()
gotPayload, _, _, err = vs.getLocalPayloadAndBlobs(context.Background(), b.Block(), transitionSt)
gotPayload, _, err = vs.getLocalPayloadAndBlobs(context.Background(), b.Block(), transitionSt)
require.NoError(t, err)
require.NotNil(t, gotPayload)