From 615feb104004d6a945ededf5862ae38325fc7ec2 Mon Sep 17 00:00:00 2001 From: rkapka Date: Wed, 10 Apr 2024 19:04:53 +0900 Subject: [PATCH] GET --- beacon-chain/cache/depositcache/BUILD.bazel | 1 + .../cache/depositcache/deposits_cache.go | 5 ++ .../cache/depositcache/testing/BUILD.bazel | 13 ++++ .../cache/depositcache/testing/mock.go | 61 +++++++++++++++++ .../cache/depositsnapshot/deposit_fetcher.go | 4 ++ beacon-chain/cache/interfaces.go | 1 + beacon-chain/deterministic-genesis/service.go | 5 ++ beacon-chain/rpc/endpoints.go | 7 ++ beacon-chain/rpc/eth/beacon/BUILD.bazel | 2 + beacon-chain/rpc/eth/beacon/handlers.go | 23 +++---- beacon-chain/rpc/eth/beacon/handlers_test.go | 9 +-- beacon-chain/rpc/eth/beacon/server.go | 2 + .../endtoend/evaluators/beaconapi/requests.go | 24 ++++++- .../endtoend/evaluators/beaconapi/types.go | 23 +++++++ testing/endtoend/evaluators/beaconapi/util.go | 13 ++-- .../endtoend/evaluators/beaconapi/verify.go | 65 ++++++++++++++----- 16 files changed, 211 insertions(+), 47 deletions(-) create mode 100644 beacon-chain/cache/depositcache/testing/BUILD.bazel create mode 100644 beacon-chain/cache/depositcache/testing/mock.go diff --git a/beacon-chain/cache/depositcache/BUILD.bazel b/beacon-chain/cache/depositcache/BUILD.bazel index d36d70566481..460f1c361708 100644 --- a/beacon-chain/cache/depositcache/BUILD.bazel +++ b/beacon-chain/cache/depositcache/BUILD.bazel @@ -16,6 +16,7 @@ go_library( "//beacon-chain/cache:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", + "//consensus-types:go_default_library", "//container/trie:go_default_library", "//crypto/hash:go_default_library", "//encoding/bytesutil:go_default_library", diff --git a/beacon-chain/cache/depositcache/deposits_cache.go b/beacon-chain/cache/depositcache/deposits_cache.go index 81355110fcc7..6525847079f4 100644 --- a/beacon-chain/cache/depositcache/deposits_cache.go +++ b/beacon-chain/cache/depositcache/deposits_cache.go @@ -18,6 +18,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/cache" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" "github.com/prysmaticlabs/prysm/v5/config/params" + consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types" "github.com/prysmaticlabs/prysm/v5/container/trie" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" @@ -312,6 +313,10 @@ func (dc *DepositCache) PruneProofs(ctx context.Context, untilDepositIndex int64 return nil } +func (dc *DepositCache) Snapshot() (*ethpb.DepositSnapshot, error) { + return nil, consensus_types.ErrUnsupportedField +} + // Deposits returns the cached internal deposit tree. func (fd *FinalizedDeposits) Deposits() cache.MerkleTree { if fd.deposits != nil { diff --git a/beacon-chain/cache/depositcache/testing/BUILD.bazel b/beacon-chain/cache/depositcache/testing/BUILD.bazel new file mode 100644 index 000000000000..19c749889b4f --- /dev/null +++ b/beacon-chain/cache/depositcache/testing/BUILD.bazel @@ -0,0 +1,13 @@ +load("@prysm//tools/go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + testonly = true, + srcs = ["mock.go"], + importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/cache/depositcache/testing", + visibility = ["//visibility:public"], + deps = [ + "//beacon-chain/cache:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + ], +) diff --git a/beacon-chain/cache/depositcache/testing/mock.go b/beacon-chain/cache/depositcache/testing/mock.go new file mode 100644 index 000000000000..8e18eb2abbe6 --- /dev/null +++ b/beacon-chain/cache/depositcache/testing/mock.go @@ -0,0 +1,61 @@ +package testing + +import ( + "context" + "math/big" + + "github.com/prysmaticlabs/prysm/v5/beacon-chain/cache" + ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" +) + +type MockDepositFetcher struct { + Snap *ethpb.DepositSnapshot +} + +func (MockDepositFetcher) AllDeposits(_ context.Context, _ *big.Int) []*ethpb.Deposit { + panic("implement me") +} + +func (MockDepositFetcher) AllDepositContainers(_ context.Context) []*ethpb.DepositContainer { + panic("implement me") +} + +func (MockDepositFetcher) DepositByPubkey(_ context.Context, _ []byte) (*ethpb.Deposit, *big.Int) { + panic("implement me") +} + +func (MockDepositFetcher) DepositsNumberAndRootAtHeight(_ context.Context, _ *big.Int) (uint64, [32]byte) { + panic("implement me") +} + +func (MockDepositFetcher) InsertPendingDeposit(_ context.Context, _ *ethpb.Deposit, _ uint64, _ int64, _ [32]byte) { + panic("implement me") +} + +func (MockDepositFetcher) PendingDeposits(_ context.Context, _ *big.Int) []*ethpb.Deposit { + panic("implement me") +} + +func (MockDepositFetcher) PendingContainers(_ context.Context, _ *big.Int) []*ethpb.DepositContainer { + panic("implement me") +} + +func (MockDepositFetcher) PrunePendingDeposits(_ context.Context, _ int64) { + panic("implement me") +} + +func (MockDepositFetcher) PruneProofs(_ context.Context, _ int64) error { + panic("implement me") +} + +func (m MockDepositFetcher) Snapshot() (*ethpb.DepositSnapshot, error) { + return m.Snap, nil +} + +func (MockDepositFetcher) FinalizedDeposits(_ context.Context) (cache.FinalizedDeposits, error) { + panic("implement me") +} + +func (MockDepositFetcher) NonFinalizedDeposits(_ context.Context, _ int64, _ *big.Int) []*ethpb.Deposit { + panic("implement me") +} diff --git a/beacon-chain/cache/depositsnapshot/deposit_fetcher.go b/beacon-chain/cache/depositsnapshot/deposit_fetcher.go index 0c6406439ee5..f49867ad0154 100644 --- a/beacon-chain/cache/depositsnapshot/deposit_fetcher.go +++ b/beacon-chain/cache/depositsnapshot/deposit_fetcher.go @@ -244,6 +244,10 @@ func (c *Cache) InsertPendingDeposit(ctx context.Context, d *ethpb.Deposit, bloc span.AddAttributes(trace.Int64Attribute("count", int64(len(c.pendingDeposits)))) } +func (c *Cache) Snapshot() (*ethpb.DepositSnapshot, error) { + return c.finalizedDeposits.depositTree.ToProto() +} + // Deposits returns the cached internal deposit tree. func (fd *finalizedDepositsContainer) Deposits() cache.MerkleTree { return fd.depositTree diff --git a/beacon-chain/cache/interfaces.go b/beacon-chain/cache/interfaces.go index 163dbd0ef777..05c2ad1128f1 100644 --- a/beacon-chain/cache/interfaces.go +++ b/beacon-chain/cache/interfaces.go @@ -25,6 +25,7 @@ type DepositFetcher interface { PendingContainers(ctx context.Context, untilBlk *big.Int) []*ethpb.DepositContainer PrunePendingDeposits(ctx context.Context, merkleTreeIndex int64) PruneProofs(ctx context.Context, untilDepositIndex int64) error + Snapshot() (*ethpb.DepositSnapshot, error) FinalizedFetcher } diff --git a/beacon-chain/deterministic-genesis/service.go b/beacon-chain/deterministic-genesis/service.go index 163acfcd4488..a522e6674b9b 100644 --- a/beacon-chain/deterministic-genesis/service.go +++ b/beacon-chain/deterministic-genesis/service.go @@ -64,6 +64,11 @@ func (s *Service) PruneProofs(ctx context.Context, untilDepositIndex int64) erro return nil } +func (s *Service) Snapshot() (*ethpb.DepositSnapshot, error) { + log.Error("Snapshot should not be called") + return nil, nil +} + // Config options for the interop service. type Config struct { GenesisTime uint64 diff --git a/beacon-chain/rpc/endpoints.go b/beacon-chain/rpc/endpoints.go index 9809833c2338..e944d93c83ea 100644 --- a/beacon-chain/rpc/endpoints.go +++ b/beacon-chain/rpc/endpoints.go @@ -358,6 +358,7 @@ func (s *Service) beaconEndpoints( FinalizationFetcher: s.cfg.FinalizationFetcher, ForkchoiceFetcher: s.cfg.ForkchoiceFetcher, CoreService: coreService, + DepositFetcher: s.cfg.DepositFetcher, } const namespace = "beacon" @@ -548,6 +549,12 @@ func (s *Service) beaconEndpoints( handler: server.GetValidatorBalances, methods: []string{http.MethodGet, http.MethodPost}, }, + { + template: "/eth/v1/beacon/deposit_snapshot", + name: namespace + ",GetDepositSnapshot", + handler: server.GetDepositSnapshot, + methods: []string{http.MethodGet}, + }, } } diff --git a/beacon-chain/rpc/eth/beacon/BUILD.bazel b/beacon-chain/rpc/eth/beacon/BUILD.bazel index 11ded5c96335..38882753d6ef 100644 --- a/beacon-chain/rpc/eth/beacon/BUILD.bazel +++ b/beacon-chain/rpc/eth/beacon/BUILD.bazel @@ -17,6 +17,7 @@ go_library( "//api/server:go_default_library", "//api/server/structs:go_default_library", "//beacon-chain/blockchain:go_default_library", + "//beacon-chain/cache:go_default_library", "//beacon-chain/cache/depositsnapshot:go_default_library", "//beacon-chain/core/altair:go_default_library", "//beacon-chain/core/blocks:go_default_library", @@ -79,6 +80,7 @@ go_test( "//api/server:go_default_library", "//api/server/structs:go_default_library", "//beacon-chain/blockchain/testing:go_default_library", + "//beacon-chain/cache/depositcache/testing:go_default_library", "//beacon-chain/cache/depositsnapshot:go_default_library", "//beacon-chain/core/signing:go_default_library", "//beacon-chain/core/time:go_default_library", diff --git a/beacon-chain/rpc/eth/beacon/handlers.go b/beacon-chain/rpc/eth/beacon/handlers.go index 03567b8be205..836084141f01 100644 --- a/beacon-chain/rpc/eth/beacon/handlers.go +++ b/beacon-chain/rpc/eth/beacon/handlers.go @@ -2054,29 +2054,24 @@ func (s *Server) GetGenesis(w http.ResponseWriter, r *http.Request) { // GetDepositSnapshot retrieves the EIP-4881 Deposit Tree Snapshot. Either a JSON or, // if the Accept header was added, bytes serialized by SSZ will be returned. func (s *Server) GetDepositSnapshot(w http.ResponseWriter, r *http.Request) { - ctx, span := trace.StartSpan(r.Context(), "beacon.GetDepositSnapshot") + _, span := trace.StartSpan(r.Context(), "beacon.GetDepositSnapshot") defer span.End() - if s.BeaconDB == nil { - httputil.HandleError(w, "Could not retrieve beaconDB", http.StatusInternalServerError) - return - } - eth1data, err := s.BeaconDB.ExecutionChainData(ctx) + snapshot, err := s.DepositFetcher.Snapshot() if err != nil { - httputil.HandleError(w, "Could not retrieve execution chain data: "+err.Error(), http.StatusInternalServerError) - return - } - if eth1data == nil { - httputil.HandleError(w, "Could not retrieve execution chain data: empty Eth1Data", http.StatusInternalServerError) + httputil.HandleError(w, "Could not retrieve snapshot: "+err.Error(), http.StatusInternalServerError) return } - snapshot := eth1data.DepositSnapshot if snapshot == nil || len(snapshot.Finalized) == 0 { - httputil.HandleError(w, "No Finalized Snapshot Available", http.StatusNotFound) + httputil.HandleError(w, "Could not retrieve snapshot: empty snapshot", http.StatusInternalServerError) return } if len(snapshot.Finalized) > depositsnapshot.DepositContractDepth { - httputil.HandleError(w, "Retrieved invalid deposit snapshot", http.StatusInternalServerError) + httputil.HandleError( + w, + fmt.Sprintf("Snapshot depth %d bigger than deposit contract depth %d", len(snapshot.Finalized), depositsnapshot.DepositContractDepth), + http.StatusInternalServerError, + ) return } if httputil.RespondWithSsz(r) { diff --git a/beacon-chain/rpc/eth/beacon/handlers_test.go b/beacon-chain/rpc/eth/beacon/handlers_test.go index f984fce36bcd..1488068bd0b4 100644 --- a/beacon-chain/rpc/eth/beacon/handlers_test.go +++ b/beacon-chain/rpc/eth/beacon/handlers_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common/hexutil" + testing2 "github.com/prysmaticlabs/prysm/v5/beacon-chain/cache/depositcache/testing" mockp2p "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/testing" logTest "github.com/sirupsen/logrus/hooks/test" "go.uber.org/mock/gomock" @@ -3575,7 +3576,6 @@ func TestGetGenesis(t *testing.T) { } func TestGetDepositSnapshot(t *testing.T) { - beaconDB := dbTest.SetupDB(t) mockTrie := depositsnapshot.NewDepositTree() deposits := [][32]byte{ bytesutil.ToBytes32([]byte{1}), @@ -3596,13 +3596,8 @@ func TestGetDepositSnapshot(t *testing.T) { require.NoError(t, err) root, err := snapshot.CalculateRoot() require.NoError(t, err) - chainData := ð.ETH1ChainData{ - DepositSnapshot: snapshot.ToProto(), - } - err = beaconDB.SaveExecutionChainData(context.Background(), chainData) - require.NoError(t, err) s := Server{ - BeaconDB: beaconDB, + DepositFetcher: &testing2.MockDepositFetcher{Snap: snapshot.ToProto()}, } request := httptest.NewRequest(http.MethodGet, "/eth/v1/beacon/deposit_snapshot", nil) diff --git a/beacon-chain/rpc/eth/beacon/server.go b/beacon-chain/rpc/eth/beacon/server.go index e7eef22493f5..f18968451ad8 100644 --- a/beacon-chain/rpc/eth/beacon/server.go +++ b/beacon-chain/rpc/eth/beacon/server.go @@ -5,6 +5,7 @@ package beacon import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/cache" blockfeed "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/block" "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/operation" "github.com/prysmaticlabs/prysm/v5/beacon-chain/db" @@ -48,4 +49,5 @@ type Server struct { BLSChangesPool blstoexec.PoolManager ForkchoiceFetcher blockchain.ForkchoiceFetcher CoreService *core.Service + DepositFetcher cache.DepositFetcher } diff --git a/testing/endtoend/evaluators/beaconapi/requests.go b/testing/endtoend/evaluators/beaconapi/requests.go index b2593993635d..03b84d52f604 100644 --- a/testing/endtoend/evaluators/beaconapi/requests.go +++ b/testing/endtoend/evaluators/beaconapi/requests.go @@ -72,6 +72,15 @@ var requests = map[string]endpoint{ withParams(func(_ primitives.Epoch) []string { return []string{"head"} })), + "/beacon/blob_sidecars/{param1}": newMetadata[structs.SidecarsResponse](v1PathTemplate, + withStart(params.BeaconConfig().DenebForkEpoch), + withSsz(), + withParams(func(_ primitives.Epoch) []string { + return []string{"head"} + })), + "/beacon/deposit_snapshot": newMetadata[structs.DepositSnapshot](v1PathTemplate, + withStart(13), // we need to wait until finalization + withSsz()), "/beacon/blinded_blocks/{param1}": newMetadata[structs.GetBlockV2Response](v1PathTemplate, withSsz(), withParams(func(_ primitives.Epoch) []string { @@ -161,8 +170,19 @@ var requests = map[string]endpoint{ } return compareJSON(pResp, lhResp) })), + "/config/spec": newMetadata[structs.GetSpecResponse](v1PathTemplate, + withSanityCheckOnly()), "/config/deposit_contract": newMetadata[structs.GetDepositContractResponse](v1PathTemplate), - "/debug/beacon/heads": newMetadata[structs.GetForkChoiceHeadsV2Response](v2PathTemplate), + "/debug/beacon/states/{param1}": newMetadata[structs.GetBeaconStateV2Response](v2PathTemplate, + withSanityCheckOnly(), + withSsz(), + withParams(func(_ primitives.Epoch) []string { + return []string{"head"} + })), + "/debug/beacon/heads": newMetadata[structs.GetForkChoiceHeadsV2Response](v2PathTemplate, + withSanityCheckOnly()), + "/debug/fork_choice": newMetadata[structs.GetForkChoiceDumpResponse](v1PathTemplate, + withSanityCheckOnly()), "/node/identity": newMetadata[structs.GetIdentityResponse](v1PathTemplate, withCustomEval(func(p interface{}, _ interface{}) error { pResp, ok := p.(*structs.GetIdentityResponse) @@ -242,7 +262,7 @@ var requests = map[string]endpoint{ } if lhResp.Data[0].Slot == "0" { // remove the first item from lighthouse data since lighthouse is returning a value despite no proposer - // there is no proposer on slot 0 so prysm don't return anything for slot 0 + // there is no proposer on slot 0 so prysm doesn't return anything for slot 0 lhResp.Data = lhResp.Data[1:] } return compareJSON(pResp, lhResp) diff --git a/testing/endtoend/evaluators/beaconapi/types.go b/testing/endtoend/evaluators/beaconapi/types.go index 27b122500c6a..c547a79e2074 100644 --- a/testing/endtoend/evaluators/beaconapi/types.go +++ b/testing/endtoend/evaluators/beaconapi/types.go @@ -4,6 +4,8 @@ import "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" type endpoint interface { getBasePath() string + sanityCheckOnlyEnabled() bool + enableSanityCheckOnly() sszEnabled() bool enableSsz() getSszResp() []byte // retrieves the Prysm SSZ response @@ -22,6 +24,7 @@ type endpoint interface { type apiEndpoint[Resp any] struct { basePath string + sanity bool ssz bool start primitives.Epoch req interface{} @@ -36,6 +39,14 @@ func (e *apiEndpoint[Resp]) getBasePath() string { return e.basePath } +func (e *apiEndpoint[Resp]) sanityCheckOnlyEnabled() bool { + return e.sanity +} + +func (e *apiEndpoint[Resp]) enableSanityCheckOnly() { + e.sanity = true +} + func (e *apiEndpoint[Resp]) sszEnabled() bool { return e.ssz } @@ -109,30 +120,42 @@ func newMetadata[Resp any](basePath string, opts ...endpointOpt) *apiEndpoint[Re type endpointOpt func(endpoint) +// We only care if the request was successful, without comparing responses. +func withSanityCheckOnly() endpointOpt { + return func(e endpoint) { + e.enableSanityCheckOnly() + } +} + +// We request SSZ data too. func withSsz() endpointOpt { return func(e endpoint) { e.enableSsz() } } +// We begin issuing the request at a particular epoch. func withStart(start primitives.Epoch) endpointOpt { return func(e endpoint) { e.setStart(start) } } +// We pass in a specific request object. func withReq(req interface{}) endpointOpt { return func(e endpoint) { e.setReq(req) } } +// We specify URL parameters. func withParams(f func(currentEpoch primitives.Epoch) []string) endpointOpt { return func(e endpoint) { e.setParams(f) } } +// We perform custom evaluation on responses. func withCustomEval(f func(interface{}, interface{}) error) endpointOpt { return func(e endpoint) { e.setCustomEval(f) diff --git a/testing/endtoend/evaluators/beaconapi/util.go b/testing/endtoend/evaluators/beaconapi/util.go index cf26eccc8543..7a96ed6047ad 100644 --- a/testing/endtoend/evaluators/beaconapi/util.go +++ b/testing/endtoend/evaluators/beaconapi/util.go @@ -70,7 +70,6 @@ func doSSZGetRequest(template string, requestPath string, beaconNodeIdx int, bnT bnType = []string{"prysm"} } - client := &http.Client{} var port int switch bnType[0] { case "prysm": @@ -88,19 +87,19 @@ func doSSZGetRequest(template string, requestPath string, beaconNodeIdx int, bnT return nil, err } req.Header.Set("Accept", "application/octet-stream") - rsp, err := client.Do(req) + resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } - if rsp.StatusCode != http.StatusOK { + if resp.StatusCode != http.StatusOK { var body interface{} - if err := json.NewDecoder(rsp.Body).Decode(&body); err != nil { + if err := json.NewDecoder(resp.Body).Decode(&body); err != nil { return nil, err } - return nil, fmt.Errorf(msgRequestFailed, bnType[0], rsp.StatusCode, body) + return nil, fmt.Errorf(msgRequestFailed, bnType[0], resp.StatusCode, body) } - defer closeBody(rsp.Body) - body, err := io.ReadAll(rsp.Body) + defer closeBody(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } diff --git a/testing/endtoend/evaluators/beaconapi/verify.go b/testing/endtoend/evaluators/beaconapi/verify.go index a16fbc94688b..f5a4a8322ddb 100644 --- a/testing/endtoend/evaluators/beaconapi/verify.go +++ b/testing/endtoend/evaluators/beaconapi/verify.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "net/http" "reflect" "strconv" "strings" @@ -14,6 +15,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + params2 "github.com/prysmaticlabs/prysm/v5/testing/endtoend/params" "github.com/prysmaticlabs/prysm/v5/testing/endtoend/policies" e2etypes "github.com/prysmaticlabs/prysm/v5/testing/endtoend/types" "github.com/prysmaticlabs/prysm/v5/time/slots" @@ -32,6 +34,7 @@ var MultiClientVerifyIntegrity = e2etypes.Evaluator{ const ( v1PathTemplate = "http://localhost:%d/eth/v1" v2PathTemplate = "http://localhost:%d/eth/v2" + v3PathTemplate = "http://localhost:%d/eth/v3" ) func verify(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error { @@ -62,26 +65,44 @@ func run(nodeIdx int) error { if m.getParams(currentEpoch) != nil { apiPath = pathFromParams(path, m.getParams(currentEpoch)) } - fmt.Printf("executing JSON path: %s\n", apiPath) - if err = compareJSONMultiClient(nodeIdx, m.getBasePath(), apiPath, m.getReq(), m.getPResp(), m.getLHResp(), m.getCustomEval()); err != nil { - return err - } - if m.sszEnabled() { - fmt.Printf("executing SSZ path: %s\n", apiPath) - b, err := compareSSZMultiClient(nodeIdx, m.getBasePath(), apiPath) - if err != nil { + + if m.sanityCheckOnlyEnabled() { + resp := m.getPResp() + if err = doJSONGetRequest(m.getBasePath(), apiPath, nodeIdx, resp); err != nil { + return errors.Wrapf(err, "issue during Prysm JSON GET request for path %s", path) + } + if resp == nil { + return fmt.Errorf("nil response from Prysm JSON GET request for path %s", path) + } + if m.sszEnabled() { + sszResp, err := doSSZGetRequest(m.getBasePath(), apiPath, nodeIdx) + if err != nil { + return errors.Wrapf(err, "issue during Prysm SSZ GET request for path %s", path) + } + if sszResp == nil { + return fmt.Errorf("nil response from Prysm SSZ GET request for path %s", path) + } + } + } else { + if err = compareJSONMultiClient(nodeIdx, m.getBasePath(), apiPath, m.getReq(), m.getPResp(), m.getLHResp(), m.getCustomEval()); err != nil { return err } - m.setSszResp(b) + if m.sszEnabled() { + b, err := compareSSZMultiClient(nodeIdx, m.getBasePath(), apiPath) + if err != nil { + return err + } + m.setSszResp(b) + } } } - return postEvaluation(requests, currentEpoch) + return postEvaluation(nodeIdx, requests, currentEpoch) } // postEvaluation performs additional evaluation after all requests have been completed. // It is useful for things such as checking if specific fields match between endpoints. -func postEvaluation(requests map[string]endpoint, epoch primitives.Epoch) error { +func postEvaluation(nodeIdx int, 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}"] @@ -147,23 +168,33 @@ func postEvaluation(requests map[string]endpoint, epoch primitives.Epoch) error return fmt.Errorf("header root %s does not match duties root %s ", header.Data.Root, duties.DependentRoot) } + // perform a health check + basePath := fmt.Sprintf(v1PathTemplate, params2.PrysmBeaconNodeGatewayPort+nodeIdx) + resp, err := http.Get(basePath + "/node/health") + if err != nil { + return errors.Wrap(err, "could not perform a health check") + } + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("health check response's status code is %d", resp.StatusCode) + } + return nil } func compareJSONMultiClient(nodeIdx int, base, path string, req, pResp, lhResp interface{}, customEval func(interface{}, interface{}) error) error { if req != nil { if err := doJSONPostRequest(base, path, nodeIdx, req, pResp); err != nil { - return errors.Wrapf(err, "could not perform Prysm JSON POST request for path %s", path) + return errors.Wrapf(err, "issue during Prysm JSON POST request for path %s", path) } if err := doJSONPostRequest(base, path, nodeIdx, req, lhResp, "lighthouse"); err != nil { - return errors.Wrapf(err, "could not perform Lighthouse JSON POST request for path %s", path) + return errors.Wrapf(err, "issue during Lighthouse JSON POST request for path %s", path) } } else { if err := doJSONGetRequest(base, path, nodeIdx, pResp); err != nil { - return errors.Wrapf(err, "could not perform Prysm JSON GET request for path %s", path) + return errors.Wrapf(err, "issue during Prysm JSON GET request for path %s", path) } if err := doJSONGetRequest(base, path, nodeIdx, lhResp, "lighthouse"); err != nil { - return errors.Wrapf(err, "could not perform Lighthouse JSON GET request for path %s", path) + return errors.Wrapf(err, "issue during Lighthouse JSON GET request for path %s", path) } } if customEval != nil { @@ -176,11 +207,11 @@ func compareJSONMultiClient(nodeIdx int, base, path string, req, pResp, lhResp i func compareSSZMultiClient(nodeIdx int, base, path string) ([]byte, error) { pResp, err := doSSZGetRequest(base, path, nodeIdx) if err != nil { - return nil, errors.Wrapf(err, "could not perform Prysm SSZ GET request for path %s", path) + return nil, errors.Wrapf(err, "issue during Prysm SSZ GET request for path %s", path) } lhResp, err := doSSZGetRequest(base, path, nodeIdx, "lighthouse") if err != nil { - return nil, errors.Wrapf(err, "could not perform Lighthouse SSZ GET request for path %s", path) + return nil, errors.Wrapf(err, "issue during Lighthouse SSZ GET request for path %s", path) } if !bytes.Equal(pResp, lhResp) { return nil, errors.New("Prysm SSZ response does not match Lighthouse SSZ response")