Skip to content

Commit

Permalink
EIP-7549: slasher
Browse files Browse the repository at this point in the history
  • Loading branch information
rkapka committed Jan 3, 2025
1 parent afeb05c commit 7325d9f
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 56 deletions.
1 change: 1 addition & 0 deletions beacon-chain/slasher/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ go_library(
"//encoding/bytesutil:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
Expand Down
97 changes: 97 additions & 0 deletions beacon-chain/slasher/chunks.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
slashertypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/slasher/types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -232,6 +233,54 @@ func (m *MinSpanChunksSlice) CheckSlashable(

surroundingVotesTotal.Inc()

// Both attestations should have the same type
if existingAttWrapper.IndexedAttestation.Version() >= version.Electra && incomingAttWrapper.IndexedAttestation.Version() < version.Electra {
incomingAttWrapper = &slashertypes.IndexedAttestationWrapper{
IndexedAttestation: &ethpb.IndexedAttestationElectra{
AttestingIndices: incomingAttWrapper.IndexedAttestation.GetAttestingIndices(),
Data: incomingAttWrapper.IndexedAttestation.GetData(),
Signature: incomingAttWrapper.IndexedAttestation.GetSignature(),
},
DataRoot: incomingAttWrapper.DataRoot,
}
}
if incomingAttWrapper.IndexedAttestation.Version() >= version.Electra && existingAttWrapper.IndexedAttestation.Version() < version.Electra {
existingAttWrapper = &slashertypes.IndexedAttestationWrapper{
IndexedAttestation: &ethpb.IndexedAttestationElectra{
AttestingIndices: existingAttWrapper.IndexedAttestation.GetAttestingIndices(),
Data: existingAttWrapper.IndexedAttestation.GetData(),
Signature: existingAttWrapper.IndexedAttestation.GetSignature(),
},
DataRoot: existingAttWrapper.DataRoot,
}
}

postElectra := incomingAttWrapper.IndexedAttestation.Version() >= version.Electra
if postElectra {
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf("wrong existing attestation type (expected %T, got %T)", &ethpb.IndexedAttestationElectra{}, existing)
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf("wrong incoming attestation type (expected %T, got %T)", &ethpb.IndexedAttestationElectra{}, incoming)
}
slashing := &ethpb.AttesterSlashingElectra{
Attestation_1: existing,
Attestation_2: incoming,
}

// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: incoming,
Attestation_2: existing,
}
}

return slashing, nil
}

existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
Expand Down Expand Up @@ -328,6 +377,54 @@ func (m *MaxSpanChunksSlice) CheckSlashable(

surroundedVotesTotal.Inc()

// Both attestations should have the same type
if existingAttWrapper.IndexedAttestation.Version() >= version.Electra && incomingAttWrapper.IndexedAttestation.Version() < version.Electra {
incomingAttWrapper = &slashertypes.IndexedAttestationWrapper{
IndexedAttestation: &ethpb.IndexedAttestationElectra{
AttestingIndices: incomingAttWrapper.IndexedAttestation.GetAttestingIndices(),
Data: incomingAttWrapper.IndexedAttestation.GetData(),
Signature: incomingAttWrapper.IndexedAttestation.GetSignature(),
},
DataRoot: incomingAttWrapper.DataRoot,
}
}
if incomingAttWrapper.IndexedAttestation.Version() >= version.Electra && existingAttWrapper.IndexedAttestation.Version() < version.Electra {
existingAttWrapper = &slashertypes.IndexedAttestationWrapper{
IndexedAttestation: &ethpb.IndexedAttestationElectra{
AttestingIndices: existingAttWrapper.IndexedAttestation.GetAttestingIndices(),
Data: existingAttWrapper.IndexedAttestation.GetData(),
Signature: existingAttWrapper.IndexedAttestation.GetSignature(),
},
DataRoot: existingAttWrapper.DataRoot,
}
}

postElectra := incomingAttWrapper.IndexedAttestation.Version() >= version.Electra
if postElectra {
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf("wrong existing attestation type (expected %T, got %T)", &ethpb.IndexedAttestationElectra{}, existing)
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf("wrong incoming attestation type (expected %T, got %T)", &ethpb.IndexedAttestationElectra{}, incoming)
}
slashing := &ethpb.AttesterSlashingElectra{
Attestation_1: existing,
Attestation_2: incoming,
}

// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: incoming,
Attestation_2: existing,
}
}

