github.com/prysmaticlabs/prysm@v1.4.4/validator/client/propose_protect.go (about) 1 package client 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/pkg/errors" 8 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 9 "github.com/prysmaticlabs/prysm/shared/blockutil" 10 "github.com/prysmaticlabs/prysm/shared/featureconfig" 11 "github.com/prysmaticlabs/prysm/shared/params" 12 "github.com/sirupsen/logrus" 13 ) 14 15 var failedPreBlockSignLocalErr = "attempted to sign a double proposal, block rejected by local protection" 16 var failedPreBlockSignExternalErr = "attempted a double proposal, block rejected by remote slashing protection" 17 var failedPostBlockSignErr = "made a double proposal, considered slashable by remote slashing protection" 18 19 func (v *validator) preBlockSignValidations( 20 ctx context.Context, pubKey [48]byte, block *ethpb.BeaconBlock, signingRoot [32]byte, 21 ) error { 22 fmtKey := fmt.Sprintf("%#x", pubKey[:]) 23 24 prevSigningRoot, proposalAtSlotExists, err := v.db.ProposalHistoryForSlot(ctx, pubKey, block.Slot) 25 if err != nil { 26 if v.emitAccountMetrics { 27 ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc() 28 } 29 return errors.Wrap(err, "failed to get proposal history") 30 } 31 32 lowestSignedProposalSlot, lowestProposalExists, err := v.db.LowestSignedProposal(ctx, pubKey) 33 if err != nil { 34 return err 35 } 36 37 // If a proposal exists in our history for the slot, we check the following: 38 // If the signing root is empty (zero hash), then we consider it slashable. If signing root is not empty, 39 // we check if it is different than the incoming block's signing root. If that is the case, 40 // we consider that proposal slashable. 41 signingRootIsDifferent := prevSigningRoot == params.BeaconConfig().ZeroHash || prevSigningRoot != signingRoot 42 if proposalAtSlotExists && signingRootIsDifferent { 43 if v.emitAccountMetrics { 44 ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc() 45 } 46 return errors.New(failedPreBlockSignLocalErr) 47 } 48 49 // Based on EIP3076, validator should refuse to sign any proposal with slot less 50 // than or equal to the minimum signed proposal present in the DB for that public key. 51 // In the case the slot of the incoming block is equal to the minimum signed proposal, we 52 // then also check the signing root is different. 53 if lowestProposalExists && signingRootIsDifferent && lowestSignedProposalSlot >= block.Slot { 54 return fmt.Errorf( 55 "could not sign block with slot <= lowest signed slot in db, lowest signed slot: %d >= block slot: %d", 56 lowestSignedProposalSlot, 57 block.Slot, 58 ) 59 } 60 61 if featureconfig.Get().SlasherProtection && v.protector != nil { 62 blockHdr, err := blockutil.BeaconBlockHeaderFromBlock(block) 63 if err != nil { 64 return errors.Wrap(err, "failed to get block header from block") 65 } 66 if !v.protector.CheckBlockSafety(ctx, blockHdr) { 67 if v.emitAccountMetrics { 68 ValidatorProposeFailVecSlasher.WithLabelValues(fmtKey).Inc() 69 } 70 return errors.New(failedPreBlockSignExternalErr) 71 } 72 } 73 74 return nil 75 } 76 77 func (v *validator) postBlockSignUpdate( 78 ctx context.Context, 79 pubKey [48]byte, 80 block *ethpb.SignedBeaconBlock, 81 signingRoot [32]byte, 82 ) error { 83 fmtKey := fmt.Sprintf("%#x", pubKey[:]) 84 if featureconfig.Get().SlasherProtection && v.protector != nil { 85 sbh, err := blockutil.SignedBeaconBlockHeaderFromBlock(block) 86 if err != nil { 87 return errors.Wrap(err, "failed to get block header from block") 88 } 89 valid, err := v.protector.CommitBlock(ctx, sbh) 90 if err != nil { 91 return err 92 } 93 if !valid { 94 if v.emitAccountMetrics { 95 ValidatorProposeFailVecSlasher.WithLabelValues(fmtKey).Inc() 96 } 97 return fmt.Errorf(failedPostBlockSignErr) 98 } 99 } 100 if err := v.db.SaveProposalHistoryForSlot(ctx, pubKey, block.Block.Slot, signingRoot[:]); err != nil { 101 if v.emitAccountMetrics { 102 ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc() 103 } 104 return errors.Wrap(err, "failed to save updated proposal history") 105 } 106 return nil 107 } 108 109 func blockLogFields(pubKey [48]byte, blk *ethpb.BeaconBlock, sig []byte) logrus.Fields { 110 fields := logrus.Fields{ 111 "proposerPublicKey": fmt.Sprintf("%#x", pubKey), 112 "proposerIndex": blk.ProposerIndex, 113 "blockSlot": blk.Slot, 114 } 115 if sig != nil { 116 fields["signature"] = fmt.Sprintf("%#x", sig) 117 } 118 return fields 119 }