Enable Deneb For E2E Scenario Tests (#13317)

* fix all cases

* update web3signer

* current progress

* fix it finally

* push it back to capella

* remove hard-coded forks

* fix failing tests

* gaz

* fix dumb bug

* fix bad test setup

* change back
This commit is contained in:
Nishant Das
2023-12-16 19:37:44 +08:00
committed by GitHub
parent c56abfb840
commit b45a6664be
39 changed files with 431 additions and 171 deletions

View File

@@ -6,10 +6,10 @@ lighthouse_archive_name = "lighthouse-%s-x86_64-unknown-linux-gnu-portable.tar.g
def e2e_deps():
http_archive(
name = "web3signer",
urls = ["https://artifacts.consensys.net/public/web3signer/raw/names/web3signer.tar.gz/versions/23.9.1/web3signer-23.9.1.tar.gz"],
sha256 = "aec9dc745cb25fd8d7b38b06e435e3138972c2cf842dd6f851d50be7bf081629",
urls = ["https://artifacts.consensys.net/public/web3signer/raw/names/web3signer.tar.gz/versions/23.11.0/web3signer-23.11.0.tar.gz"],
sha256 = "e7643a6aa32efd859e96a82cb3ea03a294fd92c22fffeab987e5ec97500867a8",
build_file = "@prysm//testing/endtoend:web3signer.BUILD",
strip_prefix = "web3signer-23.9.1",
strip_prefix = "web3signer-23.11.0",
)
http_archive(

View File

@@ -21,7 +21,6 @@ go_library(
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/endtoend/helpers:go_default_library",
"//testing/endtoend/params:go_default_library",
"//testing/endtoend/policies:go_default_library",
"//testing/endtoend/types:go_default_library",

View File

@@ -12,7 +12,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/validator"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/helpers"
)
var requests = map[string]endpoint{
@@ -47,7 +46,7 @@ var requests = map[string]endpoint{
return []string{"head"}
})),
"/beacon/states/{param1}/sync_committees": newMetadata[beacon.GetSyncCommitteeResponse](v1PathTemplate,
withStart(helpers.AltairE2EForkEpoch),
withStart(params.BeaconConfig().AltairForkEpoch),
withParams(func(_ primitives.Epoch) []string {
return []string{"head"}
})),

View File

@@ -12,9 +12,9 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/beacon"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/validator"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/helpers"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/policies"
e2etypes "github.com/prysmaticlabs/prysm/v4/testing/endtoend/types"
"github.com/prysmaticlabs/prysm/v4/time/slots"
@@ -86,7 +86,7 @@ func postEvaluation(requests map[string]endpoint, epoch primitives.Epoch) error
// verify that block SSZ responses have the correct structure
blockData := requests["/beacon/blocks/{param1}"]
blindedBlockData := requests["/beacon/blinded_blocks/{param1}"]
if epoch < helpers.AltairE2EForkEpoch {
if epoch < params.BeaconConfig().AltairForkEpoch {
b := &ethpb.SignedBeaconBlock{}
if err := b.UnmarshalSSZ(blockData.getSszResp()); err != nil {
return errors.Wrap(err, msgSSZUnmarshalFailed)
@@ -95,7 +95,7 @@ func postEvaluation(requests map[string]endpoint, epoch primitives.Epoch) error
if err := bb.UnmarshalSSZ(blindedBlockData.getSszResp()); err != nil {
return errors.Wrap(err, msgSSZUnmarshalFailed)
}
} else if epoch < helpers.BellatrixE2EForkEpoch {
} else if epoch < params.BeaconConfig().BellatrixForkEpoch {
b := &ethpb.SignedBeaconBlockAltair{}
if err := b.UnmarshalSSZ(blockData.getSszResp()); err != nil {
return errors.Wrap(err, msgSSZUnmarshalFailed)
@@ -104,7 +104,7 @@ func postEvaluation(requests map[string]endpoint, epoch primitives.Epoch) error
if err := bb.UnmarshalSSZ(blindedBlockData.getSszResp()); err != nil {
return errors.Wrap(err, msgSSZUnmarshalFailed)
}
} else if epoch < helpers.CapellaE2EForkEpoch {
} else if epoch < params.BeaconConfig().CapellaForkEpoch {
b := &ethpb.SignedBeaconBlockBellatrix{}
if err := b.UnmarshalSSZ(blockData.getSszResp()); err != nil {
return errors.Wrap(err, msgSSZUnmarshalFailed)
@@ -113,7 +113,7 @@ func postEvaluation(requests map[string]endpoint, epoch primitives.Epoch) error
if err := bb.UnmarshalSSZ(blindedBlockData.getSszResp()); err != nil {
return errors.Wrap(err, msgSSZUnmarshalFailed)
}
} else if epoch < helpers.DenebE2EForkEpoch {
} else if epoch < params.BeaconConfig().DenebForkEpoch {
b := &ethpb.SignedBeaconBlockCapella{}
if err := b.UnmarshalSSZ(blockData.getSszResp()); err != nil {
return errors.Wrap(err, msgSSZUnmarshalFailed)

View File

@@ -4,9 +4,9 @@ import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/helpers"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/policies"
e2etypes "github.com/prysmaticlabs/prysm/v4/testing/endtoend/types"
"github.com/prysmaticlabs/prysm/v4/time/slots"
@@ -16,8 +16,11 @@ import (
// BuilderIsActive checks that the builder is indeed producing the respective payloads
var BuilderIsActive = e2etypes.Evaluator{
Name: "builder_is_active_at_epoch_%d",
Policy: policies.OnwardsNthEpoch(helpers.BellatrixE2EForkEpoch),
Name: "builder_is_active_at_epoch_%d",
Policy: func(e primitives.Epoch) bool {
fEpoch := params.BeaconConfig().BellatrixForkEpoch
return policies.OnwardsNthEpoch(fEpoch)(e)
},
Evaluation: builderActive,
}
@@ -36,8 +39,8 @@ func builderActive(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) err
lowestBound = currEpoch - 1
}
if lowestBound < helpers.BellatrixE2EForkEpoch {
lowestBound = helpers.BellatrixE2EForkEpoch
if lowestBound < params.BeaconConfig().BellatrixForkEpoch {
lowestBound = params.BeaconConfig().BellatrixForkEpoch
}
blockCtrs, err := beaconClient.ListBeaconBlocks(context.Background(), &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: lowestBound}})
if err != nil {
@@ -52,7 +55,7 @@ func builderActive(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) err
if b.IsNil() {
return errors.New("nil block provided")
}
forkStartSlot, err := slots.EpochStart(helpers.BellatrixE2EForkEpoch)
forkStartSlot, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
if err != nil {
return err
}
@@ -86,7 +89,7 @@ func builderActive(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) err
if b.IsNil() {
return errors.New("nil block provided")
}
forkStartSlot, err := slots.EpochStart(helpers.BellatrixE2EForkEpoch)
forkStartSlot, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
if err != nil {
return err
}

View File

@@ -11,10 +11,10 @@ import (
"github.com/ethereum/go-ethereum/rpc"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/runtime/interop"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/components"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/helpers"
e2e "github.com/prysmaticlabs/prysm/v4/testing/endtoend/params"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/policies"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/types"
@@ -24,8 +24,11 @@ import (
)
var FeeRecipientIsPresent = types.Evaluator{
Name: "fee_recipient_is_present_%d",
Policy: policies.AfterNthEpoch(helpers.BellatrixE2EForkEpoch),
Name: "fee_recipient_is_present_%d",
Policy: func(e primitives.Epoch) bool {
fEpoch := params.BeaconConfig().BellatrixForkEpoch
return policies.AfterNthEpoch(fEpoch)(e)
},
Evaluation: feeRecipientIsPresent,
}

View File

@@ -5,11 +5,11 @@ import (
"time"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/helpers"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/policies"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/types"
"github.com/prysmaticlabs/prysm/v4/time/slots"
@@ -23,7 +23,7 @@ var startingFork = version.Phase0
var AltairForkTransition = types.Evaluator{
Name: "altair_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
altair := policies.OnEpoch(helpers.AltairE2EForkEpoch)
altair := policies.OnEpoch(params.BeaconConfig().AltairForkEpoch)
// TODO (11750): modify policies to take an end to end config
if startingFork == version.Phase0 {
return altair(e)
@@ -35,21 +35,30 @@ var AltairForkTransition = types.Evaluator{
// BellatrixForkTransition ensures that the Bellatrix hard fork has occurred successfully.
var BellatrixForkTransition = types.Evaluator{
Name: "bellatrix_fork_transition_%d",
Policy: policies.OnEpoch(helpers.BellatrixE2EForkEpoch),
Name: "bellatrix_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
fEpoch := params.BeaconConfig().BellatrixForkEpoch
return policies.OnEpoch(fEpoch)(e)
},
Evaluation: bellatrixForkOccurs,
}
// CapellaForkTransition ensures that the Capella hard fork has occurred successfully.
var CapellaForkTransition = types.Evaluator{
Name: "capella_fork_transition_%d",
Policy: policies.OnEpoch(helpers.CapellaE2EForkEpoch),
Name: "capella_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
fEpoch := params.BeaconConfig().CapellaForkEpoch
return policies.OnEpoch(fEpoch)(e)
},
Evaluation: capellaForkOccurs,
}
var DenebForkTransition = types.Evaluator{
Name: "deneb_fork_transition_%d",
Policy: policies.OnEpoch(helpers.DenebE2EForkEpoch),
Name: "deneb_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
fEpoch := params.BeaconConfig().DenebForkEpoch
return policies.OnEpoch(fEpoch)(e)
},
Evaluation: denebForkOccurs,
}
@@ -62,7 +71,7 @@ func altairForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) err
if err != nil {
return errors.Wrap(err, "failed to get stream")
}
fSlot, err := slots.EpochStart(helpers.AltairE2EForkEpoch)
fSlot, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch)
if err != nil {
return err
}
@@ -104,7 +113,7 @@ func bellatrixForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn)
if err != nil {
return errors.Wrap(err, "failed to get stream")
}
fSlot, err := slots.EpochStart(helpers.BellatrixE2EForkEpoch)
fSlot, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
if err != nil {
return err
}
@@ -149,7 +158,7 @@ func capellaForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) er
if err != nil {
return errors.Wrap(err, "failed to get stream")
}
fSlot, err := slots.EpochStart(helpers.CapellaE2EForkEpoch)
fSlot, err := slots.EpochStart(params.BeaconConfig().CapellaForkEpoch)
if err != nil {
return err
}
@@ -192,7 +201,7 @@ func denebForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) erro
if err != nil {
return errors.Wrap(err, "failed to get stream")
}
fSlot, err := slots.EpochStart(helpers.DenebE2EForkEpoch)
fSlot, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch)
if err != nil {
return err
}

View File

@@ -85,8 +85,11 @@ var ValidatorsHaveExited = e2etypes.Evaluator{
// SubmitWithdrawal sends a withdrawal from a previously exited validator.
var SubmitWithdrawal = e2etypes.Evaluator{
Name: "submit_withdrawal_epoch_%d",
Policy: policies.BetweenEpochs(helpers.CapellaE2EForkEpoch-2, helpers.CapellaE2EForkEpoch+1),
Name: "submit_withdrawal_epoch_%d",
Policy: func(currentEpoch primitives.Epoch) bool {
fEpoch := params.BeaconConfig().CapellaForkEpoch
return policies.BetweenEpochs(fEpoch-2, fEpoch+1)(currentEpoch)
},
Evaluation: submitWithdrawal,
}
@@ -99,7 +102,7 @@ var ValidatorsHaveWithdrawn = e2etypes.Evaluator{
return false
}
// Only run this for minimal setups after capella
validWithdrawnEpoch := primitives.Epoch(helpers.CapellaE2EForkEpoch + 1)
validWithdrawnEpoch := params.BeaconConfig().CapellaForkEpoch + 1
requiredPolicy := policies.OnEpoch(validWithdrawnEpoch)
return requiredPolicy(currentEpoch)

View File

@@ -19,7 +19,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/network/httputil"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/helpers"
e2eparams "github.com/prysmaticlabs/prysm/v4/testing/endtoend/params"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/policies"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/types"
@@ -53,8 +52,11 @@ var ValidatorsParticipatingAtEpoch = func(epoch primitives.Epoch) types.Evaluato
// ValidatorSyncParticipation ensures the expected amount of sync committee participants
// are active.
var ValidatorSyncParticipation = types.Evaluator{
Name: "validator_sync_participation_%d",
Policy: policies.OnwardsNthEpoch(helpers.AltairE2EForkEpoch),
Name: "validator_sync_participation_%d",
Policy: func(e primitives.Epoch) bool {
fEpoch := params.BeaconConfig().AltairForkEpoch
return policies.OnwardsNthEpoch(fEpoch)(e)
},
Evaluation: validatorsSyncParticipation,
}
@@ -125,7 +127,7 @@ func validatorsParticipating(_ *types.EvaluationContext, conns ...*grpc.ClientCo
if e2eparams.TestParams.LighthouseBeaconNodeCount != 0 {
expected = float32(expectedMulticlientParticipation)
}
if participation.Epoch > 0 && participation.Epoch.Sub(1) == helpers.BellatrixE2EForkEpoch {
if participation.Epoch > 0 && participation.Epoch.Sub(1) == params.BeaconConfig().BellatrixForkEpoch {
// Reduce Participation requirement to 95% to account for longer EE calls for
// the merge block. Target and head will likely be missed for a few validators at
// slot 0.
@@ -219,8 +221,8 @@ func validatorsSyncParticipation(_ *types.EvaluationContext, conns ...*grpc.Clie
lowestBound = currEpoch - 1
}
if lowestBound < helpers.AltairE2EForkEpoch {
lowestBound = helpers.AltairE2EForkEpoch
if lowestBound < params.BeaconConfig().AltairForkEpoch {
lowestBound = params.BeaconConfig().AltairForkEpoch
}
blockCtrs, err := altairClient.ListBeaconBlocks(context.Background(), &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: lowestBound}})
if err != nil {
@@ -235,7 +237,7 @@ func validatorsSyncParticipation(_ *types.EvaluationContext, conns ...*grpc.Clie
if b.IsNil() {
return errors.New("nil block provided")
}
forkStartSlot, err := slots.EpochStart(helpers.AltairE2EForkEpoch)
forkStartSlot, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch)
if err != nil {
return err
}
@@ -245,7 +247,7 @@ func validatorsSyncParticipation(_ *types.EvaluationContext, conns ...*grpc.Clie
}
expectedParticipation := expectedSyncParticipation
switch slots.ToEpoch(b.Block().Slot()) {
case helpers.AltairE2EForkEpoch:
case params.BeaconConfig().AltairForkEpoch:
// Drop expected sync participation figure.
expectedParticipation = 0.90
default:
@@ -276,11 +278,11 @@ func validatorsSyncParticipation(_ *types.EvaluationContext, conns ...*grpc.Clie
if b.IsNil() {
return errors.New("nil block provided")
}
forkSlot, err := slots.EpochStart(helpers.AltairE2EForkEpoch)
forkSlot, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch)
if err != nil {
return err
}
nexForkSlot, err := slots.EpochStart(helpers.BellatrixE2EForkEpoch)
nexForkSlot, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
if err != nil {
return err
}

View File

@@ -31,16 +31,12 @@ import (
)
const (
maxPollingWaitTime = 60 * time.Second // A minute so timing out doesn't take very long.
filePollingInterval = 500 * time.Millisecond
memoryHeapFileName = "node_heap_%d.pb.gz"
cpuProfileFileName = "node_cpu_profile_%d.pb.gz"
fileBufferSize = 64 * 1024
maxFileBufferSize = 1024 * 1024
AltairE2EForkEpoch = params.AltairE2EForkEpoch
BellatrixE2EForkEpoch = params.BellatrixE2EForkEpoch
CapellaE2EForkEpoch = params.CapellaE2EForkEpoch
DenebE2EForkEpoch = params.DenebE2EForkEpoch
maxPollingWaitTime = 60 * time.Second // A minute so timing out doesn't take very long.
filePollingInterval = 500 * time.Millisecond
memoryHeapFileName = "node_heap_%d.pb.gz"
cpuProfileFileName = "node_cpu_profile_%d.pb.gz"
fileBufferSize = 64 * 1024
maxFileBufferSize = 1024 * 1024
)
// Graffiti is a list of sample graffiti strings.

View File

@@ -10,7 +10,7 @@ import (
// Run mainnet e2e config with the current release validator against latest beacon node.
func TestEndToEnd_MainnetConfig_ValidatorAtCurrentRelease(t *testing.T) {
r := e2eMainnet(t, true, false, types.InitForkCfg(version.Phase0, version.Deneb, params.E2EMainnetTestConfig()))
r := e2eMainnet(t, true, false, types.InitForkCfg(version.Phase0, version.Capella, params.E2EMainnetTestConfig()))
r.run()
}

View File

@@ -9,11 +9,11 @@ import (
)
func TestEndToEnd_MinimalConfig_WithBuilder(t *testing.T) {
r := e2eMinimal(t, types.InitForkCfg(version.Phase0, version.Capella, params.E2ETestConfig()), types.WithCheckpointSync(), types.WithBuilder())
r := e2eMinimal(t, types.InitForkCfg(version.Phase0, version.Deneb, params.E2ETestConfig()), types.WithCheckpointSync(), types.WithBuilder())
r.run()
}
func TestEndToEnd_MinimalConfig_WithBuilder_ValidatorRESTApi(t *testing.T) {
r := e2eMinimal(t, types.InitForkCfg(version.Phase0, version.Capella, params.E2ETestConfig()), types.WithCheckpointSync(), types.WithBuilder(), types.WithValidatorRESTApi())
r := e2eMinimal(t, types.InitForkCfg(version.Phase0, version.Deneb, params.E2ETestConfig()), types.WithCheckpointSync(), types.WithBuilder(), types.WithValidatorRESTApi())
r.run()
}

View File

@@ -17,7 +17,7 @@ func TestEndToEnd_MultiScenarioRun(t *testing.T) {
}
func TestEndToEnd_MinimalConfig_Web3Signer(t *testing.T) {
e2eMinimal(t, types.InitForkCfg(version.Phase0, version.Capella, params.E2ETestConfig()), types.WithRemoteSigner()).run()
e2eMinimal(t, types.InitForkCfg(version.Phase0, version.Deneb, params.E2ETestConfig()), types.WithRemoteSigner()).run()
}
func TestEndToEnd_MinimalConfig_ValidatorRESTApi(t *testing.T) {

View File

@@ -50,10 +50,14 @@ const (
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
// ForkchoiceUpdatedMethodV2 v2 request string for JSON-RPC.
ForkchoiceUpdatedMethodV2 = "engine_forkchoiceUpdatedV2"
// ForkchoiceUpdatedMethodV3 v3 request string for JSON-RPC.
ForkchoiceUpdatedMethodV3 = "engine_forkchoiceUpdatedV3"
// GetPayloadMethod v1 request string for JSON-RPC.
GetPayloadMethod = "engine_getPayloadV1"
// GetPayloadMethodV2 v2 request string for JSON-RPC.
GetPayloadMethodV2 = "engine_getPayloadV2"
// GetPayloadMethodV3 v3 request string for JSON-RPC.
GetPayloadMethodV3 = "engine_getPayloadV3"
)
var (
@@ -93,15 +97,25 @@ type ExecHeaderResponseCapella struct {
} `json:"data"`
}
type ExecHeaderResponseDeneb struct {
Version string `json:"version"`
Data struct {
Signature hexutil.Bytes `json:"signature"`
Message *builderAPI.BuilderBidDeneb `json:"message"`
} `json:"data"`
}
type Builder struct {
cfg *config
address string
execClient *gethRPC.Client
currId *v1.PayloadIDBytes
currPayload interfaces.ExecutionData
mux *gMux.Router
validatorMap map[string]*eth.ValidatorRegistrationV1
srv *http.Server
cfg *config
address string
execClient *gethRPC.Client
currId *v1.PayloadIDBytes
prevBeaconRoot []byte
currPayload interfaces.ExecutionData
blobBundle *v1.BlobsBundle
mux *gMux.Router
validatorMap map[string]*eth.ValidatorRegistrationV1
srv *http.Server
}
// New creates a proxy server forwarding requests from a consensus client to an execution client.
@@ -226,7 +240,7 @@ func (p *Builder) handleEngineCalls(req, resp []byte) {
}
p.cfg.logger.Infof("Received engine call %s", rpcObj.Method)
switch rpcObj.Method {
case ForkchoiceUpdatedMethod, ForkchoiceUpdatedMethodV2:
case ForkchoiceUpdatedMethod, ForkchoiceUpdatedMethodV2, ForkchoiceUpdatedMethodV3:
result := &ForkchoiceUpdatedResponse{}
err = json.Unmarshal(resp, result)
if err != nil {
@@ -234,6 +248,19 @@ func (p *Builder) handleEngineCalls(req, resp []byte) {
return
}
p.currId = result.Result.PayloadId
if rpcObj.Method == ForkchoiceUpdatedMethodV3 {
attr := &v1.PayloadAttributesV3{}
obj, err := json.Marshal(rpcObj.Params[1])
if err != nil {
p.cfg.logger.Errorf("Could not marshal attr: %v", err)
return
}
if err := json.Unmarshal(obj, attr); err != nil {
p.cfg.logger.Errorf("Could not unmarshal attr: %v", err)
return
}
p.prevBeaconRoot = attr.ParentBeaconBlockRoot
}
p.cfg.logger.Infof("Received payload id of %#x", result.Result.PayloadId)
}
}
@@ -279,6 +306,11 @@ func (p *Builder) handleHeaderRequest(w http.ResponseWriter, req *http.Request)
}
ax := types.Slot(slot)
currEpoch := types.Epoch(ax / params.BeaconConfig().SlotsPerEpoch)
if currEpoch >= params.BeaconConfig().DenebForkEpoch {
p.handleHeaderRequestDeneb(w)
return
}
if currEpoch >= params.BeaconConfig().CapellaForkEpoch {
p.handleHeaderRequestCapella(w)
return
@@ -439,6 +471,96 @@ func (p *Builder) handleHeaderRequestCapella(w http.ResponseWriter) {
w.WriteHeader(http.StatusOK)
}
func (p *Builder) handleHeaderRequestDeneb(w http.ResponseWriter) {
b, err := p.retrievePendingBlockDeneb()
if err != nil {
p.cfg.logger.WithError(err).Error("Could not retrieve pending block")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
secKey, err := bls.RandKey()
if err != nil {
p.cfg.logger.WithError(err).Error("Could not retrieve secret key")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
v := big.NewInt(0).SetBytes(bytesutil.ReverseByteOrder(b.Value))
// we set the payload value as twice its actual one so that it always chooses builder payloads vs local payloads
v = v.Mul(v, big.NewInt(2))
// Is used as the helper modifies the big.Int
weiVal := big.NewInt(0).SetBytes(bytesutil.ReverseByteOrder(b.Value))
// we set the payload value as twice its actual one so that it always chooses builder payloads vs local payloads
weiVal = weiVal.Mul(weiVal, big.NewInt(2))
wObj, err := blocks.WrappedExecutionPayloadDeneb(b.Payload, math.WeiToGwei(weiVal))
if err != nil {
p.cfg.logger.WithError(err).Error("Could not wrap execution payload")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
hdr, err := blocks.PayloadToHeaderDeneb(wObj)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not make payload into header")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
val := builderAPI.Uint256{Int: v}
commitments := []hexutil.Bytes{}
for _, c := range b.BlobsBundle.KzgCommitments {
copiedC := c
commitments = append(commitments, copiedC)
}
wrappedHdr := &builderAPI.ExecutionPayloadHeaderDeneb{ExecutionPayloadHeaderDeneb: hdr}
bid := &builderAPI.BuilderBidDeneb{
Header: wrappedHdr,
BlobKzgCommitments: commitments,
Value: val,
Pubkey: secKey.PublicKey().Marshal(),
}
sszBid := &eth.BuilderBidDeneb{
Header: hdr,
BlobKzgCommitments: b.BlobsBundle.KzgCommitments,
Value: val.SSZBytes(),
Pubkey: secKey.PublicKey().Marshal(),
}
d, err := signing.ComputeDomain(params.BeaconConfig().DomainApplicationBuilder,
nil, /* fork version */
nil /* genesis val root */)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not compute the domain")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
rt, err := signing.ComputeSigningRoot(sszBid, d)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not compute the signing root")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
sig := secKey.Sign(rt[:])
hdrResp := &ExecHeaderResponseDeneb{
Version: "deneb",
Data: struct {
Signature hexutil.Bytes `json:"signature"`
Message *builderAPI.BuilderBidDeneb `json:"message"`
}{
Signature: sig.Marshal(),
Message: bid,
},
}
err = json.NewEncoder(w).Encode(hdrResp)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not encode response")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
p.currPayload = wObj
p.blobBundle = b.BlobsBundle
w.WriteHeader(http.StatusOK)
}
func (p *Builder) handleBlindedBlock(w http.ResponseWriter, req *http.Request) {
sb := &builderAPI.SignedBlindedBeaconBlockBellatrix{
SignedBlindedBeaconBlockBellatrix: &eth.SignedBlindedBeaconBlockBellatrix{},
@@ -453,6 +575,29 @@ func (p *Builder) handleBlindedBlock(w http.ResponseWriter, req *http.Request) {
http.Error(w, "payload not found", http.StatusInternalServerError)
return
}
if payload, err := p.currPayload.PbDeneb(); err == nil {
convertedPayload, err := builderAPI.FromProtoDeneb(payload)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not convert the payload")
http.Error(w, "payload not found", http.StatusInternalServerError)
return
}
execResp := &builderAPI.ExecPayloadResponseDeneb{
Version: "deneb",
Data: &builderAPI.ExecutionPayloadDenebAndBlobsBundle{
ExecutionPayload: &convertedPayload,
BlobsBundle: builderAPI.FromBundleProto(p.blobBundle),
},
}
err = json.NewEncoder(w).Encode(execResp)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not encode full payload response")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
return
}
if payload, err := p.currPayload.PbCapella(); err == nil {
convertedPayload, err := builderAPI.FromProtoCapella(payload)
if err != nil {
@@ -507,7 +652,7 @@ func (p *Builder) retrievePendingBlock() (*v1.ExecutionPayload, error) {
if err != nil {
return nil, err
}
payloadEnv, err := modifyExecutionPayload(*result, big.NewInt(0))
payloadEnv, err := modifyExecutionPayload(*result, big.NewInt(0), nil)
if err != nil {
return nil, err
}
@@ -531,7 +676,7 @@ func (p *Builder) retrievePendingBlockCapella() (*v1.ExecutionPayloadCapellaWith
if err != nil {
return nil, err
}
payloadEnv, err := modifyExecutionPayload(*result.ExecutionPayload, result.BlockValue)
payloadEnv, err := modifyExecutionPayload(*result.ExecutionPayload, result.BlockValue, nil)
if err != nil {
return nil, err
}
@@ -546,6 +691,34 @@ func (p *Builder) retrievePendingBlockCapella() (*v1.ExecutionPayloadCapellaWith
return capellaPayload, nil
}
func (p *Builder) retrievePendingBlockDeneb() (*v1.ExecutionPayloadDenebWithValueAndBlobsBundle, error) {
result := &engine.ExecutionPayloadEnvelope{}
if p.currId == nil {
return nil, errors.New("no payload id is cached")
}
err := p.execClient.CallContext(context.Background(), result, GetPayloadMethodV3, *p.currId)
if err != nil {
return nil, err
}
if p.prevBeaconRoot == nil {
p.cfg.logger.Errorf("previous root is nil")
}
payloadEnv, err := modifyExecutionPayload(*result.ExecutionPayload, result.BlockValue, p.prevBeaconRoot)
if err != nil {
return nil, err
}
payloadEnv.BlobsBundle = result.BlobsBundle
marshalledOutput, err := payloadEnv.MarshalJSON()
if err != nil {
return nil, err
}
denebPayload := &v1.ExecutionPayloadDenebWithValueAndBlobsBundle{}
if err = json.Unmarshal(marshalledOutput, denebPayload); err != nil {
return nil, err
}
return denebPayload, nil
}
func (p *Builder) sendHttpRequest(req *http.Request, requestBytes []byte) (*http.Response, error) {
proxyReq, err := http.NewRequest(req.Method, p.cfg.destinationUrl.String(), req.Body)
if err != nil {
@@ -608,8 +781,8 @@ func unmarshalRPCObject(b []byte) (*jsonRPCObject, error) {
return r, nil
}
func modifyExecutionPayload(execPayload engine.ExecutableData, fees *big.Int) (*engine.ExecutionPayloadEnvelope, error) {
modifiedBlock, err := executableDataToBlock(execPayload)
func modifyExecutionPayload(execPayload engine.ExecutableData, fees *big.Int, prevBeaconRoot []byte) (*engine.ExecutionPayloadEnvelope, error) {
modifiedBlock, err := executableDataToBlock(execPayload, prevBeaconRoot)
if err != nil {
return &engine.ExecutionPayloadEnvelope{}, err
}
@@ -617,7 +790,7 @@ func modifyExecutionPayload(execPayload engine.ExecutableData, fees *big.Int) (*
}
// This modifies the provided payload to imprint the builder's extra data
func executableDataToBlock(params engine.ExecutableData) (*gethTypes.Block, error) {
func executableDataToBlock(params engine.ExecutableData, prevBeaconRoot []byte) (*gethTypes.Block, error) {
txs, err := decodeTransactions(params.Transactions)
if err != nil {
return nil, err
@@ -647,6 +820,12 @@ func executableDataToBlock(params engine.ExecutableData) (*gethTypes.Block, erro
Extra: []byte("prysm-builder"), // add in extra data
MixDigest: params.Random,
WithdrawalsHash: withdrawalsRoot,
BlobGasUsed: params.BlobGasUsed,
ExcessBlobGas: params.ExcessBlobGas,
}
if prevBeaconRoot != nil {
pRoot := common.Hash(prevBeaconRoot)
header.ParentBeaconRoot = &pRoot
}
block := gethTypes.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
return block, nil