From e40fba7679a5f8519d34bee74e12d18c09bb2252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Kapka?= Date: Tue, 23 Feb 2021 16:17:07 +0100 Subject: [PATCH] Implement ListPoolAttesterSlashings in the beacon API (#8492) * pool interface and mock * implementation * gofmt * gzl * Use migration package for slashing mapping Co-authored-by: Raul Jordan --- beacon-chain/blockchain/service.go | 4 +- beacon-chain/node/node.go | 2 +- beacon-chain/operations/slashings/BUILD.bazel | 1 + beacon-chain/operations/slashings/mock.go | 43 ++++++++ beacon-chain/operations/slashings/types.go | 24 +++- beacon-chain/rpc/beacon/server.go | 2 +- beacon-chain/rpc/beaconv1/BUILD.bazel | 2 + beacon-chain/rpc/beaconv1/pool.go | 23 +++- beacon-chain/rpc/beaconv1/pool_test.go | 104 ++++++++++++++++++ beacon-chain/rpc/beaconv1/server.go | 2 +- beacon-chain/rpc/service.go | 4 +- beacon-chain/rpc/validator/server.go | 2 +- beacon-chain/sync/service.go | 4 +- proto/migration/migration.go | 43 ++++++++ 14 files changed, 246 insertions(+), 14 deletions(-) create mode 100644 beacon-chain/operations/slashings/mock.go create mode 100644 beacon-chain/rpc/beaconv1/pool_test.go diff --git a/beacon-chain/blockchain/service.go b/beacon-chain/blockchain/service.go index 32e312b009..46bc8a868b 100644 --- a/beacon-chain/blockchain/service.go +++ b/beacon-chain/blockchain/service.go @@ -52,7 +52,7 @@ type Service struct { depositCache *depositcache.DepositCache chainStartFetcher powchain.ChainStartFetcher attPool attestations.Pool - slashingPool *slashings.Pool + slashingPool slashings.PoolManager exitPool *voluntaryexits.Pool genesisTime time.Time p2p p2p.Broadcaster @@ -89,7 +89,7 @@ type Config struct { DepositCache *depositcache.DepositCache AttPool attestations.Pool ExitPool *voluntaryexits.Pool - SlashingPool *slashings.Pool + SlashingPool slashings.PoolManager P2p p2p.Broadcaster MaxRoutines int StateNotifier statefeed.Notifier diff --git a/beacon-chain/node/node.go b/beacon-chain/node/node.go index dab52bc365..be1e984a79 100644 --- a/beacon-chain/node/node.go +++ b/beacon-chain/node/node.go @@ -68,7 +68,7 @@ type BeaconNode struct { db db.Database attestationPool attestations.Pool exitPool *voluntaryexits.Pool - slashingsPool *slashings.Pool + slashingsPool slashings.PoolManager depositCache *depositcache.DepositCache stateFeed *event.Feed blockFeed *event.Feed diff --git a/beacon-chain/operations/slashings/BUILD.bazel b/beacon-chain/operations/slashings/BUILD.bazel index 07ab86affa..e3eab4cf87 100644 --- a/beacon-chain/operations/slashings/BUILD.bazel +++ b/beacon-chain/operations/slashings/BUILD.bazel @@ -7,6 +7,7 @@ go_library( "doc.go", "log.go", "metrics.go", + "mock.go", "service.go", "types.go", ], diff --git a/beacon-chain/operations/slashings/mock.go b/beacon-chain/operations/slashings/mock.go new file mode 100644 index 0000000000..3929ac04ee --- /dev/null +++ b/beacon-chain/operations/slashings/mock.go @@ -0,0 +1,43 @@ +package slashings + +import ( + "context" + + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/beacon-chain/state" +) + +// PoolMock is a fake implementation of PoolManager. +type PoolMock struct { + PendingAttSlashings []*ethpb.AttesterSlashing +} + +// PendingAttesterSlashings -- +func (m *PoolMock) PendingAttesterSlashings(ctx context.Context, state *state.BeaconState, noLimit bool) []*ethpb.AttesterSlashing { + return m.PendingAttSlashings +} + +// PendingProposerSlashings -- +func (m *PoolMock) PendingProposerSlashings(ctx context.Context, state *state.BeaconState, noLimit bool) []*ethpb.ProposerSlashing { + panic("implement me") +} + +// InsertAttesterSlashing -- +func (m *PoolMock) InsertAttesterSlashing(ctx context.Context, state *state.BeaconState, slashing *ethpb.AttesterSlashing) error { + panic("implement me") +} + +// InsertProposerSlashing -- +func (m *PoolMock) InsertProposerSlashing(ctx context.Context, state *state.BeaconState, slashing *ethpb.ProposerSlashing) error { + panic("implement me") +} + +// MarkIncludedAttesterSlashing -- +func (m *PoolMock) MarkIncludedAttesterSlashing(as *ethpb.AttesterSlashing) { + panic("implement me") +} + +// MarkIncludedProposerSlashing -- +func (m *PoolMock) MarkIncludedProposerSlashing(ps *ethpb.ProposerSlashing) { + panic("implement me") +} diff --git a/beacon-chain/operations/slashings/types.go b/beacon-chain/operations/slashings/types.go index 893de20fbf..f367424a18 100644 --- a/beacon-chain/operations/slashings/types.go +++ b/beacon-chain/operations/slashings/types.go @@ -1,14 +1,34 @@ package slashings import ( + "context" "sync" types "github.com/prysmaticlabs/eth2-types" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/beacon-chain/state" ) -// Pool implements a struct to maintain pending and recently included attester and -// proposer slashings. This pool is used by proposers to insert into new blocks. +// PoolManager maintains a pool of pending and recently included attester and proposer slashings. +// This pool is used by proposers to insert data into new blocks. +type PoolManager interface { + PendingAttesterSlashings(ctx context.Context, state *state.BeaconState, noLimit bool) []*ethpb.AttesterSlashing + PendingProposerSlashings(ctx context.Context, state *state.BeaconState, noLimit bool) []*ethpb.ProposerSlashing + InsertAttesterSlashing( + ctx context.Context, + state *state.BeaconState, + slashing *ethpb.AttesterSlashing, + ) error + InsertProposerSlashing( + ctx context.Context, + state *state.BeaconState, + slashing *ethpb.ProposerSlashing, + ) error + MarkIncludedAttesterSlashing(as *ethpb.AttesterSlashing) + MarkIncludedProposerSlashing(ps *ethpb.ProposerSlashing) +} + +// Pool is a concrete implementation of PoolManager. type Pool struct { lock sync.RWMutex pendingProposerSlashing []*ethpb.ProposerSlashing diff --git a/beacon-chain/rpc/beacon/server.go b/beacon-chain/rpc/beacon/server.go index 8e01d9fd23..9ca92baad5 100644 --- a/beacon-chain/rpc/beacon/server.go +++ b/beacon-chain/rpc/beacon/server.go @@ -41,7 +41,7 @@ type Server struct { AttestationNotifier operation.Notifier Broadcaster p2p.Broadcaster AttestationsPool attestations.Pool - SlashingsPool *slashings.Pool + SlashingsPool slashings.PoolManager CanonicalStateChan chan *pbp2p.BeaconState ChainStartChan chan time.Time ReceivedAttestationsBuffer chan *ethpb.Attestation diff --git a/beacon-chain/rpc/beaconv1/BUILD.bazel b/beacon-chain/rpc/beaconv1/BUILD.bazel index 8043b6b506..e5c59dbb1a 100644 --- a/beacon-chain/rpc/beaconv1/BUILD.bazel +++ b/beacon-chain/rpc/beaconv1/BUILD.bazel @@ -53,6 +53,7 @@ go_test( srcs = [ "blocks_test.go", "config_test.go", + "pool_test.go", "server_test.go", "state_test.go", ], @@ -61,6 +62,7 @@ go_test( "//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/db:go_default_library", "//beacon-chain/db/testing:go_default_library", + "//beacon-chain/operations/slashings:go_default_library", "//beacon-chain/p2p/testing:go_default_library", "//beacon-chain/powchain/testing:go_default_library", "//beacon-chain/state/stategen:go_default_library", diff --git a/beacon-chain/rpc/beaconv1/pool.go b/beacon-chain/rpc/beaconv1/pool.go index 1efbfed08d..94a5db6731 100644 --- a/beacon-chain/rpc/beaconv1/pool.go +++ b/beacon-chain/rpc/beaconv1/pool.go @@ -5,8 +5,11 @@ import ( "errors" ptypes "github.com/gogo/protobuf/types" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1" + "github.com/prysmaticlabs/prysm/proto/migration" + "go.opencensus.io/trace" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // ListPoolAttestations retrieves attestations known by the node but @@ -24,7 +27,23 @@ func (bs *Server) SubmitAttestation(ctx context.Context, req *ethpb.Attestation) // ListPoolAttesterSlashings retrieves attester slashings known by the node but // not necessarily incorporated into any block. func (bs *Server) ListPoolAttesterSlashings(ctx context.Context, req *ptypes.Empty) (*ethpb.AttesterSlashingsPoolResponse, error) { - return nil, errors.New("unimplemented") + ctx, span := trace.StartSpan(ctx, "beaconv1.ListPoolAttesterSlashings") + defer span.End() + + headState, err := bs.ChainInfoFetcher.HeadState(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err) + } + sourceSlashings := bs.SlashingsPool.PendingAttesterSlashings(ctx, headState, true) + + slashings := make([]*ethpb.AttesterSlashing, len(sourceSlashings)) + for i, s := range sourceSlashings { + slashings[i] = migration.V1Alpha1AttSlashingToV1(s) + } + + return ðpb.AttesterSlashingsPoolResponse{ + Data: slashings, + }, nil } // SubmitAttesterSlashing submits AttesterSlashing object to node's pool and diff --git a/beacon-chain/rpc/beaconv1/pool_test.go b/beacon-chain/rpc/beaconv1/pool_test.go new file mode 100644 index 0000000000..71a1da3937 --- /dev/null +++ b/beacon-chain/rpc/beaconv1/pool_test.go @@ -0,0 +1,104 @@ +package beaconv1 + +import ( + "context" + "testing" + + "github.com/gogo/protobuf/types" + eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + chainMock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" + "github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings" + "github.com/prysmaticlabs/prysm/proto/migration" + "github.com/prysmaticlabs/prysm/shared/bytesutil" + "github.com/prysmaticlabs/prysm/shared/testutil" + "github.com/prysmaticlabs/prysm/shared/testutil/assert" + "github.com/prysmaticlabs/prysm/shared/testutil/require" +) + +func TestListPoolAttesterSlashings(t *testing.T) { + state, err := testutil.NewBeaconState() + require.NoError(t, err) + slashing1 := ð.AttesterSlashing{ + Attestation_1: ð.IndexedAttestation{ + AttestingIndices: []uint64{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), + }, + Attestation_2: ð.IndexedAttestation{ + AttestingIndices: []uint64{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), + }, + } + slashing2 := ð.AttesterSlashing{ + Attestation_1: ð.IndexedAttestation{ + AttestingIndices: []uint64{3, 30}, + Data: ð.AttestationData{ + Slot: 3, + CommitteeIndex: 3, + BeaconBlockRoot: bytesutil.PadTo([]byte("blockroot3"), 32), + Source: ð.Checkpoint{ + Epoch: 3, + Root: bytesutil.PadTo([]byte("sourceroot3"), 32), + }, + Target: ð.Checkpoint{ + Epoch: 30, + Root: bytesutil.PadTo([]byte("targetroot3"), 32), + }, + }, + Signature: bytesutil.PadTo([]byte("signature3"), 96), + }, + Attestation_2: ð.IndexedAttestation{ + AttestingIndices: []uint64{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), + }, + } + + s := &Server{ + ChainInfoFetcher: &chainMock.ChainService{State: state}, + SlashingsPool: &slashings.PoolMock{PendingAttSlashings: []*eth.AttesterSlashing{slashing1, slashing2}}, + } + + resp, err := s.ListPoolAttesterSlashings(context.Background(), &types.Empty{}) + require.NoError(t, err) + require.Equal(t, 2, len(resp.Data)) + assert.DeepEqual(t, migration.V1Alpha1AttSlashingToV1(slashing1), resp.Data[0]) + assert.DeepEqual(t, migration.V1Alpha1AttSlashingToV1(slashing2), resp.Data[1]) +} diff --git a/beacon-chain/rpc/beaconv1/server.go b/beacon-chain/rpc/beaconv1/server.go index dc9563f75b..ff220591c1 100644 --- a/beacon-chain/rpc/beaconv1/server.go +++ b/beacon-chain/rpc/beaconv1/server.go @@ -39,7 +39,7 @@ type Server struct { AttestationNotifier operation.Notifier Broadcaster p2p.Broadcaster AttestationsPool attestations.Pool - SlashingsPool *slashings.Pool + SlashingsPool slashings.PoolManager CanonicalStateChan chan *pbp2p.BeaconState ChainStartChan chan time.Time StateGenService stategen.StateManager diff --git a/beacon-chain/rpc/service.go b/beacon-chain/rpc/service.go index bf4e3ecee0..a9ae0ba977 100644 --- a/beacon-chain/rpc/service.go +++ b/beacon-chain/rpc/service.go @@ -71,7 +71,7 @@ type Service struct { enableDebugRPCEndpoints bool attestationsPool attestations.Pool exitPool *voluntaryexits.Pool - slashingsPool *slashings.Pool + slashingsPool slashings.PoolManager syncService chainSync.Checker host string port string @@ -123,7 +123,7 @@ type Config struct { MockEth1Votes bool AttestationsPool attestations.Pool ExitPool *voluntaryexits.Pool - SlashingsPool *slashings.Pool + SlashingsPool slashings.PoolManager SyncService chainSync.Checker Broadcaster p2p.Broadcaster PeersFetcher p2p.PeersProvider diff --git a/beacon-chain/rpc/validator/server.go b/beacon-chain/rpc/validator/server.go index 06b45e6307..0ecb74cce6 100644 --- a/beacon-chain/rpc/validator/server.go +++ b/beacon-chain/rpc/validator/server.go @@ -55,7 +55,7 @@ type Server struct { BlockNotifier blockfeed.Notifier P2P p2p.Broadcaster AttPool attestations.Pool - SlashingsPool *slashings.Pool + SlashingsPool slashings.PoolManager ExitPool *voluntaryexits.Pool BlockReceiver blockchain.BlockReceiver MockEth1Votes bool diff --git a/beacon-chain/sync/service.go b/beacon-chain/sync/service.go index c512226fda..6b35841c4e 100644 --- a/beacon-chain/sync/service.go +++ b/beacon-chain/sync/service.go @@ -54,7 +54,7 @@ type Config struct { DB db.NoHeadAccessDatabase AttPool attestations.Pool ExitPool *voluntaryexits.Pool - SlashingPool *slashings.Pool + SlashingPool slashings.PoolManager Chain blockchainService InitialSync Checker StateNotifier statefeed.Notifier @@ -84,7 +84,7 @@ type Service struct { db db.NoHeadAccessDatabase attPool attestations.Pool exitPool *voluntaryexits.Pool - slashingPool *slashings.Pool + slashingPool slashings.PoolManager chain blockchainService slotToPendingBlocks *gcache.Cache seenPendingBlocks map[[32]byte]bool diff --git a/proto/migration/migration.go b/proto/migration/migration.go index 17555cdfdb..7876ae970e 100644 --- a/proto/migration/migration.go +++ b/proto/migration/migration.go @@ -50,3 +50,46 @@ func V1ToV1Alpha1Block(alphaBlk *ethpb.SignedBeaconBlock) (*ethpb_alpha.SignedBe } return v1alpha1Block, nil } + +// V1Alpha1IndexedAttToV1 converts a v1alpha1 indexed attestation to v1. +func V1Alpha1IndexedAttToV1(v1alpha1Att *ethpb_alpha.IndexedAttestation) *ethpb.IndexedAttestation { + if v1alpha1Att == nil { + return ðpb.IndexedAttestation{} + } + return ðpb.IndexedAttestation{ + AttestingIndices: v1alpha1Att.AttestingIndices, + 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 { + return ðpb.AttestationData{} + } + return ðpb.AttestationData{ + Slot: v1alpha1AttData.Slot, + CommitteeIndex: v1alpha1AttData.CommitteeIndex, + BeaconBlockRoot: v1alpha1AttData.BeaconBlockRoot, + Source: ðpb.Checkpoint{ + Root: v1alpha1AttData.Source.Root, + Epoch: v1alpha1AttData.Source.Epoch, + }, + Target: ðpb.Checkpoint{ + Root: v1alpha1AttData.Target.Root, + Epoch: v1alpha1AttData.Target.Epoch, + }, + } +} + +// V1Alpha1AttSlashingToV1 converts a v1alpha1 attester slashing to v1. +func V1Alpha1AttSlashingToV1(v1alpha1Slashing *ethpb_alpha.AttesterSlashing) *ethpb.AttesterSlashing { + if v1alpha1Slashing == nil { + return ðpb.AttesterSlashing{} + } + return ðpb.AttesterSlashing{ + Attestation_1: V1Alpha1IndexedAttToV1(v1alpha1Slashing.Attestation_1), + Attestation_2: V1Alpha1IndexedAttToV1(v1alpha1Slashing.Attestation_2), + } +}