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  }