mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-28 22:27:17 +00:00
a2d4701f6e
* Update API to return empty next page token on last page response * Update tests * Merge branch 'master' into api-return-empty-page-token-on-last-page
566 lines
15 KiB
Go
566 lines
15 KiB
Go
package beacon
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
ptypes "github.com/gogo/protobuf/types"
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
|
"github.com/prysmaticlabs/go-bitfield"
|
|
"github.com/prysmaticlabs/go-ssz"
|
|
mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
|
|
dbTest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
|
mockOps "github.com/prysmaticlabs/prysm/beacon-chain/operations/testing"
|
|
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
)
|
|
|
|
func TestServer_ListAttestations_NoResults(t *testing.T) {
|
|
db := dbTest.SetupDB(t)
|
|
defer dbTest.TeardownDB(t, db)
|
|
|
|
ctx := context.Background()
|
|
bs := &Server{
|
|
BeaconDB: db,
|
|
HeadFetcher: &mock.ChainService{
|
|
State: &pbp2p.BeaconState{Slot: 0},
|
|
},
|
|
}
|
|
wanted := ðpb.ListAttestationsResponse{
|
|
Attestations: make([]*ethpb.Attestation, 0),
|
|
TotalSize: int32(0),
|
|
NextPageToken: strconv.Itoa(0),
|
|
}
|
|
res, err := bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_SourceEpoch{SourceEpoch: 0},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !proto.Equal(wanted, res) {
|
|
t.Errorf("Wanted %v, received %v", wanted, res)
|
|
}
|
|
}
|
|
|
|
func TestServer_ListAttestations_Genesis(t *testing.T) {
|
|
db := dbTest.SetupDB(t)
|
|
defer dbTest.TeardownDB(t, db)
|
|
|
|
ctx := context.Background()
|
|
bs := &Server{
|
|
BeaconDB: db,
|
|
HeadFetcher: &mock.ChainService{
|
|
State: &pbp2p.BeaconState{Slot: 0},
|
|
},
|
|
}
|
|
|
|
// Should throw an error if no genesis data is found.
|
|
if _, err := bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_Genesis{
|
|
Genesis: true,
|
|
},
|
|
}); err != nil && !strings.Contains(err.Error(), "Could not find genesis") {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
parentRoot := [32]byte{1, 2, 3}
|
|
blk := ðpb.BeaconBlock{
|
|
Slot: 0,
|
|
ParentRoot: parentRoot[:],
|
|
}
|
|
root, err := ssz.SigningRoot(blk)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.SaveBlock(ctx, blk); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
att := ðpb.Attestation{
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
Data: ðpb.AttestationData{
|
|
Slot: 0,
|
|
BeaconBlockRoot: root[:],
|
|
},
|
|
CustodyBits: bitfield.Bitlist{0b10},
|
|
}
|
|
if err := db.SaveAttestation(ctx, att); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
wanted := ðpb.ListAttestationsResponse{
|
|
Attestations: []*ethpb.Attestation{att},
|
|
NextPageToken: "",
|
|
TotalSize: 1,
|
|
}
|
|
|
|
res, err := bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_Genesis{
|
|
Genesis: true,
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !proto.Equal(wanted, res) {
|
|
t.Errorf("Wanted %v, received %v", wanted, res)
|
|
}
|
|
|
|
// Should throw an error if there is more than 1 block
|
|
// for the genesis slot.
|
|
if err := db.SaveBlock(ctx, blk); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_Genesis{
|
|
Genesis: true,
|
|
},
|
|
}); err != nil && !strings.Contains(err.Error(), "Found more than 1") {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestServer_ListAttestations_NoPagination(t *testing.T) {
|
|
db := dbTest.SetupDB(t)
|
|
defer dbTest.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
count := uint64(10)
|
|
atts := make([]*ethpb.Attestation, 0, count)
|
|
for i := uint64(0); i < count; i++ {
|
|
attExample := ðpb.Attestation{
|
|
Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: i,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1),
|
|
}
|
|
if err := db.SaveAttestation(ctx, attExample); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
atts = append(atts, attExample)
|
|
}
|
|
|
|
bs := &Server{
|
|
BeaconDB: db,
|
|
}
|
|
|
|
received, err := bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_HeadBlockRoot{
|
|
HeadBlockRoot: []byte("root"),
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(atts, received.Attestations) {
|
|
t.Fatalf("incorrect attestations response: wanted %v, received %v", atts, received.Attestations)
|
|
}
|
|
}
|
|
|
|
func TestServer_ListAttestations_FiltersCorrectly(t *testing.T) {
|
|
db := dbTest.SetupDB(t)
|
|
defer dbTest.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
someRoot := []byte{1, 2, 3}
|
|
sourceRoot := []byte{4, 5, 6}
|
|
sourceEpoch := uint64(5)
|
|
targetRoot := []byte{7, 8, 9}
|
|
targetEpoch := uint64(7)
|
|
|
|
unknownRoot := []byte{1, 1, 1}
|
|
atts := []*ethpb.Attestation{
|
|
{
|
|
Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: someRoot,
|
|
Source: ðpb.Checkpoint{
|
|
Root: sourceRoot,
|
|
Epoch: sourceEpoch,
|
|
},
|
|
Target: ðpb.Checkpoint{
|
|
Root: targetRoot,
|
|
Epoch: targetEpoch,
|
|
},
|
|
Slot: 3,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
},
|
|
{
|
|
Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: unknownRoot,
|
|
Source: ðpb.Checkpoint{
|
|
Root: sourceRoot,
|
|
Epoch: sourceEpoch,
|
|
},
|
|
Target: ðpb.Checkpoint{
|
|
Root: targetRoot,
|
|
Epoch: targetEpoch,
|
|
},
|
|
Slot: 4,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
},
|
|
{
|
|
Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: someRoot,
|
|
Source: ðpb.Checkpoint{
|
|
Root: unknownRoot,
|
|
Epoch: sourceEpoch,
|
|
},
|
|
Target: ðpb.Checkpoint{
|
|
Root: unknownRoot,
|
|
Epoch: targetEpoch,
|
|
},
|
|
Slot: 5,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
},
|
|
}
|
|
|
|
if err := db.SaveAttestations(ctx, atts); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
bs := &Server{
|
|
BeaconDB: db,
|
|
}
|
|
|
|
received, err := bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_HeadBlockRoot{HeadBlockRoot: someRoot},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(received.Attestations) != 2 {
|
|
t.Errorf("Wanted 2 matching attestations with root %#x, received %d", someRoot, len(received.Attestations))
|
|
}
|
|
received, err = bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_SourceEpoch{SourceEpoch: sourceEpoch},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(received.Attestations) != 3 {
|
|
t.Errorf("Wanted 3 matching attestations with source epoch %d, received %d", sourceEpoch, len(received.Attestations))
|
|
}
|
|
received, err = bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_SourceRoot{SourceRoot: sourceRoot},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(received.Attestations) != 2 {
|
|
t.Errorf("Wanted 2 matching attestations with source root %#x, received %d", sourceRoot, len(received.Attestations))
|
|
}
|
|
received, err = bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_TargetEpoch{TargetEpoch: targetEpoch},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(received.Attestations) != 3 {
|
|
t.Errorf("Wanted 3 matching attestations with target epoch %d, received %d", targetEpoch, len(received.Attestations))
|
|
}
|
|
received, err = bs.ListAttestations(ctx, ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_TargetRoot{TargetRoot: targetRoot},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(received.Attestations) != 2 {
|
|
t.Errorf("Wanted 2 matching attestations with target root %#x, received %d", targetRoot, len(received.Attestations))
|
|
}
|
|
}
|
|
|
|
func TestServer_ListAttestations_Pagination_CustomPageParameters(t *testing.T) {
|
|
db := dbTest.SetupDB(t)
|
|
defer dbTest.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
count := uint64(100)
|
|
atts := make([]*ethpb.Attestation, 0, count)
|
|
for i := uint64(0); i < count; i++ {
|
|
attExample := ðpb.Attestation{
|
|
Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: i,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1),
|
|
}
|
|
if err := db.SaveAttestation(ctx, attExample); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
atts = append(atts, attExample)
|
|
}
|
|
|
|
bs := &Server{
|
|
BeaconDB: db,
|
|
}
|
|
|
|
tests := []struct {
|
|
req *ethpb.ListAttestationsRequest
|
|
res *ethpb.ListAttestationsResponse
|
|
}{
|
|
{
|
|
req: ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_HeadBlockRoot{
|
|
HeadBlockRoot: []byte("root"),
|
|
},
|
|
PageToken: strconv.Itoa(1),
|
|
PageSize: 3,
|
|
},
|
|
res: ðpb.ListAttestationsResponse{
|
|
Attestations: []*ethpb.Attestation{
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 3,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 4,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 5,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
},
|
|
NextPageToken: strconv.Itoa(2),
|
|
TotalSize: int32(count)}},
|
|
{
|
|
req: ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_HeadBlockRoot{
|
|
HeadBlockRoot: []byte("root"),
|
|
},
|
|
PageToken: strconv.Itoa(10),
|
|
PageSize: 5,
|
|
},
|
|
res: ðpb.ListAttestationsResponse{
|
|
Attestations: []*ethpb.Attestation{
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 50,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 51,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 52,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 53,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 54,
|
|
}, AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
},
|
|
NextPageToken: strconv.Itoa(11),
|
|
TotalSize: int32(count)}},
|
|
{
|
|
req: ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_HeadBlockRoot{
|
|
HeadBlockRoot: []byte("root"),
|
|
},
|
|
PageToken: strconv.Itoa(33),
|
|
PageSize: 3,
|
|
},
|
|
res: ðpb.ListAttestationsResponse{
|
|
Attestations: []*ethpb.Attestation{
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 99,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
},
|
|
NextPageToken: "",
|
|
TotalSize: int32(count)}},
|
|
{
|
|
req: ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_HeadBlockRoot{
|
|
HeadBlockRoot: []byte("root"),
|
|
},
|
|
PageSize: 2,
|
|
},
|
|
res: ðpb.ListAttestationsResponse{
|
|
Attestations: []*ethpb.Attestation{
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1)},
|
|
{Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: 1,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1),
|
|
},
|
|
},
|
|
NextPageToken: strconv.Itoa(1),
|
|
TotalSize: int32(count)}},
|
|
}
|
|
for _, test := range tests {
|
|
res, err := bs.ListAttestations(ctx, test.req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !proto.Equal(res, test.res) {
|
|
t.Errorf("Incorrect attestations response, wanted %v, received %v", test.res, res)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestServer_ListAttestations_Pagination_OutOfRange(t *testing.T) {
|
|
db := dbTest.SetupDB(t)
|
|
defer dbTest.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
count := uint64(1)
|
|
atts := make([]*ethpb.Attestation, 0, count)
|
|
for i := uint64(0); i < count; i++ {
|
|
attExample := ðpb.Attestation{
|
|
Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: i,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
}
|
|
if err := db.SaveAttestation(ctx, attExample); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
atts = append(atts, attExample)
|
|
}
|
|
|
|
bs := &Server{
|
|
BeaconDB: db,
|
|
}
|
|
|
|
req := ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_HeadBlockRoot{
|
|
HeadBlockRoot: []byte("root"),
|
|
},
|
|
PageToken: strconv.Itoa(1),
|
|
PageSize: 100,
|
|
}
|
|
wanted := fmt.Sprintf("page start %d >= list %d", req.PageSize, len(atts))
|
|
if _, err := bs.ListAttestations(ctx, req); !strings.Contains(err.Error(), wanted) {
|
|
t.Errorf("Expected error %v, received %v", wanted, err)
|
|
}
|
|
}
|
|
|
|
func TestServer_ListAttestations_Pagination_ExceedsMaxPageSize(t *testing.T) {
|
|
ctx := context.Background()
|
|
bs := &Server{}
|
|
exceedsMax := int32(params.BeaconConfig().MaxPageSize + 1)
|
|
|
|
wanted := fmt.Sprintf("Requested page size %d can not be greater than max size %d", exceedsMax, params.BeaconConfig().MaxPageSize)
|
|
req := ðpb.ListAttestationsRequest{PageToken: strconv.Itoa(0), PageSize: exceedsMax}
|
|
if _, err := bs.ListAttestations(ctx, req); !strings.Contains(err.Error(), wanted) {
|
|
t.Errorf("Expected error %v, received %v", wanted, err)
|
|
}
|
|
}
|
|
|
|
func TestServer_ListAttestations_Pagination_DefaultPageSize(t *testing.T) {
|
|
db := dbTest.SetupDB(t)
|
|
defer dbTest.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
count := uint64(params.BeaconConfig().DefaultPageSize)
|
|
atts := make([]*ethpb.Attestation, 0, count)
|
|
for i := uint64(0); i < count; i++ {
|
|
attExample := ðpb.Attestation{
|
|
Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("root"),
|
|
Slot: i,
|
|
},
|
|
AggregationBits: bitfield.Bitlist{0b11},
|
|
CustodyBits: bitfield.NewBitlist(1),
|
|
}
|
|
if err := db.SaveAttestation(ctx, attExample); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
atts = append(atts, attExample)
|
|
}
|
|
|
|
bs := &Server{
|
|
BeaconDB: db,
|
|
}
|
|
|
|
req := ðpb.ListAttestationsRequest{
|
|
QueryFilter: ðpb.ListAttestationsRequest_HeadBlockRoot{
|
|
HeadBlockRoot: []byte("root"),
|
|
},
|
|
}
|
|
res, err := bs.ListAttestations(ctx, req)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
i := 0
|
|
j := params.BeaconConfig().DefaultPageSize
|
|
if !reflect.DeepEqual(res.Attestations, atts[i:j]) {
|
|
t.Log(res.Attestations, atts[i:j])
|
|
t.Error("Incorrect attestations response")
|
|
}
|
|
}
|
|
|
|
func TestServer_AttestationPool(t *testing.T) {
|
|
ctx := context.Background()
|
|
block := ðpb.BeaconBlock{
|
|
Slot: 10,
|
|
}
|
|
bs := &Server{
|
|
Pool: &mockOps.Operations{
|
|
Attestations: []*ethpb.Attestation{
|
|
{
|
|
Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("1"),
|
|
},
|
|
},
|
|
{
|
|
Data: ðpb.AttestationData{
|
|
BeaconBlockRoot: []byte("2"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
HeadFetcher: &mock.ChainService{
|
|
Block: block,
|
|
},
|
|
}
|
|
res, err := bs.AttestationPool(ctx, &ptypes.Empty{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want, _ := bs.Pool.AttestationPoolNoVerify(ctx)
|
|
if !reflect.DeepEqual(res.Attestations, want) {
|
|
t.Errorf("Wanted AttestationPool() = %v, received %v", want, res.Attestations)
|
|
}
|
|
}
|