Permalink
Cannot retrieve contributors at this time
101 lines (95 sloc)
3.97 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
prysm/beacon-chain/core/blocks/proposer_slashing.go
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package blocks | |
import ( | |
"context" | |
"fmt" | |
"github.com/gogo/protobuf/proto" | |
"github.com/pkg/errors" | |
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" | |
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" | |
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" | |
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" | |
"github.com/prysmaticlabs/prysm/shared/params" | |
) | |
// ProcessProposerSlashings is one of the operations performed | |
// on each processed beacon block to slash proposers based on | |
// slashing conditions if any slashable events occurred. | |
// | |
// Spec pseudocode definition: | |
// def process_proposer_slashing(state: BeaconState, proposer_slashing: ProposerSlashing) -> None: | |
// """ | |
// Process ``ProposerSlashing`` operation. | |
// """ | |
// proposer = state.validator_registry[proposer_slashing.proposer_index] | |
// # Verify slots match | |
// assert proposer_slashing.header_1.slot == proposer_slashing.header_2.slot | |
// # But the headers are different | |
// assert proposer_slashing.header_1 != proposer_slashing.header_2 | |
// # Check proposer is slashable | |
// assert is_slashable_validator(proposer, get_current_epoch(state)) | |
// # Signatures are valid | |
// for header in (proposer_slashing.header_1, proposer_slashing.header_2): | |
// domain = get_domain(state, DOMAIN_BEACON_PROPOSER, slot_to_epoch(header.slot)) | |
// assert bls_verify(proposer.pubkey, signing_root(header), header.signature, domain) | |
// | |
// slash_validator(state, proposer_slashing.proposer_index) | |
func ProcessProposerSlashings( | |
_ context.Context, | |
beaconState *stateTrie.BeaconState, | |
b *ethpb.SignedBeaconBlock, | |
) (*stateTrie.BeaconState, error) { | |
if b.Block == nil || b.Block.Body == nil { | |
return nil, errors.New("block and block body can't be nil") | |
} | |
body := b.Block.Body | |
var err error | |
for idx, slashing := range body.ProposerSlashings { | |
if slashing == nil { | |
return nil, errors.New("nil proposer slashings in block body") | |
} | |
if err = VerifyProposerSlashing(beaconState, slashing); err != nil { | |
return nil, errors.Wrapf(err, "could not verify proposer slashing %d", idx) | |
} | |
beaconState, err = v.SlashValidator( | |
beaconState, slashing.Header_1.Header.ProposerIndex, | |
) | |
if err != nil { | |
return nil, errors.Wrapf(err, "could not slash proposer index %d", slashing.Header_1.Header.ProposerIndex) | |
} | |
} | |
return beaconState, nil | |
} | |
// VerifyProposerSlashing verifies that the data provided from slashing is valid. | |
func VerifyProposerSlashing( | |
beaconState *stateTrie.BeaconState, | |
slashing *ethpb.ProposerSlashing, | |
) error { | |
if slashing.Header_1 == nil || slashing.Header_1.Header == nil || slashing.Header_2 == nil || slashing.Header_2.Header == nil { | |
return errors.New("nil header cannot be verified") | |
} | |
hSlot := slashing.Header_1.Header.Slot | |
if hSlot != slashing.Header_2.Header.Slot { | |
return fmt.Errorf("mismatched header slots, received %d == %d", slashing.Header_1.Header.Slot, slashing.Header_2.Header.Slot) | |
} | |
pIdx := slashing.Header_1.Header.ProposerIndex | |
if pIdx != slashing.Header_2.Header.ProposerIndex { | |
return fmt.Errorf("mismatched indices, received %d == %d", slashing.Header_1.Header.ProposerIndex, slashing.Header_2.Header.ProposerIndex) | |
} | |
if proto.Equal(slashing.Header_1.Header, slashing.Header_2.Header) { | |
return errors.New("expected slashing headers to differ") | |
} | |
proposer, err := beaconState.ValidatorAtIndexReadOnly(slashing.Header_1.Header.ProposerIndex) | |
if err != nil { | |
return err | |
} | |
if !helpers.IsSlashableValidatorUsingTrie(proposer, helpers.SlotToEpoch(hSlot)) { | |
return fmt.Errorf("validator with key %#x is not slashable", proposer.PublicKey()) | |
} | |
headers := []*ethpb.SignedBeaconBlockHeader{slashing.Header_1, slashing.Header_2} | |
for _, header := range headers { | |
if err := helpers.ComputeDomainVerifySigningRoot(beaconState, pIdx, helpers.SlotToEpoch(hSlot), | |
header.Header, params.BeaconConfig().DomainBeaconProposer, header.Signature); err != nil { | |
return errors.Wrap(err, "could not verify beacon block header") | |
} | |
} | |
return nil | |
} |