prysm-pulse/beacon-chain/core/blocks/proposer_slashing.go
Preston Van Loon 7cc32c4dda
Various code inspection resolutions (#7438)
* remove unused code

* remove defer use in loop

* Remove unused methods and constants

* gofmt and gaz

* nilness check

* remove unused args

* Add TODO for refactoring subscribeWithBase to remove unused arg. It seems too involved to include in this sweeping PR. https://github.com/prysmaticlabs/prysm/issues/7437

* replace empty slice declaration

* Remove unnecessary type conversions

* remove redundant type declaration

* rename receivers to be consistent

* Remove bootnode query tool. It is now obsolete by discv5

* Remove relay node. It is no longer used or supported

* Revert "Remove relay node. It is no longer used or supported"

This reverts commit 4bd7717334dad85ef4766ed9bc4da711fb5fa810.

* Delete unused test directory

* Delete unsupported gcp startup script

* Delete old k8s script

* build fixes

* fix build

* go mod tidy

* revert slasher/db/kv/block_header.go

* fix build

* remove redundant nil check

* combine func args

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
Co-authored-by: Victor Farazdagi <simple.square@gmail.com>
2020-10-12 08:11:05 +00:00

102 lines
4.0 KiB
Go

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
}