2021-09-28 19:33:45 +00:00
|
|
|
package slasher
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
2022-08-16 12:20:13 +00:00
|
|
|
slashertypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/slasher/types"
|
2023-01-26 14:40:12 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
2022-08-16 12:20:13 +00:00
|
|
|
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
2021-09-28 19:33:45 +00:00
|
|
|
"go.opencensus.io/trace"
|
|
|
|
)
|
|
|
|
|
|
|
|
// detectProposerSlashings takes in signed block header wrappers and returns a list of proposer slashings detected.
|
|
|
|
func (s *Service) detectProposerSlashings(
|
|
|
|
ctx context.Context,
|
|
|
|
proposedBlocks []*slashertypes.SignedBlockHeaderWrapper,
|
|
|
|
) ([]*ethpb.ProposerSlashing, error) {
|
|
|
|
ctx, span := trace.StartSpan(ctx, "slasher.detectProposerSlashings")
|
|
|
|
defer span.End()
|
|
|
|
// We check if there are any slashable double proposals in the input list
|
|
|
|
// of proposals with respect to each other.
|
|
|
|
slashings := make([]*ethpb.ProposerSlashing, 0)
|
|
|
|
existingProposals := make(map[string]*slashertypes.SignedBlockHeaderWrapper)
|
|
|
|
for i, proposal := range proposedBlocks {
|
|
|
|
key := proposalKey(proposal)
|
|
|
|
existingProposal, ok := existingProposals[key]
|
|
|
|
if !ok {
|
|
|
|
existingProposals[key] = proposal
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if isDoubleProposal(proposedBlocks[i].SigningRoot, existingProposal.SigningRoot) {
|
|
|
|
doubleProposalsTotal.Inc()
|
|
|
|
slashing := ðpb.ProposerSlashing{
|
|
|
|
Header_1: existingProposal.SignedBeaconBlockHeader,
|
|
|
|
Header_2: proposedBlocks[i].SignedBeaconBlockHeader,
|
|
|
|
}
|
|
|
|
slashings = append(slashings, slashing)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
proposerSlashings, err := s.serviceCfg.Database.CheckDoubleBlockProposals(ctx, proposedBlocks)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "could not check for double proposals on disk")
|
|
|
|
}
|
|
|
|
if err := s.saveSafeProposals(ctx, proposedBlocks, proposerSlashings); err != nil {
|
|
|
|
return nil, errors.Wrap(err, "could not save safe proposals")
|
|
|
|
}
|
|
|
|
slashings = append(slashings, proposerSlashings...)
|
|
|
|
return slashings, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for double proposals in our database given a list of incoming block proposals.
|
|
|
|
// For the proposals that were not slashable, we save them to the database.
|
|
|
|
func (s *Service) saveSafeProposals(
|
|
|
|
ctx context.Context,
|
|
|
|
proposedBlocks []*slashertypes.SignedBlockHeaderWrapper,
|
|
|
|
proposerSlashings []*ethpb.ProposerSlashing,
|
|
|
|
) error {
|
|
|
|
ctx, span := trace.StartSpan(ctx, "slasher.saveSafeProposals")
|
|
|
|
defer span.End()
|
|
|
|
return s.serviceCfg.Database.SaveBlockProposals(
|
|
|
|
ctx,
|
|
|
|
filterSafeProposals(proposedBlocks, proposerSlashings),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func filterSafeProposals(
|
|
|
|
proposedBlocks []*slashertypes.SignedBlockHeaderWrapper,
|
|
|
|
proposerSlashings []*ethpb.ProposerSlashing,
|
|
|
|
) []*slashertypes.SignedBlockHeaderWrapper {
|
|
|
|
// We initialize a map of proposers that are safe from slashing.
|
2023-01-26 14:40:12 +00:00
|
|
|
safeProposers := make(map[primitives.ValidatorIndex]*slashertypes.SignedBlockHeaderWrapper, len(proposedBlocks))
|
2021-09-28 19:33:45 +00:00
|
|
|
for _, proposal := range proposedBlocks {
|
|
|
|
safeProposers[proposal.SignedBeaconBlockHeader.Header.ProposerIndex] = proposal
|
|
|
|
}
|
|
|
|
for _, doubleProposal := range proposerSlashings {
|
|
|
|
// If a proposer is found to have committed a slashable offense, we delete
|
|
|
|
// them from the safe proposers map.
|
|
|
|
delete(safeProposers, doubleProposal.Header_1.Header.ProposerIndex)
|
|
|
|
}
|
|
|
|
// We save all the proposals that are determined "safe" and not-slashable to our database.
|
|
|
|
safeProposals := make([]*slashertypes.SignedBlockHeaderWrapper, 0, len(safeProposers))
|
|
|
|
for _, proposal := range safeProposers {
|
|
|
|
safeProposals = append(safeProposals, proposal)
|
|
|
|
}
|
|
|
|
return safeProposals
|
|
|
|
}
|
|
|
|
|
|
|
|
func proposalKey(proposal *slashertypes.SignedBlockHeaderWrapper) string {
|
|
|
|
header := proposal.SignedBeaconBlockHeader.Header
|
|
|
|
return uintToString(uint64(header.Slot)) + ":" + uintToString(uint64(header.ProposerIndex))
|
|
|
|
}
|