mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
<!-- Thanks for sending a PR! Before submitting: 1. If this is your first PR, check out our contribution guide here https://docs.prylabs.network/docs/contribute/contribution-guidelines You will then need to sign our Contributor License Agreement (CLA), which will show up as a comment from a bot in this pull request after you open it. We cannot review code without a signed CLA. 2. Please file an associated tracking issue if this pull request is non-trivial and requires context for our team to understand. All features and most bug fixes should have an associated issue with a design discussed and decided upon. Small bug fixes and documentation improvements don't need issues. 3. New features and bug fixes must have tests. Documentation may need to be updated. If you're unsure what to update, send the PR, and we'll discuss in review. 4. Note that PRs updating dependencies and new Go versions are not accepted. Please file an issue instead. 5. A changelog entry is required for user facing issues. --> **What type of PR is this?** Bug fix **What does this PR do? Why is it needed?** validator fallbacks shouldn't work on nodes that are syncing as many of the tasks validators perform require the node to be fully synced. - 206 or any other code is interpreted as "not ready" - 200 interpreted as "ready" **Which issues(s) does this PR fix?** continuation of https://github.com/OffchainLabs/prysm/pull/15401 **Other notes for review** **Acknowledgements** - [x] I have read [CONTRIBUTING.md](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md). - [x] I have included a uniquely named [changelog fragment file](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md#maintaining-changelogmd). - [x] I have added a description with sufficient context for reviewers to understand this PR. - [x] I have tested that my changes work as expected and I added a testing plan to the PR description (if applicable).
126 lines
4.0 KiB
Go
126 lines
4.0 KiB
Go
package beacon_api
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
|
"github.com/OffchainLabs/prysm/v7/validator/client/iface"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/golang/protobuf/ptypes/empty"
|
|
"github.com/pkg/errors"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
)
|
|
|
|
var (
|
|
_ = iface.NodeClient(&beaconApiNodeClient{})
|
|
)
|
|
|
|
type beaconApiNodeClient struct {
|
|
fallbackClient iface.NodeClient
|
|
jsonRestHandler RestHandler
|
|
genesisProvider GenesisProvider
|
|
}
|
|
|
|
func (c *beaconApiNodeClient) SyncStatus(ctx context.Context, _ *empty.Empty) (*ethpb.SyncStatus, error) {
|
|
syncingResponse := structs.SyncStatusResponse{}
|
|
if err := c.jsonRestHandler.Get(ctx, "/eth/v1/node/syncing", &syncingResponse); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if syncingResponse.Data == nil {
|
|
return nil, errors.New("syncing data is nil")
|
|
}
|
|
|
|
return ðpb.SyncStatus{
|
|
Syncing: syncingResponse.Data.IsSyncing,
|
|
}, nil
|
|
}
|
|
|
|
func (c *beaconApiNodeClient) Genesis(ctx context.Context, _ *empty.Empty) (*ethpb.Genesis, error) {
|
|
genesisJson, err := c.genesisProvider.Genesis(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get genesis")
|
|
}
|
|
|
|
genesisValidatorRoot, err := hexutil.Decode(genesisJson.GenesisValidatorsRoot)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to decode genesis validator root `%s`", genesisJson.GenesisValidatorsRoot)
|
|
}
|
|
|
|
genesisTime, err := strconv.ParseInt(genesisJson.GenesisTime, 10, 64)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to parse genesis time `%s`", genesisJson.GenesisTime)
|
|
}
|
|
|
|
depositContractJson := structs.GetDepositContractResponse{}
|
|
if err = c.jsonRestHandler.Get(ctx, "/eth/v1/config/deposit_contract", &depositContractJson); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if depositContractJson.Data == nil {
|
|
return nil, errors.New("deposit contract data is nil")
|
|
}
|
|
|
|
depositContactAddress, err := hexutil.Decode(depositContractJson.Data.Address)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to decode deposit contract address `%s`", depositContractJson.Data.Address)
|
|
}
|
|
|
|
return ðpb.Genesis{
|
|
GenesisTime: ×tamppb.Timestamp{
|
|
Seconds: genesisTime,
|
|
},
|
|
DepositContractAddress: depositContactAddress,
|
|
GenesisValidatorsRoot: genesisValidatorRoot,
|
|
}, nil
|
|
}
|
|
|
|
func (c *beaconApiNodeClient) Version(ctx context.Context, _ *empty.Empty) (*ethpb.Version, error) {
|
|
var versionResponse structs.GetVersionResponse
|
|
if err := c.jsonRestHandler.Get(ctx, "/eth/v1/node/version", &versionResponse); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if versionResponse.Data == nil || versionResponse.Data.Version == "" {
|
|
return nil, errors.New("empty version response")
|
|
}
|
|
|
|
return ðpb.Version{
|
|
Version: versionResponse.Data.Version,
|
|
}, nil
|
|
}
|
|
|
|
func (c *beaconApiNodeClient) Peers(ctx context.Context, in *empty.Empty) (*ethpb.Peers, error) {
|
|
if c.fallbackClient != nil {
|
|
return c.fallbackClient.Peers(ctx, in)
|
|
}
|
|
|
|
// TODO: Implement me
|
|
return nil, errors.New("beaconApiNodeClient.Peers is not implemented. To use a fallback client, pass a fallback client as the last argument of NewBeaconApiNodeClientWithFallback.")
|
|
}
|
|
|
|
// IsReady returns true only if the node is fully synced (200 OK).
|
|
// A 206 Partial Content response indicates the node is syncing and not ready.
|
|
func (c *beaconApiNodeClient) IsReady(ctx context.Context) bool {
|
|
statusCode, err := c.jsonRestHandler.GetStatusCode(ctx, "/eth/v1/node/health")
|
|
if err != nil {
|
|
log.WithError(err).Error("failed to get health of node")
|
|
return false
|
|
}
|
|
// Only 200 OK means the node is fully synced and ready.
|
|
// 206 Partial Content means syncing, 503 means unavailable.
|
|
return statusCode == http.StatusOK
|
|
}
|
|
|
|
func NewNodeClientWithFallback(jsonRestHandler RestHandler, fallbackClient iface.NodeClient) iface.NodeClient {
|
|
b := &beaconApiNodeClient{
|
|
jsonRestHandler: jsonRestHandler,
|
|
fallbackClient: fallbackClient,
|
|
genesisProvider: &beaconApiGenesisProvider{jsonRestHandler: jsonRestHandler},
|
|
}
|
|
return b
|
|
}
|