github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/blocks/proposer_slashing.go (about)

     1  package blocks
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/pkg/errors"
     8  	types "github.com/prysmaticlabs/eth2-types"
     9  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    10  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    11  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    12  	"github.com/prysmaticlabs/prysm/shared/params"
    13  	"google.golang.org/protobuf/proto"
    14  )
    15  
    16  type slashValidatorFunc func(iface.BeaconState, types.ValidatorIndex) (iface.BeaconState, error)
    17  
    18  // ProcessProposerSlashings is one of the operations performed
    19  // on each processed beacon block to slash proposers based on
    20  // slashing conditions if any slashable events occurred.
    21  //
    22  // Spec pseudocode definition:
    23  //   def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None:
    24  //    header_1 = proposer_slashing.signed_header_1.message
    25  //    header_2 = proposer_slashing.signed_header_2.message
    26  //
    27  //    # Verify header slots match
    28  //    assert header_1.slot == header_2.slot
    29  //    # Verify header proposer indices match
    30  //    assert header_1.proposer_index == header_2.proposer_index
    31  //    # Verify the headers are different
    32  //    assert header_1 != header_2
    33  //    # Verify the proposer is slashable
    34  //    proposer = state.validators[header_1.proposer_index]
    35  //    assert is_slashable_validator(proposer, get_current_epoch(state))
    36  //    # Verify signatures
    37  //    for signed_header in (proposer_slashing.signed_header_1, proposer_slashing.signed_header_2):
    38  //        domain = get_domain(state, DOMAIN_BEACON_PROPOSER, compute_epoch_at_slot(signed_header.message.slot))
    39  //        signing_root = compute_signing_root(signed_header.message, domain)
    40  //        assert bls.Verify(proposer.pubkey, signing_root, signed_header.signature)
    41  //
    42  //    slash_validator(state, header_1.proposer_index)
    43  func ProcessProposerSlashings(
    44  	_ context.Context,
    45  	beaconState iface.BeaconState,
    46  	slashings []*ethpb.ProposerSlashing,
    47  	slashFunc slashValidatorFunc,
    48  ) (iface.BeaconState, error) {
    49  	var err error
    50  	for idx, slashing := range slashings {
    51  		if slashing == nil {
    52  			return nil, errors.New("nil proposer slashings in block body")
    53  		}
    54  		if err = VerifyProposerSlashing(beaconState, slashing); err != nil {
    55  			return nil, errors.Wrapf(err, "could not verify proposer slashing %d", idx)
    56  		}
    57  		beaconState, err = slashFunc(beaconState, slashing.Header_1.Header.ProposerIndex)
    58  		if err != nil {
    59  			return nil, errors.Wrapf(err, "could not slash proposer index %d", slashing.Header_1.Header.ProposerIndex)
    60  		}
    61  	}
    62  	return beaconState, nil
    63  }
    64  
    65  // VerifyProposerSlashing verifies that the data provided from slashing is valid.
    66  func VerifyProposerSlashing(
    67  	beaconState iface.BeaconState,
    68  	slashing *ethpb.ProposerSlashing,
    69  ) error {
    70  	if slashing.Header_1 == nil || slashing.Header_1.Header == nil || slashing.Header_2 == nil || slashing.Header_2.Header == nil {
    71  		return errors.New("nil header cannot be verified")
    72  	}
    73  	hSlot := slashing.Header_1.Header.Slot
    74  	if hSlot != slashing.Header_2.Header.Slot {
    75  		return fmt.Errorf("mismatched header slots, received %d == %d", slashing.Header_1.Header.Slot, slashing.Header_2.Header.Slot)
    76  	}
    77  	pIdx := slashing.Header_1.Header.ProposerIndex
    78  	if pIdx != slashing.Header_2.Header.ProposerIndex {
    79  		return fmt.Errorf("mismatched indices, received %d == %d", slashing.Header_1.Header.ProposerIndex, slashing.Header_2.Header.ProposerIndex)
    80  	}
    81  	if proto.Equal(slashing.Header_1.Header, slashing.Header_2.Header) {
    82  		return errors.New("expected slashing headers to differ")
    83  	}
    84  	proposer, err := beaconState.ValidatorAtIndexReadOnly(slashing.Header_1.Header.ProposerIndex)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	if !helpers.IsSlashableValidatorUsingTrie(proposer, helpers.CurrentEpoch(beaconState)) {
    89  		return fmt.Errorf("validator with key %#x is not slashable", proposer.PublicKey())
    90  	}
    91  	headers := []*ethpb.SignedBeaconBlockHeader{slashing.Header_1, slashing.Header_2}
    92  	for _, header := range headers {
    93  		if err := helpers.ComputeDomainVerifySigningRoot(beaconState, pIdx, helpers.SlotToEpoch(hSlot),
    94  			header.Header, params.BeaconConfig().DomainBeaconProposer, header.Signature); err != nil {
    95  			return errors.Wrap(err, "could not verify beacon block header")
    96  		}
    97  	}
    98  	return nil
    99  }