github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/sync/validate_voluntary_exit.go (about) 1 package sync 2 3 import ( 4 "context" 5 6 "github.com/libp2p/go-libp2p-core/peer" 7 pubsub "github.com/libp2p/go-libp2p-pubsub" 8 types "github.com/prysmaticlabs/eth2-types" 9 "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" 10 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 11 "github.com/prysmaticlabs/prysm/shared/traceutil" 12 "go.opencensus.io/trace" 13 ) 14 15 // Clients who receive a voluntary exit on this topic MUST validate the conditions within process_voluntary_exit before 16 // forwarding it across the network. 17 func (s *Service) validateVoluntaryExit(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult { 18 // Validation runs on publish (not just subscriptions), so we should approve any message from 19 // ourselves. 20 if pid == s.cfg.P2P.PeerID() { 21 return pubsub.ValidationAccept 22 } 23 24 // The head state will be too far away to validate any voluntary exit. 25 if s.cfg.InitialSync.Syncing() { 26 return pubsub.ValidationIgnore 27 } 28 29 ctx, span := trace.StartSpan(ctx, "sync.validateVoluntaryExit") 30 defer span.End() 31 32 m, err := s.decodePubsubMessage(msg) 33 if err != nil { 34 log.WithError(err).Debug("Could not decode message") 35 traceutil.AnnotateError(span, err) 36 return pubsub.ValidationReject 37 } 38 39 exit, ok := m.(*ethpb.SignedVoluntaryExit) 40 if !ok { 41 return pubsub.ValidationReject 42 } 43 44 if exit.Exit == nil { 45 return pubsub.ValidationReject 46 } 47 if s.hasSeenExitIndex(exit.Exit.ValidatorIndex) { 48 return pubsub.ValidationIgnore 49 } 50 51 headState, err := s.cfg.Chain.HeadState(ctx) 52 if err != nil { 53 return pubsub.ValidationIgnore 54 } 55 56 if uint64(exit.Exit.ValidatorIndex) >= uint64(headState.NumValidators()) { 57 return pubsub.ValidationReject 58 } 59 val, err := headState.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex) 60 if err != nil { 61 return pubsub.ValidationIgnore 62 } 63 if err := blocks.VerifyExitAndSignature(val, headState.Slot(), headState.Fork(), exit, headState.GenesisValidatorRoot()); err != nil { 64 return pubsub.ValidationReject 65 } 66 67 msg.ValidatorData = exit // Used in downstream subscriber 68 69 return pubsub.ValidationAccept 70 } 71 72 // Returns true if the node has already received a valid exit request for the validator with index `i`. 73 func (s *Service) hasSeenExitIndex(i types.ValidatorIndex) bool { 74 s.seenExitLock.RLock() 75 defer s.seenExitLock.RUnlock() 76 _, seen := s.seenExitCache.Get(i) 77 return seen 78 } 79 80 // Set exit request index `i` in seen exit request cache. 81 func (s *Service) setExitIndexSeen(i types.ValidatorIndex) { 82 s.seenExitLock.Lock() 83 defer s.seenExitLock.Unlock() 84 s.seenExitCache.Add(i, true) 85 }