return slashing, nil
}

existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
Expand Down
183 changes: 139 additions & 44 deletions beacon-chain/slasher/detect_attestations.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"golang.org/x/exp/maps"
)

Expand Down Expand Up @@ -193,33 +194,80 @@ func (s *Service) checkDoubleVotes(
// This is a double vote.
doubleVotesTotal.Inc()

existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"existing attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
existingAttWrapper.IndexedAttestation,
)
var slashing ethpb.AttSlashing

// Both attestations should have the same type
if existingAttWrapper.IndexedAttestation.Version() >= version.Electra && incomingAttWrapper.IndexedAttestation.Version() < version.Electra {
incomingAttWrapper = &slashertypes.IndexedAttestationWrapper{
IndexedAttestation: &ethpb.IndexedAttestationElectra{
AttestingIndices: incomingAttWrapper.IndexedAttestation.GetAttestingIndices(),
Data: incomingAttWrapper.IndexedAttestation.GetData(),
Signature: incomingAttWrapper.IndexedAttestation.GetSignature(),
},
DataRoot: incomingAttWrapper.DataRoot,
}
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"incoming attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
incomingAttWrapper.IndexedAttestation,
)
if incomingAttWrapper.IndexedAttestation.Version() >= version.Electra && existingAttWrapper.IndexedAttestation.Version() < version.Electra {
existingAttWrapper = &slashertypes.IndexedAttestationWrapper{
IndexedAttestation: &ethpb.IndexedAttestationElectra{
AttestingIndices: existingAttWrapper.IndexedAttestation.GetAttestingIndices(),
Data: existingAttWrapper.IndexedAttestation.GetData(),
Signature: existingAttWrapper.IndexedAttestation.GetSignature(),
},
DataRoot: existingAttWrapper.DataRoot,
}
}

slashing := &ethpb.AttesterSlashing{
Attestation_1: existing,
Attestation_2: incoming,
}
postElectra := incomingAttWrapper.IndexedAttestation.Version() >= version.Electra
if postElectra {
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf("wrong existing attestation type (expected %T, got %T)", &ethpb.IndexedAttestationElectra{}, existing)
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf("wrong incoming attestation type (expected %T, got %T)", &ethpb.IndexedAttestationElectra{}, incoming)
}
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: existing,
Attestation_2: incoming,
}

// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: incoming,
Attestation_2: existing,
}
}
} else {
existing, ok := existingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"existing attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
existingAttWrapper.IndexedAttestation,
)
}
incoming, ok := incomingAttWrapper.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"incoming attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
incomingAttWrapper.IndexedAttestation,
)
}
slashing = &ethpb.AttesterSlashing{
Attestation_1: incoming,
Attestation_2: existing,
Attestation_1: existing,
Attestation_2: incoming,
}

// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(existingAttWrapper.DataRoot[:], incomingAttWrapper.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashing{
Attestation_1: incoming,
Attestation_2: existing,
}
}
}

Expand All @@ -245,33 +293,80 @@ func (s *Service) checkDoubleVotes(
wrapper_1 := doubleVote.Wrapper_1
wrapper_2 := doubleVote.Wrapper_2

att_1, ok := wrapper_1.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"first attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
wrapper_1.IndexedAttestation,
)
var slashing ethpb.AttSlashing

