prysm-pulse/beacon-chain/slasher/detect_blocks_test.go
kasey 918129cf36
Replace statefeed Initialize (#12285)
* refactor initialization to blocking startup method

* require genesisSetter in blockchain, fix tests

* work-around gazelle weirdness

* fix dep gazelle ignores

* only call SetGenesis once

* fix typo

* validator test setup and fix to return right error

* move waitForChainStart to Start

* wire up sync Service.genesisWaiter

* fix p2p genesisWaiter plumbing

* remove extra clock type, integrate into genesis

and rename

* use time.Now when no Nower is specified

* remove unused ClockSetter

* simplify rpc context checking

* fix typo

* use clock everywhere in sync; [32]byte val root

* don't use DeepEqual to compare [32]byte and []byte

* don't use clock in init sync, not wired up yet

* use clock waiter in blockchain as well

* use cancelable contexts in tests with goroutines

* missed a reference to WithClockSetter

* Update beacon-chain/startup/genesis.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update beacon-chain/blockchain/service_test.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* more clear docs

* doc for NewClock

* move clock typedef to more logical file name

* adding documentation

* gaz

* fixes for capella

* reducing test raciness

* fix races in committee cache tests

* lint

* add tests on Duration slot math helper

* startup package test coverage

* fix bad merge

* set non-zero genesis time in tests that call Start

* happy deepsource, happy me-epsource

* replace Synced event with channel

* remove unused error

* remove accidental wip commit

* gaz!

* remove unused event constants

* remove sync statefeed subscription to fix deadlock

* remove state notifier

* fix build

---------

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
Co-authored-by: Radosław Kapka <rkapka@wp.pl>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
Co-authored-by: nisdas <nishdas93@gmail.com>
2023-05-03 04:34:01 +00:00

175 lines
5.7 KiB
Go

package slasher
import (
"context"
"testing"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing"
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
slashingsmock "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings/mock"
slashertypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/testing/util"
logTest "github.com/sirupsen/logrus/hooks/test"
)
func Test_processQueuedBlocks_DetectsDoubleProposals(t *testing.T) {
hook := logTest.NewGlobal()
slasherDB := dbtest.SetupSlasherDB(t)
beaconDB := dbtest.SetupDB(t)
ctx, cancel := context.WithCancel(context.Background())
beaconState, err := util.NewBeaconState()
require.NoError(t, err)
// Initialize validators in the state.
numVals := params.BeaconConfig().MinGenesisActiveValidatorCount
validators := make([]*ethpb.Validator, numVals)
privKeys := make([]bls.SecretKey, numVals)
for i := range validators {
privKey, err := bls.RandKey()
require.NoError(t, err)
privKeys[i] = privKey
validators[i] = &ethpb.Validator{
PublicKey: privKey.PublicKey().Marshal(),
WithdrawalCredentials: make([]byte, 32),
}
}
err = beaconState.SetValidators(validators)
require.NoError(t, err)
domain, err := signing.Domain(
beaconState.Fork(),
0,
params.BeaconConfig().DomainBeaconProposer,
beaconState.GenesisValidatorsRoot(),
)
require.NoError(t, err)
mockChain := &mock.ChainService{
State: beaconState,
}
s := &Service{
serviceCfg: &ServiceConfig{
Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{},
HeadStateFetcher: mockChain,
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
SlashingPoolInserter: &slashingsmock.PoolMock{},
ClockWaiter: startup.NewClockSynchronizer(),
},
params: DefaultParams(),
blksQueue: newBlocksQueue(),
}
parentRoot := bytesutil.ToBytes32([]byte("parent"))
err = s.serviceCfg.StateGen.SaveState(ctx, parentRoot, beaconState)
require.NoError(t, err)
currentSlotChan := make(chan primitives.Slot)
exitChan := make(chan struct{})
go func() {
s.processQueuedBlocks(ctx, currentSlotChan)
exitChan <- struct{}{}
}()
signedBlkHeaders := []*slashertypes.SignedBlockHeaderWrapper{
createProposalWrapper(t, 4, 1, []byte{1}),
createProposalWrapper(t, 4, 1, []byte{1}),
createProposalWrapper(t, 4, 1, []byte{1}),
createProposalWrapper(t, 4, 1, []byte{2}),
}
// Add valid signatures to the block headers we are testing.
for _, proposalWrapper := range signedBlkHeaders {
proposalWrapper.SignedBeaconBlockHeader.Header.ParentRoot = parentRoot[:]
headerHtr, err := proposalWrapper.SignedBeaconBlockHeader.Header.HashTreeRoot()
require.NoError(t, err)
container := &ethpb.SigningData{
ObjectRoot: headerHtr[:],
Domain: domain,
}
signingRoot, err := container.HashTreeRoot()
require.NoError(t, err)
privKey := privKeys[proposalWrapper.SignedBeaconBlockHeader.Header.ProposerIndex]
proposalWrapper.SignedBeaconBlockHeader.Signature = privKey.Sign(signingRoot[:]).Marshal()
}
s.blksQueue.extend(signedBlkHeaders)
currentSlot := primitives.Slot(4)
currentSlotChan <- currentSlot
cancel()
<-exitChan
require.LogsContain(t, hook, "Proposer slashing detected")
}
func Test_processQueuedBlocks_NotSlashable(t *testing.T) {
hook := logTest.NewGlobal()
slasherDB := dbtest.SetupSlasherDB(t)
ctx, cancel := context.WithCancel(context.Background())
beaconState, err := util.NewBeaconState()
require.NoError(t, err)
currentSlot := primitives.Slot(4)
require.NoError(t, beaconState.SetSlot(currentSlot))
mockChain := &mock.ChainService{
State: beaconState,
Slot: &currentSlot,
}
s := &Service{
serviceCfg: &ServiceConfig{
Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{},
HeadStateFetcher: mockChain,
ClockWaiter: startup.NewClockSynchronizer(),
},
params: DefaultParams(),
blksQueue: newBlocksQueue(),
}
currentSlotChan := make(chan primitives.Slot)
exitChan := make(chan struct{})
go func() {
s.processQueuedBlocks(ctx, currentSlotChan)
exitChan <- struct{}{}
}()
s.blksQueue.extend([]*slashertypes.SignedBlockHeaderWrapper{
createProposalWrapper(t, 4, 1, []byte{1}),
createProposalWrapper(t, 4, 1, []byte{1}),
})
currentSlotChan <- currentSlot
cancel()
<-exitChan
require.LogsDoNotContain(t, hook, "Proposer slashing detected")
}
func createProposalWrapper(t *testing.T, slot primitives.Slot, proposerIndex primitives.ValidatorIndex, signingRoot []byte) *slashertypes.SignedBlockHeaderWrapper {
header := &ethpb.BeaconBlockHeader{
Slot: slot,
ProposerIndex: proposerIndex,
ParentRoot: params.BeaconConfig().ZeroHash[:],
StateRoot: bytesutil.PadTo(signingRoot, 32),
BodyRoot: params.BeaconConfig().ZeroHash[:],
}
signRoot, err := header.HashTreeRoot()
require.NoError(t, err)
fakeSig := make([]byte, 96)
copy(fakeSig, "hello")
return &slashertypes.SignedBlockHeaderWrapper{
SignedBeaconBlockHeader: &ethpb.SignedBeaconBlockHeader{
Header: header,
Signature: fakeSig,
},
SigningRoot: signRoot,
}
}