github.com/prysmaticlabs/prysm@v1.4.4/validator/client/attest_protect.go (about) 1 package client 2 3 import ( 4 "context" 5 "encoding/hex" 6 "fmt" 7 8 "github.com/pkg/errors" 9 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 10 "github.com/prysmaticlabs/prysm/shared/featureconfig" 11 "github.com/prysmaticlabs/prysm/shared/slashutil" 12 "github.com/prysmaticlabs/prysm/validator/db/kv" 13 "go.opencensus.io/trace" 14 ) 15 16 var failedAttLocalProtectionErr = "attempted to make slashable attestation, rejected by local slashing protection" 17 var failedPostAttSignExternalErr = "attempted to make slashable attestation, rejected by external slasher service" 18 19 // Checks if an attestation is slashable by comparing it with the attesting 20 // history for the given public key in our DB. If it is not, we then update the history 21 // with new values and save it to the database. 22 func (v *validator) slashableAttestationCheck( 23 ctx context.Context, 24 indexedAtt *ethpb.IndexedAttestation, 25 pubKey [48]byte, 26 signingRoot [32]byte, 27 ) error { 28 ctx, span := trace.StartSpan(ctx, "validator.postAttSignUpdate") 29 defer span.End() 30 31 // Based on EIP3076, validator should refuse to sign any attestation with source epoch less 32 // than the minimum source epoch present in that signer’s attestations. 33 lowestSourceEpoch, exists, err := v.db.LowestSignedSourceEpoch(ctx, pubKey) 34 if err != nil { 35 return err 36 } 37 if exists && indexedAtt.Data.Source.Epoch < lowestSourceEpoch { 38 return fmt.Errorf( 39 "could not sign attestation lower than lowest source epoch in db, %d < %d", 40 indexedAtt.Data.Source.Epoch, 41 lowestSourceEpoch, 42 ) 43 } 44 existingSigningRoot, err := v.db.SigningRootAtTargetEpoch(ctx, pubKey, indexedAtt.Data.Target.Epoch) 45 if err != nil { 46 return err 47 } 48 signingRootsDiffer := slashutil.SigningRootsDiffer(existingSigningRoot, signingRoot) 49 50 // Based on EIP3076, validator should refuse to sign any attestation with target epoch less 51 // than or equal to the minimum target epoch present in that signer’s attestations. 52 lowestTargetEpoch, exists, err := v.db.LowestSignedTargetEpoch(ctx, pubKey) 53 if err != nil { 54 return err 55 } 56 if signingRootsDiffer && exists && indexedAtt.Data.Target.Epoch <= lowestTargetEpoch { 57 return fmt.Errorf( 58 "could not sign attestation lower than or equal to lowest target epoch in db, %d <= %d", 59 indexedAtt.Data.Target.Epoch, 60 lowestTargetEpoch, 61 ) 62 } 63 fmtKey := "0x" + hex.EncodeToString(pubKey[:]) 64 slashingKind, err := v.db.CheckSlashableAttestation(ctx, pubKey, signingRoot, indexedAtt) 65 if err != nil { 66 if v.emitAccountMetrics { 67 ValidatorAttestFailVec.WithLabelValues(fmtKey).Inc() 68 } 69 switch slashingKind { 70 case kv.DoubleVote: 71 log.Warn("Attestation is slashable as it is a double vote") 72 case kv.SurroundingVote: 73 log.Warn("Attestation is slashable as it is surrounding a previous attestation") 74 case kv.SurroundedVote: 75 log.Warn("Attestation is slashable as it is surrounded by a previous attestation") 76 } 77 return errors.Wrap(err, failedAttLocalProtectionErr) 78 } 79 80 if err := v.db.SaveAttestationForPubKey(ctx, pubKey, signingRoot, indexedAtt); err != nil { 81 return errors.Wrap(err, "could not save attestation history for validator public key") 82 } 83 84 if featureconfig.Get().SlasherProtection && v.protector != nil { 85 if !v.protector.CommitAttestation(ctx, indexedAtt) { 86 if v.emitAccountMetrics { 87 ValidatorAttestFailVecSlasher.WithLabelValues(fmtKey).Inc() 88 } 89 return errors.New(failedPostAttSignExternalErr) 90 } 91 } 92 return nil 93 }