// Both attestations should have the same type
if wrapper_1.IndexedAttestation.Version() >= version.Electra && wrapper_2.IndexedAttestation.Version() < version.Electra {
wrapper_2 = &slashertypes.IndexedAttestationWrapper{
IndexedAttestation: &ethpb.IndexedAttestationElectra{
AttestingIndices: wrapper_2.IndexedAttestation.GetAttestingIndices(),
Data: wrapper_2.IndexedAttestation.GetData(),
Signature: wrapper_2.IndexedAttestation.GetSignature(),
},
DataRoot: wrapper_2.DataRoot,
}
}
att_2, ok := wrapper_2.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"second attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
wrapper_2.IndexedAttestation,
)
if wrapper_2.IndexedAttestation.Version() >= version.Electra && wrapper_1.IndexedAttestation.Version() < version.Electra {
wrapper_1 = &slashertypes.IndexedAttestationWrapper{
IndexedAttestation: &ethpb.IndexedAttestationElectra{
AttestingIndices: wrapper_1.IndexedAttestation.GetAttestingIndices(),
Data: wrapper_1.IndexedAttestation.GetData(),
Signature: wrapper_1.IndexedAttestation.GetSignature(),
},
DataRoot: wrapper_1.DataRoot,
}
}

slashing := &ethpb.AttesterSlashing{
Attestation_1: att_1,
Attestation_2: att_2,
}
postElectra := wrapper_2.IndexedAttestation.Version() >= version.Electra
if postElectra {
existing, ok := wrapper_1.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf("wrong existing attestation type (expected %T, got %T)", &ethpb.IndexedAttestationElectra{}, existing)
}
incoming, ok := wrapper_2.IndexedAttestation.(*ethpb.IndexedAttestationElectra)
if !ok {
return nil, fmt.Errorf("wrong incoming attestation type (expected %T, got %T)", &ethpb.IndexedAttestationElectra{}, incoming)
}
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: existing,
Attestation_2: incoming,
}

// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(wrapper_1.DataRoot[:], wrapper_2.DataRoot[:]) > 0 {
// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(wrapper_1.DataRoot[:], wrapper_2.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashingElectra{
Attestation_1: incoming,
Attestation_2: existing,
}
}
} else {
att_1, ok := wrapper_1.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"first attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
wrapper_1.IndexedAttestation,
)
}
att_2, ok := wrapper_2.IndexedAttestation.(*ethpb.IndexedAttestation)
if !ok {
return nil, fmt.Errorf(
"second attestation has wrong type (expected %T, got %T)",
&ethpb.IndexedAttestation{},
wrapper_2.IndexedAttestation,
)
}
slashing = &ethpb.AttesterSlashing{
Attestation_1: att_2,
Attestation_2: att_1,
Attestation_1: att_1,
Attestation_2: att_2,
}

// Ensure the attestation with the lower data root is the first attestation.
if bytes.Compare(wrapper_1.DataRoot[:], wrapper_2.DataRoot[:]) > 0 {
slashing = &ethpb.AttesterSlashing{
Attestation_1: att_2,
Attestation_2: att_1,
}
}
}

Expand Down
20 changes: 8 additions & 12 deletions validator/client/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,18 +139,14 @@ func (v *validator) SubmitAttestation(ctx context.Context, slot primitives.Slot,
return
}

// TODO: Extend to Electra
phase0Att, ok := indexedAtt.(*ethpb.IndexedAttestation)
if ok {
// Send the attestation to the beacon node.
if err := v.db.SlashableAttestationCheck(ctx, phase0Att, pubKey, signingRoot, v.emitAccountMetrics, ValidatorAttestFailVec); err != nil {
log.WithError(err).Error("Failed attestation slashing protection check")
log.WithFields(
attestationLogFields(pubKey, indexedAtt),
).Debug("Attempted slashable attestation details")
tracing.AnnotateError(span, err)
return
}
// Send the attestation to the beacon node.
if err := v.db.SlashableAttestationCheck(ctx, indexedAtt, pubKey, signingRoot, v.emitAccountMetrics, ValidatorAttestFailVec); err != nil {
log.WithError(err).Error("Failed attestation slashing protection check")
log.WithFields(
attestationLogFields(pubKey, indexedAtt),
).Debug("Attempted slashable attestation details")
tracing.AnnotateError(span, err)
return
}

aggregationBitfield := bitfield.NewBitlist(uint64(len(duty.Committee)))
Expand Down

0 comments on commit 7325d9f

Please sign in to comment.