-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check for Signing Root Mismatch When Submitting Proposals and Importing Proposals in Slashing Interchange #8085
Changes from all commits
558edab
7fdeb78
ae8f83b
67eaa89
b46d746
6e5e900
210d362
0df245d
e44c708
ee3273d
8cd31eb
d797154
1449a0a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,13 +80,6 @@ func (v *validator) ProposeBlock(ctx context.Context, slot uint64, pubKey [48]by | |
return | ||
} | ||
|
||
if err := v.preBlockSignValidations(ctx, pubKey, b); err != nil { | ||
log.WithFields( | ||
blockLogFields(pubKey, b, nil), | ||
).WithError(err).Error("Failed block slashing protection check") | ||
return | ||
} | ||
|
||
// Sign returned block from beacon node | ||
sig, domain, err := v.signBlock(ctx, pubKey, epoch, b) | ||
if err != nil { | ||
|
@@ -101,7 +94,23 @@ func (v *validator) ProposeBlock(ctx context.Context, slot uint64, pubKey [48]by | |
Signature: sig, | ||
} | ||
|
||
if err := v.postBlockSignUpdate(ctx, pubKey, blk, domain); err != nil { | ||
signingRoot, err := helpers.ComputeSigningRoot(b, domain.SignatureDomain) | ||
if err != nil { | ||
if v.emitAccountMetrics { | ||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc() | ||
} | ||
log.WithError(err).Error("Failed to compute signing root for block") | ||
return | ||
} | ||
|
||
if err := v.preBlockSignValidations(ctx, pubKey, b, signingRoot); err != nil { | ||
log.WithFields( | ||
blockLogFields(pubKey, b, nil), | ||
).WithError(err).Error("Failed block slashing protection check") | ||
return | ||
} | ||
|
||
if err := v.postBlockSignUpdate(ctx, pubKey, blk, signingRoot); err != nil { | ||
Comment on lines
+106
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe something for another PR, but these should just be merged into 1 method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, but out of scope. Will open an issue |
||
log.WithFields( | ||
blockLogFields(pubKey, b, sig), | ||
).WithError(err).Error("Failed block slashing protection check") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,50 +6,58 @@ import ( | |
|
||
"github.com/pkg/errors" | ||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" | ||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" | ||
"github.com/prysmaticlabs/prysm/shared/blockutil" | ||
"github.com/prysmaticlabs/prysm/shared/featureconfig" | ||
"github.com/prysmaticlabs/prysm/shared/params" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
var failedPreBlockSignLocalErr = "attempted to sign a double proposal, block rejected by local protection" | ||
var failedPreBlockSignExternalErr = "attempted a double proposal, block rejected by remote slashing protection" | ||
var failedPostBlockSignErr = "made a double proposal, considered slashable by remote slashing protection" | ||
|
||
func (v *validator) preBlockSignValidations(ctx context.Context, pubKey [48]byte, block *ethpb.BeaconBlock) error { | ||
func (v *validator) preBlockSignValidations( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, maybe for another PR. Would like some documentation on what this method does here. |
||
ctx context.Context, pubKey [48]byte, block *ethpb.BeaconBlock, signingRoot [32]byte, | ||
) error { | ||
fmtKey := fmt.Sprintf("%#x", pubKey[:]) | ||
|
||
// Based on EIP3076, validator should refuse to sign any proposal with slot less | ||
// than or equal to the minimum signed proposal present in the DB for that public key. | ||
lowestSignedProposalSlot, exists, err := v.db.LowestSignedProposal(ctx, pubKey) | ||
if err != nil { | ||
return err | ||
} | ||
if exists && lowestSignedProposalSlot >= block.Slot { | ||
return fmt.Errorf( | ||
"could not sign block with slot <= lowest signed slot in db, lowest signed slot: %d >= block slot: %d", | ||
lowestSignedProposalSlot, | ||
block.Slot, | ||
) | ||
} | ||
|
||
_, exists, err = v.db.ProposalHistoryForSlot(ctx, pubKey, block.Slot) | ||
prevSigningRoot, proposalAtSlotExists, err := v.db.ProposalHistoryForSlot(ctx, pubKey, block.Slot) | ||
if err != nil { | ||
if v.emitAccountMetrics { | ||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc() | ||
} | ||
return errors.Wrap(err, "failed to get proposal history") | ||
} | ||
// If a proposal exists in our history for the slot, we assume it is slashable. | ||
// TODO(#7848): Add a more sophisticated strategy where if we indeed have the signing root, | ||
// only blocks that have a conflicting signing root with a historical proposal are slashable. | ||
if exists { | ||
|
||
lowestSignedProposalSlot, lowestProposalExists, err := v.db.LowestSignedProposal(ctx, pubKey) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// If a proposal exists in our history for the slot, we check the following: | ||
// If the signing root is empty (zero hash), then we consider it slashable. If signing root is not empty, | ||
// we check if it is different than the incoming block's signing root. If that is the case, | ||
// we consider that proposal slashable. | ||
signingRootIsDifferent := prevSigningRoot == params.BeaconConfig().ZeroHash || prevSigningRoot != signingRoot | ||
if proposalAtSlotExists && signingRootIsDifferent { | ||
if v.emitAccountMetrics { | ||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc() | ||
} | ||
return errors.New(failedPreBlockSignLocalErr) | ||
} | ||
|
||
// Based on EIP3076, validator should refuse to sign any proposal with slot less | ||
// than or equal to the minimum signed proposal present in the DB for that public key. | ||
// In the case the slot of the incoming block is equal to the minimum signed proposal, we | ||
// then also check the signing root is different. | ||
if lowestProposalExists && signingRootIsDifferent && lowestSignedProposalSlot >= block.Slot { | ||
return fmt.Errorf( | ||
"could not sign block with slot <= lowest signed slot in db, lowest signed slot: %d >= block slot: %d", | ||
lowestSignedProposalSlot, | ||
block.Slot, | ||
) | ||
} | ||
|
||
if featureconfig.Get().SlasherProtection && v.protector != nil { | ||
blockHdr, err := blockutil.BeaconBlockHeaderFromBlock(block) | ||
if err != nil { | ||
|
@@ -66,7 +74,12 @@ func (v *validator) preBlockSignValidations(ctx context.Context, pubKey [48]byte | |
return nil | ||
} | ||
|
||
func (v *validator) postBlockSignUpdate(ctx context.Context, pubKey [48]byte, block *ethpb.SignedBeaconBlock, domain *ethpb.DomainResponse) error { | ||
func (v *validator) postBlockSignUpdate( | ||
ctx context.Context, | ||
pubKey [48]byte, | ||
block *ethpb.SignedBeaconBlock, | ||
signingRoot [32]byte, | ||
) error { | ||
fmtKey := fmt.Sprintf("%#x", pubKey[:]) | ||
if featureconfig.Get().SlasherProtection && v.protector != nil { | ||
sbh, err := blockutil.SignedBeaconBlockHeaderFromBlock(block) | ||
|
@@ -84,13 +97,6 @@ func (v *validator) postBlockSignUpdate(ctx context.Context, pubKey [48]byte, bl | |
return fmt.Errorf(failedPostBlockSignErr) | ||
} | ||
} | ||
signingRoot, err := helpers.ComputeSigningRoot(block.Block, domain.SignatureDomain) | ||
if err != nil { | ||
if v.emitAccountMetrics { | ||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc() | ||
} | ||
return errors.Wrap(err, "failed to compute signing root for block") | ||
} | ||
if err := v.db.SaveProposalHistoryForSlot(ctx, pubKey, block.Block.Slot, signingRoot[:]); err != nil { | ||
if v.emitAccountMetrics { | ||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deep source was complaining of unused code