forked from prysmaticlabs/prysm
-
Notifications
You must be signed in to change notification settings - Fork 2
/
server.go
137 lines (128 loc) · 4.88 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package rpc
import (
"context"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/slasher/db"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// Server defines a server implementation of the gRPC Slasher service,
// providing RPC endpoints for retrieving slashing proofs for malicious validators.
type Server struct {
SlasherDB *db.Store
ctx context.Context
}
// IsSlashableAttestation returns an attester slashing if the attestation submitted
// is a slashable vote.
func (ss *Server) IsSlashableAttestation(ctx context.Context, req *ethpb.IndexedAttestation) (*ethpb.AttesterSlashingResponse, error) {
//TODO(#3133): add signature validation
if err := ss.SlasherDB.SaveIndexedAttestation(req); err != nil {
return nil, err
}
tEpoch := req.Data.Target.Epoch
indices := append(req.CustodyBit_0Indices, req.CustodyBit_1Indices...)
root, err := ssz.HashTreeRoot(req.Data)
if err != nil {
return nil, err
}
atsSlashinngRes := ðpb.AttesterSlashingResponse{}
for _, idx := range indices {
atts, err := ss.SlasherDB.DoubleVotes(tEpoch, idx, root[:], req)
if err != nil {
return nil, err
}
if atts != nil && len(atts) > 0 {
atsSlashinngRes.AttesterSlashing = append(atsSlashinngRes.AttesterSlashing, atts...)
}
}
for _, idx := range indices {
atts, err := ss.DetectSurroundVotes(ctx, req.Data.Source.Epoch, req.Data.Target.Epoch, idx)
if err != nil {
return nil, err
}
for _, ia := range atts {
atsSlashinngRes.AttesterSlashing = append(atsSlashinngRes.AttesterSlashing, ðpb.AttesterSlashing{
Attestation_1: req,
Attestation_2: ia,
})
}
}
return atsSlashinngRes, nil
}
// IsSlashableBlock returns a proposer slashing if the block header submitted is
// a slashable proposal.
func (ss *Server) IsSlashableBlock(ctx context.Context, psr *ethpb.ProposerSlashingRequest) (*ethpb.ProposerSlashingResponse, error) {
//TODO(#3133): add signature validation
epoch := helpers.SlotToEpoch(psr.BlockHeader.Slot)
blockHeaders, err := ss.SlasherDB.BlockHeader(epoch, psr.ValidatorIndex)
if err != nil {
return nil, errors.Wrap(err, "slasher service error while trying to retrieve blocks")
}
pSlashingsResponse := ðpb.ProposerSlashingResponse{}
presentInDb := false
for _, bh := range blockHeaders {
if proto.Equal(bh, psr.BlockHeader) {
presentInDb = true
continue
}
pSlashingsResponse.ProposerSlashing = append(pSlashingsResponse.ProposerSlashing, ðpb.ProposerSlashing{ProposerIndex: psr.ValidatorIndex, Header_1: psr.BlockHeader, Header_2: bh})
}
if len(pSlashingsResponse.ProposerSlashing) == 0 && !presentInDb {
err = ss.SlasherDB.SaveBlockHeader(epoch, psr.ValidatorIndex, psr.BlockHeader)
if err != nil {
return nil, err
}
}
return pSlashingsResponse, nil
}
// SlashableProposals is a subscription to receive all slashable proposer slashing events found by the watchtower.
func (ss *Server) SlashableProposals(req *types.Empty, server ethpb.Slasher_SlashableProposalsServer) error {
//TODO(3133): implement stream provider for newly discovered listening to slashable proposals.
return status.Error(codes.Unimplemented, "not implemented")
}
// SlashableAttestations is a subscription to receive all slashable attester slashing events found by the watchtower.
func (ss *Server) SlashableAttestations(req *types.Empty, server ethpb.Slasher_SlashableAttestationsServer) error {
//TODO(3133): implement stream provider for newly discovered listening to slashable attestation.
return status.Error(codes.Unimplemented, "not implemented")
}
// DetectSurroundVotes is a method used to return the attestation that were detected
// by min max surround detection method.
func (ss *Server) DetectSurroundVotes(ctx context.Context, source uint64, target uint64, validatorIdx uint64) ([]*ethpb.IndexedAttestation, error) {
minTargetEpoch, err := ss.DetectAndUpdateMinEpochSpan(ctx, source, target, validatorIdx)
if err != nil {
return nil, err
}
maxTargetEpoch, err := ss.DetectAndUpdateMaxEpochSpan(ctx, source, target, validatorIdx)
if err != nil {
return nil, err
}
var idxAtts []*ethpb.IndexedAttestation
if minTargetEpoch > 0 {
attestations, err := ss.SlasherDB.IndexedAttestation(minTargetEpoch, validatorIdx)
if err != nil {
return nil, err
}
for _, ia := range attestations {
if ia.Data.Source.Epoch > source && ia.Data.Target.Epoch < target {
idxAtts = append(idxAtts, ia)
}
}
}
if maxTargetEpoch > 0 {
attestations, err := ss.SlasherDB.IndexedAttestation(maxTargetEpoch, validatorIdx)
if err != nil {
return nil, err
}
for _, ia := range attestations {
if ia.Data.Source.Epoch < source && ia.Data.Target.Epoch > target {
idxAtts = append(idxAtts, ia)
}
}
}
return idxAtts, nil
}