POST version of GetValidators and GetValidatorBalances (#13199)

* POST versions of GetValidators and GetValidatorBalances

* post statuses

* balances test

* group params

* test error cases
This commit is contained in:
Radosław Kapka 2023-11-22 18:30:52 +01:00 committed by GitHub
parent 8902ad3a20
commit 4b3c511a26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 319 additions and 53 deletions

View File

@ -1,7 +1,9 @@
package beacon
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"
@ -49,7 +51,32 @@ func (s *Server) GetValidators(w http.ResponseWriter, r *http.Request) {
}
isFinalized := s.FinalizationFetcher.IsFinalized(ctx, blockRoot)
rawIds := r.URL.Query()["id"]
var req GetValidatorsRequest
if r.Method == http.MethodPost {
err = json.NewDecoder(r.Body).Decode(&req)
switch {
case err == io.EOF:
http2.HandleError(w, "No data submitted", http.StatusBadRequest)
return
case err != nil:
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
return
}
}
var statuses []string
var rawIds []string
if r.Method == http.MethodGet {
rawIds = r.URL.Query()["id"]
statuses = r.URL.Query()["status"]
} else {
rawIds = req.Ids
statuses = req.Statuses
}
for i, ss := range statuses {
statuses[i] = strings.ToLower(ss)
}
ids, ok := decodeIds(w, st, rawIds, true /* ignore unknown */)
if !ok {
return
@ -72,11 +99,6 @@ func (s *Server) GetValidators(w http.ResponseWriter, r *http.Request) {
epoch := slots.ToEpoch(st.Slot())
allBalances := st.Balances()
statuses := r.URL.Query()["status"]
for i, ss := range statuses {
statuses[i] = strings.ToLower(ss)
}
// Exit early if no matching validators were found or we don't want to further filter validators by status.
if len(readOnlyVals) == 0 || len(statuses) == 0 {
containers := make([]*ValidatorContainer, len(readOnlyVals))
@ -234,7 +256,21 @@ func (bs *Server) GetValidatorBalances(w http.ResponseWriter, r *http.Request) {
}
isFinalized := bs.FinalizationFetcher.IsFinalized(ctx, blockRoot)
rawIds := r.URL.Query()["id"]
var rawIds []string
if r.Method == http.MethodGet {
rawIds = r.URL.Query()["id"]
} else {
err = json.NewDecoder(r.Body).Decode(&rawIds)
switch {
case err == io.EOF:
http2.HandleError(w, "No data submitted", http.StatusBadRequest)
return
case err != nil:
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
return
}
}
ids, ok := decodeIds(w, st, rawIds, true /* ignore unknown */)
if !ok {
return

View File

@ -6,6 +6,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"strconv"
"strings"
"testing"
@ -26,8 +27,12 @@ import (
)
func TestGetValidators(t *testing.T) {
const exitedValIndex = 3
var st state.BeaconState
st, _ = util.DeterministicGenesisState(t, 8192)
st, _ = util.DeterministicGenesisState(t, 4)
vals := st.Validators()
vals[exitedValIndex].ExitEpoch = 0
require.NoError(t, st.SetValidators(vals))
t.Run("get all", func(t *testing.T) {
chainService := &chainMock.ChainService{}
@ -49,7 +54,7 @@ func TestGetValidators(t *testing.T) {
assert.Equal(t, http.StatusOK, writer.Code)
resp := &GetValidatorsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 8192, len(resp.Data))
require.Equal(t, 4, len(resp.Data))
val := resp.Data[0]
assert.Equal(t, "0", val.Index)
assert.Equal(t, "32000000000", val.Balance)
@ -77,7 +82,7 @@ func TestGetValidators(t *testing.T) {
request := httptest.NewRequest(
http.MethodGet,
"http://example.com/eth/v1/beacon/states/{state_id}/validators?id=15&id=26",
"http://example.com/eth/v1/beacon/states/{state_id}/validators?id=0&id=1",
nil,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
@ -89,8 +94,8 @@ func TestGetValidators(t *testing.T) {
resp := &GetValidatorsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 2, len(resp.Data))
assert.Equal(t, "15", resp.Data[0].Index)
assert.Equal(t, "26", resp.Data[1].Index)
assert.Equal(t, "0", resp.Data[0].Index)
assert.Equal(t, "1", resp.Data[1].Index)
})
t.Run("get by pubkey", func(t *testing.T) {
chainService := &chainMock.ChainService{}
@ -103,8 +108,8 @@ func TestGetValidators(t *testing.T) {
FinalizationFetcher: chainService,
}
pubkey1 := st.PubkeyAtIndex(primitives.ValidatorIndex(20))
pubkey2 := st.PubkeyAtIndex(primitives.ValidatorIndex(66))
pubkey1 := st.PubkeyAtIndex(primitives.ValidatorIndex(0))
pubkey2 := st.PubkeyAtIndex(primitives.ValidatorIndex(1))
hexPubkey1 := hexutil.Encode(pubkey1[:])
hexPubkey2 := hexutil.Encode(pubkey2[:])
request := httptest.NewRequest(
@ -121,8 +126,8 @@ func TestGetValidators(t *testing.T) {
resp := &GetValidatorsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 2, len(resp.Data))
assert.Equal(t, "20", resp.Data[0].Index)
assert.Equal(t, "66", resp.Data[1].Index)
assert.Equal(t, "0", resp.Data[0].Index)
assert.Equal(t, "1", resp.Data[1].Index)
})
t.Run("get by both index and pubkey", func(t *testing.T) {
chainService := &chainMock.ChainService{}
@ -135,11 +140,11 @@ func TestGetValidators(t *testing.T) {
FinalizationFetcher: chainService,
}
pubkey := st.PubkeyAtIndex(primitives.ValidatorIndex(20))
pubkey := st.PubkeyAtIndex(primitives.ValidatorIndex(0))
hexPubkey := hexutil.Encode(pubkey[:])
request := httptest.NewRequest(
http.MethodGet,
fmt.Sprintf("http://example.com/eth/v1/beacon/states/{state_id}/validators?id=%s&id=60", hexPubkey),
fmt.Sprintf("http://example.com/eth/v1/beacon/states/{state_id}/validators?id=%s&id=1", hexPubkey),
nil,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
@ -151,8 +156,8 @@ func TestGetValidators(t *testing.T) {
resp := &GetValidatorsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 2, len(resp.Data))
assert.Equal(t, "20", resp.Data[0].Index)
assert.Equal(t, "60", resp.Data[1].Index)
assert.Equal(t, "0", resp.Data[0].Index)
assert.Equal(t, "1", resp.Data[1].Index)
})
t.Run("state ID required", func(t *testing.T) {
s := Server{
@ -275,11 +280,139 @@ func TestGetValidators(t *testing.T) {
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, true, resp.Finalized)
})
t.Run("POST", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
}
var body bytes.Buffer
req := &GetValidatorsRequest{
Ids: []string{"0", strconv.Itoa(exitedValIndex)},
Statuses: []string{"exited"},
}
b, err := json.Marshal(req)
require.NoError(t, err)
_, err = body.Write(b)
require.NoError(t, err)
request := httptest.NewRequest(
http.MethodPost,
"http://example.com/eth/v1/beacon/states/{state_id}/validators",
&body,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetValidators(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &GetValidatorsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 1, len(resp.Data))
assert.Equal(t, "3", resp.Data[0].Index)
})
t.Run("POST nil values", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
}
var body bytes.Buffer
req := &GetValidatorsRequest{
Ids: nil,
Statuses: nil,
}
b, err := json.Marshal(req)
require.NoError(t, err)
_, err = body.Write(b)
require.NoError(t, err)
request := httptest.NewRequest(
http.MethodPost,
"http://example.com/eth/v1/beacon/states/{state_id}/validators",
&body,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetValidators(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &GetValidatorsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 4, len(resp.Data))
})
t.Run("POST empty", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
}
request := httptest.NewRequest(
http.MethodPost,
"http://example.com/eth/v1/beacon/states/{state_id}/validators",
nil,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetValidators(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &http2.DefaultErrorJson{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.StringContains(t, "No data submitted", e.Message)
})
t.Run("POST invalid", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
}
body := bytes.Buffer{}
_, err := body.WriteString("foo")
require.NoError(t, err)
request := httptest.NewRequest(
http.MethodPost,
"http://example.com/eth/v1/beacon/states/{state_id}/validators",
&body,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetValidators(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &http2.DefaultErrorJson{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.StringContains(t, "Could not decode request body", e.Message)
})
}
func TestListValidators_FilterByStatus(t *testing.T) {
func TestGetValidators_FilterByStatus(t *testing.T) {
var st state.BeaconState
st, _ = util.DeterministicGenesisState(t, 8192)
st, _ = util.DeterministicGenesisState(t, 1)
farFutureEpoch := params.BeaconConfig().FarFutureEpoch
validators := []*eth.Validator{
@ -366,7 +499,7 @@ func TestListValidators_FilterByStatus(t *testing.T) {
assert.Equal(t, http.StatusOK, writer.Code)
resp := &GetValidatorsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, 8192+2, len(resp.Data))
assert.Equal(t, 3, len(resp.Data))
for _, vc := range resp.Data {
assert.Equal(
t,
@ -397,7 +530,7 @@ func TestListValidators_FilterByStatus(t *testing.T) {
assert.Equal(t, http.StatusOK, writer.Code)
resp := &GetValidatorsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, 8192+1, len(resp.Data))
assert.Equal(t, 2, len(resp.Data))
for _, vc := range resp.Data {
require.Equal(
t,
@ -506,7 +639,7 @@ func TestListValidators_FilterByStatus(t *testing.T) {
func TestGetValidator(t *testing.T) {
var st state.BeaconState
st, _ = util.DeterministicGenesisState(t, 8192)
st, _ = util.DeterministicGenesisState(t, 2)
t.Run("get by index", func(t *testing.T) {
chainService := &chainMock.ChainService{}
@ -520,7 +653,7 @@ func TestGetValidator(t *testing.T) {
}
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/beacon/states/{state_id}/validators/{validator_id}", nil)
request = mux.SetURLVars(request, map[string]string{"state_id": "head", "validator_id": "15"})
request = mux.SetURLVars(request, map[string]string{"state_id": "head", "validator_id": "0"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
@ -528,12 +661,12 @@ func TestGetValidator(t *testing.T) {
assert.Equal(t, http.StatusOK, writer.Code)
resp := &GetValidatorResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "15", resp.Data.Index)
assert.Equal(t, "0", resp.Data.Index)
assert.Equal(t, "32000000000", resp.Data.Balance)
assert.Equal(t, "active_ongoing", resp.Data.Status)
require.NotNil(t, resp.Data.Validator)
assert.Equal(t, "0x872c61b4a7f8510ec809e5b023f5fdda2105d024c470ddbbeca4bc74e8280af0d178d749853e8f6a841083ac1b4db98f", resp.Data.Validator.Pubkey)
assert.Equal(t, "0x00b24fc624e56a5ed42a9639691e27e34b783c7237030367bd17cbef65fa6ccf", resp.Data.Validator.WithdrawalCredentials)
assert.Equal(t, "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", resp.Data.Validator.Pubkey)
assert.Equal(t, "0x00ec7ef7780c9d151597924036262dd28dc60e1228f4da6fecf9d402cb3f3594", resp.Data.Validator.WithdrawalCredentials)
assert.Equal(t, "32000000000", resp.Data.Validator.EffectiveBalance)
assert.Equal(t, false, resp.Data.Validator.Slashed)
assert.Equal(t, "0", resp.Data.Validator.ActivationEligibilityEpoch)
@ -552,7 +685,7 @@ func TestGetValidator(t *testing.T) {
FinalizationFetcher: chainService,
}
pubKey := st.PubkeyAtIndex(primitives.ValidatorIndex(20))
pubKey := st.PubkeyAtIndex(primitives.ValidatorIndex(0))
hexPubkey := hexutil.Encode(pubKey[:])
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/beacon/states/{state_id}/validators/{validator_id}", nil)
request = mux.SetURLVars(request, map[string]string{"state_id": "head", "validator_id": hexPubkey})
@ -563,7 +696,7 @@ func TestGetValidator(t *testing.T) {
assert.Equal(t, http.StatusOK, writer.Code)
resp := &GetValidatorResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, "20", resp.Data.Index)
assert.Equal(t, "0", resp.Data.Index)
})
t.Run("state ID required", func(t *testing.T) {
s := Server{
@ -657,7 +790,7 @@ func TestGetValidator(t *testing.T) {
}
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/beacon/states/{state_id}/validators/{validator_id}", nil)
request = mux.SetURLVars(request, map[string]string{"state_id": "head", "validator_id": "15"})
request = mux.SetURLVars(request, map[string]string{"state_id": "head", "validator_id": "0"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
@ -685,7 +818,7 @@ func TestGetValidator(t *testing.T) {
}
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/beacon/states/{state_id}/validators/{validator_id}", nil)
request = mux.SetURLVars(request, map[string]string{"state_id": "head", "validator_id": "15"})
request = mux.SetURLVars(request, map[string]string{"state_id": "head", "validator_id": "0"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
@ -699,7 +832,7 @@ func TestGetValidator(t *testing.T) {
func TestGetValidatorBalances(t *testing.T) {
var st state.BeaconState
count := uint64(8192)
count := uint64(4)
st, _ = util.DeterministicGenesisState(t, count)
balances := make([]uint64, count)
for i := uint64(0); i < count; i++ {
@ -727,10 +860,10 @@ func TestGetValidatorBalances(t *testing.T) {
assert.Equal(t, http.StatusOK, writer.Code)
resp := &GetValidatorBalancesResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 8192, len(resp.Data))
val := resp.Data[123]
assert.Equal(t, "123", val.Index)
assert.Equal(t, "123", val.Balance)
require.Equal(t, 4, len(resp.Data))
val := resp.Data[3]
assert.Equal(t, "3", val.Index)
assert.Equal(t, "3", val.Balance)
})
t.Run("get by index", func(t *testing.T) {
chainService := &chainMock.ChainService{}
@ -745,7 +878,7 @@ func TestGetValidatorBalances(t *testing.T) {
request := httptest.NewRequest(
http.MethodGet,
"http://example.com/eth/v1/beacon/states/{state_id}/validator_balances?id=15&id=26",
"http://example.com/eth/v1/beacon/states/{state_id}/validator_balances?id=0&id=1",
nil,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
@ -757,8 +890,8 @@ func TestGetValidatorBalances(t *testing.T) {
resp := &GetValidatorBalancesResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 2, len(resp.Data))
assert.Equal(t, "15", resp.Data[0].Index)
assert.Equal(t, "26", resp.Data[1].Index)
assert.Equal(t, "0", resp.Data[0].Index)
assert.Equal(t, "1", resp.Data[1].Index)
})
t.Run("get by pubkey", func(t *testing.T) {
chainService := &chainMock.ChainService{}
@ -770,8 +903,8 @@ func TestGetValidatorBalances(t *testing.T) {
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
}
pubkey1 := st.PubkeyAtIndex(primitives.ValidatorIndex(20))
pubkey2 := st.PubkeyAtIndex(primitives.ValidatorIndex(66))
pubkey1 := st.PubkeyAtIndex(primitives.ValidatorIndex(0))
pubkey2 := st.PubkeyAtIndex(primitives.ValidatorIndex(1))
hexPubkey1 := hexutil.Encode(pubkey1[:])
hexPubkey2 := hexutil.Encode(pubkey2[:])
@ -789,8 +922,8 @@ func TestGetValidatorBalances(t *testing.T) {
resp := &GetValidatorBalancesResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 2, len(resp.Data))
assert.Equal(t, "20", resp.Data[0].Index)
assert.Equal(t, "66", resp.Data[1].Index)
assert.Equal(t, "0", resp.Data[0].Index)
assert.Equal(t, "1", resp.Data[1].Index)
})
t.Run("get by both index and pubkey", func(t *testing.T) {
chainService := &chainMock.ChainService{}
@ -803,11 +936,11 @@ func TestGetValidatorBalances(t *testing.T) {
FinalizationFetcher: chainService,
}
pubkey := st.PubkeyAtIndex(primitives.ValidatorIndex(20))
pubkey := st.PubkeyAtIndex(primitives.ValidatorIndex(0))
hexPubkey := hexutil.Encode(pubkey[:])
request := httptest.NewRequest(
http.MethodGet,
fmt.Sprintf("http://example.com/eth/v1/beacon/states/{state_id}/validators?id=%s&id=60", hexPubkey),
fmt.Sprintf("http://example.com/eth/v1/beacon/states/{state_id}/validators?id=%s&id=1", hexPubkey),
nil,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
@ -819,8 +952,8 @@ func TestGetValidatorBalances(t *testing.T) {
resp := &GetValidatorsResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 2, len(resp.Data))
assert.Equal(t, "20", resp.Data[0].Index)
assert.Equal(t, "60", resp.Data[1].Index)
assert.Equal(t, "0", resp.Data[0].Index)
assert.Equal(t, "1", resp.Data[1].Index)
})
t.Run("unknown pubkey is ignored", func(t *testing.T) {
chainService := &chainMock.ChainService{}
@ -906,7 +1039,7 @@ func TestGetValidatorBalances(t *testing.T) {
request := httptest.NewRequest(
http.MethodGet,
"http://example.com/eth/v1/beacon/states/{state_id}/validator_balances?id=15",
"http://example.com/eth/v1/beacon/states/{state_id}/validator_balances?id=0",
nil,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
@ -938,7 +1071,7 @@ func TestGetValidatorBalances(t *testing.T) {
request := httptest.NewRequest(
http.MethodGet,
"http://example.com/eth/v1/beacon/states/{state_id}/validator_balances?id=15",
"http://example.com/eth/v1/beacon/states/{state_id}/validator_balances?id=0",
nil,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
@ -951,4 +1084,96 @@ func TestGetValidatorBalances(t *testing.T) {
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
assert.Equal(t, true, resp.Finalized)
})
t.Run("POST", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
}
pubkey1 := st.PubkeyAtIndex(primitives.ValidatorIndex(0))
pubkey2 := st.PubkeyAtIndex(primitives.ValidatorIndex(1))
hexPubkey1 := hexutil.Encode(pubkey1[:])
hexPubkey2 := hexutil.Encode(pubkey2[:])
var body bytes.Buffer
_, err := body.WriteString(fmt.Sprintf("[\"%s\",\"%s\"]", hexPubkey1, hexPubkey2))
require.NoError(t, err)
request := httptest.NewRequest(
http.MethodPost,
"http://example.com/eth/v1/beacon/states/{state_id}/validator_balances",
&body,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetValidatorBalances(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &GetValidatorBalancesResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.Equal(t, 2, len(resp.Data))
assert.Equal(t, "0", resp.Data[0].Index)
assert.Equal(t, "1", resp.Data[1].Index)
})
t.Run("POST empty", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
}
request := httptest.NewRequest(
http.MethodPost,
"http://example.com/eth/v1/beacon/states/{state_id}/validator_balances",
nil,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetValidatorBalances(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &http2.DefaultErrorJson{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.StringContains(t, "No data submitted", e.Message)
})
t.Run("POST invalid", func(t *testing.T) {
chainService := &chainMock.ChainService{}
s := Server{
Stater: &testutil.MockStater{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
}
body := bytes.Buffer{}
_, err := body.WriteString("foo")
require.NoError(t, err)
request := httptest.NewRequest(
http.MethodPost,
"http://example.com/eth/v1/beacon/states/{state_id}/validator_balances",
&body,
)
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetValidatorBalances(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &http2.DefaultErrorJson{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.StringContains(t, "Could not decode request body", e.Message)
})
}

View File

@ -76,6 +76,11 @@ type GetBlockHeaderResponse struct {
Data *shared.SignedBeaconBlockHeaderContainer `json:"data"`
}
type GetValidatorsRequest struct {
Ids []string `json:"ids"`
Statuses []string `json:"statuses"`
}
type GetValidatorsResponse struct {
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`

View File

@ -471,9 +471,9 @@ func (s *Service) Start() {
s.cfg.Router.HandleFunc("/eth/v1/beacon/headers/{block_id}", beaconChainServerV1.GetBlockHeader).Methods(http.MethodGet)
s.cfg.Router.HandleFunc("/eth/v1/beacon/genesis", beaconChainServerV1.GetGenesis).Methods(http.MethodGet)
s.cfg.Router.HandleFunc("/eth/v1/beacon/states/{state_id}/finality_checkpoints", beaconChainServerV1.GetFinalityCheckpoints).Methods(http.MethodGet)
s.cfg.Router.HandleFunc("/eth/v1/beacon/states/{state_id}/validators", beaconChainServerV1.GetValidators).Methods(http.MethodGet)
s.cfg.Router.HandleFunc("/eth/v1/beacon/states/{state_id}/validators", beaconChainServerV1.GetValidators).Methods(http.MethodGet, http.MethodPost)
s.cfg.Router.HandleFunc("/eth/v1/beacon/states/{state_id}/validators/{validator_id}", beaconChainServerV1.GetValidator).Methods(http.MethodGet)
s.cfg.Router.HandleFunc("/eth/v1/beacon/states/{state_id}/validator_balances", beaconChainServerV1.GetValidatorBalances).Methods(http.MethodGet)
s.cfg.Router.HandleFunc("/eth/v1/beacon/states/{state_id}/validator_balances", beaconChainServerV1.GetValidatorBalances).Methods(http.MethodGet, http.MethodPost)
s.cfg.Router.HandleFunc("/eth/v1/config/deposit_contract", config.GetDepositContract).Methods(http.MethodGet)
s.cfg.Router.HandleFunc("/eth/v1/config/fork_schedule", config.GetForkSchedule).Methods(http.MethodGet)