prysm-pulse/beacon-chain/rpc/apimiddleware/custom_hooks_test.go
Radosław Kapka 36b1f322c0
Various bug fixes in Eth API (#9649)
* fix block structure

* correct status code when block is not found

* make `/internal` work with events and SSZ

* test fix

* better block serialize tests

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2021-09-23 17:34:11 +00:00

584 lines
20 KiB
Go

package apimiddleware
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gogo/protobuf/types"
"github.com/prysmaticlabs/prysm/api/gateway"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpbv2 "github.com/prysmaticlabs/prysm/proto/eth/v2"
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
"github.com/prysmaticlabs/prysm/shared/testutil/require"
)
func TestWrapAttestationArray(t *testing.T) {
t.Run("ok", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitAttestationRequestJson{},
}
unwrappedAtts := []*attestationJson{{AggregationBits: "1010"}}
unwrappedAttsJson, err := json.Marshal(unwrappedAtts)
require.NoError(t, err)
var body bytes.Buffer
_, err = body.Write(unwrappedAttsJson)
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapAttestationsArray(endpoint, nil, request)
require.Equal(t, true, errJson == nil)
wrappedAtts := &submitAttestationRequestJson{}
require.NoError(t, json.NewDecoder(request.Body).Decode(wrappedAtts))
require.Equal(t, 1, len(wrappedAtts.Data), "wrong number of wrapped items")
assert.Equal(t, "1010", wrappedAtts.Data[0].AggregationBits)
})
t.Run("invalid_body", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitAttestationRequestJson{},
}
var body bytes.Buffer
_, err := body.Write([]byte("invalid"))
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapAttestationsArray(endpoint, nil, request)
require.Equal(t, false, errJson == nil)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "could not decode body"))
assert.Equal(t, http.StatusInternalServerError, errJson.StatusCode())
})
}
func TestWrapValidatorIndicesArray(t *testing.T) {
t.Run("ok", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &dutiesRequestJson{},
}
unwrappedIndices := []string{"1", "2"}
unwrappedIndicesJson, err := json.Marshal(unwrappedIndices)
require.NoError(t, err)
var body bytes.Buffer
_, err = body.Write(unwrappedIndicesJson)
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapValidatorIndicesArray(endpoint, nil, request)
require.Equal(t, true, errJson == nil)
wrappedIndices := &dutiesRequestJson{}
require.NoError(t, json.NewDecoder(request.Body).Decode(wrappedIndices))
require.Equal(t, 2, len(wrappedIndices.Index), "wrong number of wrapped items")
assert.Equal(t, "1", wrappedIndices.Index[0])
assert.Equal(t, "2", wrappedIndices.Index[1])
})
}
func TestWrapSignedAggregateAndProofArray(t *testing.T) {
t.Run("ok", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitAggregateAndProofsRequestJson{},
}
unwrappedAggs := []*signedAggregateAttestationAndProofJson{{Signature: "sig"}}
unwrappedAggsJson, err := json.Marshal(unwrappedAggs)
require.NoError(t, err)
var body bytes.Buffer
_, err = body.Write(unwrappedAggsJson)
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapSignedAggregateAndProofArray(endpoint, nil, request)
require.Equal(t, true, errJson == nil)
wrappedAggs := &submitAggregateAndProofsRequestJson{}
require.NoError(t, json.NewDecoder(request.Body).Decode(wrappedAggs))
require.Equal(t, 1, len(wrappedAggs.Data), "wrong number of wrapped items")
assert.Equal(t, "sig", wrappedAggs.Data[0].Signature)
})
t.Run("invalid_body", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitAggregateAndProofsRequestJson{},
}
var body bytes.Buffer
_, err := body.Write([]byte("invalid"))
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapSignedAggregateAndProofArray(endpoint, nil, request)
require.Equal(t, false, errJson == nil)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "could not decode body"))
assert.Equal(t, http.StatusInternalServerError, errJson.StatusCode())
})
}
func TestWrapBeaconCommitteeSubscriptionsArray(t *testing.T) {
t.Run("ok", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitBeaconCommitteeSubscriptionsRequestJson{},
}
unwrappedSubs := []*beaconCommitteeSubscribeJson{{
ValidatorIndex: "1",
CommitteeIndex: "1",
CommitteesAtSlot: "1",
Slot: "1",
IsAggregator: true,
}}
unwrappedSubsJson, err := json.Marshal(unwrappedSubs)
require.NoError(t, err)
var body bytes.Buffer
_, err = body.Write(unwrappedSubsJson)
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapBeaconCommitteeSubscriptionsArray(endpoint, nil, request)
require.Equal(t, true, errJson == nil)
wrappedSubs := &submitBeaconCommitteeSubscriptionsRequestJson{}
require.NoError(t, json.NewDecoder(request.Body).Decode(wrappedSubs))
require.Equal(t, 1, len(wrappedSubs.Data), "wrong number of wrapped items")
assert.Equal(t, "1", wrappedSubs.Data[0].ValidatorIndex)
assert.Equal(t, "1", wrappedSubs.Data[0].CommitteeIndex)
assert.Equal(t, "1", wrappedSubs.Data[0].CommitteesAtSlot)
assert.Equal(t, "1", wrappedSubs.Data[0].Slot)
assert.Equal(t, true, wrappedSubs.Data[0].IsAggregator)
})
t.Run("invalid_body", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitBeaconCommitteeSubscriptionsRequestJson{},
}
var body bytes.Buffer
_, err := body.Write([]byte("invalid"))
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapBeaconCommitteeSubscriptionsArray(endpoint, nil, request)
require.Equal(t, false, errJson == nil)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "could not decode body"))
assert.Equal(t, http.StatusInternalServerError, errJson.StatusCode())
})
}
func TestWrapSyncCommitteeSubscriptionsArray(t *testing.T) {
t.Run("ok", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitSyncCommitteeSubscriptionRequestJson{},
}
unwrappedSubs := []*syncCommitteeSubscriptionJson{
{
ValidatorIndex: "1",
SyncCommitteeIndices: []string{"1", "2"},
UntilEpoch: "1",
},
{
ValidatorIndex: "2",
SyncCommitteeIndices: []string{"3", "4"},
UntilEpoch: "2",
},
}
unwrappedSubsJson, err := json.Marshal(unwrappedSubs)
require.NoError(t, err)
var body bytes.Buffer
_, err = body.Write(unwrappedSubsJson)
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapSyncCommitteeSubscriptionsArray(endpoint, nil, request)
require.Equal(t, true, errJson == nil)
wrappedSubs := &submitSyncCommitteeSubscriptionRequestJson{}
require.NoError(t, json.NewDecoder(request.Body).Decode(wrappedSubs))
require.Equal(t, 2, len(wrappedSubs.Data), "wrong number of wrapped items")
assert.Equal(t, "1", wrappedSubs.Data[0].ValidatorIndex)
require.Equal(t, 2, len(wrappedSubs.Data[0].SyncCommitteeIndices), "wrong number of committee indices")
assert.Equal(t, "1", wrappedSubs.Data[0].SyncCommitteeIndices[0])
assert.Equal(t, "2", wrappedSubs.Data[0].SyncCommitteeIndices[1])
assert.Equal(t, "1", wrappedSubs.Data[0].UntilEpoch)
})
t.Run("invalid_body", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitSyncCommitteeSubscriptionRequestJson{},
}
var body bytes.Buffer
_, err := body.Write([]byte("invalid"))
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapSyncCommitteeSubscriptionsArray(endpoint, nil, request)
require.Equal(t, false, errJson == nil)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "could not decode body"))
assert.Equal(t, http.StatusInternalServerError, errJson.StatusCode())
})
}
func TestWrapSyncCommitteeSignaturesArray(t *testing.T) {
t.Run("ok", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitSyncCommitteeSignaturesRequestJson{},
}
unwrappedSigs := []*syncCommitteeMessageJson{{
Slot: "1",
BeaconBlockRoot: "root",
ValidatorIndex: "1",
Signature: "sig",
}}
unwrappedSigsJson, err := json.Marshal(unwrappedSigs)
require.NoError(t, err)
var body bytes.Buffer
_, err = body.Write(unwrappedSigsJson)
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapSyncCommitteeSignaturesArray(endpoint, nil, request)
require.Equal(t, true, errJson == nil)
wrappedSigs := &submitSyncCommitteeSignaturesRequestJson{}
require.NoError(t, json.NewDecoder(request.Body).Decode(wrappedSigs))
require.Equal(t, 1, len(wrappedSigs.Data), "wrong number of wrapped items")
assert.Equal(t, "1", wrappedSigs.Data[0].Slot)
assert.Equal(t, "root", wrappedSigs.Data[0].BeaconBlockRoot)
assert.Equal(t, "1", wrappedSigs.Data[0].ValidatorIndex)
assert.Equal(t, "sig", wrappedSigs.Data[0].Signature)
})
t.Run("invalid_body", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitSyncCommitteeSignaturesRequestJson{},
}
var body bytes.Buffer
_, err := body.Write([]byte("invalid"))
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapSyncCommitteeSignaturesArray(endpoint, nil, request)
require.Equal(t, false, errJson == nil)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "could not decode body"))
assert.Equal(t, http.StatusInternalServerError, errJson.StatusCode())
})
}
func TestWrapSignedContributionAndProofsArray(t *testing.T) {
t.Run("ok", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitContributionAndProofsRequestJson{},
}
unwrapped := []*signedContributionAndProofJson{
{
Message: &contributionAndProofJson{
AggregatorIndex: "1",
Contribution: &syncCommitteeContributionJson{
Slot: "1",
BeaconBlockRoot: "root",
SubcommitteeIndex: "1",
AggregationBits: "bits",
Signature: "sig",
},
SelectionProof: "proof",
},
Signature: "sig",
},
{
Message: &contributionAndProofJson{},
Signature: "sig",
},
}
unwrappedJson, err := json.Marshal(unwrapped)
require.NoError(t, err)
var body bytes.Buffer
_, err = body.Write(unwrappedJson)
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapSignedContributionAndProofsArray(endpoint, nil, request)
require.Equal(t, true, errJson == nil)
wrapped := &submitContributionAndProofsRequestJson{}
require.NoError(t, json.NewDecoder(request.Body).Decode(wrapped))
require.Equal(t, 2, len(wrapped.Data), "wrong number of wrapped items")
assert.Equal(t, "sig", wrapped.Data[0].Signature)
require.NotNil(t, wrapped.Data[0].Message)
msg := wrapped.Data[0].Message
assert.Equal(t, "1", msg.AggregatorIndex)
assert.Equal(t, "proof", msg.SelectionProof)
require.NotNil(t, msg.Contribution)
assert.Equal(t, "1", msg.Contribution.Slot)
assert.Equal(t, "root", msg.Contribution.BeaconBlockRoot)
assert.Equal(t, "1", msg.Contribution.SubcommitteeIndex)
assert.Equal(t, "bits", msg.Contribution.AggregationBits)
assert.Equal(t, "sig", msg.Contribution.Signature)
})
t.Run("invalid_body", func(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &submitContributionAndProofsRequestJson{},
}
var body bytes.Buffer
_, err := body.Write([]byte("invalid"))
require.NoError(t, err)
request := httptest.NewRequest("POST", "http://foo.example", &body)
errJson := wrapSignedContributionAndProofsArray(endpoint, nil, request)
require.Equal(t, false, errJson == nil)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "could not decode body"))
assert.Equal(t, http.StatusInternalServerError, errJson.StatusCode())
})
}
func TestPrepareGraffiti(t *testing.T) {
endpoint := gateway.Endpoint{
PostRequest: &signedBeaconBlockContainerJson{
Message: &beaconBlockJson{
Body: &beaconBlockBodyJson{},
},
},
}
t.Run("32_bytes", func(t *testing.T) {
endpoint.PostRequest.(*signedBeaconBlockContainerJson).Message.Body.Graffiti = string(bytesutil.PadTo([]byte("foo"), 32))
prepareGraffiti(endpoint, nil, nil)
assert.Equal(
t,
"0x666f6f0000000000000000000000000000000000000000000000000000000000",
endpoint.PostRequest.(*signedBeaconBlockContainerJson).Message.Body.Graffiti,
)
})
t.Run("less_than_32_bytes", func(t *testing.T) {
endpoint.PostRequest.(*signedBeaconBlockContainerJson).Message.Body.Graffiti = "foo"
prepareGraffiti(endpoint, nil, nil)
assert.Equal(
t,
"0x666f6f0000000000000000000000000000000000000000000000000000000000",
endpoint.PostRequest.(*signedBeaconBlockContainerJson).Message.Body.Graffiti,
)
})
t.Run("more_than_32_bytes", func(t *testing.T) {
endpoint.PostRequest.(*signedBeaconBlockContainerJson).Message.Body.Graffiti = string(bytesutil.PadTo([]byte("foo"), 33))
prepareGraffiti(endpoint, nil, nil)
assert.Equal(
t,
"0x666f6f0000000000000000000000000000000000000000000000000000000000",
endpoint.PostRequest.(*signedBeaconBlockContainerJson).Message.Body.Graffiti,
)
})
}
func TestPrepareValidatorAggregates(t *testing.T) {
body := &tempSyncCommitteesResponseJson{
Data: &tempSyncCommitteeValidatorsJson{
Validators: []string{"1", "2"},
ValidatorAggregates: []*tempSyncSubcommitteeValidatorsJson{
{
Validators: []string{"3", "4"},
},
{
Validators: []string{"5"},
},
},
},
}
bodyJson, err := json.Marshal(body)
require.NoError(t, err)
container := &syncCommitteesResponseJson{}
handled, errJson := prepareValidatorAggregates(bodyJson, container)
require.Equal(t, nil, errJson)
require.Equal(t, true, handled)
assert.DeepEqual(t, []string{"1", "2"}, container.Data.Validators)
require.DeepEqual(t, [][]string{{"3", "4"}, {"5"}}, container.Data.ValidatorAggregates)
}
func TestSerializeV2Block(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
response := &blockV2ResponseJson{
Version: ethpbv2.Version_PHASE0.String(),
Data: &signedBeaconBlockContainerV2Json{
Phase0Block: &beaconBlockJson{
Slot: "1",
ProposerIndex: "1",
ParentRoot: "root",
StateRoot: "root",
Body: &beaconBlockBodyJson{},
},
AltairBlock: nil,
Signature: "sig",
},
}
ok, j, errJson := serializeV2Block(response)
require.Equal(t, nil, errJson)
require.Equal(t, true, ok)
require.NotNil(t, j)
resp := &phase0BlockResponseJson{}
require.NoError(t, json.Unmarshal(j, resp))
require.NotNil(t, resp.Data)
require.NotNil(t, resp.Data.Message)
beaconBlock := resp.Data.Message
assert.Equal(t, "1", beaconBlock.Slot)
assert.Equal(t, "1", beaconBlock.ProposerIndex)
assert.Equal(t, "root", beaconBlock.ParentRoot)
assert.Equal(t, "root", beaconBlock.StateRoot)
require.NotNil(t, beaconBlock.Body)
})
t.Run("Altair", func(t *testing.T) {
response := &blockV2ResponseJson{
Version: ethpbv2.Version_ALTAIR.String(),
Data: &signedBeaconBlockContainerV2Json{
Phase0Block: nil,
AltairBlock: &beaconBlockAltairJson{
Slot: "1",
ProposerIndex: "1",
ParentRoot: "root",
StateRoot: "root",
Body: &beaconBlockBodyAltairJson{},
},
Signature: "sig",
},
}
ok, j, errJson := serializeV2Block(response)
require.Equal(t, nil, errJson)
require.Equal(t, true, ok)
require.NotNil(t, j)
resp := &altairBlockResponseJson{}
require.NoError(t, json.Unmarshal(j, resp))
require.NotNil(t, resp.Data)
require.NotNil(t, resp.Data.Message)
beaconBlock := resp.Data.Message
assert.Equal(t, "1", beaconBlock.Slot)
assert.Equal(t, "1", beaconBlock.ProposerIndex)
assert.Equal(t, "root", beaconBlock.ParentRoot)
assert.Equal(t, "root", beaconBlock.StateRoot)
require.NotNil(t, beaconBlock.Body)
})
t.Run("incorrect response type", func(t *testing.T) {
response := &types.Empty{}
ok, j, errJson := serializeV2Block(response)
require.Equal(t, false, ok)
require.Equal(t, 0, len(j))
require.NotNil(t, errJson)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "container is not of the correct type"))
})
}
func TestSerializeV2State(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
response := &beaconStateV2ResponseJson{
Version: ethpbv2.Version_PHASE0.String(),
Data: &beaconStateContainerV2Json{
Phase0State: &beaconStateJson{},
AltairState: nil,
},
}
ok, j, errJson := serializeV2State(response)
require.Equal(t, nil, errJson)
require.Equal(t, true, ok)
require.NotNil(t, j)
require.NoError(t, json.Unmarshal(j, &phase0StateResponseJson{}))
})
t.Run("Altair", func(t *testing.T) {
response := &beaconStateV2ResponseJson{
Version: ethpbv2.Version_ALTAIR.String(),
Data: &beaconStateContainerV2Json{
Phase0State: nil,
AltairState: &beaconStateV2Json{},
},
}
ok, j, errJson := serializeV2State(response)
require.Equal(t, nil, errJson)
require.Equal(t, true, ok)
require.NotNil(t, j)
require.NoError(t, json.Unmarshal(j, &altairStateResponseJson{}))
})
t.Run("incorrect response type", func(t *testing.T) {
ok, j, errJson := serializeV2State(&types.Empty{})
require.Equal(t, false, ok)
require.Equal(t, 0, len(j))
require.NotNil(t, errJson)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "container is not of the correct type"))
})
}
func TestSerializeProduceV2Block(t *testing.T) {
t.Run("Phase 0", func(t *testing.T) {
response := &produceBlockResponseV2Json{
Version: ethpbv2.Version_PHASE0.String(),
Data: &beaconBlockContainerV2Json{
Phase0Block: &beaconBlockJson{
Slot: "1",
ProposerIndex: "1",
ParentRoot: "root",
StateRoot: "root",
Body: &beaconBlockBodyJson{},
},
AltairBlock: nil,
},
}
ok, j, errJson := serializeProducedV2Block(response)
require.Equal(t, nil, errJson)
require.Equal(t, true, ok)
require.NotNil(t, j)
resp := &phase0ProduceBlockResponseJson{}
require.NoError(t, json.Unmarshal(j, resp))
require.NotNil(t, resp.Data)
require.NotNil(t, resp.Data)
beaconBlock := resp.Data
assert.Equal(t, "1", beaconBlock.Slot)
assert.Equal(t, "1", beaconBlock.ProposerIndex)
assert.Equal(t, "root", beaconBlock.ParentRoot)
assert.Equal(t, "root", beaconBlock.StateRoot)
require.NotNil(t, beaconBlock.Body)
})
t.Run("Altair", func(t *testing.T) {
response := &produceBlockResponseV2Json{
Version: ethpbv2.Version_ALTAIR.String(),
Data: &beaconBlockContainerV2Json{
Phase0Block: nil,
AltairBlock: &beaconBlockAltairJson{
Slot: "1",
ProposerIndex: "1",
ParentRoot: "root",
StateRoot: "root",
Body: &beaconBlockBodyAltairJson{},
},
},
}
ok, j, errJson := serializeProducedV2Block(response)
require.Equal(t, nil, errJson)
require.Equal(t, true, ok)
require.NotNil(t, j)
resp := &altairProduceBlockResponseJson{}
require.NoError(t, json.Unmarshal(j, resp))
require.NotNil(t, resp.Data)
require.NotNil(t, resp.Data)
beaconBlock := resp.Data
assert.Equal(t, "1", beaconBlock.Slot)
assert.Equal(t, "1", beaconBlock.ProposerIndex)
assert.Equal(t, "root", beaconBlock.ParentRoot)
assert.Equal(t, "root", beaconBlock.StateRoot)
require.NotNil(t, beaconBlock.Body)
})
t.Run("incorrect response type", func(t *testing.T) {
response := &types.Empty{}
ok, j, errJson := serializeProducedV2Block(response)
require.Equal(t, false, ok)
require.Equal(t, 0, len(j))
require.NotNil(t, errJson)
assert.Equal(t, true, strings.Contains(errJson.Msg(), "container is not of the correct type"))
})
}