mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-20 16:41:11 +00:00
7a294e861e
* Slasher: Ensure all gorouting are stopped before running `Stop` actions. Fixes #13550. In tests, `exitChan` are now useless since waitgroup are used to wait for all goroutines to be stopped. * `slasher.go`: Add comments and rename some variables. - NFC * `detect_blocks.go`: Improve. - NFC - Rename some variables. - Add comments. - Use second element of `range` when possible. * `chunks.go`: Remove `_`receivers. - NFC * `validateAttestationIntegrity`: Improve documentation. - NFC * `filterAttestations`: Avoid `else`and rename variable. - NFC * `slasher.go`: Fix and add comments. * `SaveAttestationRecordsForValidators`: Remove unused code. * `LastEpochWrittenForValidators`: Name variables consistently. - NFC Avoid mixes between `indice(s)`and `index(es)`. * `SaveLastEpochsWrittenForValidators`: Name variables consistently. - NFC * `CheckAttesterDoubleVotes`: Rename variables and add comments. - NFC * `schema.go`: Add comments. - NFC * `processQueuedAttestations`: Add comments. - NFC * `checkDoubleVotes`: Rename variable. - NFC * `Test_processQueuedAttestations`: Ensure there is no error log. * `shouldNotBeSlashable` => `shouldBeSlashable` * `Test_processQueuedAttestations`: Add 2 test cases: - Same target with different signing roots - Same target with same signing roots * `checkDoubleVotesOnDisk` ==> `checkDoubleVotes`. Before this commit, `checkDoubleVotes` did two tasks: - Checking if there are any slashable double votes in the input list of attestations with respect to each other. - Checking if there are any slashable double votes in the input list of attestations with respect to our database. However, `checkDoubleVotes` is called only in `checkSlashableAttestations`. And `checkSlashableAttestations` is called only in: - `processQueuedAttestations`, and in - `IsSlashableAttestation` Study of case `processQueuedAttestations`: --------------------------------------------- In `processQueuedAttestations`, `checkSlashableAttestations` is ALWAYS called after `Database.SaveAttestationRecordsForValidators`. It means that, when calling `checkSlashableAttestations`, `validAtts` are ALREADY stored in the DB. Each attestation of `validAtts` will be checked twice: - Against the other attestations of `validAtts` (the portion of deleted code) - Against the content of the database. One of those two checks is redundent. ==> We can remove the check against other attestations in `validAtts`. Study of case `Database.SaveAttestationRecordsForValidators`: ---------------------------------------------------------------- In `Database.SaveAttestationRecordsForValidators`, `checkSlashableAttestations` is ALWAYS called with a list of attestations containing only ONE attestation. This only attestaion will be checked twice: - Against itself, and an attestation cannot conflict with itself. - Against the content of the database. ==> We can remove the check against other attestations in `validAtts`. ========================= In both cases, we showed that we can remove the check of attestation against the content of `validAtts`, and the corresponding test `Test_checkDoubleVotes_SlashableInputAttestations`. * `Test_processQueuedBlocks_DetectsDoubleProposals`: Wrap proposals. So we can add new proposals later. * Fix slasher multiple proposals false negative. If a first batch of blocks is sent with: - validator 1 - slot 4 - signing root 1 - validator 1 - slot 5 - signing root 1 Then, if a second batch of blocks is sent with: - validator 1 - slot 4 - signing root 2 Because we have two blocks proposed by the same validator (1) and for the same slot (4), but with two different signing roots (1 and 2), the validator 1 should be slashed. This is not the case before this commit. A new test case has been added as well to check this. Fixes #13551 * `params.go`: Change comments. - NFC * `CheckSlashable`: Keep the happy path without indentation. * `detectAllAttesterSlashings` => `checkSurrounds`. * Update beacon-chain/db/slasherkv/slasher.go Co-authored-by: Sammy Rosso <15244892+saolyn@users.noreply.github.com> * Update beacon-chain/db/slasherkv/slasher.go Co-authored-by: Sammy Rosso <15244892+saolyn@users.noreply.github.com> * `CheckAttesterDoubleVotes`: Keep happy path without indentation. Well, even if, in our case, "happy path" mean slashing. * 'SaveAttestationRecordsForValidators': Save the first attestation. In case of multiple votes, arbitrarily save the first attestation. Saving the first one in particular has no functional impact, since in any case all attestations will be tested against the content of the database. So all but the first one will be detected as slashable. However, saving the first one and not an other one let us not to modify the end to end tests, since they expect the first one to be saved in the database. * Rename `min` => `minimum`. Not to conflict with the new `min` built-in function. * `couldNotSaveSlashableAtt` ==> `couldNotCheckSlashableAtt` --------- Co-authored-by: Sammy Rosso <15244892+saolyn@users.noreply.github.com>
82 lines
3.1 KiB
Go
82 lines
3.1 KiB
Go
package slasher
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/pkg/errors"
|
|
slashertypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/types"
|
|
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
|
"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,
|
|
incomingProposals []*slashertypes.SignedBlockHeaderWrapper,
|
|
) ([]*ethpb.ProposerSlashing, error) {
|
|
ctx, span := trace.StartSpan(ctx, "slasher.detectProposerSlashings")
|
|
defer span.End()
|
|
|
|
// internalSlashings will contain any slashable double proposals in the input list
|
|
// of proposals with respect to each other.
|
|
internalSlashings := []*ethpb.ProposerSlashing{}
|
|
|
|
existingProposals := make(map[string]*slashertypes.SignedBlockHeaderWrapper)
|
|
|
|
// We check if there are any slashable double proposals in the input list
|
|
// of proposals with respect to each other.
|
|
for _, incomingProposal := range incomingProposals {
|
|
key := proposalKey(incomingProposal)
|
|
existingProposal, ok := existingProposals[key]
|
|
|
|
// If we have not seen this proposal before, we add it to our map of existing proposals
|
|
// and we continue to the next proposal.
|
|
if !ok {
|
|
existingProposals[key] = incomingProposal
|
|
continue
|
|
}
|
|
|
|
// If we have seen this proposal before, we check if it is a double proposal.
|
|
if isDoubleProposal(incomingProposal.SigningRoot, existingProposal.SigningRoot) {
|
|
doubleProposalsTotal.Inc()
|
|
|
|
slashing := ðpb.ProposerSlashing{
|
|
Header_1: existingProposal.SignedBeaconBlockHeader,
|
|
Header_2: incomingProposal.SignedBeaconBlockHeader,
|
|
}
|
|
|
|
internalSlashings = append(internalSlashings, slashing)
|
|
}
|
|
}
|
|
|
|
// We check if there are any slashable double proposals in the input list
|
|
// of proposals with respect to the slasher database.
|
|
databaseSlashings, err := s.serviceCfg.Database.CheckDoubleBlockProposals(ctx, incomingProposals)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not check for double proposals on disk")
|
|
}
|
|
|
|
// We save the safe proposals (with respect to the database) to our database.
|
|
// If some proposals in incomingProposals are slashable with respect to each other,
|
|
// we (arbitrarily) save the last one to the database.
|
|
if err := s.serviceCfg.Database.SaveBlockProposals(ctx, incomingProposals); err != nil {
|
|
return nil, errors.Wrap(err, "could not save safe proposals")
|
|
}
|
|
|
|
// totalSlashings contain all slashings we have detected.
|
|
totalSlashings := append(internalSlashings, databaseSlashings...)
|
|
return totalSlashings, nil
|
|
}
|
|
|
|
// proposalKey build a key which is a combination of the slot and the proposer index.
|
|
// If a validator proposes several blocks for the same slot, then several (potentially slashable)
|
|
// proposals will correspond to the same key.
|
|
func proposalKey(proposal *slashertypes.SignedBlockHeaderWrapper) string {
|
|
header := proposal.SignedBeaconBlockHeader.Header
|
|
|
|
slotKey := uintToString(uint64(header.Slot))
|
|
proposerIndexKey := uintToString(uint64(header.ProposerIndex))
|
|
|
|
return slotKey + ":" + proposerIndexKey
|
|
}
|