diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e324fe5f3f6..40ae44f6fff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,8 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve - Return false from HasBlock if the block is being synced. - Cleanup forkchoice on failed insertions. - Use read only validator for core processing to avoid unnecessary copying. -- Use ROBlock across block processing pipeline +- Use ROBlock across block processing pipeline. +- Added missing Eth-Consensus-Version headers to GetBlockAttestationsV2 and GetAttesterSlashingsV2 endpoints. ### Deprecated diff --git a/beacon-chain/rpc/eth/beacon/handlers.go b/beacon-chain/rpc/eth/beacon/handlers.go index ec7d713011ea..f6a8a3a273e0 100644 --- a/beacon-chain/rpc/eth/beacon/handlers.go +++ b/beacon-chain/rpc/eth/beacon/handlers.go @@ -269,6 +269,7 @@ func (s *Server) GetBlockAttestationsV2(w http.ResponseWriter, r *http.Request) Finalized: s.FinalizationFetcher.IsFinalized(ctx, root), Data: attBytes, } + w.Header().Set(api.VersionHeader, version.String(v)) httputil.WriteJson(w, resp) } diff --git a/beacon-chain/rpc/eth/beacon/handlers_pool.go b/beacon-chain/rpc/eth/beacon/handlers_pool.go index 0b5612bae65d..96c6f405f0e7 100644 --- a/beacon-chain/rpc/eth/beacon/handlers_pool.go +++ b/beacon-chain/rpc/eth/beacon/handlers_pool.go @@ -496,36 +496,41 @@ func (s *Server) GetAttesterSlashingsV2(w http.ResponseWriter, r *http.Request) httputil.HandleError(w, "Could not get head state: "+err.Error(), http.StatusInternalServerError) return } + var attStructs []interface{} sourceSlashings := s.SlashingsPool.PendingAttesterSlashings(ctx, headState, true /* return unlimited slashings */) + for _, slashing := range sourceSlashings { - if slashing.Version() >= version.Electra { + var attStruct interface{} + if headState.Version() >= version.Electra { a, ok := slashing.(*eth.AttesterSlashingElectra) if !ok { - httputil.HandleError(w, fmt.Sprintf("Unable to convert electra slashing of type %T to an Electra slashing", slashing), http.StatusInternalServerError) + httputil.HandleError(w, fmt.Sprintf("Unable to convert slashing of type %T to an Electra slashing", slashing), http.StatusInternalServerError) return } - attStruct := structs.AttesterSlashingElectraFromConsensus(a) - attStructs = append(attStructs, attStruct) + attStruct = structs.AttesterSlashingElectraFromConsensus(a) } else { a, ok := slashing.(*eth.AttesterSlashing) if !ok { httputil.HandleError(w, fmt.Sprintf("Unable to convert slashing of type %T to a Phase0 slashing", slashing), http.StatusInternalServerError) return } - attStruct := structs.AttesterSlashingFromConsensus(a) - attStructs = append(attStructs, attStruct) + attStruct = structs.AttesterSlashingFromConsensus(a) } + attStructs = append(attStructs, attStruct) } + attBytes, err := json.Marshal(attStructs) if err != nil { httputil.HandleError(w, fmt.Sprintf("Failed to marshal slashing: %v", err), http.StatusInternalServerError) return } + resp := &structs.GetAttesterSlashingsResponse{ - Version: version.String(sourceSlashings[0].Version()), + Version: version.String(headState.Version()), Data: attBytes, } + w.Header().Set(api.VersionHeader, version.String(headState.Version())) httputil.WriteJson(w, resp) } diff --git a/beacon-chain/rpc/eth/beacon/handlers_pool_test.go b/beacon-chain/rpc/eth/beacon/handlers_pool_test.go index 9b549c1e45fe..dae551ae2106 100644 --- a/beacon-chain/rpc/eth/beacon/handlers_pool_test.go +++ b/beacon-chain/rpc/eth/beacon/handlers_pool_test.go @@ -1131,93 +1131,147 @@ func TestGetAttesterSlashings(t *testing.T) { } t.Run("V1", func(t *testing.T) { - bs, err := util.NewBeaconState() - require.NoError(t, err) + t.Run("ok", func(t *testing.T) { + bs, err := util.NewBeaconState() + require.NoError(t, err) - s := &Server{ - ChainInfoFetcher: &blockchainmock.ChainService{State: bs}, - SlashingsPool: &slashingsmock.PoolMock{PendingAttSlashings: []ethpbv1alpha1.AttSlashing{slashing1PreElectra, slashing2PreElectra}}, - } + s := &Server{ + ChainInfoFetcher: &blockchainmock.ChainService{State: bs}, + SlashingsPool: &slashingsmock.PoolMock{PendingAttSlashings: []ethpbv1alpha1.AttSlashing{slashing1PreElectra, slashing2PreElectra}}, + } - request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/beacon/pool/attester_slashings", nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} + request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/beacon/pool/attester_slashings", nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} - s.GetAttesterSlashings(writer, request) - require.Equal(t, http.StatusOK, writer.Code) - resp := &structs.GetAttesterSlashingsResponse{} - require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp)) - require.NotNil(t, resp) - require.NotNil(t, resp.Data) + s.GetAttesterSlashings(writer, request) + require.Equal(t, http.StatusOK, writer.Code) + resp := &structs.GetAttesterSlashingsResponse{} + require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp)) + require.NotNil(t, resp) + require.NotNil(t, resp.Data) - var slashings []*structs.AttesterSlashing - require.NoError(t, json.Unmarshal(resp.Data, &slashings)) + var slashings []*structs.AttesterSlashing + require.NoError(t, json.Unmarshal(resp.Data, &slashings)) - ss, err := structs.AttesterSlashingsToConsensus(slashings) - require.NoError(t, err) + ss, err := structs.AttesterSlashingsToConsensus(slashings) + require.NoError(t, err) - require.DeepEqual(t, slashing1PreElectra, ss[0]) - require.DeepEqual(t, slashing2PreElectra, ss[1]) + require.DeepEqual(t, slashing1PreElectra, ss[0]) + require.DeepEqual(t, slashing2PreElectra, ss[1]) + }) + t.Run("no slashings", func(t *testing.T) { + bs, err := util.NewBeaconState() + require.NoError(t, err) + + s := &Server{ + ChainInfoFetcher: &blockchainmock.ChainService{State: bs}, + SlashingsPool: &slashingsmock.PoolMock{PendingAttSlashings: []ethpbv1alpha1.AttSlashing{}}, + } + + request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/beacon/pool/attester_slashings", nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetAttesterSlashings(writer, request) + require.Equal(t, http.StatusOK, writer.Code) + resp := &structs.GetAttesterSlashingsResponse{} + require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp)) + require.NotNil(t, resp) + require.NotNil(t, resp.Data) + + var slashings []*structs.AttesterSlashing + require.NoError(t, json.Unmarshal(resp.Data, &slashings)) + require.Equal(t, 0, len(slashings)) + }) }) - t.Run("V2-post-electra", func(t *testing.T) { - bs, err := util.NewBeaconStateElectra() - require.NoError(t, err) + t.Run("V2", func(t *testing.T) { + t.Run("post-electra-ok", func(t *testing.T) { + bs, err := util.NewBeaconStateElectra() + require.NoError(t, err) - s := &Server{ - ChainInfoFetcher: &blockchainmock.ChainService{State: bs}, - SlashingsPool: &slashingsmock.PoolMock{PendingAttSlashings: []ethpbv1alpha1.AttSlashing{slashing1PostElectra, slashing2PostElectra}}, - } + s := &Server{ + ChainInfoFetcher: &blockchainmock.ChainService{State: bs}, + SlashingsPool: &slashingsmock.PoolMock{PendingAttSlashings: []ethpbv1alpha1.AttSlashing{slashing1PostElectra, slashing2PostElectra}}, + } - request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v2/beacon/pool/attester_slashings", nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} + request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v2/beacon/pool/attester_slashings", nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} - s.GetAttesterSlashingsV2(writer, request) - require.Equal(t, http.StatusOK, writer.Code) - resp := &structs.GetAttesterSlashingsResponse{} - require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp)) - require.NotNil(t, resp) - require.NotNil(t, resp.Data) - assert.Equal(t, "electra", resp.Version) + s.GetAttesterSlashingsV2(writer, request) + require.Equal(t, http.StatusOK, writer.Code) + resp := &structs.GetAttesterSlashingsResponse{} + require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp)) + require.NotNil(t, resp) + require.NotNil(t, resp.Data) + assert.Equal(t, "electra", resp.Version) - // Unmarshal resp.Data into a slice of slashings - var slashings []*structs.AttesterSlashingElectra - require.NoError(t, json.Unmarshal(resp.Data, &slashings)) + // Unmarshal resp.Data into a slice of slashings + var slashings []*structs.AttesterSlashingElectra + require.NoError(t, json.Unmarshal(resp.Data, &slashings)) - ss, err := structs.AttesterSlashingsElectraToConsensus(slashings) - require.NoError(t, err) + ss, err := structs.AttesterSlashingsElectraToConsensus(slashings) + require.NoError(t, err) - require.DeepEqual(t, slashing1PostElectra, ss[0]) - require.DeepEqual(t, slashing2PostElectra, ss[1]) - }) - t.Run("V2-pre-electra", func(t *testing.T) { - bs, err := util.NewBeaconState() - require.NoError(t, err) + require.DeepEqual(t, slashing1PostElectra, ss[0]) + require.DeepEqual(t, slashing2PostElectra, ss[1]) + }) + t.Run("pre-electra-ok", func(t *testing.T) { + bs, err := util.NewBeaconState() + require.NoError(t, err) - s := &Server{ - ChainInfoFetcher: &blockchainmock.ChainService{State: bs}, - SlashingsPool: &slashingsmock.PoolMock{PendingAttSlashings: []ethpbv1alpha1.AttSlashing{slashing1PreElectra, slashing2PreElectra}}, - } + s := &Server{ + ChainInfoFetcher: &blockchainmock.ChainService{State: bs}, + SlashingsPool: &slashingsmock.PoolMock{PendingAttSlashings: []ethpbv1alpha1.AttSlashing{slashing1PreElectra, slashing2PreElectra}}, + } - request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/beacon/pool/attester_slashings", nil) - writer := httptest.NewRecorder() - writer.Body = &bytes.Buffer{} + request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/beacon/pool/attester_slashings", nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} - s.GetAttesterSlashingsV2(writer, request) - require.Equal(t, http.StatusOK, writer.Code) - resp := &structs.GetAttesterSlashingsResponse{} - require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp)) - require.NotNil(t, resp) - require.NotNil(t, resp.Data) + s.GetAttesterSlashingsV2(writer, request) + require.Equal(t, http.StatusOK, writer.Code) + resp := &structs.GetAttesterSlashingsResponse{} + require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp)) + require.NotNil(t, resp) + require.NotNil(t, resp.Data) - var slashings []*structs.AttesterSlashing - require.NoError(t, json.Unmarshal(resp.Data, &slashings)) + var slashings []*structs.AttesterSlashing + require.NoError(t, json.Unmarshal(resp.Data, &slashings)) - ss, err := structs.AttesterSlashingsToConsensus(slashings) - require.NoError(t, err) + ss, err := structs.AttesterSlashingsToConsensus(slashings) + require.NoError(t, err) - require.DeepEqual(t, slashing1PreElectra, ss[0]) - require.DeepEqual(t, slashing2PreElectra, ss[1]) + require.DeepEqual(t, slashing1PreElectra, ss[0]) + require.DeepEqual(t, slashing2PreElectra, ss[1]) + }) + t.Run("no-slashings", func(t *testing.T) { + bs, err := util.NewBeaconStateElectra() + require.NoError(t, err) + + s := &Server{ + ChainInfoFetcher: &blockchainmock.ChainService{State: bs}, + SlashingsPool: &slashingsmock.PoolMock{PendingAttSlashings: []ethpbv1alpha1.AttSlashing{}}, + } + + request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v2/beacon/pool/attester_slashings", nil) + writer := httptest.NewRecorder() + writer.Body = &bytes.Buffer{} + + s.GetAttesterSlashingsV2(writer, request) + require.Equal(t, http.StatusOK, writer.Code) + resp := &structs.GetAttesterSlashingsResponse{} + require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp)) + require.NotNil(t, resp) + require.NotNil(t, resp.Data) + assert.Equal(t, "electra", resp.Version) + + // Unmarshal resp.Data into a slice of slashings + var slashings []*structs.AttesterSlashingElectra + require.NoError(t, json.Unmarshal(resp.Data, &slashings)) + require.Equal(t, 0, len(slashings)) + }) }) }