diff --git a/api/client/beacon/BUILD.bazel b/api/client/beacon/BUILD.bazel index 0b70b6ae59..0378f357f5 100644 --- a/api/client/beacon/BUILD.bazel +++ b/api/client/beacon/BUILD.bazel @@ -20,6 +20,7 @@ go_library( "//encoding/ssz/detect:go_default_library", "//io/file:go_default_library", "//network/forks:go_default_library", + "//proto/eth/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//runtime/version:go_default_library", "//time/slots:go_default_library", diff --git a/api/client/beacon/client.go b/api/client/beacon/client.go index 1563305c0f..5b30a83fd9 100644 --- a/api/client/beacon/client.go +++ b/api/client/beacon/client.go @@ -17,6 +17,7 @@ import ( "time" "github.com/prysmaticlabs/prysm/v3/network/forks" + v1 "github.com/prysmaticlabs/prysm/v3/proto/eth/v1" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" @@ -33,6 +34,7 @@ const ( getForkForStatePath = "/eth/v1/beacon/states/{{.Id}}/fork" getWeakSubjectivityPath = "/eth/v1/beacon/weak_subjectivity" getForkSchedulePath = "/eth/v1/config/fork_schedule" + getConfigSpecPath = "/eth/v1/config/spec" getStatePath = "/eth/v2/debug/beacon/states" getNodeVersionPath = "/eth/v1/node/version" changeBLStoExecutionPath = "/eth/v1/beacon/pool/bls_to_execution_changes" @@ -252,6 +254,20 @@ func (c *Client) GetForkSchedule(ctx context.Context) (forks.OrderedSchedule, er return ofs, nil } +// GetConfigSpec retrieve the current configs of the network used by the beacon node. +func (c *Client) GetConfigSpec(ctx context.Context) (*v1.SpecResponse, error) { + body, err := c.get(ctx, getConfigSpecPath) + if err != nil { + return nil, errors.Wrap(err, "error requesting configSpecPath") + } + fsr := &v1.SpecResponse{} + err = json.Unmarshal(body, fsr) + if err != nil { + return nil, err + } + return fsr, nil +} + type NodeVersion struct { implementation string semver string diff --git a/cmd/prysmctl/validator/BUILD.bazel b/cmd/prysmctl/validator/BUILD.bazel index bfa64df34e..cacfd1e9d5 100644 --- a/cmd/prysmctl/validator/BUILD.bazel +++ b/cmd/prysmctl/validator/BUILD.bazel @@ -16,8 +16,7 @@ go_library( "//cmd/validator/flags:go_default_library", "//config/features:go_default_library", "//config/fieldparams:go_default_library", - "//config/params:go_default_library", - "//encoding/bytesutil:go_default_library", + "//consensus-types/primitives:go_default_library", "//runtime/tos:go_default_library", "@com_github_ethereum_go_ethereum//common:go_default_library", "@com_github_logrusorgru_aurora//:go_default_library", diff --git a/cmd/prysmctl/validator/withdraw.go b/cmd/prysmctl/validator/withdraw.go index 2b8cdcdc09..0c106a4d4e 100644 --- a/cmd/prysmctl/validator/withdraw.go +++ b/cmd/prysmctl/validator/withdraw.go @@ -7,6 +7,7 @@ import ( "io/fs" "os" "path/filepath" + "strconv" "strings" "github.com/ethereum/go-ethereum/common" @@ -15,8 +16,7 @@ import ( "github.com/prysmaticlabs/prysm/v3/api/client/beacon" "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware" fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" - "github.com/prysmaticlabs/prysm/v3/config/params" - "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" + "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" log "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" "go.opencensus.io/trace" @@ -53,7 +53,7 @@ func getWithdrawalMessagesFromPathFlag(c *cli.Context) ([]*apimiddleware.SignedB } var to []*apimiddleware.SignedBLSToExecutionChangeJson if err := json.Unmarshal(b, &to); err != nil { - log.Warnf("provided file: %s, is not a list of signed withdrawal messages", foundFilePath) + log.Warnf("provided file: %s, is not a list of signed withdrawal messages. Error:%s", foundFilePath, err.Error()) continue } // verify 0x from file and add if needed @@ -93,7 +93,19 @@ func callWithdrawalEndpoints(ctx context.Context, host string, request []*apimid if err != nil { return errors.Wrap(err, "could not retrieve current fork information") } - if !(params.BeaconConfig().ForkVersionSchedule[bytesutil.ToBytes4(fork.CurrentVersion)] >= params.BeaconConfig().CapellaForkEpoch) { + spec, err := client.GetConfigSpec(ctx) + if err != nil { + return err + } + forkEpoch, ok := spec.Data["CAPELLA_FORK_EPOCH"] + if !ok { + return errors.New("Configs used on beacon node do not contain CAPELLA_FORK_EPOCH") + } + capellaForkEpoch, err := strconv.Atoi(forkEpoch) + if err != nil { + return errors.New("could not convert CAPELLA_FORK_EPOCH to a number") + } + if fork.Epoch < primitives.Epoch(capellaForkEpoch) { return errors.New("setting withdrawals using the BLStoExecutionChange endpoint is only available after the Capella/Shanghai hard fork.") } err = client.SubmitChangeBLStoExecution(ctx, request) diff --git a/cmd/prysmctl/validator/withdraw_test.go b/cmd/prysmctl/validator/withdraw_test.go index 6f69a637f8..d40ff54cf2 100644 --- a/cmd/prysmctl/validator/withdraw_test.go +++ b/cmd/prysmctl/validator/withdraw_test.go @@ -41,12 +41,19 @@ func getHappyPathTestServer(file string, t *testing.T) *httptest.Server { Data: &apimiddleware.ForkJson{ PreviousVersion: hexutil.Encode(params.BeaconConfig().CapellaForkVersion), CurrentVersion: hexutil.Encode(params.BeaconConfig().CapellaForkVersion), - Epoch: fmt.Sprintf("%d", params.BeaconConfig().CapellaForkEpoch), + Epoch: "1350", }, ExecutionOptimistic: false, Finalized: true, }) require.NoError(t, err) + } else if r.RequestURI == "/eth/v1/config/spec" { + m := make(map[string]string) + m["CAPELLA_FORK_EPOCH"] = "1350" + err := json.NewEncoder(w).Encode(&apimiddleware.SpecResponseJson{ + Data: m, + }) + require.NoError(t, err) } } @@ -231,6 +238,15 @@ func TestCallWithdrawalEndpoint_Errors(t *testing.T) { Finalized: true, }) require.NoError(t, err) + } else if r.RequestURI == "/eth/v1/config/spec" { + w.WriteHeader(200) + w.Header().Set("Content-Type", "application/json") + m := make(map[string]string) + m["CAPELLA_FORK_EPOCH"] = "1350" + err := json.NewEncoder(w).Encode(&apimiddleware.SpecResponseJson{ + Data: m, + }) + require.NoError(t, err) } else { w.WriteHeader(400) w.Header().Set("Content-Type", "application/json") @@ -268,16 +284,26 @@ func TestCallWithdrawalEndpoint_ForkBeforeCapella(t *testing.T) { srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(&apimiddleware.StateForkResponseJson{ - Data: &apimiddleware.ForkJson{ - PreviousVersion: hexutil.Encode(params.BeaconConfig().BellatrixForkVersion), - CurrentVersion: hexutil.Encode(params.BeaconConfig().BellatrixForkVersion), - Epoch: fmt.Sprintf("%d", params.BeaconConfig().BellatrixForkEpoch), - }, - ExecutionOptimistic: false, - Finalized: true, - }) - require.NoError(t, err) + if r.RequestURI == "/eth/v1/beacon/states/head/fork" { + + err := json.NewEncoder(w).Encode(&apimiddleware.StateForkResponseJson{ + Data: &apimiddleware.ForkJson{ + PreviousVersion: hexutil.Encode(params.BeaconConfig().BellatrixForkVersion), + CurrentVersion: hexutil.Encode(params.BeaconConfig().BellatrixForkVersion), + Epoch: "1000", + }, + ExecutionOptimistic: false, + Finalized: true, + }) + require.NoError(t, err) + } else if r.RequestURI == "/eth/v1/config/spec" { + m := make(map[string]string) + m["CAPELLA_FORK_EPOCH"] = "1350" + err := json.NewEncoder(w).Encode(&apimiddleware.SpecResponseJson{ + Data: m, + }) + require.NoError(t, err) + } })) err = srv.Listener.Close() require.NoError(t, err)