mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 07:58:22 -05:00
ETH2 API: Implement ListPoolAttestations endpoint (#8902)
* Implement ListPoolAttestations * Spacing * add lil doc * Fix testing and rework logic
This commit is contained in:
@@ -2,7 +2,7 @@ package beaconv1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1"
|
||||
ethpb_alpha "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -16,9 +16,40 @@ import (
|
||||
)
|
||||
|
||||
// ListPoolAttestations retrieves attestations known by the node but
|
||||
// not necessarily incorporated into any block.
|
||||
// not necessarily incorporated into any block. Allows filtering by committee index or slot.
|
||||
func (bs *Server) ListPoolAttestations(ctx context.Context, req *ethpb.AttestationsPoolRequest) (*ethpb.AttestationsPoolResponse, error) {
|
||||
return nil, errors.New("unimplemented")
|
||||
ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolAttestations")
|
||||
defer span.End()
|
||||
|
||||
attestations := bs.AttestationsPool.AggregatedAttestations()
|
||||
unaggAtts, err := bs.AttestationsPool.UnaggregatedAttestations()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not get unaggregated attestations: %v", err)
|
||||
}
|
||||
attestations = append(attestations, unaggAtts...)
|
||||
isEmptyReq := req.Slot == nil && req.CommitteeIndex == nil
|
||||
if isEmptyReq {
|
||||
fmt.Println("return all")
|
||||
allAtts := make([]*ethpb.Attestation, len(attestations))
|
||||
for i, att := range attestations {
|
||||
allAtts[i] = migration.V1Alpha1AttestationToV1(att)
|
||||
}
|
||||
return ðpb.AttestationsPoolResponse{Data: allAtts}, nil
|
||||
}
|
||||
|
||||
filteredAtts := make([]*ethpb.Attestation, 0, len(attestations))
|
||||
for _, att := range attestations {
|
||||
bothDefined := req.Slot != nil && req.CommitteeIndex != nil
|
||||
committeeIndexMatch := req.CommitteeIndex != nil && att.Data.CommitteeIndex == *req.CommitteeIndex
|
||||
slotMatch := req.Slot != nil && att.Data.Slot == *req.Slot
|
||||
|
||||
if bothDefined && committeeIndexMatch && slotMatch {
|
||||
filteredAtts = append(filteredAtts, migration.V1Alpha1AttestationToV1(att))
|
||||
} else if !bothDefined && (committeeIndexMatch || slotMatch) {
|
||||
filteredAtts = append(filteredAtts, migration.V1Alpha1AttestationToV1(att))
|
||||
}
|
||||
}
|
||||
return ðpb.AttestationsPoolResponse{Data: filteredAtts}, nil
|
||||
}
|
||||
|
||||
// SubmitAttestations submits Attestation object to node. If attestation passes all validation
|
||||
|
||||
@@ -26,6 +26,178 @@ import (
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
func TestListPoolAttestations(t *testing.T) {
|
||||
state, err := testutil.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
att1 := ð.Attestation{
|
||||
AggregationBits: []byte{1, 10},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 1,
|
||||
CommitteeIndex: 1,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("blockroot1"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: bytesutil.PadTo([]byte("sourceroot1"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 10,
|
||||
Root: bytesutil.PadTo([]byte("targetroot1"), 32),
|
||||
},
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("signature1"), 96),
|
||||
}
|
||||
att2 := ð.Attestation{
|
||||
AggregationBits: []byte{4, 40},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 4,
|
||||
CommitteeIndex: 4,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("blockroot4"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 4,
|
||||
Root: bytesutil.PadTo([]byte("sourceroot4"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 40,
|
||||
Root: bytesutil.PadTo([]byte("targetroot4"), 32),
|
||||
},
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("signature4"), 96),
|
||||
}
|
||||
att3 := ð.Attestation{
|
||||
AggregationBits: []byte{2, 20},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 2,
|
||||
CommitteeIndex: 2,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("blockroot2"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 2,
|
||||
Root: bytesutil.PadTo([]byte("sourceroot2"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 20,
|
||||
Root: bytesutil.PadTo([]byte("targetroot2"), 32),
|
||||
},
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("signature2"), 96),
|
||||
}
|
||||
att4 := ð.Attestation{
|
||||
AggregationBits: []byte{2, 20},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 4,
|
||||
CommitteeIndex: 4,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("blockroot2"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 2,
|
||||
Root: bytesutil.PadTo([]byte("sourceroot2"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 20,
|
||||
Root: bytesutil.PadTo([]byte("targetroot2"), 32),
|
||||
},
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("signature2"), 96),
|
||||
}
|
||||
att5 := ð.Attestation{
|
||||
AggregationBits: []byte{1, 10},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 2,
|
||||
CommitteeIndex: 4,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("blockroot1"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 2,
|
||||
Root: bytesutil.PadTo([]byte("sourceroot2"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 20,
|
||||
Root: bytesutil.PadTo([]byte("targetroot2"), 32),
|
||||
},
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("signature1"), 96),
|
||||
}
|
||||
att6 := ð.Attestation{
|
||||
AggregationBits: []byte{2, 20},
|
||||
Data: ð.AttestationData{
|
||||
Slot: 2,
|
||||
CommitteeIndex: 4,
|
||||
BeaconBlockRoot: bytesutil.PadTo([]byte("blockroot2"), 32),
|
||||
Source: ð.Checkpoint{
|
||||
Epoch: 2,
|
||||
Root: bytesutil.PadTo([]byte("sourceroot2"), 32),
|
||||
},
|
||||
Target: ð.Checkpoint{
|
||||
Epoch: 20,
|
||||
Root: bytesutil.PadTo([]byte("targetroot2"), 32),
|
||||
},
|
||||
},
|
||||
Signature: bytesutil.PadTo([]byte("signature2"), 96),
|
||||
}
|
||||
s := &Server{
|
||||
ChainInfoFetcher: &chainMock.ChainService{State: state},
|
||||
AttestationsPool: attestations.NewPool(),
|
||||
}
|
||||
require.NoError(t, s.AttestationsPool.SaveAggregatedAttestations([]*eth.Attestation{att1, att2, att3, att4, att5, att6}))
|
||||
|
||||
t.Run("empty request", func(t *testing.T) {
|
||||
req := ðpb.AttestationsPoolRequest{}
|
||||
resp, err := s.ListPoolAttestations(context.Background(), req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 6, len(resp.Data))
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att1), resp.Data[0])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att2), resp.Data[1])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att3), resp.Data[2])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att4), resp.Data[3])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att5), resp.Data[4])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att6), resp.Data[5])
|
||||
})
|
||||
|
||||
t.Run("slot request", func(t *testing.T) {
|
||||
slot := eth2types.Slot(2)
|
||||
req := ðpb.AttestationsPoolRequest{
|
||||
Slot: &slot,
|
||||
}
|
||||
resp, err := s.ListPoolAttestations(context.Background(), req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 3, len(resp.Data))
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att3), resp.Data[0])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att5), resp.Data[1])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att6), resp.Data[2])
|
||||
assert.DeepEqual(t, att3.Data.Slot, slot)
|
||||
})
|
||||
|
||||
t.Run("index request", func(t *testing.T) {
|
||||
index := eth2types.CommitteeIndex(4)
|
||||
req := ðpb.AttestationsPoolRequest{
|
||||
CommitteeIndex: &index,
|
||||
}
|
||||
resp, err := s.ListPoolAttestations(context.Background(), req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 4, len(resp.Data))
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att2), resp.Data[0])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att4), resp.Data[1])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att5), resp.Data[2])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att6), resp.Data[3])
|
||||
assert.DeepEqual(t, att2.Data.CommitteeIndex, index)
|
||||
})
|
||||
|
||||
t.Run("both slot + index request", func(t *testing.T) {
|
||||
slot := eth2types.Slot(2)
|
||||
index := eth2types.CommitteeIndex(4)
|
||||
req := ðpb.AttestationsPoolRequest{
|
||||
Slot: &slot,
|
||||
CommitteeIndex: &index,
|
||||
}
|
||||
resp, err := s.ListPoolAttestations(context.Background(), req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(resp.Data))
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att5), resp.Data[0])
|
||||
assert.DeepSSZEqual(t, migration.V1Alpha1AttestationToV1(att6), resp.Data[1])
|
||||
assert.DeepEqual(t, att5.Data.CommitteeIndex, index)
|
||||
assert.DeepEqual(t, att6.Data.CommitteeIndex, index)
|
||||
assert.DeepEqual(t, att5.Data.Slot, slot)
|
||||
assert.DeepEqual(t, att6.Data.Slot, slot)
|
||||
})
|
||||
}
|
||||
|
||||
func TestListPoolAttesterSlashings(t *testing.T) {
|
||||
state, err := testutil.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -63,6 +63,18 @@ func V1Alpha1IndexedAttToV1(v1alpha1Att *ethpb_alpha.IndexedAttestation) *ethpb.
|
||||
}
|
||||
}
|
||||
|
||||
// V1Alpha1AttestationToV1 converts a v1alpha1 attestation to v1.
|
||||
func V1Alpha1AttestationToV1(v1alpha1Att *ethpb_alpha.Attestation) *ethpb.Attestation {
|
||||
if v1alpha1Att == nil {
|
||||
return ðpb.Attestation{}
|
||||
}
|
||||
return ðpb.Attestation{
|
||||
AggregationBits: v1alpha1Att.AggregationBits,
|
||||
Data: V1Alpha1AttDataToV1(v1alpha1Att.Data),
|
||||
Signature: v1alpha1Att.Signature,
|
||||
}
|
||||
}
|
||||
|
||||
// V1Alpha1AttDataToV1 converts a v1alpha1 attestation data to v1.
|
||||
func V1Alpha1AttDataToV1(v1alpha1AttData *ethpb_alpha.AttestationData) *ethpb.AttestationData {
|
||||
if v1alpha1AttData == nil || v1alpha1AttData.Source == nil || v1alpha1AttData.Target == nil {
|
||||
|
||||
Reference in New Issue
Block a user