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>
This commit is contained in:
kasey
2023-05-02 23:34:01 -05:00
committed by GitHub
parent 5b8084b829
commit 918129cf36
119 changed files with 2207 additions and 2416 deletions

View File

@@ -58,6 +58,7 @@ go_library(
"//beacon-chain/operations/slashings:go_default_library", "//beacon-chain/operations/slashings:go_default_library",
"//beacon-chain/operations/voluntaryexits:go_default_library", "//beacon-chain/operations/voluntaryexits:go_default_library",
"//beacon-chain/p2p:go_default_library", "//beacon-chain/p2p:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen:go_default_library",
"//config/features:go_default_library", "//config/features:go_default_library",
@@ -119,6 +120,7 @@ go_test(
"receive_attestation_test.go", "receive_attestation_test.go",
"receive_block_test.go", "receive_block_test.go",
"service_test.go", "service_test.go",
"setup_test.go",
"weak_subjectivity_checks_test.go", "weak_subjectivity_checks_test.go",
], ],
embed = [":go_default_library"], embed = [":go_default_library"],
@@ -168,6 +170,7 @@ go_test(
"mock_test.go", "mock_test.go",
"receive_block_test.go", "receive_block_test.go",
"service_norace_test.go", "service_norace_test.go",
"setup_test.go",
], ],
embed = [":go_default_library"], embed = [":go_default_library"],
gc_goopts = [ gc_goopts = [

View File

@@ -85,6 +85,12 @@ type ForkFetcher interface {
TimeFetcher TimeFetcher
} }
// TemporalOracle is like ForkFetcher minus CurrentFork()
type TemporalOracle interface {
GenesisFetcher
TimeFetcher
}
// CanonicalFetcher retrieves the current chain's canonical information. // CanonicalFetcher retrieves the current chain's canonical information.
type CanonicalFetcher interface { type CanonicalFetcher interface {
IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error) IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error)
@@ -327,7 +333,7 @@ func (s *Service) HeadValidatorIndexToPublicKey(_ context.Context, index primiti
} }
// IsOptimistic returns true if the current head is optimistic. // IsOptimistic returns true if the current head is optimistic.
func (s *Service) IsOptimistic(ctx context.Context) (bool, error) { func (s *Service) IsOptimistic(_ context.Context) (bool, error) {
if slots.ToEpoch(s.CurrentSlot()) < params.BeaconConfig().BellatrixForkEpoch { if slots.ToEpoch(s.CurrentSlot()) < params.BeaconConfig().BellatrixForkEpoch {
return false, nil return false, nil
} }

View File

@@ -10,7 +10,6 @@ import (
forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types" forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native" state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
@@ -72,16 +71,8 @@ func TestHeadRoot_Nil(t *testing.T) {
} }
func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) { func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, fcs := tr.ctx, tr.fcs
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fcs),
WithStateGen(stategen.New(beaconDB, fcs)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, _ := util.DeterministicGenesisState(t, 32) gs, _ := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs)) require.NoError(t, service.saveGenesisData(ctx, gs))
@@ -97,16 +88,8 @@ func TestFinalizedCheckpt_GenesisRootOk(t *testing.T) {
} }
func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) { func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fcs),
WithStateGen(stategen.New(beaconDB, fcs)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
jroot := [32]byte{'j'} jroot := [32]byte{'j'}
cp := &forkchoicetypes.Checkpoint{Epoch: 6, Root: jroot} cp := &forkchoicetypes.Checkpoint{Epoch: 6, Root: jroot}
@@ -120,16 +103,8 @@ func TestCurrentJustifiedCheckpt_CanRetrieve(t *testing.T) {
} }
func TestFinalizedBlockHash(t *testing.T) { func TestFinalizedBlockHash(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fcs),
WithStateGen(stategen.New(beaconDB, fcs)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
r := [32]byte{'f'} r := [32]byte{'f'}
cp := &forkchoicetypes.Checkpoint{Epoch: 6, Root: r} cp := &forkchoicetypes.Checkpoint{Epoch: 6, Root: r}
@@ -170,16 +145,9 @@ func TestHeadSlot_CanRetrieve(t *testing.T) {
} }
func TestHeadRoot_CanRetrieve(t *testing.T) { func TestHeadRoot_CanRetrieve(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fcs),
WithStateGen(stategen.New(beaconDB, fcs)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, _ := util.DeterministicGenesisState(t, 32) gs, _ := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs)) require.NoError(t, service.saveGenesisData(ctx, gs))
@@ -189,16 +157,8 @@ func TestHeadRoot_CanRetrieve(t *testing.T) {
} }
func TestHeadRoot_UseDB(t *testing.T) { func TestHeadRoot_UseDB(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB := tr.ctx, tr.db
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fcs),
WithStateGen(stategen.New(beaconDB, fcs)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.head = &head{root: params.BeaconConfig().ZeroHash} service.head = &head{root: params.BeaconConfig().ZeroHash}
b := util.NewBeaconBlock() b := util.NewBeaconBlock()

View File

@@ -9,14 +9,11 @@ import (
gethtypes "github.com/ethereum/go-ethereum/core/types" gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks"
testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/execution" "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution"
mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing" mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types" forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types"
bstate "github.com/prysmaticlabs/prysm/v4/beacon-chain/state" bstate "github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native" state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/features" "github.com/prysmaticlabs/prysm/v4/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -33,23 +30,16 @@ import (
) )
func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) { func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
beaconDB := testDB.SetupDB(t) ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair()) altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair())
altairBlkRoot, err := altairBlk.Block().HashTreeRoot() altairBlkRoot, err := altairBlk.Block().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockBellatrix()) bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockBellatrix())
bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot() bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, _ := util.DeterministicGenesisState(t, 10) st, _ := util.DeterministicGenesisState(t, 10)
service.head = &head{ service.head = &head{
state: st, state: st,
@@ -96,23 +86,15 @@ func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) {
} }
func Test_NotifyForkchoiceUpdate(t *testing.T) { func Test_NotifyForkchoiceUpdate(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
beaconDB := testDB.SetupDB(t) ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair()) altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair())
altairBlkRoot, err := altairBlk.Block().HashTreeRoot() altairBlkRoot, err := altairBlk.Block().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockBellatrix()) bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockBellatrix())
bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot() bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, _ := util.DeterministicGenesisState(t, 10) st, _ := util.DeterministicGenesisState(t, 10)
service.head = &head{ service.head = &head{
state: st, state: st,
@@ -264,8 +246,8 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
} }
func Test_NotifyForkchoiceUpdate_NIlLVH(t *testing.T) { func Test_NotifyForkchoiceUpdate_NIlLVH(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
beaconDB := testDB.SetupDB(t) ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
// Prepare blocks // Prepare blocks
ba := util.NewBeaconBlockBellatrix() ba := util.NewBeaconBlockBellatrix()
@@ -297,12 +279,6 @@ func Test_NotifyForkchoiceUpdate_NIlLVH(t *testing.T) {
brd, err := wbd.Block().HashTreeRoot() brd, err := wbd.Block().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
// Insert blocks into forkchoice
service := setupBeaconChain(t, beaconDB)
fcs := doublylinkedtree.New()
service.cfg.ForkChoiceStore = fcs
service.cfg.ProposerSlotIndexCache = cache.NewProposerPayloadIDsCache()
fcs.SetBalancesByRooter(func(context.Context, [32]byte) ([]uint64, error) { return []uint64{50, 100, 200}, nil }) fcs.SetBalancesByRooter(func(context.Context, [32]byte) ([]uint64, error) { return []uint64{50, 100, 200}, nil })
require.NoError(t, fcs.UpdateJustifiedCheckpoint(ctx, &forkchoicetypes.Checkpoint{})) require.NoError(t, fcs.UpdateJustifiedCheckpoint(ctx, &forkchoicetypes.Checkpoint{}))
ojc := &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} ojc := &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
@@ -358,8 +334,8 @@ func Test_NotifyForkchoiceUpdate_NIlLVH(t *testing.T) {
// 3. the blockchain package calls fcu to obtain heads G -> F -> D. // 3. the blockchain package calls fcu to obtain heads G -> F -> D.
func Test_NotifyForkchoiceUpdateRecursive_DoublyLinkedTree(t *testing.T) { func Test_NotifyForkchoiceUpdateRecursive_DoublyLinkedTree(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
beaconDB := testDB.SetupDB(t) ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
// Prepare blocks // Prepare blocks
ba := util.NewBeaconBlockBellatrix() ba := util.NewBeaconBlockBellatrix()
@@ -414,12 +390,6 @@ func Test_NotifyForkchoiceUpdateRecursive_DoublyLinkedTree(t *testing.T) {
brg, err := wbg.Block().HashTreeRoot() brg, err := wbg.Block().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
// Insert blocks into forkchoice
service := setupBeaconChain(t, beaconDB)
fcs := doublylinkedtree.New()
service.cfg.ForkChoiceStore = fcs
service.cfg.ProposerSlotIndexCache = cache.NewProposerPayloadIDsCache()
fcs.SetBalancesByRooter(func(context.Context, [32]byte) ([]uint64, error) { return []uint64{50, 100, 200}, nil }) fcs.SetBalancesByRooter(func(context.Context, [32]byte) ([]uint64, error) { return []uint64{50, 100, 200}, nil })
require.NoError(t, fcs.UpdateJustifiedCheckpoint(ctx, &forkchoicetypes.Checkpoint{})) require.NoError(t, fcs.UpdateJustifiedCheckpoint(ctx, &forkchoicetypes.Checkpoint{}))
ojc := &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} ojc := &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
@@ -497,15 +467,9 @@ func Test_NotifyNewPayload(t *testing.T) {
cfg := params.BeaconConfig() cfg := params.BeaconConfig()
cfg.TerminalTotalDifficulty = "2" cfg.TerminalTotalDifficulty = "2"
params.OverrideBeaconConfig(cfg) params.OverrideBeaconConfig(cfg)
service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
ctx, fcs := tr.ctx, tr.fcs
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
phase0State, _ := util.DeterministicGenesisState(t, 1) phase0State, _ := util.DeterministicGenesisState(t, 1)
altairState, _ := util.DeterministicGenesisStateAltair(t, 1) altairState, _ := util.DeterministicGenesisStateAltair(t, 1)
bellatrixState, _ := util.DeterministicGenesisStateBellatrix(t, 2) bellatrixState, _ := util.DeterministicGenesisStateBellatrix(t, 2)
@@ -536,8 +500,6 @@ func Test_NotifyNewPayload(t *testing.T) {
} }
bellatrixBlk, err := consensusblocks.NewSignedBeaconBlock(util.HydrateSignedBeaconBlockBellatrix(blk)) bellatrixBlk, err := consensusblocks.NewSignedBeaconBlock(util.HydrateSignedBeaconBlockBellatrix(blk))
require.NoError(t, err) require.NoError(t, err)
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epochsSinceFinalitySaveHotStateDB)) st := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epochsSinceFinalitySaveHotStateDB))
service.genesisTime = time.Now().Add(time.Duration(-1*int64(st)*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second) service.genesisTime = time.Now().Add(time.Duration(-1*int64(st)*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second)
r, err := bellatrixBlk.Block().HashTreeRoot() r, err := bellatrixBlk.Block().HashTreeRoot()
@@ -744,14 +706,10 @@ func Test_NotifyNewPayload_SetOptimisticToValid(t *testing.T) {
cfg := params.BeaconConfig() cfg := params.BeaconConfig()
cfg.TerminalTotalDifficulty = "2" cfg.TerminalTotalDifficulty = "2"
params.OverrideBeaconConfig(cfg) params.OverrideBeaconConfig(cfg)
ctx := context.Background()
beaconDB := testDB.SetupDB(t) service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
fcs := doublylinkedtree.New() ctx := tr.ctx
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
bellatrixState, _ := util.DeterministicGenesisStateBellatrix(t, 2) bellatrixState, _ := util.DeterministicGenesisStateBellatrix(t, 2)
blk := &ethpb.SignedBeaconBlockBellatrix{ blk := &ethpb.SignedBeaconBlockBellatrix{
Block: &ethpb.BeaconBlockBellatrix{ Block: &ethpb.BeaconBlockBellatrix{
@@ -764,8 +722,6 @@ func Test_NotifyNewPayload_SetOptimisticToValid(t *testing.T) {
} }
bellatrixBlk, err := consensusblocks.NewSignedBeaconBlock(blk) bellatrixBlk, err := consensusblocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
service, err := NewService(ctx, opts...)
require.NoError(t, err)
e := &mockExecution.EngineClient{BlockByHashMap: map[[32]byte]*v1.ExecutionBlock{}} e := &mockExecution.EngineClient{BlockByHashMap: map[[32]byte]*v1.ExecutionBlock{}}
e.BlockByHashMap[[32]byte{'a'}] = &v1.ExecutionBlock{ e.BlockByHashMap[[32]byte{'a'}] = &v1.ExecutionBlock{
Header: gethtypes.Header{ Header: gethtypes.Header{
@@ -788,17 +744,9 @@ func Test_NotifyNewPayload_SetOptimisticToValid(t *testing.T) {
} }
func Test_GetPayloadAttribute(t *testing.T) { func Test_GetPayloadAttribute(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
// Cache miss
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, _ := util.DeterministicGenesisStateBellatrix(t, 1) st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0, []byte{}) hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0, []byte{})
require.Equal(t, false, hasPayload) require.Equal(t, false, hasPayload)
@@ -826,22 +774,15 @@ func Test_GetPayloadAttribute(t *testing.T) {
} }
func Test_GetPayloadAttribute_PrepareAllPayloads(t *testing.T) { func Test_GetPayloadAttribute_PrepareAllPayloads(t *testing.T) {
ctx := context.Background() hook := logTest.NewGlobal()
resetCfg := features.InitWithReset(&features.Flags{ resetCfg := features.InitWithReset(&features.Flags{
PrepareAllPayloads: true, PrepareAllPayloads: true,
}) })
defer resetCfg() defer resetCfg()
beaconDB := testDB.SetupDB(t) service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
opts := []Option{ ctx := tr.ctx
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
hook := logTest.NewGlobal()
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, _ := util.DeterministicGenesisStateBellatrix(t, 1) st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
hasPayload, attr, vId := service.getPayloadAttribute(ctx, st, 0, []byte{}) hasPayload, attr, vId := service.getPayloadAttribute(ctx, st, 0, []byte{})
require.Equal(t, true, hasPayload) require.Equal(t, true, hasPayload)
@@ -851,17 +792,9 @@ func Test_GetPayloadAttribute_PrepareAllPayloads(t *testing.T) {
} }
func Test_GetPayloadAttributeV2(t *testing.T) { func Test_GetPayloadAttributeV2(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
// Cache miss
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, _ := util.DeterministicGenesisStateCapella(t, 1) st, _ := util.DeterministicGenesisStateCapella(t, 1)
hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0, []byte{}) hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0, []byte{})
require.Equal(t, false, hasPayload) require.Equal(t, false, hasPayload)
@@ -897,18 +830,9 @@ func Test_GetPayloadAttributeV2(t *testing.T) {
func Test_UpdateLastValidatedCheckpoint(t *testing.T) { func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
params.SetupTestConfigCleanup(t) params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig()) params.OverrideBeaconConfig(params.MainnetConfig())
service, tr := minimalTestService(t)
ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New()
stateGen := stategen.New(beaconDB, fcs)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stateGen),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
var genesisStateRoot [32]byte var genesisStateRoot [32]byte
genesisBlk := blocks.NewGenesisBlock(genesisStateRoot[:]) genesisBlk := blocks.NewGenesisBlock(genesisStateRoot[:])
util.SaveBlock(t, ctx, beaconDB, genesisBlk) util.SaveBlock(t, ctx, beaconDB, genesisBlk)
@@ -1013,16 +937,8 @@ func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
} }
func TestService_removeInvalidBlockAndState(t *testing.T) { func TestService_removeInvalidBlockAndState(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fc := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
// Deleting unknown block should not error. // Deleting unknown block should not error.
require.NoError(t, service.removeInvalidBlockAndState(ctx, [][32]byte{{'a'}, {'b'}, {'c'}})) require.NoError(t, service.removeInvalidBlockAndState(ctx, [][32]byte{{'a'}, {'b'}, {'c'}}))
@@ -1066,18 +982,10 @@ func TestService_removeInvalidBlockAndState(t *testing.T) {
} }
func TestService_getPayloadHash(t *testing.T) { func TestService_getPayloadHash(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fc := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
_, err = service.getPayloadHash(ctx, []byte{}) _, err := service.getPayloadHash(ctx, []byte{})
require.ErrorIs(t, errBlockNotFoundInCacheOrDB, err) require.ErrorIs(t, errBlockNotFoundInCacheOrDB, err)
b := util.NewBeaconBlock() b := util.NewBeaconBlock()

View File

@@ -8,8 +8,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing" mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -145,23 +143,15 @@ func TestService_forkchoiceUpdateWithExecution_exceptionalCases(t *testing.T) {
} }
func TestService_forkchoiceUpdateWithExecution_SameHeadRootNewProposer(t *testing.T) { func TestService_forkchoiceUpdateWithExecution_SameHeadRootNewProposer(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair()) altairBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockAltair())
altairBlkRoot, err := altairBlk.Block().HashTreeRoot() altairBlkRoot, err := altairBlk.Block().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockBellatrix()) bellatrixBlk := util.SaveBlock(t, ctx, beaconDB, util.NewBeaconBlockBellatrix())
bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot() bellatrixBlkRoot, err := bellatrixBlk.Block().HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, _ := util.DeterministicGenesisState(t, 10) st, _ := util.DeterministicGenesisState(t, 10)
service.head = &head{ service.head = &head{
state: st, state: st,
@@ -200,18 +190,10 @@ func TestService_forkchoiceUpdateWithExecution_SameHeadRootNewProposer(t *testin
func TestShouldOverrideFCU(t *testing.T) { func TestShouldOverrideFCU(t *testing.T) {
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, fcs := tr.ctx, tr.fcs
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
service, err := NewService(ctx, opts...)
service.SetGenesisTime(time.Now().Add(-time.Duration(2*params.BeaconConfig().SecondsPerSlot) * time.Second)) service.SetGenesisTime(time.Now().Add(-time.Duration(2*params.BeaconConfig().SecondsPerSlot) * time.Second))
require.NoError(t, err)
headRoot := [32]byte{'b'} headRoot := [32]byte{'b'}
parentRoot := [32]byte{'a'} parentRoot := [32]byte{'a'}
ojc := &ethpb.Checkpoint{} ojc := &ethpb.Checkpoint{}

View File

@@ -9,10 +9,8 @@ import (
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types" forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/blstoexec" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/blstoexec"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -581,18 +579,9 @@ func TestSaveOrphanedAtts_CanFilter_DoublyLinkedTrie(t *testing.T) {
} }
func TestUpdateHead_noSavedChanges(t *testing.T) { func TestUpdateHead_noSavedChanges(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
ojp := &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]} ojp := &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
st, blkRoot, err := prepareForkchoiceState(ctx, 0, [32]byte{}, [32]byte{}, [32]byte{}, ojp, ojp) st, blkRoot, err := prepareForkchoiceState(ctx, 0, [32]byte{}, [32]byte{}, [32]byte{}, ojp, ojp)
require.NoError(t, err) require.NoError(t, err)

View File

@@ -5,16 +5,19 @@ import (
testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree" doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
) )
func testServiceOptsWithDB(t *testing.T) []Option { func testServiceOptsWithDB(t *testing.T) []Option {
beaconDB := testDB.SetupDB(t) beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New() fcs := doublylinkedtree.New()
cs := startup.NewClockSynchronizer()
return []Option{ return []Option{
WithDatabase(beaconDB), WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)), WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs), WithForkChoiceStore(fcs),
WithClockSynchronizer(cs),
} }
} }
@@ -22,5 +25,6 @@ func testServiceOptsWithDB(t *testing.T) []Option {
// in your code path. this is a lightweight way to satisfy the stategen/beacondb // in your code path. this is a lightweight way to satisfy the stategen/beacondb
// initialization requirements w/o the overhead of db init. // initialization requirements w/o the overhead of db init.
func testServiceOptsNoDB() []Option { func testServiceOptsNoDB() []Option {
return []Option{} cs := startup.NewClockSynchronizer()
return []Option{WithClockSynchronizer(cs)}
} }

View File

@@ -13,6 +13,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1" ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
@@ -163,3 +164,11 @@ func WithFinalizedStateAtStartUp(st state.BeaconState) Option {
return nil return nil
} }
} }
func WithClockSynchronizer(gs *startup.ClockSynchronizer) Option {
return func(s *Service) error {
s.clockSetter = gs
s.clockWaiter = gs
return nil
}
}

View File

@@ -1,17 +1,13 @@
package blockchain package blockchain
import ( import (
"context"
"fmt" "fmt"
"math/big" "math/big"
"testing" "testing"
gethtypes "github.com/ethereum/go-ethereum/core/types" gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/holiman/uint256" "github.com/holiman/uint256"
testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
mocks "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing" mocks "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
@@ -108,16 +104,8 @@ func Test_validateMergeBlock(t *testing.T) {
cfg.TerminalTotalDifficulty = "2" cfg.TerminalTotalDifficulty = "2"
params.OverrideBeaconConfig(cfg) params.OverrideBeaconConfig(cfg)
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
engine := &mocks.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlock{}} engine := &mocks.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlock{}}
service.cfg.ExecutionEngineCaller = engine service.cfg.ExecutionEngineCaller = engine
@@ -158,16 +146,8 @@ func Test_validateMergeBlock(t *testing.T) {
} }
func Test_getBlkParentHashAndTD(t *testing.T) { func Test_getBlkParentHashAndTD(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
engine := &mocks.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlock{}} engine := &mocks.EngineClient{BlockByHashMap: map[[32]byte]*enginev1.ExecutionBlock{}}
service.cfg.ExecutionEngineCaller = engine service.cfg.ExecutionEngineCaller = engine
@@ -239,14 +219,9 @@ func Test_validateTerminalBlockHash(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, true, ok) require.Equal(t, true, ok)
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
blk, err := blocks.NewSignedBeaconBlock(util.HydrateSignedBeaconBlockBellatrix(&ethpb.SignedBeaconBlockBellatrix{})) blk, err := blocks.NewSignedBeaconBlock(util.HydrateSignedBeaconBlockBellatrix(&ethpb.SignedBeaconBlockBellatrix{}))
require.NoError(t, err) require.NoError(t, err)
blk.SetSlot(1) blk.SetSlot(1)

View File

@@ -6,9 +6,6 @@ import (
"time" "time"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -21,19 +18,10 @@ import (
) )
func TestStore_OnAttestation_ErrorConditions(t *testing.T) { func TestStore_OnAttestation_ErrorConditions(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB := tr.ctx, tr.db
fc := doublylinkedtree.New() _, err := blockTree1(t, beaconDB, []byte{'g'})
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fc),
WithStateGen(stategen.New(beaconDB, fc)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
_, err = blockTree1(t, beaconDB, []byte{'g'})
require.NoError(t, err) require.NoError(t, err)
blkWithoutState := util.NewBeaconBlock() blkWithoutState := util.NewBeaconBlock()
@@ -128,17 +116,9 @@ func TestStore_OnAttestation_ErrorConditions(t *testing.T) {
} }
func TestStore_OnAttestation_Ok_DoublyLinkedTree(t *testing.T) { func TestStore_OnAttestation_Ok_DoublyLinkedTree(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
genesisState, pks := util.DeterministicGenesisState(t, 64) genesisState, pks := util.DeterministicGenesisState(t, 64)
service.SetGenesisTime(time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0)) service.SetGenesisTime(time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0))
require.NoError(t, service.saveGenesisData(ctx, genesisState)) require.NoError(t, service.saveGenesisData(ctx, genesisState))
@@ -158,15 +138,8 @@ func TestStore_OnAttestation_Ok_DoublyLinkedTree(t *testing.T) {
} }
func TestStore_SaveCheckpointState(t *testing.T) { func TestStore_SaveCheckpointState(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
s, err := util.NewBeaconState() s, err := util.NewBeaconState()
require.NoError(t, err) require.NoError(t, err)
@@ -220,15 +193,8 @@ func TestStore_SaveCheckpointState(t *testing.T) {
} }
func TestStore_UpdateCheckpointState(t *testing.T) { func TestStore_UpdateCheckpointState(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
epoch := primitives.Epoch(1) epoch := primitives.Epoch(1)
baseState, _ := util.DeterministicGenesisState(t, 1) baseState, _ := util.DeterministicGenesisState(t, 1)

View File

@@ -6,7 +6,6 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/async/event"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state" statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
@@ -652,28 +651,21 @@ func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion
// This routine checks if there is a cached proposer payload ID available for the next slot proposer. // This routine checks if there is a cached proposer payload ID available for the next slot proposer.
// If there is not, it will call forkchoice updated with the correct payload attribute then cache the payload ID. // If there is not, it will call forkchoice updated with the correct payload attribute then cache the payload ID.
func (s *Service) fillMissingPayloadIDRoutine(ctx context.Context, stateFeed *event.Feed) { func (s *Service) spawnLateBlockTasksLoop() {
// Wait for state to be initialized.
stateChannel := make(chan *feed.Event, 1)
stateSub := stateFeed.Subscribe(stateChannel)
go func() { go func() {
select { _, err := s.clockWaiter.WaitForClock(s.ctx)
case <-s.ctx.Done(): if err != nil {
stateSub.Unsubscribe() log.WithError(err).Error("spawnLateBlockTasksLoop encountered an error waiting for initialization")
return return
case <-stateChannel:
stateSub.Unsubscribe()
break
} }
attThreshold := params.BeaconConfig().SecondsPerSlot / 3 attThreshold := params.BeaconConfig().SecondsPerSlot / 3
ticker := slots.NewSlotTickerWithOffset(s.genesisTime, time.Duration(attThreshold)*time.Second, params.BeaconConfig().SecondsPerSlot) ticker := slots.NewSlotTickerWithOffset(s.genesisTime, time.Duration(attThreshold)*time.Second, params.BeaconConfig().SecondsPerSlot)
for { for {
select { select {
case <-ticker.C(): case <-ticker.C():
s.lateBlockTasks(ctx) s.lateBlockTasks(s.ctx)
case <-ctx.Done(): case <-s.ctx.Done():
log.Debug("Context closed, exiting routine") log.Debug("Context closed, exiting routine")
return return
} }

View File

@@ -12,9 +12,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
gethtypes "github.com/ethereum/go-ethereum/core/types" gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/pkg/errors" "github.com/pkg/errors"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache/depositcache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
@@ -24,9 +22,7 @@ import (
mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing" mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree" doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types" forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/features" "github.com/prysmaticlabs/prysm/v4/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -46,18 +42,9 @@ import (
) )
func TestStore_OnBlock(t *testing.T) { func TestStore_OnBlock(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
ctx, beaconDB, fcs := tr.ctx, tr.db, tr.fcs
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
var genesisStateRoot [32]byte var genesisStateRoot [32]byte
genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
util.SaveBlock(t, ctx, beaconDB, genesis) util.SaveBlock(t, ctx, beaconDB, genesis)
@@ -152,17 +139,8 @@ func TestStore_OnBlock(t *testing.T) {
} }
func TestStore_OnBlockBatch(t *testing.T) { func TestStore_OnBlockBatch(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fc := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, keys := util.DeterministicGenesisState(t, 64) st, keys := util.DeterministicGenesisState(t, 64)
require.NoError(t, service.saveGenesisData(ctx, st)) require.NoError(t, service.saveGenesisData(ctx, st))
@@ -185,7 +163,7 @@ func TestStore_OnBlockBatch(t *testing.T) {
blks = append(blks, wsb) blks = append(blks, wsb)
blkRoots = append(blkRoots, root) blkRoots = append(blkRoots, root)
} }
err = service.onBlockBatch(ctx, blks, blkRoots[1:]) err := service.onBlockBatch(ctx, blks, blkRoots[1:])
require.ErrorIs(t, errWrongBlockCount, err) require.ErrorIs(t, errWrongBlockCount, err)
err = service.onBlockBatch(ctx, blks, blkRoots) err = service.onBlockBatch(ctx, blks, blkRoots)
require.NoError(t, err) require.NoError(t, err)
@@ -196,17 +174,9 @@ func TestStore_OnBlockBatch(t *testing.T) {
} }
func TestStore_OnBlockBatch_NotifyNewPayload(t *testing.T) { func TestStore_OnBlockBatch_NotifyNewPayload(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fc := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, keys := util.DeterministicGenesisState(t, 64) st, keys := util.DeterministicGenesisState(t, 64)
require.NoError(t, service.saveGenesisData(ctx, st)) require.NoError(t, service.saveGenesisData(ctx, st))
bState := st.Copy() bState := st.Copy()
@@ -227,22 +197,12 @@ func TestStore_OnBlockBatch_NotifyNewPayload(t *testing.T) {
blks = append(blks, wsb) blks = append(blks, wsb)
blkRoots = append(blkRoots, root) blkRoots = append(blkRoots, root)
} }
err = service.onBlockBatch(ctx, blks, blkRoots) require.NoError(t, service.onBlockBatch(ctx, blks, blkRoots))
require.NoError(t, err)
} }
func TestCachedPreState_CanGetFromStateSummary(t *testing.T) { func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB := tr.ctx, tr.db
fc := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, keys := util.DeterministicGenesisState(t, 64) st, keys := util.DeterministicGenesisState(t, 64)
require.NoError(t, service.saveGenesisData(ctx, st)) require.NoError(t, service.saveGenesisData(ctx, st))
@@ -260,16 +220,8 @@ func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
} }
func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) { func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB := tr.ctx, tr.db
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
st, _ := util.DeterministicGenesisState(t, 64) st, _ := util.DeterministicGenesisState(t, 64)
require.NoError(t, service.saveGenesisData(ctx, st)) require.NoError(t, service.saveGenesisData(ctx, st))
@@ -309,16 +261,8 @@ func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
} }
func TestFillForkChoiceMissingBlocks_RootsMatch(t *testing.T) { func TestFillForkChoiceMissingBlocks_RootsMatch(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB := tr.ctx, tr.db
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
st, _ := util.DeterministicGenesisState(t, 64) st, _ := util.DeterministicGenesisState(t, 64)
require.NoError(t, service.saveGenesisData(ctx, st)) require.NoError(t, service.saveGenesisData(ctx, st))
@@ -360,16 +304,8 @@ func TestFillForkChoiceMissingBlocks_RootsMatch(t *testing.T) {
} }
func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) { func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB := tr.ctx, tr.db
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
var genesisStateRoot [32]byte var genesisStateRoot [32]byte
genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
@@ -418,17 +354,8 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized(t *testing.T) {
} }
func TestFillForkChoiceMissingBlocks_FinalizedSibling(t *testing.T) { func TestFillForkChoiceMissingBlocks_FinalizedSibling(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB := tr.ctx, tr.db
fc := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fc)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.cfg.ForkChoiceStore = doublylinkedtree.New()
var genesisStateRoot [32]byte var genesisStateRoot [32]byte
genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) genesis := blocks.NewGenesisBlock(genesisStateRoot[:])
@@ -566,17 +493,8 @@ func TestAncestorByDB_CtxErr(t *testing.T) {
} }
func TestAncestor_HandleSkipSlot(t *testing.T) { func TestAncestor_HandleSkipSlot(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) beaconDB := tr.db
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
b1 := util.NewBeaconBlock() b1 := util.NewBeaconBlock()
b1.Block.Slot = 1 b1.Block.Slot = 1
@@ -657,17 +575,8 @@ func TestAncestor_CanUseForkchoice(t *testing.T) {
} }
func TestAncestor_CanUseDB(t *testing.T) { func TestAncestor_CanUseDB(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, beaconDB := tr.ctx, tr.db
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
b1 := util.NewBeaconBlock() b1 := util.NewBeaconBlock()
b1.Block.Slot = 1 b1.Block.Slot = 1
@@ -732,21 +641,8 @@ func TestHandleEpochBoundary_UpdateFirstSlot(t *testing.T) {
} }
func TestOnBlock_CanFinalize_WithOnTick(t *testing.T) { func TestOnBlock_CanFinalize_WithOnTick(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, fcs := tr.ctx, tr.fcs
fcs := doublylinkedtree.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithDepositCache(depositCache),
WithStateNotifier(&mock.MockStateNotifier{}),
WithAttestationPool(attestations.NewPool()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, keys := util.DeterministicGenesisState(t, 32) gs, keys := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs)) require.NoError(t, service.saveGenesisData(ctx, gs))
@@ -782,21 +678,8 @@ func TestOnBlock_CanFinalize_WithOnTick(t *testing.T) {
} }
func TestOnBlock_CanFinalize(t *testing.T) { func TestOnBlock_CanFinalize(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithDepositCache(depositCache),
WithStateNotifier(&mock.MockStateNotifier{}),
WithAttestationPool(attestations.NewPool()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, keys := util.DeterministicGenesisState(t, 32) gs, keys := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs)) require.NoError(t, service.saveGenesisData(ctx, gs))
@@ -830,39 +713,15 @@ func TestOnBlock_CanFinalize(t *testing.T) {
} }
func TestOnBlock_NilBlock(t *testing.T) { func TestOnBlock_NilBlock(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithDepositCache(depositCache),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
err = service.onBlock(ctx, nil, [32]byte{}) err := service.onBlock(tr.ctx, nil, [32]byte{})
require.Equal(t, true, IsInvalidBlock(err)) require.Equal(t, true, IsInvalidBlock(err))
} }
func TestOnBlock_InvalidSignature(t *testing.T) { func TestOnBlock_InvalidSignature(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithDepositCache(depositCache),
WithStateNotifier(&mock.MockStateNotifier{}),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, keys := util.DeterministicGenesisState(t, 32) gs, keys := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs)) require.NoError(t, service.saveGenesisData(ctx, gs))
@@ -885,21 +744,8 @@ func TestOnBlock_CallNewPayloadAndForkchoiceUpdated(t *testing.T) {
config.BellatrixForkEpoch = 2 config.BellatrixForkEpoch = 2
params.OverrideBeaconConfig(config) params.OverrideBeaconConfig(config)
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithDepositCache(depositCache),
WithStateNotifier(&mock.MockStateNotifier{}),
WithAttestationPool(attestations.NewPool()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, keys := util.DeterministicGenesisState(t, 32) gs, keys := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs)) require.NoError(t, service.saveGenesisData(ctx, gs))
@@ -918,13 +764,8 @@ func TestOnBlock_CallNewPayloadAndForkchoiceUpdated(t *testing.T) {
} }
func TestInsertFinalizedDeposits(t *testing.T) { func TestInsertFinalizedDeposits(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
opts := testServiceOptsWithDB(t) ctx, depositCache := tr.ctx, tr.dc
depositCache, err := depositcache.New()
require.NoError(t, err)
opts = append(opts, WithDepositCache(depositCache))
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, _ := util.DeterministicGenesisState(t, 32) gs, _ := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs)) require.NoError(t, service.saveGenesisData(ctx, gs))
@@ -952,13 +793,8 @@ func TestInsertFinalizedDeposits(t *testing.T) {
} }
func TestInsertFinalizedDeposits_MultipleFinalizedRoutines(t *testing.T) { func TestInsertFinalizedDeposits_MultipleFinalizedRoutines(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
opts := testServiceOptsWithDB(t) ctx, depositCache := tr.ctx, tr.dc
depositCache, err := depositcache.New()
require.NoError(t, err)
opts = append(opts, WithDepositCache(depositCache))
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, _ := util.DeterministicGenesisState(t, 32) gs, _ := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs)) require.NoError(t, service.saveGenesisData(ctx, gs))
@@ -1085,18 +921,8 @@ func Test_validateMergeTransitionBlock(t *testing.T) {
cfg.TerminalBlockHash = params.BeaconConfig().ZeroHash cfg.TerminalBlockHash = params.BeaconConfig().ZeroHash
params.OverrideBeaconConfig(cfg) params.OverrideBeaconConfig(cfg)
ctx := context.Background() service, tr := minimalTestService(t, WithProposerIdsCache(cache.NewProposerPayloadIDsCache()))
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
WithAttestationPool(attestations.NewPool()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
aHash := common.BytesToHash([]byte("a")) aHash := common.BytesToHash([]byte("a"))
bHash := common.BytesToHash([]byte("b")) bHash := common.BytesToHash([]byte("b"))
@@ -1223,17 +1049,8 @@ func Test_validateMergeTransitionBlock(t *testing.T) {
} }
func TestService_insertSlashingsToForkChoiceStore(t *testing.T) { func TestService_insertSlashingsToForkChoiceStore(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
beaconState, privKeys := util.DeterministicGenesisState(t, 100) beaconState, privKeys := util.DeterministicGenesisState(t, 100)
att1 := util.HydrateIndexedAttestation(&ethpb.IndexedAttestation{ att1 := util.HydrateIndexedAttestation(&ethpb.IndexedAttestation{
@@ -1274,21 +1091,8 @@ func TestService_insertSlashingsToForkChoiceStore(t *testing.T) {
} }
func TestOnBlock_ProcessBlocksParallel(t *testing.T) { func TestOnBlock_ProcessBlocksParallel(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fcs := doublylinkedtree.New()
depositCache, err := depositcache.New()
require.NoError(t, err)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
WithDepositCache(depositCache),
WithStateNotifier(&mock.MockStateNotifier{}),
WithAttestationPool(attestations.NewPool()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
gs, keys := util.DeterministicGenesisState(t, 32) gs, keys := util.DeterministicGenesisState(t, 32)
require.NoError(t, service.saveGenesisData(ctx, gs)) require.NoError(t, service.saveGenesisData(ctx, gs))
@@ -1353,17 +1157,8 @@ func TestOnBlock_ProcessBlocksParallel(t *testing.T) {
} }
func Test_verifyBlkFinalizedSlot_invalidBlock(t *testing.T) { func Test_verifyBlkFinalizedSlot_invalidBlock(t *testing.T) {
ctx := context.Background() service, _ := minimalTestService(t)
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fcs)),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 1})) require.NoError(t, service.cfg.ForkChoiceStore.UpdateFinalizedCheckpoint(&forkchoicetypes.Checkpoint{Epoch: 1}))
blk := util.HydrateBeaconBlock(&ethpb.BeaconBlock{Slot: 1}) blk := util.HydrateBeaconBlock(&ethpb.BeaconBlock{Slot: 1})
wb, err := consensusblocks.NewBeaconBlock(blk) wb, err := consensusblocks.NewBeaconBlock(blk)
@@ -1386,22 +1181,9 @@ func TestStore_NoViableHead_FCU(t *testing.T) {
config.BellatrixForkEpoch = 2 config.BellatrixForkEpoch = 2
params.OverrideBeaconConfig(config) params.OverrideBeaconConfig(config)
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
mockEngine := &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrAcceptedSyncingPayloadStatus} mockEngine := &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrAcceptedSyncingPayloadStatus}
fc := doublylinkedtree.New() service, tr := minimalTestService(t, WithExecutionEngineCaller(mockEngine))
opts := []Option{ ctx := tr.ctx
WithDatabase(beaconDB),
WithAttestationPool(attestations.NewPool()),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
WithStateNotifier(&mock.MockStateNotifier{}),
WithExecutionEngineCaller(mockEngine),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, keys := util.DeterministicGenesisState(t, 64) st, keys := util.DeterministicGenesisState(t, 64)
stateRoot, err := st.HashTreeRoot(ctx) stateRoot, err := st.HashTreeRoot(ctx)
@@ -1546,22 +1328,9 @@ func TestStore_NoViableHead_NewPayload(t *testing.T) {
config.BellatrixForkEpoch = 2 config.BellatrixForkEpoch = 2
params.OverrideBeaconConfig(config) params.OverrideBeaconConfig(config)
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
mockEngine := &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrAcceptedSyncingPayloadStatus} mockEngine := &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrAcceptedSyncingPayloadStatus}
fc := doublylinkedtree.New() service, tr := minimalTestService(t, WithExecutionEngineCaller(mockEngine))
opts := []Option{ ctx := tr.ctx
WithDatabase(beaconDB),
WithAttestationPool(attestations.NewPool()),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
WithStateNotifier(&mock.MockStateNotifier{}),
WithExecutionEngineCaller(mockEngine),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, keys := util.DeterministicGenesisState(t, 64) st, keys := util.DeterministicGenesisState(t, 64)
stateRoot, err := st.HashTreeRoot(ctx) stateRoot, err := st.HashTreeRoot(ctx)
@@ -1707,22 +1476,9 @@ func TestStore_NoViableHead_Liveness(t *testing.T) {
config.BellatrixForkEpoch = 2 config.BellatrixForkEpoch = 2
params.OverrideBeaconConfig(config) params.OverrideBeaconConfig(config)
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
mockEngine := &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrAcceptedSyncingPayloadStatus} mockEngine := &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrAcceptedSyncingPayloadStatus}
fc := doublylinkedtree.New() service, tr := minimalTestService(t, WithExecutionEngineCaller(mockEngine))
opts := []Option{ ctx := tr.ctx
WithDatabase(beaconDB),
WithAttestationPool(attestations.NewPool()),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
WithStateNotifier(&mock.MockStateNotifier{}),
WithExecutionEngineCaller(mockEngine),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, keys := util.DeterministicGenesisState(t, 64) st, keys := util.DeterministicGenesisState(t, 64)
stateRoot, err := st.HashTreeRoot(ctx) stateRoot, err := st.HashTreeRoot(ctx)
@@ -1915,27 +1671,9 @@ func TestNoViableHead_Reboot(t *testing.T) {
config.BellatrixForkEpoch = 2 config.BellatrixForkEpoch = 2
params.OverrideBeaconConfig(config) params.OverrideBeaconConfig(config)
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
mockEngine := &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrAcceptedSyncingPayloadStatus} mockEngine := &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrAcceptedSyncingPayloadStatus}
attSrv, err := attestations.NewService(ctx, &attestations.Config{}) service, tr := minimalTestService(t, WithExecutionEngineCaller(mockEngine))
require.NoError(t, err) ctx := tr.ctx
newfc := doublylinkedtree.New()
newStateGen := stategen.New(beaconDB, newfc)
newfc.SetBalancesByRooter(newStateGen.ActiveNonSlashedBalancesByRoot)
opts := []Option{
WithDatabase(beaconDB),
WithAttestationPool(attestations.NewPool()),
WithStateGen(newStateGen),
WithForkChoiceStore(newfc),
WithStateNotifier(&mock.MockStateNotifier{}),
WithExecutionEngineCaller(mockEngine),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
WithAttestationService(attSrv),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
genesisState, keys := util.DeterministicGenesisState(t, 64) genesisState, keys := util.DeterministicGenesisState(t, 64)
stateRoot, err := genesisState.HashTreeRoot(ctx) stateRoot, err := genesisState.HashTreeRoot(ctx)
@@ -2084,18 +1822,8 @@ func TestNoViableHead_Reboot(t *testing.T) {
} }
func TestOnBlock_HandleBlockAttestations(t *testing.T) { func TestOnBlock_HandleBlockAttestations(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx := tr.ctx
fc := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithAttestationPool(attestations.NewPool()),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
WithStateNotifier(&mock.MockStateNotifier{}),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, keys := util.DeterministicGenesisState(t, 64) st, keys := util.DeterministicGenesisState(t, 64)
stateRoot, err := st.HashTreeRoot(ctx) stateRoot, err := st.HashTreeRoot(ctx)
@@ -2155,18 +1883,8 @@ func TestOnBlock_HandleBlockAttestations(t *testing.T) {
func TestFillMissingBlockPayloadId_DiffSlotExitEarly(t *testing.T) { func TestFillMissingBlockPayloadId_DiffSlotExitEarly(t *testing.T) {
logHook := logTest.NewGlobal() logHook := logTest.NewGlobal()
fc := doublylinkedtree.New() service, tr := minimalTestService(t)
ctx := context.Background() service.lateBlockTasks(tr.ctx)
beaconDB := testDB.SetupDB(t)
opts := []Option{
WithForkChoiceStore(fc),
WithStateGen(stategen.New(beaconDB, fc)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.lateBlockTasks(ctx)
require.LogsDoNotContain(t, logHook, "could not perform late block tasks") require.LogsDoNotContain(t, logHook, "could not perform late block tasks")
} }
@@ -2177,24 +1895,14 @@ func TestFillMissingBlockPayloadId_PrepareAllPayloads(t *testing.T) {
}) })
defer resetCfg() defer resetCfg()
fc := doublylinkedtree.New() service, tr := minimalTestService(t)
ctx := context.Background() service.lateBlockTasks(tr.ctx)
beaconDB := testDB.SetupDB(t)
opts := []Option{
WithForkChoiceStore(fc),
WithStateGen(stategen.New(beaconDB, fc)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.lateBlockTasks(ctx)
require.LogsDoNotContain(t, logHook, "could not perform late block tasks") require.LogsDoNotContain(t, logHook, "could not perform late block tasks")
} }
// Helper function to simulate the block being on time or delayed for proposer // Helper function to simulate the block being on time or delayed for proposer
// boost. It alters the genesisTime tracked by the store. // boost. It alters the genesisTime tracked by the store.
func driftGenesisTime(s *Service, slot int64, delay int64) { func driftGenesisTime(s *Service, slot, delay int64) {
offset := slot*int64(params.BeaconConfig().SecondsPerSlot) - delay offset := slot*int64(params.BeaconConfig().SecondsPerSlot) - delay
s.SetGenesisTime(time.Unix(time.Now().Unix()-offset, 0)) s.SetGenesisTime(time.Unix(time.Now().Unix()-offset, 0))
} }

View File

@@ -7,8 +7,6 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/async/event"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/config/features" "github.com/prysmaticlabs/prysm/v4/config/features"
@@ -67,20 +65,13 @@ func (s *Service) VerifyLmdFfgConsistency(ctx context.Context, a *ethpb.Attestat
} }
// This routine processes fork choice attestations from the pool to account for validator votes and fork choice. // This routine processes fork choice attestations from the pool to account for validator votes and fork choice.
func (s *Service) spawnProcessAttestationsRoutine(stateFeed *event.Feed) { func (s *Service) spawnProcessAttestationsRoutine() {
// Wait for state to be initialized.
stateChannel := make(chan *feed.Event, 1)
stateSub := stateFeed.Subscribe(stateChannel)
go func() { go func() {
select { _, err := s.clockWaiter.WaitForClock(s.ctx)
case <-s.ctx.Done(): if err != nil {
stateSub.Unsubscribe() log.WithError(err).Error("spawnProcessAttestationsRoutine failed to receive genesis data")
return return
case <-stateChannel:
stateSub.Unsubscribe()
break
} }
if s.genesisTime.IsZero() { if s.genesisTime.IsZero() {
log.Warn("ProcessAttestations routine waiting for genesis time") log.Warn("ProcessAttestations routine waiting for genesis time")
for s.genesisTime.IsZero() { for s.genesisTime.IsZero() {

View File

@@ -7,11 +7,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types" forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -31,22 +27,18 @@ var (
func TestAttestationCheckPtState_FarFutureSlot(t *testing.T) { func TestAttestationCheckPtState_FarFutureSlot(t *testing.T) {
helpers.ClearCache() helpers.ClearCache()
beaconDB := testDB.SetupDB(t) service, _ := minimalTestService(t)
chainService := setupBeaconChain(t, beaconDB) service.genesisTime = time.Now()
chainService.genesisTime = time.Now()
e := primitives.Epoch(slots.MaxSlotBuffer/uint64(params.BeaconConfig().SlotsPerEpoch) + 1) e := primitives.Epoch(slots.MaxSlotBuffer/uint64(params.BeaconConfig().SlotsPerEpoch) + 1)
_, err := chainService.AttestationTargetState(context.Background(), &ethpb.Checkpoint{Epoch: e}) _, err := service.AttestationTargetState(context.Background(), &ethpb.Checkpoint{Epoch: e})
require.ErrorContains(t, "exceeds max allowed value relative to the local clock", err) require.ErrorContains(t, "exceeds max allowed value relative to the local clock", err)
} }
func TestVerifyLMDFFGConsistent_NotOK(t *testing.T) { func TestVerifyLMDFFGConsistent_NotOK(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
opts := testServiceOptsWithDB(t) ctx := tr.ctx
service, err := NewService(ctx, opts...)
require.NoError(t, err)
b32 := util.NewBeaconBlock() b32 := util.NewBeaconBlock()
b32.Block.Slot = 32 b32.Block.Slot = 32
@@ -69,11 +61,8 @@ func TestVerifyLMDFFGConsistent_NotOK(t *testing.T) {
} }
func TestVerifyLMDFFGConsistent_OK(t *testing.T) { func TestVerifyLMDFFGConsistent_OK(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
ctx := tr.ctx
opts := testServiceOptsWithDB(t)
service, err := NewService(ctx, opts...)
require.NoError(t, err)
b32 := util.NewBeaconBlock() b32 := util.NewBeaconBlock()
b32.Block.Slot = 32 b32.Block.Slot = 32
@@ -96,13 +85,10 @@ func TestVerifyLMDFFGConsistent_OK(t *testing.T) {
} }
func TestProcessAttestations_Ok(t *testing.T) { func TestProcessAttestations_Ok(t *testing.T) {
service, tr := minimalTestService(t)
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
ctx := context.Background() ctx := tr.ctx
opts := testServiceOptsWithDB(t)
opts = append(opts, WithAttestationPool(attestations.NewPool()))
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.genesisTime = prysmTime.Now().Add(-1 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second) service.genesisTime = prysmTime.Now().Add(-1 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second)
genesisState, pks := util.DeterministicGenesisState(t, 64) genesisState, pks := util.DeterministicGenesisState(t, 64)
require.NoError(t, genesisState.SetGenesisTime(uint64(prysmTime.Now().Unix())-params.BeaconConfig().SecondsPerSlot)) require.NoError(t, genesisState.SetGenesisTime(uint64(prysmTime.Now().Unix())-params.BeaconConfig().SecondsPerSlot))
@@ -126,21 +112,9 @@ func TestProcessAttestations_Ok(t *testing.T) {
} }
func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) { func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, fcs := tr.ctx, tr.fcs
fcs := doublylinkedtree.New()
newStateGen := stategen.New(beaconDB, fcs)
fcs.SetBalancesByRooter(newStateGen.ActiveNonSlashedBalancesByRoot)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(newStateGen),
WithAttestationPool(attestations.NewPool()),
WithStateNotifier(&mockBeaconNode{}),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.genesisTime = prysmTime.Now().Add(-2 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second) service.genesisTime = prysmTime.Now().Add(-2 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second)
genesisState, pks := util.DeterministicGenesisState(t, 64) genesisState, pks := util.DeterministicGenesisState(t, 64)
require.NoError(t, service.saveGenesisData(ctx, genesisState)) require.NoError(t, service.saveGenesisData(ctx, genesisState))
@@ -189,21 +163,9 @@ func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
} }
func TestService_UpdateHead_NoAtts(t *testing.T) { func TestService_UpdateHead_NoAtts(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) ctx, fcs := tr.ctx, tr.fcs
fcs := doublylinkedtree.New()
newStateGen := stategen.New(beaconDB, fcs)
fcs.SetBalancesByRooter(newStateGen.ActiveNonSlashedBalancesByRoot)
opts := []Option{
WithDatabase(beaconDB),
WithAttestationPool(attestations.NewPool()),
WithStateNotifier(&mockBeaconNode{}),
WithStateGen(newStateGen),
WithForkChoiceStore(fcs),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.genesisTime = prysmTime.Now().Add(-2 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second) service.genesisTime = prysmTime.Now().Add(-2 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second)
genesisState, pks := util.DeterministicGenesisState(t, 64) genesisState, pks := util.DeterministicGenesisState(t, 64)
require.NoError(t, service.saveGenesisData(ctx, genesisState)) require.NoError(t, service.saveGenesisData(ctx, genesisState))

View File

@@ -7,12 +7,7 @@ import (
"time" "time"
blockchainTesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" blockchainTesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/blstoexec"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
@@ -125,22 +120,15 @@ func TestService_ReceiveBlock(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
wg.Add(1) wg.Add(1)
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
beaconDB := testDB.SetupDB(t) s, tr := minimalTestService(t,
WithFinalizedStateAtStartUp(genesis),
WithExitPool(voluntaryexits.NewPool()),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}))
beaconDB := tr.db
genesisBlockRoot := bytesutil.ToBytes32(nil) genesisBlockRoot := bytesutil.ToBytes32(nil)
require.NoError(t, beaconDB.SaveState(ctx, genesis, genesisBlockRoot)) require.NoError(t, beaconDB.SaveState(ctx, genesis, genesisBlockRoot))
fc := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fc),
WithAttestationPool(attestations.NewPool()),
WithExitPool(voluntaryexits.NewPool()),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
WithStateGen(stategen.New(beaconDB, fc)),
WithFinalizedStateAtStartUp(genesis),
}
s, err := NewService(ctx, opts...)
require.NoError(t, err)
// Initialize it here. // Initialize it here.
_ = s.cfg.StateNotifier.StateFeed() _ = s.cfg.StateNotifier.StateFeed()
require.NoError(t, s.saveGenesisData(ctx, genesis)) require.NoError(t, s.saveGenesisData(ctx, genesis))
@@ -162,25 +150,16 @@ func TestService_ReceiveBlock(t *testing.T) {
} }
func TestService_ReceiveBlockUpdateHead(t *testing.T) { func TestService_ReceiveBlockUpdateHead(t *testing.T) {
ctx := context.Background() s, tr := minimalTestService(t,
WithExitPool(voluntaryexits.NewPool()),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}))
ctx, beaconDB := tr.ctx, tr.db
genesis, keys := util.DeterministicGenesisState(t, 64) genesis, keys := util.DeterministicGenesisState(t, 64)
b, err := util.GenerateFullBlock(genesis, keys, util.DefaultBlockGenConfig(), 1) b, err := util.GenerateFullBlock(genesis, keys, util.DefaultBlockGenConfig(), 1)
assert.NoError(t, err) assert.NoError(t, err)
beaconDB := testDB.SetupDB(t)
genesisBlockRoot := bytesutil.ToBytes32(nil) genesisBlockRoot := bytesutil.ToBytes32(nil)
require.NoError(t, beaconDB.SaveState(ctx, genesis, genesisBlockRoot)) require.NoError(t, beaconDB.SaveState(ctx, genesis, genesisBlockRoot))
fc := doublylinkedtree.New()
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fc),
WithAttestationPool(attestations.NewPool()),
WithExitPool(voluntaryexits.NewPool()),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
WithStateGen(stategen.New(beaconDB, fc)),
}
s, err := NewService(ctx, opts...)
require.NoError(t, err)
// Initialize it here. // Initialize it here.
_ = s.cfg.StateNotifier.StateFeed() _ = s.cfg.StateNotifier.StateFeed()
require.NoError(t, s.saveGenesisData(ctx, genesis)) require.NoError(t, s.saveGenesisData(ctx, genesis))
@@ -246,17 +225,8 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
fc := doublylinkedtree.New() s, _ := minimalTestService(t, WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}))
beaconDB := testDB.SetupDB(t) err := s.saveGenesisData(ctx, genesis)
opts := []Option{
WithDatabase(beaconDB),
WithForkChoiceStore(fc),
WithStateNotifier(&blockchainTesting.MockStateNotifier{RecordEvents: true}),
WithStateGen(stategen.New(beaconDB, fc)),
}
s, err := NewService(ctx, opts...)
require.NoError(t, err)
err = s.saveGenesisData(ctx, genesis)
require.NoError(t, err) require.NoError(t, err)
root, err := tt.args.block.Block.HashTreeRoot() root, err := tt.args.block.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
@@ -276,10 +246,7 @@ func TestService_ReceiveBlockBatch(t *testing.T) {
} }
func TestService_HasBlock(t *testing.T) { func TestService_HasBlock(t *testing.T) {
opts := testServiceOptsWithDB(t) s, _ := minimalTestService(t)
opts = append(opts, WithStateNotifier(&blockchainTesting.MockStateNotifier{}))
s, err := NewService(context.Background(), opts...)
require.NoError(t, err)
r := [32]byte{'a'} r := [32]byte{'a'}
if s.HasBlock(context.Background(), r) { if s.HasBlock(context.Background(), r) {
t.Error("Should not have block") t.Error("Should not have block")
@@ -299,10 +266,8 @@ func TestService_HasBlock(t *testing.T) {
} }
func TestCheckSaveHotStateDB_Enabling(t *testing.T) { func TestCheckSaveHotStateDB_Enabling(t *testing.T) {
opts := testServiceOptsWithDB(t)
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
s, err := NewService(context.Background(), opts...) s, _ := minimalTestService(t)
require.NoError(t, err)
st := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epochsSinceFinalitySaveHotStateDB)) st := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epochsSinceFinalitySaveHotStateDB))
s.genesisTime = time.Now().Add(time.Duration(-1*int64(st)*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second) s.genesisTime = time.Now().Add(time.Duration(-1*int64(st)*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second)
@@ -312,9 +277,9 @@ func TestCheckSaveHotStateDB_Enabling(t *testing.T) {
func TestCheckSaveHotStateDB_Disabling(t *testing.T) { func TestCheckSaveHotStateDB_Disabling(t *testing.T) {
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
opts := testServiceOptsWithDB(t)
s, err := NewService(context.Background(), opts...) s, _ := minimalTestService(t)
require.NoError(t, err)
st := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epochsSinceFinalitySaveHotStateDB)) st := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epochsSinceFinalitySaveHotStateDB))
s.genesisTime = time.Now().Add(time.Duration(-1*int64(st)*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second) s.genesisTime = time.Now().Add(time.Duration(-1*int64(st)*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second)
require.NoError(t, s.checkSaveHotStateDB(context.Background())) require.NoError(t, s.checkSaveHotStateDB(context.Background()))
@@ -326,9 +291,7 @@ func TestCheckSaveHotStateDB_Disabling(t *testing.T) {
func TestCheckSaveHotStateDB_Overflow(t *testing.T) { func TestCheckSaveHotStateDB_Overflow(t *testing.T) {
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
opts := testServiceOptsWithDB(t) s, _ := minimalTestService(t)
s, err := NewService(context.Background(), opts...)
require.NoError(t, err)
s.genesisTime = time.Now() s.genesisTime = time.Now()
require.NoError(t, s.checkSaveHotStateDB(context.Background())) require.NoError(t, s.checkSaveHotStateDB(context.Background()))
@@ -336,19 +299,8 @@ func TestCheckSaveHotStateDB_Overflow(t *testing.T) {
} }
func TestHandleBlockBLSToExecutionChanges(t *testing.T) { func TestHandleBlockBLSToExecutionChanges(t *testing.T) {
ctx := context.Background() service, tr := minimalTestService(t)
beaconDB := testDB.SetupDB(t) pool := tr.blsPool
fc := doublylinkedtree.New()
pool := blstoexec.NewPool()
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, fc)),
WithForkChoiceStore(fc),
WithStateNotifier(&blockchainTesting.MockStateNotifier{}),
WithBLSToExecPool(pool),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
t.Run("pre Capella block", func(t *testing.T) { t.Run("pre Capella block", func(t *testing.T) {
body := &ethpb.BeaconBlockBodyBellatrix{} body := &ethpb.BeaconBlockBodyBellatrix{}

View File

@@ -27,6 +27,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/features" "github.com/prysmaticlabs/prysm/v4/config/features"
@@ -57,6 +58,8 @@ type Service struct {
initSyncBlocks map[[32]byte]interfaces.ReadOnlySignedBeaconBlock initSyncBlocks map[[32]byte]interfaces.ReadOnlySignedBeaconBlock
initSyncBlocksLock sync.RWMutex initSyncBlocksLock sync.RWMutex
wsVerifier *WeakSubjectivityVerifier wsVerifier *WeakSubjectivityVerifier
clockSetter startup.ClockSetter
clockWaiter startup.ClockWaiter
} }
// config options for the service. // config options for the service.
@@ -83,6 +86,8 @@ type config struct {
ExecutionEngineCaller execution.EngineCaller ExecutionEngineCaller execution.EngineCaller
} }
var ErrMissingClockSetter = errors.New("blockchain Service initialized without a startup.ClockSetter")
// NewService instantiates a new block service instance that will // NewService instantiates a new block service instance that will
// be registered into a running beacon node. // be registered into a running beacon node.
func NewService(ctx context.Context, opts ...Option) (*Service, error) { func NewService(ctx context.Context, opts ...Option) (*Service, error) {
@@ -100,6 +105,9 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
return nil, err return nil, err
} }
} }
if srv.clockSetter == nil {
return nil, ErrMissingClockSetter
}
var err error var err error
srv.wsVerifier, err = NewWeakSubjectivityVerifier(srv.cfg.WeakSubjectivityCheckpt, srv.cfg.BeaconDB) srv.wsVerifier, err = NewWeakSubjectivityVerifier(srv.cfg.WeakSubjectivityCheckpt, srv.cfg.BeaconDB)
if err != nil { if err != nil {
@@ -121,8 +129,8 @@ func (s *Service) Start() {
log.Fatal(err) log.Fatal(err)
} }
} }
s.spawnProcessAttestationsRoutine(s.cfg.StateNotifier.StateFeed()) s.spawnProcessAttestationsRoutine()
s.fillMissingPayloadIDRoutine(s.ctx, s.cfg.StateNotifier.StateFeed()) s.spawnLateBlockTasksLoop()
} }
// Stop the blockchain service's main event loop and associated goroutines. // Stop the blockchain service's main event loop and associated goroutines.
@@ -236,13 +244,10 @@ func (s *Service) StartFromSavedState(saved state.BeaconState) error {
return errors.Wrap(err, "could not verify initial checkpoint provided for chain sync") return errors.Wrap(err, "could not verify initial checkpoint provided for chain sync")
} }
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{ vr := bytesutil.ToBytes32(saved.GenesisValidatorsRoot())
Type: statefeed.Initialized, if err := s.clockSetter.SetClock(startup.NewClock(s.genesisTime, vr)); err != nil {
Data: &statefeed.InitializedData{ return errors.Wrap(err, "failed to initialize blockchain service")
StartTime: s.genesisTime, }
GenesisValidatorsRoot: saved.GenesisValidatorsRoot(),
},
})
return nil return nil
} }
@@ -359,15 +364,10 @@ func (s *Service) onExecutionChainStart(ctx context.Context, genesisTime time.Ti
} }
go slots.CountdownToGenesis(ctx, genesisTime, uint64(initializedState.NumValidators()), gRoot) go slots.CountdownToGenesis(ctx, genesisTime, uint64(initializedState.NumValidators()), gRoot)
// We send out a state initialized event to the rest of the services vr := bytesutil.ToBytes32(initializedState.GenesisValidatorsRoot())
// running in the beacon node. if err := s.clockSetter.SetClock(startup.NewClock(genesisTime, vr)); err != nil {
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{ log.WithError(err).Fatal("failed to initialize blockchain service from execution start event")
Type: statefeed.Initialized, }
Data: &statefeed.InitializedData{
StartTime: genesisTime,
GenesisValidatorsRoot: initializedState.GenesisValidatorsRoot(),
},
})
} }
// initializes the state and genesis block of the beacon chain to persistent storage // initializes the state and genesis block of the beacon chain to persistent storage

View File

@@ -8,13 +8,9 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/prysmaticlabs/prysm/v4/async/event"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache/depositcache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache/depositcache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
@@ -25,7 +21,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native" state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/features" "github.com/prysmaticlabs/prysm/v4/config/features"
@@ -40,45 +36,8 @@ import (
"github.com/prysmaticlabs/prysm/v4/testing/util" "github.com/prysmaticlabs/prysm/v4/testing/util"
"github.com/prysmaticlabs/prysm/v4/time/slots" "github.com/prysmaticlabs/prysm/v4/time/slots"
logTest "github.com/sirupsen/logrus/hooks/test" logTest "github.com/sirupsen/logrus/hooks/test"
"google.golang.org/protobuf/proto"
) )
type mockBeaconNode struct {
stateFeed *event.Feed
}
// StateFeed mocks the same method in the beacon node.
func (mbn *mockBeaconNode) StateFeed() *event.Feed {
if mbn.stateFeed == nil {
mbn.stateFeed = new(event.Feed)
}
return mbn.stateFeed
}
type mockBroadcaster struct {
broadcastCalled bool
}
func (mb *mockBroadcaster) Broadcast(_ context.Context, _ proto.Message) error {
mb.broadcastCalled = true
return nil
}
func (mb *mockBroadcaster) BroadcastAttestation(_ context.Context, _ uint64, _ *ethpb.Attestation) error {
mb.broadcastCalled = true
return nil
}
func (mb *mockBroadcaster) BroadcastSyncCommitteeMessage(_ context.Context, _ uint64, _ *ethpb.SyncCommitteeMessage) error {
mb.broadcastCalled = true
return nil
}
func (mb *mockBroadcaster) BroadcastBLSChanges(_ context.Context, _ []*ethpb.SignedBLSToExecutionChange) {
}
var _ p2p.Broadcaster = (*mockBroadcaster)(nil)
func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service { func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
ctx := context.Background() ctx := context.Background()
var web3Service *execution.Service var web3Service *execution.Service
@@ -141,6 +100,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
WithAttestationService(attService), WithAttestationService(attService),
WithStateGen(stateGen), WithStateGen(stateGen),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()), WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
WithClockSynchronizer(startup.NewClockSynchronizer()),
} }
chainService, err := NewService(ctx, opts...) chainService, err := NewService(ctx, opts...)
@@ -157,12 +117,14 @@ func TestChainStartStop_Initialized(t *testing.T) {
chainService := setupBeaconChain(t, beaconDB) chainService := setupBeaconChain(t, beaconDB)
gt := time.Unix(23, 0)
genesisBlk := util.NewBeaconBlock() genesisBlk := util.NewBeaconBlock()
blkRoot, err := genesisBlk.Block.HashTreeRoot() blkRoot, err := genesisBlk.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, genesisBlk) util.SaveBlock(t, ctx, beaconDB, genesisBlk)
s, err := util.NewBeaconState() s, err := util.NewBeaconState()
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, s.SetGenesisTime(uint64(gt.Unix())))
require.NoError(t, s.SetSlot(1)) require.NoError(t, s.SetSlot(1))
require.NoError(t, beaconDB.SaveState(ctx, s, blkRoot)) require.NoError(t, beaconDB.SaveState(ctx, s, blkRoot))
require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, blkRoot)) require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, blkRoot))
@@ -192,12 +154,14 @@ func TestChainStartStop_GenesisZeroHashes(t *testing.T) {
chainService := setupBeaconChain(t, beaconDB) chainService := setupBeaconChain(t, beaconDB)
gt := time.Unix(23, 0)
genesisBlk := util.NewBeaconBlock() genesisBlk := util.NewBeaconBlock()
blkRoot, err := genesisBlk.Block.HashTreeRoot() blkRoot, err := genesisBlk.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
wsb := util.SaveBlock(t, ctx, beaconDB, genesisBlk) wsb := util.SaveBlock(t, ctx, beaconDB, genesisBlk)
s, err := util.NewBeaconState() s, err := util.NewBeaconState()
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, s.SetGenesisTime(uint64(gt.Unix())))
require.NoError(t, beaconDB.SaveState(ctx, s, blkRoot)) require.NoError(t, beaconDB.SaveState(ctx, s, blkRoot))
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, blkRoot)) require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, blkRoot))
require.NoError(t, beaconDB.SaveBlock(ctx, wsb)) require.NoError(t, beaconDB.SaveBlock(ctx, wsb))
@@ -264,12 +228,14 @@ func TestChainService_CorrectGenesisRoots(t *testing.T) {
chainService := setupBeaconChain(t, beaconDB) chainService := setupBeaconChain(t, beaconDB)
gt := time.Unix(23, 0)
genesisBlk := util.NewBeaconBlock() genesisBlk := util.NewBeaconBlock()
blkRoot, err := genesisBlk.Block.HashTreeRoot() blkRoot, err := genesisBlk.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
util.SaveBlock(t, ctx, beaconDB, genesisBlk) util.SaveBlock(t, ctx, beaconDB, genesisBlk)
s, err := util.NewBeaconState() s, err := util.NewBeaconState()
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, s.SetGenesisTime(uint64(gt.Unix())))
require.NoError(t, s.SetSlot(0)) require.NoError(t, s.SetSlot(0))
require.NoError(t, beaconDB.SaveState(ctx, s, blkRoot)) require.NoError(t, beaconDB.SaveState(ctx, s, blkRoot))
require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, blkRoot)) require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, blkRoot))
@@ -290,14 +256,9 @@ func TestChainService_CorrectGenesisRoots(t *testing.T) {
} }
func TestChainService_InitializeChainInfo(t *testing.T) { func TestChainService_InitializeChainInfo(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlock() genesis := util.NewBeaconBlock()
genesisRoot, err := genesis.Block.HashTreeRoot() genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot))
util.SaveBlock(t, ctx, beaconDB, genesis)
finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1 finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1
headBlock := util.NewBeaconBlock() headBlock := util.NewBeaconBlock()
@@ -309,23 +270,18 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
require.NoError(t, headState.SetGenesisValidatorsRoot(params.BeaconConfig().ZeroHash[:])) require.NoError(t, headState.SetGenesisValidatorsRoot(params.BeaconConfig().ZeroHash[:]))
headRoot, err := headBlock.Block.HashTreeRoot() headRoot, err := headBlock.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
c, tr := minimalTestService(t, WithFinalizedStateAtStartUp(headState))
ctx, beaconDB, stateGen := tr.ctx, tr.db, tr.sg
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot))
util.SaveBlock(t, ctx, beaconDB, genesis)
require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot)) require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot))
require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot)) require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot))
util.SaveBlock(t, ctx, beaconDB, headBlock) util.SaveBlock(t, ctx, beaconDB, headBlock)
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]})) require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]}))
attSrv, err := attestations.NewService(ctx, &attestations.Config{})
require.NoError(t, err)
fc := doublylinkedtree.New()
stateGen := stategen.New(beaconDB, fc)
c, err := NewService(ctx,
WithForkChoiceStore(fc),
WithDatabase(beaconDB),
WithStateGen(stateGen),
WithAttestationService(attSrv),
WithStateNotifier(&mock.MockStateNotifier{}),
WithFinalizedStateAtStartUp(headState))
require.NoError(t, err)
require.NoError(t, stateGen.SaveState(ctx, headRoot, headState)) require.NoError(t, stateGen.SaveState(ctx, headRoot, headState))
require.NoError(t, c.StartFromSavedState(headState)) require.NoError(t, c.StartFromSavedState(headState))
headBlk, err := c.HeadBlock(ctx) headBlk, err := c.HeadBlock(ctx)
require.NoError(t, err) require.NoError(t, err)
@@ -345,14 +301,9 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
} }
func TestChainService_InitializeChainInfo_SetHeadAtGenesis(t *testing.T) { func TestChainService_InitializeChainInfo_SetHeadAtGenesis(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlock() genesis := util.NewBeaconBlock()
genesisRoot, err := genesis.Block.HashTreeRoot() genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot))
util.SaveBlock(t, ctx, beaconDB, genesis)
finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1 finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1
headBlock := util.NewBeaconBlock() headBlock := util.NewBeaconBlock()
@@ -364,27 +315,21 @@ func TestChainService_InitializeChainInfo_SetHeadAtGenesis(t *testing.T) {
require.NoError(t, headState.SetGenesisValidatorsRoot(params.BeaconConfig().ZeroHash[:])) require.NoError(t, headState.SetGenesisValidatorsRoot(params.BeaconConfig().ZeroHash[:]))
headRoot, err := headBlock.Block.HashTreeRoot() headRoot, err := headBlock.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot))
c, tr := minimalTestService(t, WithFinalizedStateAtStartUp(headState))
ctx, beaconDB := tr.ctx, tr.db
util.SaveBlock(t, ctx, beaconDB, genesis)
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot))
require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot)) require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot))
require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot))
util.SaveBlock(t, ctx, beaconDB, headBlock) util.SaveBlock(t, ctx, beaconDB, headBlock)
attSrv, err := attestations.NewService(ctx, &attestations.Config{})
require.NoError(t, err)
ss := &ethpb.StateSummary{ ss := &ethpb.StateSummary{
Slot: finalizedSlot, Slot: finalizedSlot,
Root: headRoot[:], Root: headRoot[:],
} }
require.NoError(t, beaconDB.SaveStateSummary(ctx, ss)) require.NoError(t, beaconDB.SaveStateSummary(ctx, ss))
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Root: headRoot[:], Epoch: slots.ToEpoch(finalizedSlot)})) require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Root: headRoot[:], Epoch: slots.ToEpoch(finalizedSlot)}))
fc := doublylinkedtree.New()
stateGen := stategen.New(beaconDB, fc)
c, err := NewService(ctx,
WithForkChoiceStore(fc),
WithDatabase(beaconDB),
WithStateGen(stateGen),
WithAttestationService(attSrv),
WithStateNotifier(&mock.MockStateNotifier{}),
WithFinalizedStateAtStartUp(headState))
require.NoError(t, err)
require.NoError(t, c.StartFromSavedState(headState)) require.NoError(t, c.StartFromSavedState(headState))
s, err := c.HeadState(ctx) s, err := c.HeadState(ctx)
@@ -460,17 +405,21 @@ func TestServiceStop_SaveCachedBlocks(t *testing.T) {
} }
func TestProcessChainStartTime_ReceivedFeed(t *testing.T) { func TestProcessChainStartTime_ReceivedFeed(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t) beaconDB := testDB.SetupDB(t)
service := setupBeaconChain(t, beaconDB) service := setupBeaconChain(t, beaconDB)
stateChannel := make(chan *feed.Event, 1) mgs := &MockClockSetter{}
stateSub := service.cfg.StateNotifier.StateFeed().Subscribe(stateChannel) service.clockSetter = mgs
defer stateSub.Unsubscribe() gt := time.Now()
service.onExecutionChainStart(context.Background(), time.Now()) service.onExecutionChainStart(context.Background(), gt)
gs, err := beaconDB.GenesisState(ctx)
stateEvent := <-stateChannel require.NoError(t, err)
require.Equal(t, int(stateEvent.Type), statefeed.Initialized) require.NotEqual(t, nil, gs)
_, ok := stateEvent.Data.(*statefeed.InitializedData) require.Equal(t, 32, len(gs.GenesisValidatorsRoot()))
require.Equal(t, true, ok) var zero [32]byte
require.DeepNotEqual(t, gs.GenesisValidatorsRoot(), zero[:])
require.Equal(t, gt, mgs.G.GenesisTime())
require.Equal(t, bytesutil.ToBytes32(gs.GenesisValidatorsRoot()), mgs.G.GenesisValidatorsRoot())
} }
func BenchmarkHasBlockDB(b *testing.B) { func BenchmarkHasBlockDB(b *testing.B) {
@@ -519,15 +468,10 @@ func TestChainService_EverythingOptimistic(t *testing.T) {
EnableStartOptimistic: true, EnableStartOptimistic: true,
}) })
defer resetFn() defer resetFn()
beaconDB := testDB.SetupDB(t)
ctx := context.Background()
genesis := util.NewBeaconBlock() genesis := util.NewBeaconBlock()
genesisRoot, err := genesis.Block.HashTreeRoot() genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot))
util.SaveBlock(t, ctx, beaconDB, genesis)
finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1 finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1
headBlock := util.NewBeaconBlock() headBlock := util.NewBeaconBlock()
headBlock.Block.Slot = finalizedSlot headBlock.Block.Slot = finalizedSlot
@@ -538,21 +482,17 @@ func TestChainService_EverythingOptimistic(t *testing.T) {
require.NoError(t, headState.SetGenesisValidatorsRoot(params.BeaconConfig().ZeroHash[:])) require.NoError(t, headState.SetGenesisValidatorsRoot(params.BeaconConfig().ZeroHash[:]))
headRoot, err := headBlock.Block.HashTreeRoot() headRoot, err := headBlock.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
c, tr := minimalTestService(t, WithFinalizedStateAtStartUp(headState))
ctx, beaconDB, stateGen := tr.ctx, tr.db, tr.sg
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, genesisRoot))
util.SaveBlock(t, ctx, beaconDB, genesis)
require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot)) require.NoError(t, beaconDB.SaveState(ctx, headState, headRoot))
require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot)) require.NoError(t, beaconDB.SaveState(ctx, headState, genesisRoot))
util.SaveBlock(t, ctx, beaconDB, headBlock) util.SaveBlock(t, ctx, beaconDB, headBlock)
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]})) require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]}))
attSrv, err := attestations.NewService(ctx, &attestations.Config{})
require.NoError(t, err)
fc := doublylinkedtree.New()
stateGen := stategen.New(beaconDB, fc)
c, err := NewService(ctx,
WithForkChoiceStore(fc),
WithDatabase(beaconDB),
WithStateGen(stateGen),
WithAttestationService(attSrv),
WithStateNotifier(&mock.MockStateNotifier{}),
WithFinalizedStateAtStartUp(headState))
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, stateGen.SaveState(ctx, headRoot, headState)) require.NoError(t, stateGen.SaveState(ctx, headRoot, headState))
require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, &ethpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]})) require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, &ethpb.Checkpoint{Epoch: slots.ToEpoch(finalizedSlot), Root: headRoot[:]}))
@@ -562,3 +502,19 @@ func TestChainService_EverythingOptimistic(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, true, op) require.Equal(t, true, op)
} }
// MockClockSetter satisfies the ClockSetter interface for testing the conditions where blockchain.Service should
// call SetGenesis.
type MockClockSetter struct {
G *startup.Clock
Err error
}
var _ startup.ClockSetter = &MockClockSetter{}
// SetClock satisfies the ClockSetter interface.
// The value is written to an exported field 'G' so that it can be accessed in tests.
func (s *MockClockSetter) SetClock(g *startup.Clock) error {
s.G = g
return s.Err
}

View File

@@ -0,0 +1,115 @@
package blockchain
import (
"context"
"testing"
"github.com/prysmaticlabs/prysm/v4/async/event"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache/depositcache"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
testDB "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/blstoexec"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"google.golang.org/protobuf/proto"
)
type mockBeaconNode struct {
stateFeed *event.Feed
}
// StateFeed mocks the same method in the beacon node.
func (mbn *mockBeaconNode) StateFeed() *event.Feed {
if mbn.stateFeed == nil {
mbn.stateFeed = new(event.Feed)
}
return mbn.stateFeed
}
type mockBroadcaster struct {
broadcastCalled bool
}
func (mb *mockBroadcaster) Broadcast(_ context.Context, _ proto.Message) error {
mb.broadcastCalled = true
return nil
}
func (mb *mockBroadcaster) BroadcastAttestation(_ context.Context, _ uint64, _ *ethpb.Attestation) error {
mb.broadcastCalled = true
return nil
}
func (mb *mockBroadcaster) BroadcastSyncCommitteeMessage(_ context.Context, _ uint64, _ *ethpb.SyncCommitteeMessage) error {
mb.broadcastCalled = true
return nil
}
func (mb *mockBroadcaster) BroadcastBLSChanges(_ context.Context, _ []*ethpb.SignedBLSToExecutionChange) {
}
var _ p2p.Broadcaster = (*mockBroadcaster)(nil)
type testServiceRequirements struct {
ctx context.Context
db db.Database
fcs forkchoice.ForkChoicer
sg *stategen.State
notif statefeed.Notifier
cs *startup.ClockSynchronizer
attPool attestations.Pool
attSrv *attestations.Service
blsPool *blstoexec.Pool
dc *depositcache.DepositCache
}
func minimalTestService(t *testing.T, opts ...Option) (*Service, *testServiceRequirements) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
fcs := doublylinkedtree.New()
sg := stategen.New(beaconDB, fcs)
notif := &mockBeaconNode{}
fcs.SetBalancesByRooter(sg.ActiveNonSlashedBalancesByRoot)
cs := startup.NewClockSynchronizer()
attPool := attestations.NewPool()
attSrv, err := attestations.NewService(ctx, &attestations.Config{Pool: attPool})
require.NoError(t, err)
blsPool := blstoexec.NewPool()
dc, err := depositcache.New()
require.NoError(t, err)
req := &testServiceRequirements{
ctx: ctx,
db: beaconDB,
fcs: fcs,
sg: sg,
notif: notif,
cs: cs,
attPool: attPool,
attSrv: attSrv,
blsPool: blsPool,
dc: dc,
}
defOpts := []Option{WithDatabase(req.db),
WithStateNotifier(req.notif),
WithStateGen(req.sg),
WithForkChoiceStore(req.fcs),
WithClockSynchronizer(req.cs),
WithAttestationPool(req.attPool),
WithAttestationService(req.attSrv),
WithBLSToExecPool(req.blsPool),
WithDepositCache(dc),
}
// append the variadic opts so they override the defaults by being processed afterwards
opts = append(defOpts, opts...)
s, err := NewService(req.ctx, opts...)
require.NoError(t, err)
return s, req
}

View File

@@ -15,10 +15,10 @@ const (
BlockProcessed = iota + 1 BlockProcessed = iota + 1
// ChainStarted is sent when enough validators are active to start proposing blocks. // ChainStarted is sent when enough validators are active to start proposing blocks.
ChainStarted ChainStarted
// Initialized is sent when the internal beacon node's state is ready to be accessed. // deprecated: Initialized is sent when the internal beacon node's state is ready to be accessed.
Initialized _
// Synced is sent when the beacon node has completed syncing and is ready to participate in the network. // deprecated: Synced is sent when the beacon node has completed syncing and is ready to participate in the network.
Synced _
// Reorg is an event sent when the new head is not a descendant of the previous head. // Reorg is an event sent when the new head is not a descendant of the previous head.
Reorg Reorg
// FinalizedCheckpoint event. // FinalizedCheckpoint event.

View File

@@ -48,6 +48,7 @@ go_test(
"attestation_test.go", "attestation_test.go",
"beacon_committee_test.go", "beacon_committee_test.go",
"block_test.go", "block_test.go",
"main_test.go",
"randao_test.go", "randao_test.go",
"rewards_penalties_test.go", "rewards_penalties_test.go",
"shuffle_test.go", "shuffle_test.go",

View File

@@ -0,0 +1,13 @@
package helpers
import (
"os"
"testing"
)
// run ClearCache before each test to prevent cross-test side effects
func TestMain(m *testing.M) {
ClearCache()
code := m.Run()
os.Exit(code)
}

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"testing" "testing"
"time"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/altair" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/altair"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -241,10 +240,44 @@ func TestProcessBlock_AllEventsTrackedVals(t *testing.T) {
func TestLogAggregatedPerformance(t *testing.T) { func TestLogAggregatedPerformance(t *testing.T) {
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
s := setupService(t) latestPerformance := map[primitives.ValidatorIndex]ValidatorLatestPerformance{
1: {
balance: 32000000000,
},
2: {
balance: 32000000000,
},
12: {
balance: 31900000000,
},
15: {
balance: 31900000000,
},
}
aggregatedPerformance := map[primitives.ValidatorIndex]ValidatorAggregatedPerformance{
1: {
startEpoch: 0,
startBalance: 31700000000,
totalAttestedCount: 12,
totalRequestedCount: 15,
totalDistance: 14,
totalCorrectHead: 8,
totalCorrectSource: 11,
totalCorrectTarget: 12,
totalProposedCount: 1,
totalSyncCommitteeContributions: 0,
totalSyncCommitteeAggregations: 0,
},
2: {},
12: {},
15: {},
}
s := &Service{
latestPerformance: latestPerformance,
aggregatedPerformance: aggregatedPerformance,
}
s.logAggregatedPerformance() s.logAggregatedPerformance()
time.Sleep(3000 * time.Millisecond)
wanted := "\"Aggregated performance since launch\" AttestationInclusion=\"80.00%\"" + wanted := "\"Aggregated performance since launch\" AttestationInclusion=\"80.00%\"" +
" AverageInclusionDistance=1.2 BalanceChangePct=\"0.95%\" CorrectlyVotedHeadPct=\"66.67%\" " + " AverageInclusionDistance=1.2 BalanceChangePct=\"0.95%\" CorrectlyVotedHeadPct=\"66.67%\" " +
"CorrectlyVotedSourcePct=\"91.67%\" CorrectlyVotedTargetPct=\"100.00%\" StartBalance=31700000000 " + "CorrectlyVotedSourcePct=\"91.67%\" CorrectlyVotedTargetPct=\"100.00%\" StartBalance=31700000000 " +

View File

@@ -19,13 +19,8 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var ( // Error when the context is closed while waiting for sync.
// Error when event feed data is not statefeed.SyncedData. var errContextClosedWhileWaiting = errors.New("context closed while waiting for beacon to sync to latest Head")
errNotSyncedData = errors.New("event feed data is not of type *statefeed.SyncedData")
// Error when the context is closed while waiting for sync.
errContextClosedWhileWaiting = errors.New("context closed while waiting for beacon to sync to latest Head")
)
// ValidatorLatestPerformance keeps track of the latest participation of the validator // ValidatorLatestPerformance keeps track of the latest participation of the validator
type ValidatorLatestPerformance struct { type ValidatorLatestPerformance struct {
@@ -63,6 +58,7 @@ type ValidatorMonitorConfig struct {
AttestationNotifier operation.Notifier AttestationNotifier operation.Notifier
HeadFetcher blockchain.HeadFetcher HeadFetcher blockchain.HeadFetcher
StateGen stategen.StateManager StateGen stategen.StateManager
InitialSyncComplete chan struct{}
} }
// Service is the main structure that tracks validators and reports logs and // Service is the main structure that tracks validators and reports logs and
@@ -131,7 +127,7 @@ func (s *Service) run(stateChannel chan *feed.Event, stateSub event.Subscription
return return
} }
if err := s.waitForSync(stateChannel, stateSub); err != nil { if err := s.waitForSync(s.config.InitialSyncComplete); err != nil {
log.WithError(err) log.WithError(err)
return return
} }
@@ -197,24 +193,13 @@ func (s *Service) Stop() error {
} }
// waitForSync waits until the beacon node is synced to the latest head. // waitForSync waits until the beacon node is synced to the latest head.
func (s *Service) waitForSync(stateChannel chan *feed.Event, stateSub event.Subscription) error { func (s *Service) waitForSync(syncChan chan struct{}) error {
for { select {
select { case <-syncChan:
case e := <-stateChannel: return nil
if e.Type == statefeed.Synced { case <-s.ctx.Done():
_, ok := e.Data.(*statefeed.SyncedData) log.Debug("Context closed, exiting goroutine")
if !ok { return errContextClosedWhileWaiting
return errNotSyncedData
}
return nil
}
case <-s.ctx.Done():
log.Debug("Context closed, exiting goroutine")
return errContextClosedWhileWaiting
case err := <-stateSub.Err():
log.WithError(err).Error("Could not subscribe to state notifier")
return err
}
} }
} }

View File

@@ -93,6 +93,7 @@ func setupService(t *testing.T) *Service {
StateNotifier: chainService.StateNotifier(), StateNotifier: chainService.StateNotifier(),
HeadFetcher: chainService, HeadFetcher: chainService,
AttestationNotifier: chainService.OperationNotifier(), AttestationNotifier: chainService.OperationNotifier(),
InitialSyncComplete: make(chan struct{}),
}, },
ctx: context.Background(), ctx: context.Background(),
@@ -140,34 +141,9 @@ func TestNewService(t *testing.T) {
func TestStart(t *testing.T) { func TestStart(t *testing.T) {
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
s := setupService(t) s := setupService(t)
stateChannel := make(chan *feed.Event, 1)
stateSub := s.config.StateNotifier.StateFeed().Subscribe(stateChannel)
defer stateSub.Unsubscribe()
wg := &sync.WaitGroup{}
wg.Add(1)
s.Start() s.Start()
close(s.config.InitialSyncComplete)
go func() {
select {
case stateEvent := <-stateChannel:
if stateEvent.Type == statefeed.Synced {
_, ok := stateEvent.Data.(*statefeed.SyncedData)
require.Equal(t, true, ok, "Event feed data is not type *statefeed.SyncedData")
}
case <-s.ctx.Done():
}
wg.Done()
}()
for sent := 0; sent == 0; {
sent = s.config.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Synced,
Data: &statefeed.SyncedData{
StartTime: time.Now(),
},
})
}
// wait for Logrus // wait for Logrus
time.Sleep(1000 * time.Millisecond) time.Sleep(1000 * time.Millisecond)
@@ -267,26 +243,29 @@ func TestMonitorRoutine(t *testing.T) {
} }
func TestWaitForSync(t *testing.T) { func TestWaitForSync(t *testing.T) {
s := setupService(t) ctx, cancel := context.WithCancel(context.Background())
stateChannel := make(chan *feed.Event, 1) s := &Service{ctx: ctx}
stateSub := s.config.StateNotifier.StateFeed().Subscribe(stateChannel) syncChan := make(chan struct{})
defer stateSub.Unsubscribe()
wg := &sync.WaitGroup{}
wg.Add(1)
go func() { go func() {
err := s.waitForSync(stateChannel, stateSub) // Failsafe to make sure tests never get deadlocked; we should always go through the happy path before 500ms.
require.NoError(t, err) // Otherwise, the NoError assertion below will fail.
wg.Done() time.Sleep(500 * time.Millisecond)
cancel()
}() }()
go func() {
close(syncChan)
}()
require.NoError(t, s.waitForSync(syncChan))
}
stateChannel <- &feed.Event{ func TestWaitForSyncCanceled(t *testing.T) {
Type: statefeed.Synced, ctx, cancel := context.WithCancel(context.Background())
Data: &statefeed.SyncedData{ s := &Service{ctx: ctx}
StartTime: time.Now(), syncChan := make(chan struct{})
},
} cancel()
require.ErrorIs(t, s.waitForSync(syncChan), errContextClosedWhileWaiting)
} }
func TestRun(t *testing.T) { func TestRun(t *testing.T) {
@@ -295,21 +274,11 @@ func TestRun(t *testing.T) {
stateChannel := make(chan *feed.Event, 1) stateChannel := make(chan *feed.Event, 1)
stateSub := s.config.StateNotifier.StateFeed().Subscribe(stateChannel) stateSub := s.config.StateNotifier.StateFeed().Subscribe(stateChannel)
wg := &sync.WaitGroup{}
wg.Add(1)
go func() { go func() {
s.run(stateChannel, stateSub) s.run(stateChannel, stateSub)
wg.Done()
}() }()
close(s.config.InitialSyncComplete)
stateChannel <- &feed.Event{ time.Sleep(100 * time.Millisecond)
Type: statefeed.Synced,
Data: &statefeed.SyncedData{
StartTime: time.Now(),
},
}
//wait for Logrus
time.Sleep(1000 * time.Millisecond)
require.LogsContain(t, hook, "Synced to head epoch, starting reporting performance") require.LogsContain(t, hook, "Synced to head epoch, starting reporting performance")
} }

View File

@@ -40,6 +40,7 @@ go_library(
"//beacon-chain/rpc:go_default_library", "//beacon-chain/rpc:go_default_library",
"//beacon-chain/rpc/apimiddleware:go_default_library", "//beacon-chain/rpc/apimiddleware:go_default_library",
"//beacon-chain/slasher:go_default_library", "//beacon-chain/slasher:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library", "//beacon-chain/sync:go_default_library",

View File

@@ -42,6 +42,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc" "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/apimiddleware" "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/apimiddleware"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher" "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
regularsync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" regularsync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
@@ -107,6 +108,8 @@ type BeaconNode struct {
GenesisInitializer genesis.Initializer GenesisInitializer genesis.Initializer
CheckpointInitializer checkpoint.Initializer CheckpointInitializer checkpoint.Initializer
forkChoicer forkchoice.ForkChoicer forkChoicer forkchoice.ForkChoicer
clockWaiter startup.ClockWaiter
initialSyncComplete chan struct{}
} }
// New creates a new node instance, sets up configuration options, and registers // New creates a new node instance, sets up configuration options, and registers
@@ -177,12 +180,16 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
proposerIdsCache: cache.NewProposerPayloadIDsCache(), proposerIdsCache: cache.NewProposerPayloadIDsCache(),
} }
beacon.initialSyncComplete = make(chan struct{})
for _, opt := range opts { for _, opt := range opts {
if err := opt(beacon); err != nil { if err := opt(beacon); err != nil {
return nil, err return nil, err
} }
} }
synchronizer := startup.NewClockSynchronizer()
beacon.clockWaiter = synchronizer
beacon.forkChoicer = doublylinkedtree.New() beacon.forkChoicer = doublylinkedtree.New()
depositAddress, err := execution.DepositContractAddress() depositAddress, err := execution.DepositContractAddress()
if err != nil { if err != nil {
@@ -229,17 +236,17 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
} }
log.Debugln("Registering Blockchain Service") log.Debugln("Registering Blockchain Service")
if err := beacon.registerBlockchainService(beacon.forkChoicer); err != nil { if err := beacon.registerBlockchainService(beacon.forkChoicer, synchronizer); err != nil {
return nil, err return nil, err
} }
log.Debugln("Registering Initial Sync Service") log.Debugln("Registering Initial Sync Service")
if err := beacon.registerInitialSyncService(); err != nil { if err := beacon.registerInitialSyncService(beacon.initialSyncComplete); err != nil {
return nil, err return nil, err
} }
log.Debugln("Registering Sync Service") log.Debugln("Registering Sync Service")
if err := beacon.registerSyncService(); err != nil { if err := beacon.registerSyncService(beacon.initialSyncComplete); err != nil {
return nil, err return nil, err
} }
@@ -265,7 +272,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
} }
log.Debugln("Registering Validator Monitoring Service") log.Debugln("Registering Validator Monitoring Service")
if err := beacon.registerValidatorMonitorService(); err != nil { if err := beacon.registerValidatorMonitorService(beacon.initialSyncComplete); err != nil {
return nil, err return nil, err
} }
@@ -548,6 +555,7 @@ func (b *BeaconNode) registerP2P(cliCtx *cli.Context) error {
EnableUPnP: cliCtx.Bool(cmd.EnableUPnPFlag.Name), EnableUPnP: cliCtx.Bool(cmd.EnableUPnPFlag.Name),
StateNotifier: b, StateNotifier: b,
DB: b.db, DB: b.db,
ClockWaiter: b.clockWaiter,
}) })
if err != nil { if err != nil {
return err return err
@@ -581,7 +589,7 @@ func (b *BeaconNode) registerAttestationPool() error {
return b.services.RegisterService(s) return b.services.RegisterService(s)
} }
func (b *BeaconNode) registerBlockchainService(fc forkchoice.ForkChoicer) error { func (b *BeaconNode) registerBlockchainService(fc forkchoice.ForkChoicer, gs *startup.ClockSynchronizer) error {
var web3Service *execution.Service var web3Service *execution.Service
if err := b.services.FetchService(&web3Service); err != nil { if err := b.services.FetchService(&web3Service); err != nil {
return err return err
@@ -611,6 +619,7 @@ func (b *BeaconNode) registerBlockchainService(fc forkchoice.ForkChoicer) error
blockchain.WithSlasherAttestationsFeed(b.slasherAttestationsFeed), blockchain.WithSlasherAttestationsFeed(b.slasherAttestationsFeed),
blockchain.WithFinalizedStateAtStartUp(b.finalizedStateAtStartUp), blockchain.WithFinalizedStateAtStartUp(b.finalizedStateAtStartUp),
blockchain.WithProposerIdsCache(b.proposerIdsCache), blockchain.WithProposerIdsCache(b.proposerIdsCache),
blockchain.WithClockSynchronizer(gs),
) )
blockchainService, err := blockchain.NewService(b.ctx, opts...) blockchainService, err := blockchain.NewService(b.ctx, opts...)
@@ -652,7 +661,7 @@ func (b *BeaconNode) registerPOWChainService() error {
return b.services.RegisterService(web3Service) return b.services.RegisterService(web3Service)
} }
func (b *BeaconNode) registerSyncService() error { func (b *BeaconNode) registerSyncService(initialSyncComplete chan struct{}) error {
var web3Service *execution.Service var web3Service *execution.Service
if err := b.services.FetchService(&web3Service); err != nil { if err := b.services.FetchService(&web3Service); err != nil {
return err return err
@@ -674,7 +683,6 @@ func (b *BeaconNode) registerSyncService() error {
regularsync.WithP2P(b.fetchP2P()), regularsync.WithP2P(b.fetchP2P()),
regularsync.WithChainService(chainService), regularsync.WithChainService(chainService),
regularsync.WithInitialSync(initSync), regularsync.WithInitialSync(initSync),
regularsync.WithStateNotifier(b),
regularsync.WithBlockNotifier(b), regularsync.WithBlockNotifier(b),
regularsync.WithAttestationNotifier(b), regularsync.WithAttestationNotifier(b),
regularsync.WithOperationNotifier(b), regularsync.WithOperationNotifier(b),
@@ -687,22 +695,26 @@ func (b *BeaconNode) registerSyncService() error {
regularsync.WithSlasherAttestationsFeed(b.slasherAttestationsFeed), regularsync.WithSlasherAttestationsFeed(b.slasherAttestationsFeed),
regularsync.WithSlasherBlockHeadersFeed(b.slasherBlockHeadersFeed), regularsync.WithSlasherBlockHeadersFeed(b.slasherBlockHeadersFeed),
regularsync.WithExecutionPayloadReconstructor(web3Service), regularsync.WithExecutionPayloadReconstructor(web3Service),
regularsync.WithClockWaiter(b.clockWaiter),
regularsync.WithInitialSyncComplete(initialSyncComplete),
) )
return b.services.RegisterService(rs) return b.services.RegisterService(rs)
} }
func (b *BeaconNode) registerInitialSyncService() error { func (b *BeaconNode) registerInitialSyncService(complete chan struct{}) error {
var chainService *blockchain.Service var chainService *blockchain.Service
if err := b.services.FetchService(&chainService); err != nil { if err := b.services.FetchService(&chainService); err != nil {
return err return err
} }
is := initialsync.NewService(b.ctx, &initialsync.Config{ is := initialsync.NewService(b.ctx, &initialsync.Config{
DB: b.db, DB: b.db,
Chain: chainService, Chain: chainService,
P2P: b.fetchP2P(), P2P: b.fetchP2P(),
StateNotifier: b, StateNotifier: b,
BlockNotifier: b, BlockNotifier: b,
ClockWaiter: b.clockWaiter,
InitialSyncComplete: complete,
}) })
return b.services.RegisterService(is) return b.services.RegisterService(is)
} }
@@ -834,6 +846,7 @@ func (b *BeaconNode) registerRPCService(router *mux.Router) error {
ProposerIdsCache: b.proposerIdsCache, ProposerIdsCache: b.proposerIdsCache,
BlockBuilder: b.fetchBuilderService(), BlockBuilder: b.fetchBuilderService(),
Router: router, Router: router,
ClockWaiter: b.clockWaiter,
}) })
return b.services.RegisterService(rpcService) return b.services.RegisterService(rpcService)
@@ -934,7 +947,7 @@ func (b *BeaconNode) registerDeterminsticGenesisService() error {
return nil return nil
} }
func (b *BeaconNode) registerValidatorMonitorService() error { func (b *BeaconNode) registerValidatorMonitorService(initialSyncComplete chan struct{}) error {
cliSlice := b.cliCtx.IntSlice(cmd.ValidatorMonitorIndicesFlag.Name) cliSlice := b.cliCtx.IntSlice(cmd.ValidatorMonitorIndicesFlag.Name)
if cliSlice == nil { if cliSlice == nil {
return nil return nil
@@ -953,6 +966,7 @@ func (b *BeaconNode) registerValidatorMonitorService() error {
AttestationNotifier: b, AttestationNotifier: b,
StateGen: b.stateGen, StateGen: b.stateGen,
HeadFetcher: chainService, HeadFetcher: chainService,
InitialSyncComplete: initialSyncComplete,
} }
svc, err := monitor.NewService(b.ctx, monitorConfig, tracked) svc, err := monitor.NewService(b.ctx, monitorConfig, tracked)
if err != nil { if err != nil {

View File

@@ -164,7 +164,7 @@ func TestMonitor_RegisteredCorrectly(t *testing.T) {
require.NoError(t, cliCtx.Set(cmd.ValidatorMonitorIndicesFlag.Name, "1,2")) require.NoError(t, cliCtx.Set(cmd.ValidatorMonitorIndicesFlag.Name, "1,2"))
n := &BeaconNode{ctx: context.Background(), cliCtx: cliCtx, services: runtime.NewServiceRegistry()} n := &BeaconNode{ctx: context.Background(), cliCtx: cliCtx, services: runtime.NewServiceRegistry()}
require.NoError(t, n.services.RegisterService(&blockchain.Service{})) require.NoError(t, n.services.RegisterService(&blockchain.Service{}))
require.NoError(t, n.registerValidatorMonitorService()) require.NoError(t, n.registerValidatorMonitorService(make(chan struct{})))
var mService *monitor.Service var mService *monitor.Service
require.NoError(t, n.services.FetchService(&mService)) require.NoError(t, n.services.FetchService(&mService))

View File

@@ -44,7 +44,6 @@ go_library(
"//async:go_default_library", "//async:go_default_library",
"//beacon-chain/cache:go_default_library", "//beacon-chain/cache:go_default_library",
"//beacon-chain/core/altair:go_default_library", "//beacon-chain/core/altair:go_default_library",
"//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/state:go_default_library", "//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/time:go_default_library", "//beacon-chain/core/time:go_default_library",
@@ -54,6 +53,7 @@ go_library(
"//beacon-chain/p2p/peers/peerdata:go_default_library", "//beacon-chain/p2p/peers/peerdata:go_default_library",
"//beacon-chain/p2p/peers/scorers:go_default_library", "//beacon-chain/p2p/peers/scorers:go_default_library",
"//beacon-chain/p2p/types:go_default_library", "//beacon-chain/p2p/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//cmd/beacon-chain/flags:go_default_library", "//cmd/beacon-chain/flags:go_default_library",
"//config/params:go_default_library", "//config/params:go_default_library",
"//consensus-types/primitives:go_default_library", "//consensus-types/primitives:go_default_library",
@@ -132,11 +132,8 @@ go_test(
flaky = True, flaky = True,
tags = ["requires-network"], tags = ["requires-network"],
deps = [ deps = [
"//async/event:go_default_library",
"//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/blockchain/testing:go_default_library",
"//beacon-chain/cache:go_default_library", "//beacon-chain/cache:go_default_library",
"//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/signing:go_default_library", "//beacon-chain/core/signing:go_default_library",
"//beacon-chain/db/testing:go_default_library", "//beacon-chain/db/testing:go_default_library",
@@ -146,6 +143,7 @@ go_test(
"//beacon-chain/p2p/peers/scorers:go_default_library", "//beacon-chain/p2p/peers/scorers:go_default_library",
"//beacon-chain/p2p/testing:go_default_library", "//beacon-chain/p2p/testing:go_default_library",
"//beacon-chain/p2p/types:go_default_library", "//beacon-chain/p2p/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//cmd/beacon-chain/flags:go_default_library", "//cmd/beacon-chain/flags:go_default_library",
"//config/fieldparams:go_default_library", "//config/fieldparams:go_default_library",
"//config/params:go_default_library", "//config/params:go_default_library",

View File

@@ -3,6 +3,7 @@ package p2p
import ( import (
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state" statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
) )
// Config for the p2p service. These parameters are set from application level flags // Config for the p2p service. These parameters are set from application level flags
@@ -28,4 +29,5 @@ type Config struct {
DenyListCIDR []string DenyListCIDR []string
StateNotifier statefeed.Notifier StateNotifier statefeed.Notifier
DB db.ReadOnlyDatabase DB db.ReadOnlyDatabase
ClockWaiter startup.ClockWaiter
} }

View File

@@ -22,12 +22,11 @@ import (
"github.com/prysmaticlabs/go-bitfield" "github.com/prysmaticlabs/go-bitfield"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers/peerdata" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers/peerdata"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers/scorers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers/scorers"
testp2p "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" testp2p "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/wrapper" "github.com/prysmaticlabs/prysm/v4/consensus-types/wrapper"
leakybucket "github.com/prysmaticlabs/prysm/v4/container/leaky-bucket" leakybucket "github.com/prysmaticlabs/prysm/v4/container/leaky-bucket"
@@ -169,8 +168,10 @@ func TestMultiAddrConversion_OK(t *testing.T) {
} }
func TestStaticPeering_PeersAreAdded(t *testing.T) { func TestStaticPeering_PeersAreAdded(t *testing.T) {
cs := startup.NewClockSynchronizer()
cfg := &Config{ cfg := &Config{
MaxPeers: 30, MaxPeers: 30,
ClockWaiter: cs,
} }
port := 6000 port := 6000
var staticPeers []string var staticPeers []string
@@ -204,16 +205,8 @@ func TestStaticPeering_PeersAreAdded(t *testing.T) {
<-exitRoutine <-exitRoutine
}() }()
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed). var vr [32]byte
for sent := 0; sent == 0; { require.NoError(t, cs.SetClock(startup.NewClock(time.Now(), vr)))
sent = s.stateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: time.Now(),
GenesisValidatorsRoot: make([]byte, 32),
},
})
}
time.Sleep(4 * time.Second) time.Sleep(4 * time.Second)
ps := s.host.Network().Peers() ps := s.host.Network().Peers()
assert.Equal(t, 5, len(ps), "Not all peers added to peerstore") assert.Equal(t, 5, len(ps), "Not all peers added to peerstore")

View File

@@ -125,7 +125,6 @@ func TestStartDiscv5_SameForkDigests_DifferentNextForkData(t *testing.T) {
cfg: &Config{UDPPort: uint(port)}, cfg: &Config{UDPPort: uint(port)},
genesisTime: genesisTime, genesisTime: genesisTime,
genesisValidatorsRoot: genesisValidatorsRoot, genesisValidatorsRoot: genesisValidatorsRoot,
stateNotifier: &mock.MockStateNotifier{},
} }
bootListener, err := s.createListener(ipAddr, pkey) bootListener, err := s.createListener(ipAddr, pkey)
require.NoError(t, err) require.NoError(t, err)
@@ -155,7 +154,6 @@ func TestStartDiscv5_SameForkDigests_DifferentNextForkData(t *testing.T) {
cfg: cfg, cfg: cfg,
genesisTime: genesisTime, genesisTime: genesisTime,
genesisValidatorsRoot: genesisValidatorsRoot, genesisValidatorsRoot: genesisValidatorsRoot,
stateNotifier: &mock.MockStateNotifier{},
} }
listener, err := s.startDiscoveryV5(ipAddr, pkey) listener, err := s.startDiscoveryV5(ipAddr, pkey)
assert.NoError(t, err, "Could not start discovery for node") assert.NoError(t, err, "Could not start discovery for node")

View File

@@ -9,10 +9,8 @@ import (
pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/network/forks" "github.com/prysmaticlabs/prysm/v4/network/forks"
@@ -337,28 +335,16 @@ func TestService_MonitorsStateForkUpdates(t *testing.T) {
params.SetupTestConfigCleanup(t) params.SetupTestConfigCleanup(t)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
notifier := &mock.MockStateNotifier{} cs := startup.NewClockSynchronizer()
s, err := NewService(ctx, &Config{ s, err := NewService(ctx, &Config{ClockWaiter: cs})
StateNotifier: notifier,
})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, false, s.isInitialized()) require.Equal(t, false, s.isInitialized())
go s.awaitStateInitialized() go s.awaitStateInitialized()
for n := 0; n == 0; { vr := bytesutil.ToBytes32(bytesutil.PadTo([]byte("genesis"), 32))
if ctx.Err() != nil { require.NoError(t, cs.SetClock(startup.NewClock(prysmTime.Now(), vr)))
t.Fatal(ctx.Err())
}
n = notifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: prysmTime.Now(),
GenesisValidatorsRoot: bytesutil.PadTo([]byte("genesis"), 32),
},
})
}
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)

View File

@@ -11,20 +11,23 @@ import (
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder"
testp2p "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" testp2p "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/testing/assert" "github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require" "github.com/prysmaticlabs/prysm/v4/testing/require"
) )
func TestService_PublishToTopicConcurrentMapWrite(t *testing.T) { func TestService_PublishToTopicConcurrentMapWrite(t *testing.T) {
cs := startup.NewClockSynchronizer()
s, err := NewService(context.Background(), &Config{ s, err := NewService(context.Background(), &Config{
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
ClockWaiter: cs,
}) })
require.NoError(t, err) require.NoError(t, err)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
go s.awaitStateInitialized() go s.awaitStateInitialized()
fd := initializeStateWithForkDigest(ctx, t, s.stateNotifier.StateFeed()) fd := initializeStateWithForkDigest(ctx, t, cs)
if !s.isInitialized() { if !s.isInitialized() {
t.Fatal("service was not initialized") t.Fatal("service was not initialized")

View File

@@ -20,8 +20,6 @@ import (
"github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/async" "github.com/prysmaticlabs/prysm/v4/async"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers/scorers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers/scorers"
@@ -77,7 +75,6 @@ type Service struct {
initializationLock sync.Mutex initializationLock sync.Mutex
dv5Listener Listener dv5Listener Listener
startupErr error startupErr error
stateNotifier statefeed.Notifier
ctx context.Context ctx context.Context
host host.Host host host.Host
genesisTime time.Time genesisTime time.Time
@@ -93,13 +90,12 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) {
_ = cancel // govet fix for lost cancel. Cancel is handled in service.Stop(). _ = cancel // govet fix for lost cancel. Cancel is handled in service.Stop().
s := &Service{ s := &Service{
ctx: ctx, ctx: ctx,
stateNotifier: cfg.StateNotifier, cancel: cancel,
cancel: cancel, cfg: cfg,
cfg: cfg, isPreGenesis: true,
isPreGenesis: true, joinedTopics: make(map[string]*pubsub.Topic, len(gossipTopicMappings)),
joinedTopics: make(map[string]*pubsub.Topic, len(gossipTopicMappings)), subnetsLock: make(map[uint64]*sync.RWMutex),
subnetsLock: make(map[uint64]*sync.RWMutex),
} }
dv5Nodes := parseBootStrapAddrs(s.cfg.BootstrapNodeAddr) dv5Nodes := parseBootStrapAddrs(s.cfg.BootstrapNodeAddr)
@@ -383,38 +379,19 @@ func (s *Service) pingPeers() {
func (s *Service) awaitStateInitialized() { func (s *Service) awaitStateInitialized() {
s.initializationLock.Lock() s.initializationLock.Lock()
defer s.initializationLock.Unlock() defer s.initializationLock.Unlock()
if s.isInitialized() { if s.isInitialized() {
return return
} }
clock, err := s.cfg.ClockWaiter.WaitForClock(s.ctx)
stateChannel := make(chan *feed.Event, 1) if err != nil {
stateSub := s.stateNotifier.StateFeed().Subscribe(stateChannel) log.WithError(err).Fatal("failed to receive initial genesis data")
cleanup := stateSub.Unsubscribe }
defer cleanup() s.genesisTime = clock.GenesisTime()
for { gvr := clock.GenesisValidatorsRoot()
select { s.genesisValidatorsRoot = gvr[:]
case event := <-stateChannel: _, err = s.currentForkDigest() // initialize fork digest cache
if event.Type == statefeed.Initialized { if err != nil {
data, ok := event.Data.(*statefeed.InitializedData) log.WithError(err).Error("Could not initialize fork digest")
if !ok {
// log.Fatalf will prevent defer from being called
cleanup()
log.Fatalf("Received wrong data over state initialized feed: %v", data)
}
s.genesisTime = data.StartTime
s.genesisValidatorsRoot = data.GenesisValidatorsRoot
_, err := s.currentForkDigest() // initialize fork digest cache
if err != nil {
log.WithError(err).Error("Could not initialize fork digest")
}
return
}
case <-s.ctx.Done():
log.Debug("Context closed, exiting goroutine")
return
}
} }
} }

View File

@@ -15,13 +15,11 @@ import (
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
noise "github.com/libp2p/go-libp2p/p2p/security/noise" noise "github.com/libp2p/go-libp2p/p2p/security/noise"
"github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr"
"github.com/prysmaticlabs/prysm/v4/async/event"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers/scorers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers/scorers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/network/forks" "github.com/prysmaticlabs/prysm/v4/network/forks"
@@ -102,30 +100,22 @@ func TestService_Start_OnlyStartsOnce(t *testing.T) {
params.SetupTestConfigCleanup(t) params.SetupTestConfigCleanup(t)
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
cs := startup.NewClockSynchronizer()
cfg := &Config{ cfg := &Config{
TCPPort: 2000, TCPPort: 2000,
UDPPort: 2000, UDPPort: 2000,
StateNotifier: &mock.MockStateNotifier{}, ClockWaiter: cs,
} }
s, err := NewService(context.Background(), cfg) s, err := NewService(context.Background(), cfg)
require.NoError(t, err) require.NoError(t, err)
s.stateNotifier = &mock.MockStateNotifier{}
s.dv5Listener = &mockListener{} s.dv5Listener = &mockListener{}
exitRoutine := make(chan bool) exitRoutine := make(chan bool)
go func() { go func() {
s.Start() s.Start()
<-exitRoutine <-exitRoutine
}() }()
// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed). var vr [32]byte
for sent := 0; sent == 0; { require.NoError(t, cs.SetClock(startup.NewClock(time.Now(), vr)))
sent = s.stateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: time.Now(),
GenesisValidatorsRoot: make([]byte, 32),
},
})
}
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
assert.Equal(t, true, s.started, "Expected service to be started") assert.Equal(t, true, s.started, "Expected service to be started")
s.Start() s.Start()
@@ -155,17 +145,17 @@ func TestService_Status_NoGenesisTimeSet(t *testing.T) {
func TestService_Start_NoDiscoverFlag(t *testing.T) { func TestService_Start_NoDiscoverFlag(t *testing.T) {
params.SetupTestConfigCleanup(t) params.SetupTestConfigCleanup(t)
cs := startup.NewClockSynchronizer()
cfg := &Config{ cfg := &Config{
TCPPort: 2000, TCPPort: 2000,
UDPPort: 2000, UDPPort: 2000,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
NoDiscovery: true, // <-- no s.dv5Listener is created NoDiscovery: true, // <-- no s.dv5Listener is created
ClockWaiter: cs,
} }
s, err := NewService(context.Background(), cfg) s, err := NewService(context.Background(), cfg)
require.NoError(t, err) require.NoError(t, err)
s.stateNotifier = &mock.MockStateNotifier{}
// required params to addForkEntry in s.forkWatcher // required params to addForkEntry in s.forkWatcher
s.genesisTime = time.Now() s.genesisTime = time.Now()
beaconCfg := params.BeaconConfig().Copy() beaconCfg := params.BeaconConfig().Copy()
@@ -181,16 +171,8 @@ func TestService_Start_NoDiscoverFlag(t *testing.T) {
<-exitRoutine <-exitRoutine
}() }()
// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed). var vr [32]byte
for sent := 0; sent == 0; { require.NoError(t, cs.SetClock(startup.NewClock(time.Now(), vr)))
sent = s.stateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: time.Now(),
GenesisValidatorsRoot: make([]byte, 32),
},
})
}
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
@@ -207,11 +189,11 @@ func TestListenForNewNodes(t *testing.T) {
_, pkey := createAddrAndPrivKey(t) _, pkey := createAddrAndPrivKey(t)
ipAddr := net.ParseIP("127.0.0.1") ipAddr := net.ParseIP("127.0.0.1")
genesisTime := prysmTime.Now() genesisTime := prysmTime.Now()
genesisValidatorsRoot := make([]byte, 32) var gvr [32]byte
s := &Service{ s := &Service{
cfg: cfg, cfg: cfg,
genesisTime: genesisTime, genesisTime: genesisTime,
genesisValidatorsRoot: genesisValidatorsRoot, genesisValidatorsRoot: gvr[:],
} }
bootListener, err := s.createListener(ipAddr, pkey) bootListener, err := s.createListener(ipAddr, pkey)
require.NoError(t, err) require.NoError(t, err)
@@ -229,11 +211,12 @@ func TestListenForNewNodes(t *testing.T) {
var listeners []*discover.UDPv5 var listeners []*discover.UDPv5
var hosts []host.Host var hosts []host.Host
// setup other nodes. // setup other nodes.
cs := startup.NewClockSynchronizer()
cfg = &Config{ cfg = &Config{
BootstrapNodeAddr: []string{bootNode.String()}, BootstrapNodeAddr: []string{bootNode.String()},
Discv5BootStrapAddr: []string{bootNode.String()}, Discv5BootStrapAddr: []string{bootNode.String()},
MaxPeers: 30, MaxPeers: 30,
StateNotifier: notifier, ClockWaiter: cs,
} }
for i := 1; i <= 5; i++ { for i := 1; i <= 5; i++ {
h, pkey, ipAddr := createHost(t, port+i) h, pkey, ipAddr := createHost(t, port+i)
@@ -242,7 +225,7 @@ func TestListenForNewNodes(t *testing.T) {
s := &Service{ s := &Service{
cfg: cfg, cfg: cfg,
genesisTime: genesisTime, genesisTime: genesisTime,
genesisValidatorsRoot: genesisValidatorsRoot, genesisValidatorsRoot: gvr[:],
} }
listener, err := s.startDiscoveryV5(ipAddr, pkey) listener, err := s.startDiscoveryV5(ipAddr, pkey)
assert.NoError(t, err, "Could not start discovery for node") assert.NoError(t, err, "Could not start discovery for node")
@@ -276,16 +259,9 @@ func TestListenForNewNodes(t *testing.T) {
<-exitRoutine <-exitRoutine
}() }()
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed).
for sent := 0; sent == 0; { require.NoError(t, cs.SetClock(startup.NewClock(genesisTime, gvr)))
sent = s.stateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: genesisTime,
GenesisValidatorsRoot: genesisValidatorsRoot,
},
})
}
time.Sleep(4 * time.Second) time.Sleep(4 * time.Second)
assert.Equal(t, 5, len(s.host.Network().Peers()), "Not all peers added to peerstore") assert.Equal(t, 5, len(s.host.Network().Peers()), "Not all peers added to peerstore")
require.NoError(t, s.Stop()) require.NoError(t, s.Stop())
@@ -327,11 +303,12 @@ func TestService_JoinLeaveTopic(t *testing.T) {
params.SetupTestConfigCleanup(t) params.SetupTestConfigCleanup(t)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
s, err := NewService(ctx, &Config{StateNotifier: &mock.MockStateNotifier{}}) gs := startup.NewClockSynchronizer()
s, err := NewService(ctx, &Config{StateNotifier: &mock.MockStateNotifier{}, ClockWaiter: gs})
require.NoError(t, err) require.NoError(t, err)
go s.awaitStateInitialized() go s.awaitStateInitialized()
fd := initializeStateWithForkDigest(ctx, t, s.stateNotifier.StateFeed()) fd := initializeStateWithForkDigest(ctx, t, gs)
assert.Equal(t, 0, len(s.joinedTopics)) assert.Equal(t, 0, len(s.joinedTopics))
@@ -358,23 +335,12 @@ func TestService_JoinLeaveTopic(t *testing.T) {
// initializeStateWithForkDigest sets up the state feed initialized event and returns the fork // initializeStateWithForkDigest sets up the state feed initialized event and returns the fork
// digest associated with that genesis event. // digest associated with that genesis event.
func initializeStateWithForkDigest(ctx context.Context, t *testing.T, ef *event.Feed) [4]byte { func initializeStateWithForkDigest(_ context.Context, t *testing.T, gs startup.ClockSetter) [4]byte {
gt := prysmTime.Now() gt := prysmTime.Now()
gvr := bytesutil.PadTo([]byte("genesis validators root"), 32) gvr := bytesutil.ToBytes32(bytesutil.PadTo([]byte("genesis validators root"), 32))
for n := 0; n == 0; { require.NoError(t, gs.SetClock(startup.NewClock(gt, gvr)))
if ctx.Err() != nil {
t.Fatal(ctx.Err())
}
n = ef.Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: gt,
GenesisValidatorsRoot: gvr,
},
})
}
fd, err := forks.CreateForkDigest(gt, gvr) fd, err := forks.CreateForkDigest(gt, gvr[:])
require.NoError(t, err) require.NoError(t, err)
time.Sleep(50 * time.Millisecond) // wait for pubsub filter to initialize. time.Sleep(50 * time.Millisecond) // wait for pubsub filter to initialize.

View File

@@ -12,10 +12,8 @@ import (
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
"github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/crypto"
"github.com/prysmaticlabs/go-bitfield" "github.com/prysmaticlabs/go-bitfield"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed" "github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags" "github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/wrapper" "github.com/prysmaticlabs/prysm/v4/consensus-types/wrapper"
@@ -88,15 +86,17 @@ func TestStartDiscV5_DiscoverPeersWithSubnets(t *testing.T) {
// Make one service on port 4001. // Make one service on port 4001.
port = 4001 port = 4001
gs := startup.NewClockSynchronizer()
cfg := &Config{ cfg := &Config{
BootstrapNodeAddr: []string{bootNode.String()}, BootstrapNodeAddr: []string{bootNode.String()},
Discv5BootStrapAddr: []string{bootNode.String()}, Discv5BootStrapAddr: []string{bootNode.String()},
MaxPeers: 30, MaxPeers: 30,
UDPPort: uint(port), UDPPort: uint(port),
ClockWaiter: gs,
} }
cfg.StateNotifier = &mock.MockStateNotifier{}
s, err = NewService(context.Background(), cfg) s, err = NewService(context.Background(), cfg)
require.NoError(t, err) require.NoError(t, err)
exitRoutine := make(chan bool) exitRoutine := make(chan bool)
go func() { go func() {
s.Start() s.Start()
@@ -104,15 +104,8 @@ func TestStartDiscV5_DiscoverPeersWithSubnets(t *testing.T) {
}() }()
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed). // Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed).
for sent := 0; sent == 0; { var vr [32]byte
sent = s.stateNotifier.StateFeed().Send(&feed.Event{ require.NoError(t, gs.SetClock(startup.NewClock(time.Now(), vr)))
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: time.Now(),
GenesisValidatorsRoot: make([]byte, 32),
},
})
}
// Wait for the nodes to have their local routing tables to be populated with the other nodes // Wait for the nodes to have their local routing tables to be populated with the other nodes
time.Sleep(6 * discoveryWaitTime) time.Sleep(6 * discoveryWaitTime)

View File

@@ -36,6 +36,7 @@ go_library(
"//beacon-chain/rpc/prysm/v1alpha1/node:go_default_library", "//beacon-chain/rpc/prysm/v1alpha1/node:go_default_library",
"//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library", "//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library",
"//beacon-chain/slasher:go_default_library", "//beacon-chain/slasher:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library", "//beacon-chain/sync:go_default_library",
"//config/features:go_default_library", "//config/features:go_default_library",

View File

@@ -55,6 +55,7 @@ go_library(
"//beacon-chain/operations/synccommittee:go_default_library", "//beacon-chain/operations/synccommittee:go_default_library",
"//beacon-chain/operations/voluntaryexits:go_default_library", "//beacon-chain/operations/voluntaryexits:go_default_library",
"//beacon-chain/p2p:go_default_library", "//beacon-chain/p2p:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library", "//beacon-chain/sync:go_default_library",

View File

@@ -7,12 +7,10 @@ import (
"context" "context"
"time" "time"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain" "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/builder" "github.com/prysmaticlabs/prysm/v4/beacon-chain/builder"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache/depositcache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache/depositcache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
blockfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/block" blockfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/block"
opfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/operation" opfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/operation"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state" statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
@@ -25,6 +23,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -74,6 +73,7 @@ type Server struct {
ExecutionEngineCaller execution.EngineCaller ExecutionEngineCaller execution.EngineCaller
BlockBuilder builder.BlockBuilder BlockBuilder builder.BlockBuilder
BLSChangesPool blstoexec.PoolManager BLSChangesPool blstoexec.PoolManager
ClockWaiter startup.ClockWaiter
} }
// WaitForActivation checks if a validator public key exists in the active validator registry of the current // WaitForActivation checks if a validator public key exists in the active validator registry of the current
@@ -170,30 +170,17 @@ func (vs *Server) WaitForChainStart(_ *emptypb.Empty, stream ethpb.BeaconNodeVal
return stream.Send(res) return stream.Send(res)
} }
stateChannel := make(chan *feed.Event, 1) clock, err := vs.ClockWaiter.WaitForClock(vs.Ctx)
stateSub := vs.StateNotifier.StateFeed().Subscribe(stateChannel) if err != nil {
defer stateSub.Unsubscribe() return status.Error(codes.Canceled, "Context canceled")
for {
select {
case event := <-stateChannel:
if event.Type == statefeed.Initialized {
data, ok := event.Data.(*statefeed.InitializedData)
if !ok {
return errors.New("event data is not type *statefeed.InitializedData")
}
log.WithField("starttime", data.StartTime).Debug("Received chain started event")
log.Debug("Sending genesis time notification to connected validator clients")
res := &ethpb.ChainStartResponse{
Started: true,
GenesisTime: uint64(data.StartTime.Unix()),
GenesisValidatorsRoot: data.GenesisValidatorsRoot,
}
return stream.Send(res)
}
case <-stateSub.Err():
return status.Error(codes.Aborted, "Subscriber closed, exiting goroutine")
case <-vs.Ctx.Done():
return status.Error(codes.Canceled, "Context canceled")
}
} }
log.WithField("starttime", clock.GenesisTime()).Debug("Received chain started event")
log.Debug("Sending genesis time notification to connected validator clients")
gvr := clock.GenesisValidatorsRoot()
res := &ethpb.ChainStartResponse{
Started: true,
GenesisTime: uint64(clock.GenesisTime().Unix()),
GenesisValidatorsRoot: gvr[:],
}
return stream.Send(res)
} }

View File

@@ -10,9 +10,8 @@ import (
"github.com/prysmaticlabs/prysm/v4/async/event" "github.com/prysmaticlabs/prysm/v4/async/event"
mockChain "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mockChain "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/cache/depositcache" "github.com/prysmaticlabs/prysm/v4/beacon-chain/cache/depositcache"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing" mockExecution "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native" state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/crypto/bls" "github.com/prysmaticlabs/prysm/v4/crypto/bls"
@@ -189,13 +188,14 @@ func TestWaitForActivation_MultipleStatuses(t *testing.T) {
func TestWaitForChainStart_ContextClosed(t *testing.T) { func TestWaitForChainStart_ContextClosed(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
chainService := &mockChain.ChainService{} chainService := &mockChain.ChainService{}
Server := &Server{ server := &Server{
Ctx: ctx, Ctx: ctx,
ChainStartFetcher: &mockExecution.FaultyExecutionChain{ ChainStartFetcher: &mockExecution.FaultyExecutionChain{
ChainFeed: new(event.Feed), ChainFeed: new(event.Feed),
}, },
StateNotifier: chainService.StateNotifier(), StateNotifier: chainService.StateNotifier(),
HeadFetcher: chainService, HeadFetcher: chainService,
ClockWaiter: startup.NewClockSynchronizer(),
} }
exitRoutine := make(chan bool) exitRoutine := make(chan bool)
@@ -204,7 +204,7 @@ func TestWaitForChainStart_ContextClosed(t *testing.T) {
mockStream := mock.NewMockBeaconNodeValidator_WaitForChainStartServer(ctrl) mockStream := mock.NewMockBeaconNodeValidator_WaitForChainStartServer(ctrl)
mockStream.EXPECT().Context().Return(ctx) mockStream.EXPECT().Context().Return(ctx)
go func(tt *testing.T) { go func(tt *testing.T) {
err := Server.WaitForChainStart(&emptypb.Empty{}, mockStream) err := server.WaitForChainStart(&emptypb.Empty{}, mockStream)
assert.ErrorContains(tt, "Context canceled", err) assert.ErrorContains(tt, "Context canceled", err)
<-exitRoutine <-exitRoutine
}(t) }(t)
@@ -243,11 +243,9 @@ func TestWaitForChainStart_AlreadyStarted(t *testing.T) {
} }
func TestWaitForChainStart_HeadStateDoesNotExist(t *testing.T) { func TestWaitForChainStart_HeadStateDoesNotExist(t *testing.T) {
genesisValidatorsRoot := params.BeaconConfig().ZeroHash
// Set head state to nil // Set head state to nil
chainService := &mockChain.ChainService{State: nil} chainService := &mockChain.ChainService{State: nil}
notifier := chainService.StateNotifier() gs := startup.NewClockSynchronizer()
Server := &Server{ Server := &Server{
Ctx: context.Background(), Ctx: context.Background(),
ChainStartFetcher: &mockExecution.Chain{ ChainStartFetcher: &mockExecution.Chain{
@@ -255,6 +253,7 @@ func TestWaitForChainStart_HeadStateDoesNotExist(t *testing.T) {
}, },
StateNotifier: chainService.StateNotifier(), StateNotifier: chainService.StateNotifier(),
HeadFetcher: chainService, HeadFetcher: chainService,
ClockWaiter: gs,
} }
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
@@ -267,15 +266,7 @@ func TestWaitForChainStart_HeadStateDoesNotExist(t *testing.T) {
assert.NoError(t, Server.WaitForChainStart(&emptypb.Empty{}, mockStream), "Could not call RPC method") assert.NoError(t, Server.WaitForChainStart(&emptypb.Empty{}, mockStream), "Could not call RPC method")
wg.Done() wg.Done()
}() }()
// Simulate a late state initialization event, so that
// method is able to handle race condition here.
notifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: time.Unix(0, 0),
GenesisValidatorsRoot: genesisValidatorsRoot[:],
},
})
util.WaitTimeout(wg, time.Second) util.WaitTimeout(wg, time.Second)
} }
@@ -284,6 +275,8 @@ func TestWaitForChainStart_NotStartedThenLogFired(t *testing.T) {
genesisValidatorsRoot := bytesutil.ToBytes32([]byte("validators")) genesisValidatorsRoot := bytesutil.ToBytes32([]byte("validators"))
chainService := &mockChain.ChainService{} chainService := &mockChain.ChainService{}
gs := startup.NewClockSynchronizer()
Server := &Server{ Server := &Server{
Ctx: context.Background(), Ctx: context.Background(),
ChainStartFetcher: &mockExecution.FaultyExecutionChain{ ChainStartFetcher: &mockExecution.FaultyExecutionChain{
@@ -291,6 +284,7 @@ func TestWaitForChainStart_NotStartedThenLogFired(t *testing.T) {
}, },
StateNotifier: chainService.StateNotifier(), StateNotifier: chainService.StateNotifier(),
HeadFetcher: chainService, HeadFetcher: chainService,
ClockWaiter: gs,
} }
exitRoutine := make(chan bool) exitRoutine := make(chan bool)
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
@@ -310,15 +304,7 @@ func TestWaitForChainStart_NotStartedThenLogFired(t *testing.T) {
}(t) }(t)
// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed). // Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed).
for sent := 0; sent == 0; { require.NoError(t, gs.SetClock(startup.NewClock(time.Unix(0, 0), genesisValidatorsRoot)))
sent = Server.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: time.Unix(0, 0),
GenesisValidatorsRoot: genesisValidatorsRoot[:],
},
})
}
exitRoutine <- true exitRoutine <- true
require.LogsContain(t, hook, "Sending genesis time") require.LogsContain(t, hook, "Sending genesis time")

View File

@@ -41,6 +41,7 @@ import (
nodev1alpha1 "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/node" nodev1alpha1 "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/node"
validatorv1alpha1 "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/validator" validatorv1alpha1 "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/validator"
slasherservice "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher" slasherservice "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
chainSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" chainSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
"github.com/prysmaticlabs/prysm/v4/config/features" "github.com/prysmaticlabs/prysm/v4/config/features"
@@ -120,6 +121,7 @@ type Config struct {
OptimisticModeFetcher blockchain.OptimisticModeFetcher OptimisticModeFetcher blockchain.OptimisticModeFetcher
BlockBuilder builder.BlockBuilder BlockBuilder builder.BlockBuilder
Router *mux.Router Router *mux.Router
ClockWaiter startup.ClockWaiter
} }
// NewService instantiates a new RPC service instance that will // NewService instantiates a new RPC service instance that will
@@ -246,6 +248,7 @@ func (s *Service) Start() {
ProposerSlotIndexCache: s.cfg.ProposerIdsCache, ProposerSlotIndexCache: s.cfg.ProposerIdsCache,
BlockBuilder: s.cfg.BlockBuilder, BlockBuilder: s.cfg.BlockBuilder,
BLSChangesPool: s.cfg.BLSChangesPool, BLSChangesPool: s.cfg.BLSChangesPool,
ClockWaiter: s.cfg.ClockWaiter,
} }
validatorServerV1 := &validator.Server{ validatorServerV1 := &validator.Server{
HeadFetcher: s.cfg.HeadFetcher, HeadFetcher: s.cfg.HeadFetcher,

View File

@@ -26,11 +26,11 @@ go_library(
"//async/event:go_default_library", "//async/event:go_default_library",
"//beacon-chain/blockchain:go_default_library", "//beacon-chain/blockchain:go_default_library",
"//beacon-chain/core/blocks:go_default_library", "//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/state:go_default_library", "//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/db:go_default_library", "//beacon-chain/db:go_default_library",
"//beacon-chain/operations/slashings:go_default_library", "//beacon-chain/operations/slashings:go_default_library",
"//beacon-chain/slasher/types:go_default_library", "//beacon-chain/slasher/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library", "//beacon-chain/sync:go_default_library",
@@ -70,14 +70,13 @@ go_test(
deps = [ deps = [
"//async/event:go_default_library", "//async/event:go_default_library",
"//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/blockchain/testing:go_default_library",
"//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/core/signing:go_default_library", "//beacon-chain/core/signing:go_default_library",
"//beacon-chain/db/testing:go_default_library", "//beacon-chain/db/testing:go_default_library",
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library", "//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
"//beacon-chain/operations/slashings/mock:go_default_library", "//beacon-chain/operations/slashings/mock:go_default_library",
"//beacon-chain/slasher/mock:go_default_library", "//beacon-chain/slasher/mock:go_default_library",
"//beacon-chain/slasher/types:go_default_library", "//beacon-chain/slasher/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync/initial-sync/testing:go_default_library", "//beacon-chain/sync/initial-sync/testing:go_default_library",
"//config/fieldparams:go_default_library", "//config/fieldparams:go_default_library",

View File

@@ -11,6 +11,7 @@ import (
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
slashingsmock "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings/mock" slashingsmock "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings/mock"
slashertypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/types" slashertypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/crypto/bls" "github.com/prysmaticlabs/prysm/v4/crypto/bls"
@@ -239,6 +240,7 @@ func Test_processQueuedAttestations(t *testing.T) {
HeadStateFetcher: mockChain, HeadStateFetcher: mockChain,
AttestationStateFetcher: mockChain, AttestationStateFetcher: mockChain,
SlashingPoolInserter: &slashingsmock.PoolMock{}, SlashingPoolInserter: &slashingsmock.PoolMock{},
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(t, err) require.NoError(t, err)
s.genesisTime = genesisTime s.genesisTime = genesisTime
@@ -296,6 +298,7 @@ func Test_processQueuedAttestations_MultipleChunkIndices(t *testing.T) {
HeadStateFetcher: mockChain, HeadStateFetcher: mockChain,
AttestationStateFetcher: mockChain, AttestationStateFetcher: mockChain,
SlashingPoolInserter: &slashingsmock.PoolMock{}, SlashingPoolInserter: &slashingsmock.PoolMock{},
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(t, err) require.NoError(t, err)
s.genesisTime = genesisTime s.genesisTime = genesisTime
@@ -361,6 +364,7 @@ func Test_processQueuedAttestations_OverlappingChunkIndices(t *testing.T) {
HeadStateFetcher: mockChain, HeadStateFetcher: mockChain,
AttestationStateFetcher: mockChain, AttestationStateFetcher: mockChain,
SlashingPoolInserter: &slashingsmock.PoolMock{}, SlashingPoolInserter: &slashingsmock.PoolMock{},
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(t, err) require.NoError(t, err)
s.genesisTime = genesisTime s.genesisTime = genesisTime
@@ -475,6 +479,7 @@ func Test_applyAttestationForValidator_MinSpanChunk(t *testing.T) {
&ServiceConfig{ &ServiceConfig{
Database: slasherDB, Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -535,6 +540,7 @@ func Test_applyAttestationForValidator_MaxSpanChunk(t *testing.T) {
&ServiceConfig{ &ServiceConfig{
Database: slasherDB, Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -602,6 +608,7 @@ func Test_checkDoubleVotes_SlashableInputAttestations(t *testing.T) {
&ServiceConfig{ &ServiceConfig{
Database: slasherDB, Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -638,6 +645,7 @@ func Test_checkDoubleVotes_SlashableAttestationsOnDisk(t *testing.T) {
&ServiceConfig{ &ServiceConfig{
Database: slasherDB, Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -683,6 +691,7 @@ func testLoadChunks(t *testing.T, kind slashertypes.ChunkKind) {
&ServiceConfig{ &ServiceConfig{
Database: slasherDB, Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -769,6 +778,7 @@ func TestService_processQueuedAttestations(t *testing.T) {
Database: slasherDB, Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
HeadStateFetcher: mockChain, HeadStateFetcher: mockChain,
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -805,6 +815,7 @@ func BenchmarkCheckSlashableAttestations(b *testing.B) {
Database: slasherDB, Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
HeadStateFetcher: mockChain, HeadStateFetcher: mockChain,
ClockWaiter: startup.NewClockSynchronizer(),
}) })
require.NoError(b, err) require.NoError(b, err)

View File

@@ -10,6 +10,7 @@ import (
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree" doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
slashingsmock "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings/mock" slashingsmock "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings/mock"
slashertypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/types" 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/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -63,6 +64,7 @@ func Test_processQueuedBlocks_DetectsDoubleProposals(t *testing.T) {
HeadStateFetcher: mockChain, HeadStateFetcher: mockChain,
StateGen: stategen.New(beaconDB, doublylinkedtree.New()), StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
SlashingPoolInserter: &slashingsmock.PoolMock{}, SlashingPoolInserter: &slashingsmock.PoolMock{},
ClockWaiter: startup.NewClockSynchronizer(),
}, },
params: DefaultParams(), params: DefaultParams(),
blksQueue: newBlocksQueue(), blksQueue: newBlocksQueue(),
@@ -129,6 +131,7 @@ func Test_processQueuedBlocks_NotSlashable(t *testing.T) {
Database: slasherDB, Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
HeadStateFetcher: mockChain, HeadStateFetcher: mockChain,
ClockWaiter: startup.NewClockSynchronizer(),
}, },
params: DefaultParams(), params: DefaultParams(),
blksQueue: newBlocksQueue(), blksQueue: newBlocksQueue(),

View File

@@ -8,6 +8,7 @@ import (
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
slashertypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/types" slashertypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
params2 "github.com/prysmaticlabs/prysm/v4/config/params" params2 "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
@@ -24,6 +25,7 @@ func TestSlasher_receiveAttestations_OK(t *testing.T) {
serviceCfg: &ServiceConfig{ serviceCfg: &ServiceConfig{
IndexedAttestationsFeed: new(event.Feed), IndexedAttestationsFeed: new(event.Feed),
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
ClockWaiter: startup.NewClockSynchronizer(),
}, },
attsQueue: newAttestationsQueue(), attsQueue: newAttestationsQueue(),
} }
@@ -207,6 +209,7 @@ func TestSlasher_receiveAttestations_OnlyValidAttestations(t *testing.T) {
serviceCfg: &ServiceConfig{ serviceCfg: &ServiceConfig{
IndexedAttestationsFeed: new(event.Feed), IndexedAttestationsFeed: new(event.Feed),
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
ClockWaiter: startup.NewClockSynchronizer(),
}, },
attsQueue: newAttestationsQueue(), attsQueue: newAttestationsQueue(),
} }
@@ -245,6 +248,7 @@ func TestSlasher_receiveBlocks_OK(t *testing.T) {
serviceCfg: &ServiceConfig{ serviceCfg: &ServiceConfig{
BeaconBlockHeadersFeed: new(event.Feed), BeaconBlockHeadersFeed: new(event.Feed),
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
ClockWaiter: startup.NewClockSynchronizer(),
}, },
blksQueue: newBlocksQueue(), blksQueue: newBlocksQueue(),
} }
@@ -288,6 +292,7 @@ func TestService_processQueuedBlocks(t *testing.T) {
Database: slasherDB, Database: slasherDB,
StateNotifier: &mock.MockStateNotifier{}, StateNotifier: &mock.MockStateNotifier{},
HeadStateFetcher: mockChain, HeadStateFetcher: mockChain,
ClockWaiter: startup.NewClockSynchronizer(),
}, },
blksQueue: newBlocksQueue(), blksQueue: newBlocksQueue(),
} }

View File

@@ -10,10 +10,10 @@ import (
"github.com/prysmaticlabs/prysm/v4/async/event" "github.com/prysmaticlabs/prysm/v4/async/event"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain" "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state" statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -39,6 +39,7 @@ type ServiceConfig struct {
SlashingPoolInserter slashings.PoolInserter SlashingPoolInserter slashings.PoolInserter
HeadStateFetcher blockchain.HeadFetcher HeadStateFetcher blockchain.HeadFetcher
SyncChecker sync.Checker SyncChecker sync.Checker
ClockWaiter startup.ClockWaiter
} }
// SlashingChecker is an interface for defining services that the beacon node may interact with to provide slashing data. // SlashingChecker is an interface for defining services that the beacon node may interact with to provide slashing data.
@@ -167,43 +168,19 @@ func (s *Service) Stop() error {
} }
// Status of the slasher service. // Status of the slasher service.
func (_ *Service) Status() error { func (*Service) Status() error {
return nil return nil
} }
func (s *Service) waitForChainInitialization() { func (s *Service) waitForChainInitialization() {
stateChannel := make(chan *feed.Event, 1) clock, err := s.serviceCfg.ClockWaiter.WaitForClock(s.ctx)
stateSub := s.serviceCfg.StateNotifier.StateFeed().Subscribe(stateChannel) if err != nil {
defer stateSub.Unsubscribe() log.WithError(err).Error("Could not receive chain start notification")
for {
select {
case stateEvent := <-stateChannel:
// Wait for us to receive the genesis time via a chain started notification.
if stateEvent.Type == statefeed.Initialized {
// Alternatively, if the chain has already started, we then read the genesis
// time value from this data.
data, ok := stateEvent.Data.(*statefeed.InitializedData)
if !ok {
log.Error(
"Could not receive chain start notification, want *statefeed.ChainStartedData",
)
return
}
s.genesisTime = data.StartTime
log.WithField("genesisTime", s.genesisTime).Info(
"Slasher received chain initialization event",
)
return
}
case err := <-stateSub.Err():
log.WithError(err).Error(
"Slasher could not subscribe to state events",
)
return
case <-s.ctx.Done():
return
}
} }
s.genesisTime = clock.GenesisTime()
log.WithField("genesisTime", s.genesisTime).Info(
"Slasher received chain initialization event",
)
} }
func (s *Service) waitForSync(genesisTime time.Time) { func (s *Service) waitForSync(genesisTime time.Time) {

View File

@@ -8,10 +8,9 @@ import (
"github.com/prysmaticlabs/prysm/v4/async/event" "github.com/prysmaticlabs/prysm/v4/async/event"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
mockslasher "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock" mockslasher "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/testing/require" "github.com/prysmaticlabs/prysm/v4/testing/require"
@@ -42,6 +41,7 @@ func TestService_StartStop_ChainInitialized(t *testing.T) {
State: beaconState, State: beaconState,
Slot: &currentSlot, Slot: &currentSlot,
} }
gs := startup.NewClockSynchronizer()
srv, err := New(context.Background(), &ServiceConfig{ srv, err := New(context.Background(), &ServiceConfig{
IndexedAttestationsFeed: new(event.Feed), IndexedAttestationsFeed: new(event.Feed),
BeaconBlockHeadersFeed: new(event.Feed), BeaconBlockHeadersFeed: new(event.Feed),
@@ -49,14 +49,13 @@ func TestService_StartStop_ChainInitialized(t *testing.T) {
Database: slasherDB, Database: slasherDB,
HeadStateFetcher: mockChain, HeadStateFetcher: mockChain,
SyncChecker: &mockSync.Sync{IsSyncing: false}, SyncChecker: &mockSync.Sync{IsSyncing: false},
ClockWaiter: gs,
}) })
require.NoError(t, err) require.NoError(t, err)
go srv.Start() go srv.Start()
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
srv.serviceCfg.StateNotifier.StateFeed().Send(&feed.Event{ var vr [32]byte
Type: statefeed.Initialized, require.NoError(t, gs.SetClock(startup.NewClock(time.Now(), vr)))
Data: &statefeed.InitializedData{StartTime: time.Now()},
})
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
srv.attsSlotTicker = &slots.SlotTicker{} srv.attsSlotTicker = &slots.SlotTicker{}
srv.blocksSlotTicker = &slots.SlotTicker{} srv.blocksSlotTicker = &slots.SlotTicker{}

View File

@@ -0,0 +1,31 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"clock.go",
"synchronizer.go",
],
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/startup",
visibility = ["//visibility:public"],
deps = [
"//consensus-types/primitives:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"clock_test.go",
"synchronizer_test.go",
],
embed = [":go_default_library"],
deps = [
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//testing/require:go_default_library",
],
)

View File

@@ -0,0 +1,75 @@
package startup
import (
"time"
types "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/time/slots"
)
// Nower is a function that can return the current time.
// In Clock, Now() will use time.Now by default, but a Nower can be set using WithNower in NewClock
// to customize the return value for Now() in tests.
type Nower func() time.Time
// Clock abstracts important time-related concerns in the beacon chain:
// - provides a time.Now() construct that can be overridden in tests
// - GenesisTime() to know the genesis time or use genesis time determination as a synchronization point.
// - CurrentSlot: convenience conversion for current time -> slot
// (support backwards compatibility with the TimeFetcher interface)
// - GenesisValidatorsRoot: is determined at the same point as genesis time and is needed by some of the same code,
// so it is also bundled for convenience.
type Clock struct {
t time.Time
vr [32]byte
now Nower
}
// GenesisTime returns the genesis timestamp.
func (g *Clock) GenesisTime() time.Time {
return g.t
}
// GenesisValidatorsRoot returns the genesis state validator root
func (g *Clock) GenesisValidatorsRoot() [32]byte {
return g.vr
}
// CurrentSlot returns the current slot relative to the time.Time value that Clock embeds.
func (g *Clock) CurrentSlot() types.Slot {
now := g.now()
return slots.Duration(g.t, now)
}
// Now provides a value for time.Now() that can be overridden in tests.
func (g *Clock) Now() time.Time {
return g.now()
}
// ClockOpt is a functional option to change the behavior of a clock value made by NewClock.
// It is primarily intended as a way to inject an alternate time.Now() callback (WithNower) for testing.
type ClockOpt func(*Clock)
// WithNower allows tests in particular to inject an alternate implementation of time.Now (vs using system time)
func WithNower(n Nower) ClockOpt {
return func(g *Clock) {
g.now = n
}
}
// NewClock constructs a Clock value from a genesis timestamp (t) and a Genesis Validator Root (vr).
// The WithNower ClockOpt can be used in tests to specify an alternate `time.Now` implementation,
// for instance to return a value for `Now` spanning a certain number of slots from genesis time, to control the current slot.
func NewClock(t time.Time, vr [32]byte, opts ...ClockOpt) *Clock {
c := &Clock{
t: t,
vr: vr,
}
for _, o := range opts {
o(c)
}
if c.now == nil {
c.now = time.Now
}
return c
}

View File

@@ -0,0 +1,49 @@
package startup
import (
"testing"
"time"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func TestClock(t *testing.T) {
vr := [32]byte{}
cases := []struct {
name string
nSlots primitives.Slot
}{
{
name: "3 slots",
nSlots: 3,
},
{
name: "0 slots",
nSlots: 0,
},
{
name: "1 epoch",
nSlots: params.BeaconConfig().SlotsPerEpoch,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
genesis, now := testInterval(c.nSlots)
nower := func() time.Time { return now }
cl := NewClock(genesis, vr, WithNower(nower))
require.Equal(t, genesis, cl.GenesisTime())
require.Equal(t, now, cl.Now())
require.Equal(t, c.nSlots, cl.CurrentSlot())
})
}
}
func testInterval(nSlots primitives.Slot) (time.Time, time.Time) {
oneSlot := time.Second * time.Duration(params.BeaconConfig().SecondsPerSlot)
var start uint64 = 23
endOffset := oneSlot * time.Duration(nSlots)
startTime := time.Unix(int64(start), 0)
return startTime, startTime.Add(endOffset)
}

View File

@@ -0,0 +1,60 @@
package startup
import (
"context"
"github.com/pkg/errors"
)
var errClockSet = errors.New("refusing to change clock after it is set")
// ClockSynchronizer provides a synchronization mechanism for services that rely on the genesis time and validator root
// being known before getting to work.
type ClockSynchronizer struct {
ready chan struct{}
c *Clock
}
// ClockWaiter specifies the WaitForClock method. ClockSynchronizer works in a 1:N pattern, with 1 thread calling
// SetClock, and the others blocking on a call to WaitForClock until the expected *Clock value is set.
type ClockWaiter interface {
WaitForClock(context.Context) (*Clock, error)
}
// ClockSetter specifies the SetClock method. ClockSynchronizer works in a 1:N pattern, so in a given graph of services,
// only one service should be given the ClockSetter, and all others relying on the service's activation should use
// ClockWaiter.
type ClockSetter interface {
SetClock(c *Clock) error
}
// SetClock sets the Clock value `c` and unblocks all threads waiting for `c` via WaitForClock.
// Calling SetClock more than once will return an error, as calling this function is meant to be a signal
// that the system is ready to start.
func (w *ClockSynchronizer) SetClock(c *Clock) error {
if w.c != nil {
return errors.Wrapf(errClockSet, "when SetClock called, Clock already set to time=%d", w.c.GenesisTime().Unix())
}
w.c = c
close(w.ready)
return nil
}
// WaitForClock will block the caller until the *Clock value is available. If the provided context is canceled (eg via
// a deadline set upstream), the function will return the error given by ctx.Err().
func (w *ClockSynchronizer) WaitForClock(ctx context.Context) (*Clock, error) {
select {
case <-w.ready:
return w.c, nil
case <-ctx.Done():
return nil, ctx.Err()
}
}
// NewClockSynchronizer initializes a single instance of ClockSynchronizer that must be used by all ClockWaiters that
// need to be synchronized to a ClockSetter (ie blockchain service).
func NewClockSynchronizer() *ClockSynchronizer {
return &ClockSynchronizer{
ready: make(chan struct{}),
}
}

View File

@@ -0,0 +1,51 @@
package startup
import (
"context"
"testing"
"time"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func TestSynchronizerErrOnSecondSet(t *testing.T) {
s := NewClockSynchronizer()
require.NoError(t, s.SetClock(NewClock(time.Now(), [32]byte{})))
require.ErrorIs(t, s.SetClock(NewClock(time.Now(), [32]byte{})), errClockSet)
}
func TestWaitForClockCanceled(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
s := NewClockSynchronizer()
c, err := s.WaitForClock(ctx)
require.Equal(t, true, c == nil)
require.ErrorIs(t, err, context.Canceled)
}
func TestWaitForClock(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
s := NewClockSynchronizer()
var vr [32]byte
copy(vr[:], bytesutil.PadTo([]byte("valroot"), 32))
genesis := time.Unix(23, 0)
later := time.Unix(42, 0)
nower := func() time.Time { return later }
expect := NewClock(genesis, vr, WithNower(nower))
go func() {
// This is just to ensure the test doesn't hang.
// If we hit this cancellation case, then the happy path failed and the NoError assertion etc below will fail.
time.Sleep(time.Second)
cancel()
}()
go func() {
require.NoError(t, s.SetClock(expect))
}()
c, err := s.WaitForClock(ctx)
require.NoError(t, err)
require.Equal(t, later, c.Now())
require.Equal(t, genesis, c.GenesisTime())
require.Equal(t, vr, c.GenesisValidatorsRoot())
}

View File

@@ -65,7 +65,6 @@ go_library(
"//beacon-chain/core/feed:go_default_library", "//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/block:go_default_library", "//beacon-chain/core/feed/block:go_default_library",
"//beacon-chain/core/feed/operation:go_default_library", "//beacon-chain/core/feed/operation:go_default_library",
"//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/signing:go_default_library", "//beacon-chain/core/signing:go_default_library",
"//beacon-chain/core/transition:go_default_library", "//beacon-chain/core/transition:go_default_library",
@@ -82,6 +81,7 @@ go_library(
"//beacon-chain/p2p/encoder:go_default_library", "//beacon-chain/p2p/encoder:go_default_library",
"//beacon-chain/p2p/peers:go_default_library", "//beacon-chain/p2p/peers:go_default_library",
"//beacon-chain/p2p/types:go_default_library", "//beacon-chain/p2p/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen:go_default_library",
"//cache/lru:go_default_library", "//cache/lru:go_default_library",
@@ -179,7 +179,6 @@ go_test(
"//beacon-chain/core/altair:go_default_library", "//beacon-chain/core/altair:go_default_library",
"//beacon-chain/core/feed:go_default_library", "//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/operation:go_default_library", "//beacon-chain/core/feed/operation:go_default_library",
"//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/core/helpers:go_default_library", "//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/signing:go_default_library", "//beacon-chain/core/signing:go_default_library",
"//beacon-chain/core/time:go_default_library", "//beacon-chain/core/time:go_default_library",
@@ -198,6 +197,7 @@ go_test(
"//beacon-chain/p2p/peers:go_default_library", "//beacon-chain/p2p/peers:go_default_library",
"//beacon-chain/p2p/testing:go_default_library", "//beacon-chain/p2p/testing:go_default_library",
"//beacon-chain/p2p/types:go_default_library", "//beacon-chain/p2p/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library", "//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/stategen:go_default_library",

View File

@@ -37,7 +37,6 @@ func TestBroadcastBLSChanges(t *testing.T) {
WithP2P(mockp2p.NewTestP2P(t)), WithP2P(mockp2p.NewTestP2P(t)),
WithInitialSync(&mockSync.Sync{IsSyncing: false}), WithInitialSync(&mockSync.Sync{IsSyncing: false}),
WithChainService(chainService), WithChainService(chainService),
WithStateNotifier(chainService.StateNotifier()),
WithOperationNotifier(chainService.OperationNotifier()), WithOperationNotifier(chainService.OperationNotifier()),
WithBlsToExecPool(blstoexec.NewPool()), WithBlsToExecPool(blstoexec.NewPool()),
) )
@@ -71,7 +70,6 @@ func TestRateBLSChanges(t *testing.T) {
WithP2P(p1), WithP2P(p1),
WithInitialSync(&mockSync.Sync{IsSyncing: false}), WithInitialSync(&mockSync.Sync{IsSyncing: false}),
WithChainService(chainService), WithChainService(chainService),
WithStateNotifier(chainService.StateNotifier()),
WithOperationNotifier(chainService.OperationNotifier()), WithOperationNotifier(chainService.OperationNotifier()),
WithBlsToExecPool(blstoexec.NewPool()), WithBlsToExecPool(blstoexec.NewPool()),
) )
@@ -141,7 +139,6 @@ func TestBroadcastBLSBatch_changes_slice(t *testing.T) {
WithP2P(p1), WithP2P(p1),
WithInitialSync(&mockSync.Sync{IsSyncing: false}), WithInitialSync(&mockSync.Sync{IsSyncing: false}),
WithChainService(chainService), WithChainService(chainService),
WithStateNotifier(chainService.StateNotifier()),
WithOperationNotifier(chainService.OperationNotifier()), WithOperationNotifier(chainService.OperationNotifier()),
WithBlsToExecPool(blstoexec.NewPool()), WithBlsToExecPool(blstoexec.NewPool()),
) )

View File

@@ -4,8 +4,6 @@ import (
"github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/protocol" "github.com/libp2p/go-libp2p/core/protocol"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
) )
@@ -13,33 +11,29 @@ import (
const forkDigestLength = 4 const forkDigestLength = 4
// writes peer's current context for the expected payload to the stream. // writes peer's current context for the expected payload to the stream.
func writeContextToStream(objCtx []byte, stream network.Stream, chain blockchain.ForkFetcher) error { func writeContextToStream(objCtx []byte, stream network.Stream) error {
// The rpc context for our v2 methods is the fork-digest of // The rpc context for our v2 methods is the fork-digest of
// the relevant payload. We write the associated fork-digest(context) // the relevant payload. We write the associated fork-digest(context)
// into the stream for the payload. // into the stream for the payload.
rpcCtx, err := rpcContext(stream, chain) rpcCtx, err := expectRpcContext(stream)
if err != nil { if err != nil {
return err return err
} }
// Exit early if there is an empty context. // Exit early if an empty context is expected.
if len(rpcCtx) == 0 { if !rpcCtx {
return nil return nil
} }
// Always choose the object's context when writing to the stream. _, err = stream.Write(objCtx)
if objCtx != nil {
rpcCtx = objCtx
}
_, err = stream.Write(rpcCtx)
return err return err
} }
// reads any attached context-bytes to the payload. // reads any attached context-bytes to the payload.
func readContextFromStream(stream network.Stream, chain blockchain.ForkFetcher) ([]byte, error) { func readContextFromStream(stream network.Stream) ([]byte, error) {
rpcCtx, err := rpcContext(stream, chain) hasCtx, err := expectRpcContext(stream)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(rpcCtx) == 0 { if !hasCtx {
return []byte{}, nil return []byte{}, nil
} }
// Read context (fork-digest) from stream // Read context (fork-digest) from stream
@@ -50,26 +44,18 @@ func readContextFromStream(stream network.Stream, chain blockchain.ForkFetcher)
return b, nil return b, nil
} }
// retrieve expected context depending on rpc topic schema version. func expectRpcContext(stream network.Stream) (bool, error) {
func rpcContext(stream network.Stream, chain blockchain.ForkFetcher) ([]byte, error) {
_, _, version, err := p2p.TopicDeconstructor(string(stream.Protocol())) _, _, version, err := p2p.TopicDeconstructor(string(stream.Protocol()))
if err != nil { if err != nil {
return nil, err return false, err
} }
switch version { switch version {
case p2p.SchemaVersionV1: case p2p.SchemaVersionV1:
// Return empty context for a v1 method. return false, nil
return []byte{}, nil
case p2p.SchemaVersionV2: case p2p.SchemaVersionV2:
currFork := chain.CurrentFork() return true, nil
genRoot := chain.GenesisValidatorsRoot()
digest, err := signing.ComputeForkDigest(currFork.CurrentVersion, genRoot[:])
if err != nil {
return nil, err
}
return digest[:], nil
default: default:
return nil, errors.New("invalid version of %s registered for topic: %s") return false, errors.New("invalid version of %s registered for topic: %s")
} }
} }

View File

@@ -31,7 +31,7 @@ func TestContextWrite_NoWrites(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// Nothing will be written to the stream // Nothing will be written to the stream
assert.NoError(t, writeContextToStream(nil, strm, nil)) assert.NoError(t, writeContextToStream([]byte{}, strm))
if util.WaitTimeout(wg, 1*time.Second) { if util.WaitTimeout(wg, 1*time.Second) {
t.Fatal("Did not receive stream within 1 sec") t.Fatal("Did not receive stream within 1 sec")
} }
@@ -48,7 +48,7 @@ func TestContextRead_NoReads(t *testing.T) {
wantedData := []byte{'A', 'B', 'C', 'D'} wantedData := []byte{'A', 'B', 'C', 'D'}
nPeer.BHost.SetStreamHandler(core.ProtocolID(prID), func(stream network.Stream) { nPeer.BHost.SetStreamHandler(core.ProtocolID(prID), func(stream network.Stream) {
// No Context will be read from it // No Context will be read from it
dt, err := readContextFromStream(stream, nil) dt, err := readContextFromStream(stream)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 0, len(dt)) assert.Equal(t, 0, len(dt))

View File

@@ -49,7 +49,7 @@ func (s *Service) decodePubsubMessage(msg *pubsub.Message) (ssz.Unmarshaler, err
} }
// Handle different message types across forks. // Handle different message types across forks.
if topic == p2p.BlockSubnetTopicFormat { if topic == p2p.BlockSubnetTopicFormat {
m, err = extractBlockDataType(fDigest[:], s.cfg.chain) m, err = extractBlockDataType(fDigest[:], s.cfg.clock)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -15,6 +15,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2ptesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
@@ -81,8 +82,9 @@ func TestService_decodePubsubMessage(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
chain := &mock.ChainService{ValidatorsRoot: [32]byte{}, Genesis: time.Now()}
s := &Service{ s := &Service{
cfg: &config{p2p: p2ptesting.NewTestP2P(t), chain: &mock.ChainService{ValidatorsRoot: [32]byte{}, Genesis: time.Now()}}, cfg: &config{p2p: p2ptesting.NewTestP2P(t), chain: chain, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot)},
} }
if tt.topic != "" { if tt.topic != "" {
if tt.input == nil { if tt.input == nil {

View File

@@ -13,6 +13,9 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var ErrNoValidDigest = errors.New("no valid digest matched")
var ErrUnrecognizedVersion = errors.New("cannot determine context bytes for unrecognized object")
var responseCodeSuccess = byte(0x00) var responseCodeSuccess = byte(0x00)
var responseCodeInvalidRequest = byte(0x01) var responseCodeInvalidRequest = byte(0x01)
var responseCodeServerError = byte(0x02) var responseCodeServerError = byte(0x02)

View File

@@ -12,7 +12,7 @@ import (
// Is a background routine that observes for new incoming forks. Depending on the epoch // Is a background routine that observes for new incoming forks. Depending on the epoch
// it will be in charge of subscribing/unsubscribing the relevant topics at the fork boundaries. // it will be in charge of subscribing/unsubscribing the relevant topics at the fork boundaries.
func (s *Service) forkWatcher() { func (s *Service) forkWatcher() {
slotTicker := slots.NewSlotTicker(s.cfg.chain.GenesisTime(), params.BeaconConfig().SecondsPerSlot) slotTicker := slots.NewSlotTicker(s.cfg.clock.GenesisTime(), params.BeaconConfig().SecondsPerSlot)
for { for {
select { select {
// In the event of a node restart, we will still end up subscribing to the correct // In the event of a node restart, we will still end up subscribing to the correct
@@ -42,8 +42,8 @@ func (s *Service) forkWatcher() {
// Checks if there is a fork in the next epoch and if there is // Checks if there is a fork in the next epoch and if there is
// it registers the appropriate gossip and rpc topics. // it registers the appropriate gossip and rpc topics.
func (s *Service) registerForUpcomingFork(currEpoch primitives.Epoch) error { func (s *Service) registerForUpcomingFork(currEpoch primitives.Epoch) error {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
isNextForkEpoch, err := forks.IsForkNextEpoch(s.cfg.chain.GenesisTime(), genRoot[:]) isNextForkEpoch, err := forks.IsForkNextEpoch(s.cfg.clock.GenesisTime(), genRoot[:])
if err != nil { if err != nil {
return errors.Wrap(err, "Could not retrieve next fork epoch") return errors.Wrap(err, "Could not retrieve next fork epoch")
} }
@@ -70,7 +70,7 @@ func (s *Service) registerForUpcomingFork(currEpoch primitives.Epoch) error {
// Checks if there was a fork in the previous epoch, and if there // Checks if there was a fork in the previous epoch, and if there
// was then we deregister the topics from that particular fork. // was then we deregister the topics from that particular fork.
func (s *Service) deregisterFromPastFork(currEpoch primitives.Epoch) error { func (s *Service) deregisterFromPastFork(currEpoch primitives.Epoch) error {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
// This method takes care of the de-registration of // This method takes care of the de-registration of
// old gossip pubsub handlers. Once we are at the epoch // old gossip pubsub handlers. Once we are at the epoch
// after the fork, we de-register from all the outdated topics. // after the fork, we de-register from all the outdated topics.

View File

@@ -9,6 +9,7 @@ import (
mockChain "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mockChain "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -29,19 +30,21 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
name: "no fork in the next epoch", name: "no fork in the next epoch",
svcCreator: func(t *testing.T) *Service { svcCreator: func(t *testing.T) *Service {
peer2peer := p2ptest.NewTestP2P(t) peer2peer := p2ptest.NewTestP2P(t)
gt := time.Now().Add(time.Duration(-params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().SlotsPerEpoch))) * time.Second)
vr := [32]byte{'A'}
chainService := &mockChain.ChainService{ chainService := &mockChain.ChainService{
Genesis: time.Now().Add(time.Duration(-params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().SlotsPerEpoch))) * time.Second), Genesis: gt,
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
r := &Service{ r := &Service{
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
cfg: &config{ cfg: &config{
p2p: peer2peer, p2p: peer2peer,
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(), clock: startup.NewClock(gt, vr),
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -58,9 +61,11 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
name: "altair fork in the next epoch", name: "altair fork in the next epoch",
svcCreator: func(t *testing.T) *Service { svcCreator: func(t *testing.T) *Service {
peer2peer := p2ptest.NewTestP2P(t) peer2peer := p2ptest.NewTestP2P(t)
gt := time.Now().Add(-4 * oneEpoch())
vr := [32]byte{'A'}
chainService := &mockChain.ChainService{ chainService := &mockChain.ChainService{
Genesis: time.Now().Add(-4 * oneEpoch()), Genesis: gt,
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
} }
bCfg := params.BeaconConfig().Copy() bCfg := params.BeaconConfig().Copy()
bCfg.AltairForkEpoch = 5 bCfg.AltairForkEpoch = 5
@@ -71,10 +76,10 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
cfg: &config{ cfg: &config{
p2p: peer2peer, p2p: peer2peer,
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(), clock: startup.NewClock(gt, vr),
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -84,7 +89,7 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
currEpoch: 4, currEpoch: 4,
wantErr: false, wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) { postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(5, genRoot[:]) digest, err := forks.ForkDigestFromEpoch(5, genRoot[:])
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, true, s.subHandler.digestExists(digest)) assert.Equal(t, true, s.subHandler.digestExists(digest))
@@ -115,10 +120,10 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
cfg: &config{ cfg: &config{
p2p: peer2peer, p2p: peer2peer,
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(), clock: startup.NewClock(chainService.Genesis, chainService.ValidatorsRoot),
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -128,7 +133,7 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
currEpoch: 4, currEpoch: 4,
wantErr: false, wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) { postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(5, genRoot[:]) digest, err := forks.ForkDigestFromEpoch(5, genRoot[:])
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, true, s.subHandler.digestExists(digest)) assert.Equal(t, true, s.subHandler.digestExists(digest))
@@ -167,15 +172,16 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
Genesis: time.Now().Add(-oneEpoch()), Genesis: time.Now().Add(-oneEpoch()),
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: [32]byte{'A'},
} }
clock := startup.NewClock(chainService.Genesis, chainService.ValidatorsRoot)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
r := &Service{ r := &Service{
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
cfg: &config{ cfg: &config{
p2p: peer2peer, p2p: peer2peer,
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(), clock: clock,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -207,6 +213,7 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
Genesis: time.Now().Add(-4 * oneEpoch()), Genesis: time.Now().Add(-4 * oneEpoch()),
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: [32]byte{'A'},
} }
clock := startup.NewClock(chainService.Genesis, chainService.ValidatorsRoot)
bCfg := params.BeaconConfig().Copy() bCfg := params.BeaconConfig().Copy()
bCfg.AltairForkEpoch = 3 bCfg.AltairForkEpoch = 3
params.OverrideBeaconConfig(bCfg) params.OverrideBeaconConfig(bCfg)
@@ -216,10 +223,10 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
cfg: &config{ cfg: &config{
p2p: peer2peer, p2p: peer2peer,
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(), clock: clock,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -232,7 +239,7 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
chainService.Genesis = prevGenesis chainService.Genesis = prevGenesis
r.registerRPCHandlersAltair() r.registerRPCHandlersAltair()
genRoot := r.cfg.chain.GenesisValidatorsRoot() genRoot := r.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(0, genRoot[:]) digest, err := forks.ForkDigestFromEpoch(0, genRoot[:])
assert.NoError(t, err) assert.NoError(t, err)
r.registerSubscribers(0, digest) r.registerSubscribers(0, digest)
@@ -248,7 +255,7 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
currEpoch: 4, currEpoch: 4,
wantErr: false, wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) { postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(0, genRoot[:]) digest, err := forks.ForkDigestFromEpoch(0, genRoot[:])
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, false, s.subHandler.digestExists(digest)) assert.Equal(t, false, s.subHandler.digestExists(digest))
@@ -281,6 +288,7 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
Genesis: time.Now().Add(-4 * oneEpoch()), Genesis: time.Now().Add(-4 * oneEpoch()),
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: [32]byte{'A'},
} }
clock := startup.NewClock(chainService.Genesis, chainService.ValidatorsRoot)
bCfg := params.BeaconConfig().Copy() bCfg := params.BeaconConfig().Copy()
bCfg.AltairForkEpoch = 1 bCfg.AltairForkEpoch = 1
bCfg.BellatrixForkEpoch = 3 bCfg.BellatrixForkEpoch = 3
@@ -291,15 +299,15 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
cfg: &config{ cfg: &config{
p2p: peer2peer, p2p: peer2peer,
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(), clock: clock,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
} }
genRoot := r.cfg.chain.GenesisValidatorsRoot() genRoot := r.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(1, genRoot[:]) digest, err := forks.ForkDigestFromEpoch(1, genRoot[:])
assert.NoError(t, err) assert.NoError(t, err)
r.registerSubscribers(1, digest) r.registerSubscribers(1, digest)
@@ -315,7 +323,7 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
currEpoch: 4, currEpoch: 4,
wantErr: false, wantErr: false,
postSvcCheck: func(t *testing.T, s *Service) { postSvcCheck: func(t *testing.T, s *Service) {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(1, genRoot[:]) digest, err := forks.ForkDigestFromEpoch(1, genRoot[:])
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, false, s.subHandler.digestExists(digest)) assert.Equal(t, false, s.subHandler.digestExists(digest))

View File

@@ -18,7 +18,6 @@ go_library(
deps = [ deps = [
"//async/abool:go_default_library", "//async/abool:go_default_library",
"//beacon-chain/blockchain:go_default_library", "//beacon-chain/blockchain:go_default_library",
"//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/block:go_default_library", "//beacon-chain/core/feed/block:go_default_library",
"//beacon-chain/core/feed/state:go_default_library", "//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/core/transition:go_default_library", "//beacon-chain/core/transition:go_default_library",
@@ -26,6 +25,7 @@ go_library(
"//beacon-chain/p2p:go_default_library", "//beacon-chain/p2p:go_default_library",
"//beacon-chain/p2p/peers/scorers:go_default_library", "//beacon-chain/p2p/peers/scorers:go_default_library",
"//beacon-chain/p2p/types:go_default_library", "//beacon-chain/p2p/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/sync:go_default_library", "//beacon-chain/sync:go_default_library",
"//cmd/beacon-chain/flags:go_default_library", "//cmd/beacon-chain/flags:go_default_library",
"//config/params:go_default_library", "//config/params:go_default_library",
@@ -107,10 +107,7 @@ go_test(
embed = [":go_default_library"], embed = [":go_default_library"],
deps = [ deps = [
"//async/abool:go_default_library", "//async/abool:go_default_library",
"//async/event:go_default_library",
"//beacon-chain/blockchain/testing:go_default_library", "//beacon-chain/blockchain/testing:go_default_library",
"//beacon-chain/core/feed:go_default_library",
"//beacon-chain/core/feed/state:go_default_library",
"//beacon-chain/db:go_default_library", "//beacon-chain/db:go_default_library",
"//beacon-chain/db/testing:go_default_library", "//beacon-chain/db/testing:go_default_library",
"//beacon-chain/p2p:go_default_library", "//beacon-chain/p2p:go_default_library",
@@ -118,6 +115,7 @@ go_test(
"//beacon-chain/p2p/peers/scorers:go_default_library", "//beacon-chain/p2p/peers/scorers:go_default_library",
"//beacon-chain/p2p/testing:go_default_library", "//beacon-chain/p2p/testing:go_default_library",
"//beacon-chain/p2p/types:go_default_library", "//beacon-chain/p2p/types:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/sync:go_default_library", "//beacon-chain/sync:go_default_library",
"//cmd/beacon-chain/flags:go_default_library", "//cmd/beacon-chain/flags:go_default_library",
"//config/params:go_default_library", "//config/params:go_default_library",

View File

@@ -11,6 +11,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2pTypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types" p2pTypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
prysmsync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" prysmsync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags" "github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -86,6 +87,7 @@ type blocksFetcher struct {
capacityWeight float64 // how remaining capacity affects peer selection capacityWeight float64 // how remaining capacity affects peer selection
mode syncMode // allows to use fetcher in different sync scenarios mode syncMode // allows to use fetcher in different sync scenarios
quit chan struct{} // termination notifier quit chan struct{} // termination notifier
clock *startup.Clock
} }
// peerLock restricts fetcher actions on per peer basis. Currently, used for rate limiting. // peerLock restricts fetcher actions on per peer basis. Currently, used for rate limiting.

View File

@@ -14,6 +14,7 @@ import (
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
p2pm "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" p2pm "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2pt "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2pt "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
beaconsync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" beaconsync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags" "github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -548,7 +549,10 @@ func TestBlocksFetcher_RequestBlocksRateLimitingLocks(t *testing.T) {
defer cancel() defer cancel()
fetcher := newBlocksFetcher(ctx, &blocksFetcherConfig{p2p: p1}) fetcher := newBlocksFetcher(ctx, &blocksFetcherConfig{p2p: p1})
fetcher.rateLimiter = leakybucket.NewCollector(float64(req.Count), int64(req.Count*burstFactor), 1*time.Second, false) fetcher.rateLimiter = leakybucket.NewCollector(float64(req.Count), int64(req.Count*burstFactor), 1*time.Second, false)
fetcher.chain = &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} gt := time.Now()
vr := [32]byte{}
fetcher.chain = &mock.ChainService{Genesis: gt, ValidatorsRoot: vr}
fetcher.clock = startup.NewClock(gt, vr)
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
wg := new(sync.WaitGroup) wg := new(sync.WaitGroup)
wg.Add(1) wg.Add(1)
@@ -614,7 +618,10 @@ func TestBlocksFetcher_WaitForBandwidth(t *testing.T) {
defer cancel() defer cancel()
fetcher := newBlocksFetcher(ctx, &blocksFetcherConfig{p2p: p1}) fetcher := newBlocksFetcher(ctx, &blocksFetcherConfig{p2p: p1})
fetcher.rateLimiter = leakybucket.NewCollector(float64(req.Count), int64(req.Count*burstFactor), 5*time.Second, false) fetcher.rateLimiter = leakybucket.NewCollector(float64(req.Count), int64(req.Count*burstFactor), 5*time.Second, false)
fetcher.chain = &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} gt := time.Now()
vr := [32]byte{}
fetcher.chain = &mock.ChainService{Genesis: gt, ValidatorsRoot: vr}
fetcher.clock = startup.NewClock(gt, vr)
start := time.Now() start := time.Now()
assert.NoError(t, fetcher.waitForBandwidth(p2.PeerID(), 10)) assert.NoError(t, fetcher.waitForBandwidth(p2.PeerID(), 10))
dur := time.Since(start) dur := time.Since(start)
@@ -647,10 +654,10 @@ func TestBlocksFetcher_requestBlocksFromPeerReturningInvalidBlocks(t *testing.T)
for i := req.StartSlot; i < req.StartSlot.Add(req.Count*req.Step); i += primitives.Slot(req.Step) { for i := req.StartSlot; i < req.StartSlot.Add(req.Count*req.Step); i += primitives.Slot(req.Step) {
blk := util.NewBeaconBlock() blk := util.NewBeaconBlock()
blk.Block.Slot = i blk.Block.Slot = i
mchain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} tor := startup.NewClock(time.Now(), [32]byte{})
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, mchain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
} }
assert.NoError(t, stream.Close()) assert.NoError(t, stream.Close())
} }
@@ -671,10 +678,10 @@ func TestBlocksFetcher_requestBlocksFromPeerReturningInvalidBlocks(t *testing.T)
for i := req.StartSlot; i < req.StartSlot.Add(req.Count*req.Step+1); i += primitives.Slot(req.Step) { for i := req.StartSlot; i < req.StartSlot.Add(req.Count*req.Step+1); i += primitives.Slot(req.Step) {
blk := util.NewBeaconBlock() blk := util.NewBeaconBlock()
blk.Block.Slot = i blk.Block.Slot = i
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} tor := startup.NewClock(time.Now(), [32]byte{})
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
} }
assert.NoError(t, stream.Close()) assert.NoError(t, stream.Close())
} }
@@ -695,16 +702,16 @@ func TestBlocksFetcher_requestBlocksFromPeerReturningInvalidBlocks(t *testing.T)
return func(stream network.Stream) { return func(stream network.Stream) {
blk := util.NewBeaconBlock() blk := util.NewBeaconBlock()
blk.Block.Slot = 163 blk.Block.Slot = 163
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} tor := startup.NewClock(time.Now(), [32]byte{})
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
blk = util.NewBeaconBlock() blk = util.NewBeaconBlock()
blk.Block.Slot = 162 blk.Block.Slot = 162
wsb, err = blocks.NewSignedBeaconBlock(blk) wsb, err = blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
assert.NoError(t, stream.Close()) assert.NoError(t, stream.Close())
} }
}, },
@@ -724,17 +731,17 @@ func TestBlocksFetcher_requestBlocksFromPeerReturningInvalidBlocks(t *testing.T)
return func(stream network.Stream) { return func(stream network.Stream) {
blk := util.NewBeaconBlock() blk := util.NewBeaconBlock()
blk.Block.Slot = 160 blk.Block.Slot = 160
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} tor := startup.NewClock(time.Now(), [32]byte{})
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
blk = util.NewBeaconBlock() blk = util.NewBeaconBlock()
blk.Block.Slot = 160 blk.Block.Slot = 160
wsb, err = blocks.NewSignedBeaconBlock(blk) wsb, err = blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
assert.NoError(t, stream.Close()) assert.NoError(t, stream.Close())
} }
}, },
@@ -757,19 +764,19 @@ func TestBlocksFetcher_requestBlocksFromPeerReturningInvalidBlocks(t *testing.T)
}() }()
for i := req.StartSlot; i < req.StartSlot.Add(req.Count*req.Step); i += primitives.Slot(req.Step) { for i := req.StartSlot; i < req.StartSlot.Add(req.Count*req.Step); i += primitives.Slot(req.Step) {
blk := util.NewBeaconBlock() blk := util.NewBeaconBlock()
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} tor := startup.NewClock(time.Now(), [32]byte{})
// Patch mid block, with invalid slot number. // Patch mid block, with invalid slot number.
if i == req.StartSlot.Add(req.Count*req.Step/2) { if i == req.StartSlot.Add(req.Count*req.Step/2) {
blk.Block.Slot = req.StartSlot - 1 blk.Block.Slot = req.StartSlot - 1
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
break break
} }
blk.Block.Slot = i blk.Block.Slot = i
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
} }
} }
}, },
@@ -792,19 +799,19 @@ func TestBlocksFetcher_requestBlocksFromPeerReturningInvalidBlocks(t *testing.T)
}() }()
for i := req.StartSlot; i < req.StartSlot.Add(req.Count*req.Step); i += primitives.Slot(req.Step) { for i := req.StartSlot; i < req.StartSlot.Add(req.Count*req.Step); i += primitives.Slot(req.Step) {
blk := util.NewBeaconBlock() blk := util.NewBeaconBlock()
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} tor := startup.NewClock(time.Now(), [32]byte{})
// Patch mid block, with invalid slot number. // Patch mid block, with invalid slot number.
if i == req.StartSlot.Add(req.Count*req.Step/2) { if i == req.StartSlot.Add(req.Count*req.Step/2) {
blk.Block.Slot = req.StartSlot.Add(req.Count * req.Step) blk.Block.Slot = req.StartSlot.Add(req.Count * req.Step)
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
break break
} }
blk.Block.Slot = i blk.Block.Slot = i
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
} }
} }
}, },
@@ -824,16 +831,16 @@ func TestBlocksFetcher_requestBlocksFromPeerReturningInvalidBlocks(t *testing.T)
return func(stream network.Stream) { return func(stream network.Stream) {
blk := util.NewBeaconBlock() blk := util.NewBeaconBlock()
blk.Block.Slot = 100 blk.Block.Slot = 100
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} tor := startup.NewClock(time.Now(), [32]byte{})
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
blk = util.NewBeaconBlock() blk = util.NewBeaconBlock()
blk.Block.Slot = 105 blk.Block.Slot = 105
wsb, err = blocks.NewSignedBeaconBlock(blk) wsb, err = blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
assert.NoError(t, stream.Close()) assert.NoError(t, stream.Close())
} }
}, },
@@ -852,16 +859,16 @@ func TestBlocksFetcher_requestBlocksFromPeerReturningInvalidBlocks(t *testing.T)
return func(stream network.Stream) { return func(stream network.Stream) {
blk := util.NewBeaconBlock() blk := util.NewBeaconBlock()
blk.Block.Slot = 100 blk.Block.Slot = 100
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} tor := startup.NewClock(time.Now(), [32]byte{})
wsb, err := blocks.NewSignedBeaconBlock(blk) wsb, err := blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
blk = util.NewBeaconBlock() blk = util.NewBeaconBlock()
blk.Block.Slot = 103 blk.Block.Slot = 103
wsb, err = blocks.NewSignedBeaconBlock(blk) wsb, err = blocks.NewSignedBeaconBlock(blk)
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p1.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, tor, p1.Encoding(), wsb))
assert.NoError(t, stream.Close()) assert.NoError(t, stream.Close())
} }
}, },

View File

@@ -17,6 +17,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers"
p2pt "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2pt "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
p2pTypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types" p2pTypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
beaconsync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync" beaconsync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags" "github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -210,11 +211,10 @@ func connectPeer(t *testing.T, host *p2pt.TestP2P, datum *peerData, peerStatus *
ret = ret[:req.Count] ret = ret[:req.Count]
} }
mChain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
for i := 0; i < len(ret); i++ { for i := 0; i < len(ret); i++ {
wsb, err := blocks.NewSignedBeaconBlock(ret[i]) wsb, err := blocks.NewSignedBeaconBlock(ret[i])
require.NoError(t, err) require.NoError(t, err)
assert.NoError(t, beaconsync.WriteBlockChunk(stream, mChain, p.Encoding(), wsb)) assert.NoError(t, beaconsync.WriteBlockChunk(stream, startup.NewClock(time.Now(), [32]byte{}), p.Encoding(), wsb))
} }
}) })
@@ -283,10 +283,9 @@ func connectPeerHavingBlocks(
if uint64(i) >= uint64(len(blks)) { if uint64(i) >= uint64(len(blks)) {
break break
} }
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
wsb, err := blocks.NewSignedBeaconBlock(blks[i]) wsb, err := blocks.NewSignedBeaconBlock(blks[i])
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, beaconsync.WriteBlockChunk(stream, chain, p.Encoding(), wsb)) require.NoError(t, beaconsync.WriteBlockChunk(stream, startup.NewClock(time.Now(), [32]byte{}), p.Encoding(), wsb))
} }
}) })

View File

@@ -11,11 +11,11 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/async/abool" "github.com/prysmaticlabs/prysm/v4/async/abool"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain" "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
blockfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/block" blockfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/block"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state" statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags" "github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/runtime" "github.com/prysmaticlabs/prysm/v4/runtime"
@@ -34,11 +34,13 @@ type blockchainService interface {
// Config to set up the initial sync service. // Config to set up the initial sync service.
type Config struct { type Config struct {
P2P p2p.P2P P2P p2p.P2P
DB db.ReadOnlyDatabase DB db.ReadOnlyDatabase
Chain blockchainService Chain blockchainService
StateNotifier statefeed.Notifier StateNotifier statefeed.Notifier
BlockNotifier blockfeed.Notifier BlockNotifier blockfeed.Notifier
ClockWaiter startup.ClockWaiter
InitialSyncComplete chan struct{}
} }
// Service service. // Service service.
@@ -50,6 +52,7 @@ type Service struct {
chainStarted *abool.AtomicBool chainStarted *abool.AtomicBool
counter *ratecounter.RateCounter counter *ratecounter.RateCounter
genesisChan chan time.Time genesisChan chan time.Time
clock *startup.Clock
} }
// NewService configures the initial sync service responsible for bringing the node up to the // NewService configures the initial sync service responsible for bringing the node up to the
@@ -66,31 +69,34 @@ func NewService(ctx context.Context, cfg *Config) *Service {
genesisChan: make(chan time.Time), genesisChan: make(chan time.Time),
} }
// The reason why we have this goroutine in the constructor is to avoid a race condition
// between services' Start method and the initialization event.
// See https://github.com/prysmaticlabs/prysm/issues/10602 for details.
go s.waitForStateInitialization()
return s return s
} }
// Start the initial sync service. // Start the initial sync service.
func (s *Service) Start() { func (s *Service) Start() {
// Wait for state initialized event. log.Info("Waiting for state to be initialized")
genesis := <-s.genesisChan clock, err := s.cfg.ClockWaiter.WaitForClock(s.ctx)
if genesis.IsZero() { if err != nil {
log.WithError(err).Error("initial-sync failed to receive startup event")
return
}
s.clock = clock
log.Info("Received state initialized event")
gt := clock.GenesisTime()
if gt.IsZero() {
log.Debug("Exiting Initial Sync Service") log.Debug("Exiting Initial Sync Service")
return return
} }
if genesis.After(prysmTime.Now()) { if gt.After(prysmTime.Now()) {
s.markSynced(genesis) s.markSynced()
log.WithField("genesisTime", genesis).Info("Genesis time has not arrived - not syncing") log.WithField("genesisTime", gt).Info("Genesis time has not arrived - not syncing")
return return
} }
currentSlot := slots.Since(genesis) currentSlot := clock.CurrentSlot()
if slots.ToEpoch(currentSlot) == 0 { if slots.ToEpoch(currentSlot) == 0 {
log.WithField("genesisTime", genesis).Info("Chain started within the last epoch - not syncing") log.WithField("genesisTime", gt).Info("Chain started within the last epoch - not syncing")
s.markSynced(genesis) s.markSynced()
return return
} }
s.chainStarted.Set() s.chainStarted.Set()
@@ -98,18 +104,18 @@ func (s *Service) Start() {
// Are we already in sync, or close to it? // Are we already in sync, or close to it?
if slots.ToEpoch(s.cfg.Chain.HeadSlot()) == slots.ToEpoch(currentSlot) { if slots.ToEpoch(s.cfg.Chain.HeadSlot()) == slots.ToEpoch(currentSlot) {
log.Info("Already synced to the current chain head") log.Info("Already synced to the current chain head")
s.markSynced(genesis) s.markSynced()
return return
} }
s.waitForMinimumPeers() s.waitForMinimumPeers()
if err := s.roundRobinSync(genesis); err != nil { if err := s.roundRobinSync(gt); err != nil {
if errors.Is(s.ctx.Err(), context.Canceled) { if errors.Is(s.ctx.Err(), context.Canceled) {
return return
} }
panic(err) panic(err)
} }
log.Infof("Synced up to slot %d", s.cfg.Chain.HeadSlot()) log.Infof("Synced up to slot %d", s.cfg.Chain.HeadSlot())
s.markSynced(genesis) s.markSynced()
} }
// Stop initial sync. // Stop initial sync.
@@ -181,48 +187,8 @@ func (s *Service) waitForMinimumPeers() {
} }
} }
// waitForStateInitialization makes sure that beacon node is ready to be accessed: it is either
// already properly configured or system waits up until state initialized event is triggered.
func (s *Service) waitForStateInitialization() {
// Wait for state to be initialized.
stateChannel := make(chan *feed.Event, 1)
stateSub := s.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
defer stateSub.Unsubscribe()
log.Info("Waiting for state to be initialized")
for {
select {
case event := <-stateChannel:
if event.Type == statefeed.Initialized {
data, ok := event.Data.(*statefeed.InitializedData)
if !ok {
log.Error("Event feed data is not type *statefeed.InitializedData")
continue
}
log.WithField("starttime", data.StartTime).Debug("Received state initialized event")
s.genesisChan <- data.StartTime
return
}
case <-s.ctx.Done():
log.Debug("Context closed, exiting goroutine")
// Send a zero time in the event we are exiting.
s.genesisChan <- time.Time{}
return
case err := <-stateSub.Err():
log.WithError(err).Error("Subscription to state notifier failed")
// Send a zero time in the event we are exiting.
s.genesisChan <- time.Time{}
return
}
}
}
// markSynced marks node as synced and notifies feed listeners. // markSynced marks node as synced and notifies feed listeners.
func (s *Service) markSynced(genesis time.Time) { func (s *Service) markSynced() {
s.synced.Set() s.synced.Set()
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{ close(s.cfg.InitialSyncComplete)
Type: statefeed.Synced,
Data: &statefeed.SyncedData{
StartTime: genesis,
},
})
} }

View File

@@ -8,12 +8,10 @@ import (
"github.com/paulbellamy/ratecounter" "github.com/paulbellamy/ratecounter"
"github.com/prysmaticlabs/prysm/v4/async/abool" "github.com/prysmaticlabs/prysm/v4/async/abool"
"github.com/prysmaticlabs/prysm/v4/async/event"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
p2pt "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2pt "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags" "github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -36,7 +34,7 @@ func TestService_InitStartStop(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
assert func() assert func()
methodRuns func(fd *event.Feed) setGenesis func() *startup.Clock
chainService func() *mock.ChainService chainService func() *mock.ChainService
}{ }{
{ {
@@ -61,15 +59,9 @@ func TestService_InitStartStop(t *testing.T) {
ValidatorsRoot: [32]byte{}, ValidatorsRoot: [32]byte{},
} }
}, },
methodRuns: func(fd *event.Feed) { setGenesis: func() *startup.Clock {
// Send valid event. var vr [32]byte
fd.Send(&feed.Event{ return startup.NewClock(time.Unix(4113849600, 0), vr)
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: time.Unix(4113849600, 0),
GenesisValidatorsRoot: make([]byte, 32),
},
})
}, },
assert: func() { assert: func() {
assert.LogsContain(t, hook, "Genesis time has not arrived - not syncing") assert.LogsContain(t, hook, "Genesis time has not arrived - not syncing")
@@ -91,15 +83,9 @@ func TestService_InitStartStop(t *testing.T) {
ValidatorsRoot: [32]byte{}, ValidatorsRoot: [32]byte{},
} }
}, },
methodRuns: func(fd *event.Feed) { setGenesis: func() *startup.Clock {
// Send valid event. var vr [32]byte
fd.Send(&feed.Event{ return startup.NewClock(time.Now().Add(-5*time.Minute), vr)
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: time.Now().Add(-5 * time.Minute),
GenesisValidatorsRoot: make([]byte, 32),
},
})
}, },
assert: func() { assert: func() {
assert.LogsContain(t, hook, "Chain started within the last epoch - not syncing") assert.LogsContain(t, hook, "Chain started within the last epoch - not syncing")
@@ -124,16 +110,10 @@ func TestService_InitStartStop(t *testing.T) {
ValidatorsRoot: [32]byte{}, ValidatorsRoot: [32]byte{},
} }
}, },
methodRuns: func(fd *event.Feed) { setGenesis: func() *startup.Clock {
futureSlot := primitives.Slot(27354) futureSlot := primitives.Slot(27354)
// Send valid event. var vr [32]byte
fd.Send(&feed.Event{ return startup.NewClock(makeGenesisTime(futureSlot), vr)
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: makeGenesisTime(futureSlot),
GenesisValidatorsRoot: make([]byte, 32),
},
})
}, },
assert: func() { assert: func() {
assert.LogsContain(t, hook, "Starting initial chain sync...") assert.LogsContain(t, hook, "Starting initial chain sync...")
@@ -161,16 +141,18 @@ func TestService_InitStartStop(t *testing.T) {
mc = tt.chainService() mc = tt.chainService()
} }
// Initialize feed // Initialize feed
notifier := &mock.MockStateNotifier{} gs := startup.NewClockSynchronizer()
s := NewService(ctx, &Config{ s := NewService(ctx, &Config{
P2P: p, P2P: p,
Chain: mc, Chain: mc,
StateNotifier: notifier, ClockWaiter: gs,
StateNotifier: &mock.MockStateNotifier{},
InitialSyncComplete: make(chan struct{}),
}) })
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
assert.NotNil(t, s) assert.NotNil(t, s)
if tt.methodRuns != nil { if tt.setGenesis != nil {
tt.methodRuns(notifier.StateFeed()) require.NoError(t, gs.SetClock(tt.setGenesis()))
} }
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
@@ -197,10 +179,11 @@ func TestService_InitStartStop(t *testing.T) {
func TestService_waitForStateInitialization(t *testing.T) { func TestService_waitForStateInitialization(t *testing.T) {
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
newService := func(ctx context.Context, mc *mock.ChainService) *Service { newService := func(ctx context.Context, mc *mock.ChainService) (*Service, *startup.ClockSynchronizer) {
cs := startup.NewClockSynchronizer()
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
s := &Service{ s := &Service{
cfg: &Config{Chain: mc, StateNotifier: mc.StateNotifier()}, cfg: &Config{Chain: mc, StateNotifier: mc.StateNotifier(), ClockWaiter: cs, InitialSyncComplete: make(chan struct{})},
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
synced: abool.New(), synced: abool.New(),
@@ -208,7 +191,7 @@ func TestService_waitForStateInitialization(t *testing.T) {
counter: ratecounter.NewRateCounter(counterSeconds * time.Second), counter: ratecounter.NewRateCounter(counterSeconds * time.Second),
genesisChan: make(chan time.Time), genesisChan: make(chan time.Time),
} }
return s return s, cs
} }
t.Run("no state and context close", func(t *testing.T) { t.Run("no state and context close", func(t *testing.T) {
@@ -216,13 +199,11 @@ func TestService_waitForStateInitialization(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
s := newService(ctx, &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}) s, _ := newService(ctx, &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}})
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(1) wg.Add(1)
go func() { go func() {
go s.waitForStateInitialization() s.Start()
currTime := <-s.genesisChan
assert.Equal(t, true, currTime.IsZero())
wg.Done() wg.Done()
}() }()
go func() { go func() {
@@ -235,7 +216,7 @@ func TestService_waitForStateInitialization(t *testing.T) {
t.Fatalf("Test should have exited by now, timed out") t.Fatalf("Test should have exited by now, timed out")
} }
assert.LogsContain(t, hook, "Waiting for state to be initialized") assert.LogsContain(t, hook, "Waiting for state to be initialized")
assert.LogsContain(t, hook, "Context closed, exiting goroutine") assert.LogsContain(t, hook, "initial-sync failed to receive startup event")
assert.LogsDoNotContain(t, hook, "Subscription to state notifier failed") assert.LogsDoNotContain(t, hook, "Subscription to state notifier failed")
}) })
@@ -243,41 +224,30 @@ func TestService_waitForStateInitialization(t *testing.T) {
defer hook.Reset() defer hook.Reset()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
s := newService(ctx, &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}})
expectedGenesisTime := time.Unix(358544700, 0) st, err := util.NewBeaconState()
var receivedGenesisTime time.Time require.NoError(t, err)
gt := time.Unix(int64(st.GenesisTime()), 0)
s, gs := newService(ctx, &mock.ChainService{State: st, Genesis: gt, ValidatorsRoot: [32]byte{}})
expectedGenesisTime := gt
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(1) wg.Add(1)
go func() { go func() {
go s.waitForStateInitialization() s.Start()
receivedGenesisTime = <-s.genesisChan
assert.Equal(t, false, receivedGenesisTime.IsZero())
wg.Done() wg.Done()
}() }()
rg := func() time.Time { return gt.Add(time.Second * 12) }
go func() { go func() {
time.AfterFunc(500*time.Millisecond, func() { time.AfterFunc(200*time.Millisecond, func() {
// Send invalid event at first. var vr [32]byte
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{ require.NoError(t, gs.SetClock(startup.NewClock(expectedGenesisTime, vr, startup.WithNower(rg))))
Type: statefeed.Initialized,
Data: &statefeed.BlockProcessedData{},
})
// Send valid event.
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: expectedGenesisTime,
GenesisValidatorsRoot: make([]byte, 32),
},
})
}) })
}() }()
if util.WaitTimeout(wg, time.Second*2) { if util.WaitTimeout(wg, time.Second*2) {
t.Fatalf("Test should have exited by now, timed out") t.Fatalf("Test should have exited by now, timed out")
} }
assert.Equal(t, expectedGenesisTime, receivedGenesisTime)
assert.LogsContain(t, hook, "Event feed data is not type *statefeed.InitializedData")
assert.LogsContain(t, hook, "Waiting for state to be initialized") assert.LogsContain(t, hook, "Waiting for state to be initialized")
assert.LogsContain(t, hook, "Received state initialized event") assert.LogsContain(t, hook, "Received state initialized event")
assert.LogsDoNotContain(t, hook, "Context closed, exiting goroutine") assert.LogsDoNotContain(t, hook, "Context closed, exiting goroutine")
@@ -287,29 +257,17 @@ func TestService_waitForStateInitialization(t *testing.T) {
defer hook.Reset() defer hook.Reset()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
s := newService(ctx, &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}) s, gs := newService(ctx, &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}})
// Initialize mock feed // Initialize mock feed
_ = s.cfg.StateNotifier.StateFeed() _ = s.cfg.StateNotifier.StateFeed()
expectedGenesisTime := time.Now().Add(60 * time.Second) expectedGenesisTime := time.Now().Add(60 * time.Second)
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
s.waitForStateInitialization()
wg.Done()
}()
wg.Add(1) wg.Add(1)
go func() { go func() {
time.AfterFunc(500*time.Millisecond, func() { time.AfterFunc(500*time.Millisecond, func() {
// Send valid event. var vr [32]byte
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{ require.NoError(t, gs.SetClock(startup.NewClock(expectedGenesisTime, vr)))
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: expectedGenesisTime,
GenesisValidatorsRoot: make([]byte, 32),
},
})
}) })
s.Start() s.Start()
wg.Done() wg.Done()
@@ -326,11 +284,12 @@ func TestService_waitForStateInitialization(t *testing.T) {
func TestService_markSynced(t *testing.T) { func TestService_markSynced(t *testing.T) {
mc := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} mc := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel() defer cancel()
s := NewService(ctx, &Config{ s := NewService(ctx, &Config{
Chain: mc, Chain: mc,
StateNotifier: mc.StateNotifier(), StateNotifier: mc.StateNotifier(),
InitialSyncComplete: make(chan struct{}),
}) })
require.NotNil(t, s) require.NotNil(t, s)
assert.Equal(t, false, s.chainStarted.IsSet()) assert.Equal(t, false, s.chainStarted.IsSet())
@@ -340,33 +299,16 @@ func TestService_markSynced(t *testing.T) {
s.chainStarted.Set() s.chainStarted.Set()
assert.ErrorContains(t, "syncing", s.Status()) assert.ErrorContains(t, "syncing", s.Status())
expectedGenesisTime := time.Unix(358544700, 0)
var receivedGenesisTime time.Time
stateChannel := make(chan *feed.Event, 1)
stateSub := s.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
defer stateSub.Unsubscribe()
wg := &sync.WaitGroup{}
wg.Add(1)
go func() { go func() {
select { s.markSynced()
case stateEvent := <-stateChannel:
if stateEvent.Type == statefeed.Synced {
data, ok := stateEvent.Data.(*statefeed.SyncedData)
require.Equal(t, true, ok, "Event feed data is not type *statefeed.SyncedData")
receivedGenesisTime = data.StartTime
}
case <-s.ctx.Done():
}
wg.Done()
}() }()
s.markSynced(expectedGenesisTime)
if util.WaitTimeout(wg, time.Second*2) { select {
t.Fatalf("Test should have exited by now, timed out") case <-s.cfg.InitialSyncComplete:
case <-ctx.Done():
require.NoError(t, ctx.Err()) // this is an error because it means initial sync complete failed to close
} }
assert.Equal(t, expectedGenesisTime, receivedGenesisTime)
assert.Equal(t, false, s.Syncing()) assert.Equal(t, false, s.Syncing())
} }
@@ -459,9 +401,7 @@ func TestService_Initialized(t *testing.T) {
} }
func TestService_Synced(t *testing.T) { func TestService_Synced(t *testing.T) {
s := NewService(context.Background(), &Config{ s := NewService(context.Background(), &Config{})
StateNotifier: &mock.MockStateNotifier{},
})
s.synced.UnSet() s.synced.UnSet()
assert.Equal(t, false, s.Synced()) assert.Equal(t, false, s.Synced())
s.synced.Set() s.synced.Set()

View File

@@ -130,7 +130,7 @@ var (
func (s *Service) updateMetrics() { func (s *Service) updateMetrics() {
// do not update metrics if genesis time // do not update metrics if genesis time
// has not been initialized // has not been initialized
if s.cfg.chain.GenesisTime().IsZero() { if s.cfg.clock.GenesisTime().IsZero() {
return return
} }
// We update the dynamic subnet topics. // We update the dynamic subnet topics.
@@ -138,8 +138,8 @@ func (s *Service) updateMetrics() {
if err != nil { if err != nil {
log.WithError(err).Debugf("Could not compute fork digest") log.WithError(err).Debugf("Could not compute fork digest")
} }
indices := s.aggregatorSubnetIndices(s.cfg.chain.CurrentSlot()) indices := s.aggregatorSubnetIndices(s.cfg.clock.CurrentSlot())
syncIndices := cache.SyncSubnetIDs.GetAllSubnets(slots.ToEpoch(s.cfg.chain.CurrentSlot())) syncIndices := cache.SyncSubnetIDs.GetAllSubnets(slots.ToEpoch(s.cfg.clock.CurrentSlot()))
attTopic := p2p.GossipTypeMapping[reflect.TypeOf(&pb.Attestation{})] attTopic := p2p.GossipTypeMapping[reflect.TypeOf(&pb.Attestation{})]
syncTopic := p2p.GossipTypeMapping[reflect.TypeOf(&pb.SyncCommitteeMessage{})] syncTopic := p2p.GossipTypeMapping[reflect.TypeOf(&pb.SyncCommitteeMessage{})]
attTopic += s.cfg.p2p.Encoding().ProtocolSuffix() attTopic += s.cfg.p2p.Encoding().ProtocolSuffix()

View File

@@ -4,7 +4,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/async/event" "github.com/prysmaticlabs/prysm/v4/async/event"
blockfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/block" blockfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/block"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/operation" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/operation"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/execution" "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
@@ -13,6 +12,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
) )
@@ -88,13 +88,6 @@ func WithInitialSync(initialSync Checker) Option {
} }
} }
func WithStateNotifier(stateNotifier statefeed.Notifier) Option {
return func(s *Service) error {
s.cfg.stateNotifier = stateNotifier
return nil
}
}
func WithBlockNotifier(blockNotifier blockfeed.Notifier) Option { func WithBlockNotifier(blockNotifier blockfeed.Notifier) Option {
return func(s *Service) error { return func(s *Service) error {
s.cfg.blockNotifier = blockNotifier s.cfg.blockNotifier = blockNotifier
@@ -136,3 +129,17 @@ func WithExecutionPayloadReconstructor(r execution.ExecutionPayloadReconstructor
return nil return nil
} }
} }
func WithClockWaiter(cw startup.ClockWaiter) Option {
return func(s *Service) error {
s.clockWaiter = cw
return nil
}
}
func WithInitialSyncComplete(c chan struct{}) Option {
return func(s *Service) error {
s.initialSyncComplete = c
return nil
}
}

View File

@@ -46,7 +46,7 @@ func (s *Service) processPendingAtts(ctx context.Context) error {
// Before a node processes pending attestations queue, it verifies // Before a node processes pending attestations queue, it verifies
// the attestations in the queue are still valid. Attestations will // the attestations in the queue are still valid. Attestations will
// be deleted from the queue if invalid (ie. getting staled from falling too many slots behind). // be deleted from the queue if invalid (ie. getting staled from falling too many slots behind).
s.validatePendingAtts(ctx, s.cfg.chain.CurrentSlot()) s.validatePendingAtts(ctx, s.cfg.clock.CurrentSlot())
s.pendingAttsLock.RLock() s.pendingAttsLock.RLock()
roots := make([][32]byte, 0, len(s.blkRootToPendingAtts)) roots := make([][32]byte, 0, len(s.blkRootToPendingAtts))
@@ -76,7 +76,7 @@ func (s *Service) processPendingAtts(ctx context.Context) error {
} else { } else {
// Pending attestation's missing block has not arrived yet. // Pending attestation's missing block has not arrived yet.
log.WithFields(logrus.Fields{ log.WithFields(logrus.Fields{
"currentSlot": s.cfg.chain.CurrentSlot(), "currentSlot": s.cfg.clock.CurrentSlot(),
"attSlot": attestations[0].Message.Aggregate.Data.Slot, "attSlot": attestations[0].Message.Aggregate.Data.Slot,
"attCount": len(attestations), "attCount": len(attestations),
"blockRoot": hex.EncodeToString(bytesutil.Trunc(bRoot[:])), "blockRoot": hex.EncodeToString(bytesutil.Trunc(bRoot[:])),

View File

@@ -16,6 +16,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru" lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -42,8 +43,9 @@ func TestProcessPendingAtts_NoBlockRequestBlock(t *testing.T) {
p1.Peers().SetConnectionState(p2.PeerID(), peers.PeerConnected) p1.Peers().SetConnectionState(p2.PeerID(), peers.PeerConnected)
p1.Peers().SetChainState(p2.PeerID(), &ethpb.Status{}) p1.Peers().SetChainState(p2.PeerID(), &ethpb.Status{})
chain := &mock.ChainService{Genesis: prysmTime.Now(), FinalizedCheckPoint: &ethpb.Checkpoint{}}
r := &Service{ r := &Service{
cfg: &config{p2p: p1, beaconDB: db, chain: &mock.ChainService{Genesis: prysmTime.Now(), FinalizedCheckPoint: &ethpb.Checkpoint{}}}, cfg: &config{p2p: p1, beaconDB: db, chain: chain, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot)},
blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof), blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof),
chainStarted: abool.New(), chainStarted: abool.New(),
} }
@@ -105,20 +107,22 @@ func TestProcessPendingAtts_HasBlockSaveUnAggregatedAtt(t *testing.T) {
require.NoError(t, beaconState.SetGenesisTime(uint64(time.Now().Unix()))) require.NoError(t, beaconState.SetGenesisTime(uint64(time.Now().Unix())))
chain := &mock.ChainService{Genesis: time.Now(),
State: beaconState,
FinalizedCheckPoint: &ethpb.Checkpoint{
Root: aggregateAndProof.Aggregate.Data.BeaconBlockRoot,
Epoch: 0,
},
}
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
r := &Service{ r := &Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
beaconDB: db, beaconDB: db,
chain: &mock.ChainService{Genesis: time.Now(), chain: chain,
State: beaconState, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
FinalizedCheckPoint: &ethpb.Checkpoint{ attPool: attestations.NewPool(),
Root: aggregateAndProof.Aggregate.Data.BeaconBlockRoot,
Epoch: 0,
},
},
attPool: attestations.NewPool(),
}, },
blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof), blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof),
seenUnAggregatedAttestationCache: lruwrpr.New(10), seenUnAggregatedAttestationCache: lruwrpr.New(10),
@@ -147,14 +151,16 @@ func TestProcessPendingAtts_NoBroadcastWithBadSignature(t *testing.T) {
p1 := p2ptest.NewTestP2P(t) p1 := p2ptest.NewTestP2P(t)
s, _ := util.DeterministicGenesisState(t, 256) s, _ := util.DeterministicGenesisState(t, 256)
chain := &mock.ChainService{
State: s,
Genesis: prysmTime.Now(), FinalizedCheckPoint: &ethpb.Checkpoint{Root: make([]byte, 32)}}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
beaconDB: db, beaconDB: db,
chain: &mock.ChainService{ chain: chain,
State: s, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
Genesis: prysmTime.Now(), FinalizedCheckPoint: &ethpb.Checkpoint{Root: make([]byte, 32)}}, attPool: attestations.NewPool(),
attPool: attestations.NewPool(),
}, },
blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof), blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof),
} }
@@ -224,18 +230,20 @@ func TestProcessPendingAtts_NoBroadcastWithBadSignature(t *testing.T) {
require.NoError(t, s.SetGenesisTime(uint64(time.Now().Unix()))) require.NoError(t, s.SetGenesisTime(uint64(time.Now().Unix())))
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
chain2 := &mock.ChainService{Genesis: time.Now(),
State: s,
FinalizedCheckPoint: &ethpb.Checkpoint{
Root: aggregateAndProof.Aggregate.Data.BeaconBlockRoot,
Epoch: 0,
}}
r = &Service{ r = &Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
beaconDB: db, beaconDB: db,
chain: &mock.ChainService{Genesis: time.Now(), chain: chain2,
State: s, clock: startup.NewClock(chain2.Genesis, chain2.ValidatorsRoot),
FinalizedCheckPoint: &ethpb.Checkpoint{ attPool: attestations.NewPool(),
Root: aggregateAndProof.Aggregate.Data.BeaconBlockRoot,
Epoch: 0,
}},
attPool: attestations.NewPool(),
}, },
blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof), blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof),
seenUnAggregatedAttestationCache: lruwrpr.New(10), seenUnAggregatedAttestationCache: lruwrpr.New(10),
@@ -305,20 +313,22 @@ func TestProcessPendingAtts_HasBlockSaveAggregatedAtt(t *testing.T) {
require.NoError(t, beaconState.SetGenesisTime(uint64(time.Now().Unix()))) require.NoError(t, beaconState.SetGenesisTime(uint64(time.Now().Unix())))
chain := &mock.ChainService{Genesis: time.Now(),
DB: db,
State: beaconState,
FinalizedCheckPoint: &ethpb.Checkpoint{
Root: aggregateAndProof.Aggregate.Data.BeaconBlockRoot,
Epoch: 0,
}}
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
r := &Service{ r := &Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
beaconDB: db, beaconDB: db,
chain: &mock.ChainService{Genesis: time.Now(), chain: chain,
DB: db, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
State: beaconState, attPool: attestations.NewPool(),
FinalizedCheckPoint: &ethpb.Checkpoint{
Root: aggregateAndProof.Aggregate.Data.BeaconBlockRoot,
Epoch: 0,
}},
attPool: attestations.NewPool(),
}, },
blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof), blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof),
seenAggregatedAttestationCache: lruwrpr.New(10), seenAggregatedAttestationCache: lruwrpr.New(10),

View File

@@ -37,7 +37,7 @@ func (s *Service) processPendingBlocksQueue() {
locker := new(sync.Mutex) locker := new(sync.Mutex)
async.RunEvery(s.ctx, processPendingBlocksPeriod, func() { async.RunEvery(s.ctx, processPendingBlocksPeriod, func() {
// Don't process the pending blocks if genesis time has not been set. The chain is not ready. // Don't process the pending blocks if genesis time has not been set. The chain is not ready.
if !s.isGenesisTimeSet() { if !s.chainIsStarted() {
return return
} }
locker.Lock() locker.Lock()
@@ -69,7 +69,7 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
for _, slot := range ss { for _, slot := range ss {
// process the blocks during their respective slot. // process the blocks during their respective slot.
// otherwise wait for the right slot to process the block. // otherwise wait for the right slot to process the block.
if slot > s.cfg.chain.CurrentSlot() { if slot > s.cfg.clock.CurrentSlot() {
continue continue
} }
@@ -445,12 +445,6 @@ func (s *Service) addPendingBlockToCache(b interfaces.ReadOnlySignedBeaconBlock)
return nil return nil
} }
// Returns true if the genesis time has been set in chain service.
// Without the genesis time, the chain does not start.
func (s *Service) isGenesisTimeSet() bool {
return s.cfg.chain.GenesisTime().Unix() != 0
}
// This converts input string to slot. // This converts input string to slot.
func cacheKeyToSlot(s string) primitives.Slot { func cacheKeyToSlot(s string) primitives.Slot {
b := []byte(s) b := []byte(s)

View File

@@ -20,6 +20,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types" p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
@@ -51,6 +52,7 @@ func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks1(t *testing.T) {
Epoch: 0, Epoch: 0,
}, },
}, },
clock: startup.NewClock(time.Unix(0, 0), [32]byte{}),
stateGen: stategen.New(db, doublylinkedtree.New()), stateGen: stategen.New(db, doublylinkedtree.New()),
}, },
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
@@ -123,6 +125,7 @@ func TestRegularSyncBeaconBlockSubscriber_OptimisticStatus(t *testing.T) {
Epoch: 0, Epoch: 0,
}, },
}, },
clock: startup.NewClock(time.Unix(0, 0), [32]byte{}),
stateGen: stategen.New(db, doublylinkedtree.New()), stateGen: stategen.New(db, doublylinkedtree.New()),
}, },
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
@@ -196,6 +199,7 @@ func TestRegularSyncBeaconBlockSubscriber_ExecutionEngineTimesOut(t *testing.T)
}, },
ReceiveBlockMockErr: execution.ErrHTTPTimeout, ReceiveBlockMockErr: execution.ErrHTTPTimeout,
}, },
clock: startup.NewClock(time.Unix(0, 0), [32]byte{}),
stateGen: stategen.New(db, fcs), stateGen: stategen.New(db, fcs),
}, },
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
@@ -323,6 +327,7 @@ func TestRegularSyncBeaconBlockSubscriber_DoNotReprocessBlock(t *testing.T) {
Epoch: 0, Epoch: 0,
}, },
}, },
clock: startup.NewClock(time.Unix(0, 0), [32]byte{}),
stateGen: stategen.New(db, doublylinkedtree.New()), stateGen: stategen.New(db, doublylinkedtree.New()),
}, },
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
@@ -391,6 +396,7 @@ func TestRegularSyncBeaconBlockSubscriber_ProcessPendingBlocks_2Chains(t *testin
Root: make([]byte, 32), Root: make([]byte, 32),
}, },
}, },
clock: startup.NewClock(time.Unix(0, 0), [32]byte{}),
stateGen: stategen.New(db, doublylinkedtree.New()), stateGen: stategen.New(db, doublylinkedtree.New()),
}, },
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
@@ -583,18 +589,20 @@ func TestService_BatchRootRequest(t *testing.T) {
p1.Connect(p2) p1.Connect(p2)
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
chain := &mock.ChainService{
FinalizedCheckPoint: &ethpb.Checkpoint{
Epoch: 1,
Root: make([]byte, 32),
},
ValidatorsRoot: [32]byte{},
Genesis: time.Now(),
}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
beaconDB: db, beaconDB: db,
chain: &mock.ChainService{ chain: chain,
FinalizedCheckPoint: &ethpb.Checkpoint{ clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
Epoch: 1,
Root: make([]byte, 32),
},
ValidatorsRoot: [32]byte{},
Genesis: time.Now(),
},
}, },
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
seenPendingBlocks: make(map[[32]byte]bool), seenPendingBlocks: make(map[[32]byte]bool),
@@ -713,6 +721,7 @@ func TestService_ProcessPendingBlockOnCorrectSlot(t *testing.T) {
p2p: p1, p2p: p1,
beaconDB: db, beaconDB: db,
chain: &mockChain, chain: &mockChain,
clock: startup.NewClock(mockChain.Genesis, mockChain.ValidatorsRoot),
stateGen: stategen.New(db, fcs), stateGen: stategen.New(db, fcs),
}, },
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),

View File

@@ -33,7 +33,7 @@ type rpcHandler func(context.Context, interface{}, libp2pcore.Stream) error
// registerRPCHandlers for p2p RPC. // registerRPCHandlers for p2p RPC.
func (s *Service) registerRPCHandlers() { func (s *Service) registerRPCHandlers() {
currEpoch := slots.ToEpoch(s.cfg.chain.CurrentSlot()) currEpoch := slots.ToEpoch(s.cfg.clock.CurrentSlot())
// Register V2 handlers if we are past altair fork epoch. // Register V2 handlers if we are past altair fork epoch.
if currEpoch >= params.BeaconConfig().AltairForkEpoch { if currEpoch >= params.BeaconConfig().AltairForkEpoch {
s.registerRPC( s.registerRPC(

View File

@@ -228,7 +228,7 @@ func (s *Service) validateRangeRequest(r *pb.BeaconBlocksByRangeRequest) error {
// Add a buffer for possible large range requests from nodes syncing close to the // Add a buffer for possible large range requests from nodes syncing close to the
// head of the chain. // head of the chain.
buffer := rangeLimit * 2 buffer := rangeLimit * 2
highestExpectedSlot := s.cfg.chain.CurrentSlot().Add(uint64(buffer)) highestExpectedSlot := s.cfg.clock.CurrentSlot().Add(uint64(buffer))
// Ensure all request params are within appropriate bounds // Ensure all request params are within appropriate bounds
if count == 0 || count > maxRequestBlocks { if count == 0 || count > maxRequestBlocks {

View File

@@ -20,6 +20,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types" p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags" "github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -63,7 +64,13 @@ func TestRPCBeaconBlocksByRange_RPCHandlerReturnsBlocks(t *testing.T) {
} }
// Start service with 160 as allowed blocks capacity (and almost zero capacity recovery). // Start service with 160 as allowed blocks capacity (and almost zero capacity recovery).
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} r := &Service{
cfg: &config{
p2p: p1, beaconDB: d, chain: &chainMock.ChainService{},
clock: startup.NewClock(time.Unix(0, 0), [32]byte{}),
},
rateLimiter: newRateLimiter(p1),
}
pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1) pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1)
topic := string(pcl) topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(0.000001, int64(req.Count*10), time.Second, false) r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(0.000001, int64(req.Count*10), time.Second, false)
@@ -125,7 +132,8 @@ func TestRPCBeaconBlocksByRange_ReturnCorrectNumberBack(t *testing.T) {
require.NoError(t, d.SaveGenesisBlockRoot(context.Background(), genRoot)) require.NoError(t, d.SaveGenesisBlockRoot(context.Background(), genRoot))
// Start service with 160 as allowed blocks capacity (and almost zero capacity recovery). // Start service with 160 as allowed blocks capacity (and almost zero capacity recovery).
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1) pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1)
topic := string(pcl) topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(0.000001, int64(req.Count*10), time.Second, false) r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(0.000001, int64(req.Count*10), time.Second, false)
@@ -239,6 +247,7 @@ func TestRPCBeaconBlocksByRange_ReconstructsPayloads(t *testing.T) {
beaconDB: d, beaconDB: d,
chain: &chainMock.ChainService{}, chain: &chainMock.ChainService{},
executionPayloadReconstructor: mockEngine, executionPayloadReconstructor: mockEngine,
clock: startup.NewClock(time.Unix(0, 0), [32]byte{}),
}, },
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }
@@ -309,7 +318,8 @@ func TestRPCBeaconBlocksByRange_RPCHandlerReturnsSortedBlocks(t *testing.T) {
} }
// Start service with 160 as allowed blocks capacity (and almost zero capacity recovery). // Start service with 160 as allowed blocks capacity (and almost zero capacity recovery).
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1) pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1)
topic := string(pcl) topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(0.000001, int64(req.Count*10), time.Second, false) r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(0.000001, int64(req.Count*10), time.Second, false)
@@ -374,7 +384,7 @@ func TestRPCBeaconBlocksByRange_ReturnsGenesisBlock(t *testing.T) {
prevRoot = rt prevRoot = rt
} }
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: startup.NewClock(time.Unix(0, 0), [32]byte{})}, rateLimiter: newRateLimiter(p1)}
pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1) pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1)
topic := string(pcl) topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, time.Second, false) r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, time.Second, false)
@@ -465,7 +475,8 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
capacity := int64(flags.Get().BlockBatchLimit * 3) capacity := int64(flags.Get().BlockBatchLimit * 3)
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1) pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1)
topic := string(pcl) topic := string(pcl)
@@ -491,7 +502,8 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
capacity := int64(flags.Get().BlockBatchLimit * 3) capacity := int64(flags.Get().BlockBatchLimit * 3)
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1) pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1)
topic := string(pcl) topic := string(pcl)
@@ -521,7 +533,8 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
capacity := int64(flags.Get().BlockBatchLimit * flags.Get().BlockBatchLimitBurstFactor) capacity := int64(flags.Get().BlockBatchLimit * flags.Get().BlockBatchLimitBurstFactor)
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1) pcl := protocol.ID(p2p.RPCBlocksByRangeTopicV1)
topic := string(pcl) topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(0.000001, capacity, time.Second, false) r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(0.000001, capacity, time.Second, false)
@@ -552,11 +565,13 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
func TestRPCBeaconBlocksByRange_validateRangeRequest(t *testing.T) { func TestRPCBeaconBlocksByRange_validateRangeRequest(t *testing.T) {
slotsSinceGenesis := primitives.Slot(1000) slotsSinceGenesis := primitives.Slot(1000)
offset := int64(slotsSinceGenesis.Mul(params.BeaconConfig().SecondsPerSlot)) offset := int64(slotsSinceGenesis.Mul(params.BeaconConfig().SecondsPerSlot))
chain := &chainMock.ChainService{
Genesis: time.Now().Add(time.Second * time.Duration(-1*offset)),
}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
chain: &chainMock.ChainService{ chain: chain,
Genesis: time.Now().Add(time.Second * time.Duration(-1*offset)), clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
},
}, },
} }
@@ -720,7 +735,8 @@ func TestRPCBeaconBlocksByRange_EnforceResponseInvariants(t *testing.T) {
p1.Connect(p2) p1.Connect(p2)
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false) r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false)
req := &ethpb.BeaconBlocksByRangeRequest{ req := &ethpb.BeaconBlocksByRangeRequest{
StartSlot: 448, StartSlot: 448,
@@ -888,7 +904,8 @@ func TestRPCBeaconBlocksByRange_FilterBlocks(t *testing.T) {
p1.Connect(p2) p1.Connect(p2)
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false) r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false)
req := &ethpb.BeaconBlocksByRangeRequest{ req := &ethpb.BeaconBlocksByRangeRequest{
StartSlot: 1, StartSlot: 1,
@@ -919,7 +936,8 @@ func TestRPCBeaconBlocksByRange_FilterBlocks(t *testing.T) {
p1.Connect(p2) p1.Connect(p2)
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false) r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false)
req := &ethpb.BeaconBlocksByRangeRequest{ req := &ethpb.BeaconBlocksByRangeRequest{
StartSlot: 1, StartSlot: 1,
@@ -954,7 +972,8 @@ func TestRPCBeaconBlocksByRange_FilterBlocks(t *testing.T) {
p1.Connect(p2) p1.Connect(p2)
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false) r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false)
req := &ethpb.BeaconBlocksByRangeRequest{ req := &ethpb.BeaconBlocksByRangeRequest{
StartSlot: 1, StartSlot: 1,
@@ -989,7 +1008,8 @@ func TestRPCBeaconBlocksByRange_FilterBlocks(t *testing.T) {
p1.Connect(p2) p1.Connect(p2)
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false) r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false)
req := &ethpb.BeaconBlocksByRangeRequest{ req := &ethpb.BeaconBlocksByRangeRequest{
StartSlot: 1, StartSlot: 1,
@@ -1029,7 +1049,8 @@ func TestRPCBeaconBlocksByRange_FilterBlocks(t *testing.T) {
p1.Connect(p2) p1.Connect(p2)
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}}, rateLimiter: newRateLimiter(p1)} clock := startup.NewClock(time.Unix(0, 0), [32]byte{})
r := &Service{cfg: &config{p2p: p1, beaconDB: d, chain: &chainMock.ChainService{}, clock: clock}, rateLimiter: newRateLimiter(p1)}
r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false) r.rateLimiter.limiterMap[string(pcl)] = leakybucket.NewCollector(0.000001, 640, time.Second, false)
req := &ethpb.BeaconBlocksByRangeRequest{ req := &ethpb.BeaconBlocksByRangeRequest{
StartSlot: 1, StartSlot: 1,

View File

@@ -19,7 +19,7 @@ func (s *Service) sendRecentBeaconBlocksRequest(ctx context.Context, blockRoots
ctx, cancel := context.WithTimeout(ctx, respTimeout) ctx, cancel := context.WithTimeout(ctx, respTimeout)
defer cancel() defer cancel()
_, err := SendBeaconBlocksByRootRequest(ctx, s.cfg.chain, s.cfg.p2p, id, blockRoots, func(blk interfaces.ReadOnlySignedBeaconBlock) error { _, err := SendBeaconBlocksByRootRequest(ctx, s.cfg.clock, s.cfg.p2p, id, blockRoots, func(blk interfaces.ReadOnlySignedBeaconBlock) error {
blkRoot, err := blk.Block().HashTreeRoot() blkRoot, err := blk.Block().HashTreeRoot()
if err != nil { if err != nil {
return err return err

View File

@@ -19,6 +19,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
p2pTypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types" p2pTypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
@@ -50,7 +51,7 @@ func TestRecentBeaconBlocksRPCHandler_ReturnsBlocks(t *testing.T) {
blkRoots = append(blkRoots, root) blkRoots = append(blkRoots, root)
} }
r := &Service{cfg: &config{p2p: p1, beaconDB: d}, rateLimiter: newRateLimiter(p1)} r := &Service{cfg: &config{p2p: p1, beaconDB: d, clock: startup.NewClock(time.Unix(0, 0), [32]byte{})}, rateLimiter: newRateLimiter(p1)}
r.cfg.chain = &mock.ChainService{ValidatorsRoot: [32]byte{}} r.cfg.chain = &mock.ChainService{ValidatorsRoot: [32]byte{}}
pcl := protocol.ID(p2p.RPCBlocksByRootTopicV1) pcl := protocol.ID(p2p.RPCBlocksByRootTopicV1)
topic := string(pcl) topic := string(pcl)
@@ -148,8 +149,9 @@ func TestRecentBeaconBlocksRPCHandler_ReturnsBlocks_ReconstructsPayload(t *testi
p2p: p1, p2p: p1,
beaconDB: d, beaconDB: d,
executionPayloadReconstructor: mockEngine, executionPayloadReconstructor: mockEngine,
chain: &mock.ChainService{ValidatorsRoot: [32]byte{}},
clock: startup.NewClock(time.Unix(0, 0), [32]byte{}),
}, rateLimiter: newRateLimiter(p1)} }, rateLimiter: newRateLimiter(p1)}
r.cfg.chain = &mock.ChainService{ValidatorsRoot: [32]byte{}}
pcl := protocol.ID(p2p.RPCBlocksByRootTopicV1) pcl := protocol.ID(p2p.RPCBlocksByRootTopicV1)
topic := string(pcl) topic := string(pcl)
r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, time.Second, false) r.rateLimiter.limiterMap[topic] = leakybucket.NewCollector(10000, 10000, time.Second, false)
@@ -204,16 +206,18 @@ func TestRecentBeaconBlocks_RPCRequestSent(t *testing.T) {
expectedRoots := p2pTypes.BeaconBlockByRootsReq{blockBRoot, blockARoot} expectedRoots := p2pTypes.BeaconBlockByRootsReq{blockBRoot, blockARoot}
chain := &mock.ChainService{
State: genesisState,
FinalizedCheckPoint: finalizedCheckpt,
Root: blockARoot[:],
Genesis: time.Now(),
ValidatorsRoot: [32]byte{},
}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
chain: &mock.ChainService{ chain: chain,
State: genesisState, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
FinalizedCheckPoint: finalizedCheckpt,
Root: blockARoot[:],
Genesis: time.Now(),
ValidatorsRoot: [32]byte{},
},
}, },
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
seenPendingBlocks: make(map[[32]byte]bool), seenPendingBlocks: make(map[[32]byte]bool),

View File

@@ -20,42 +20,48 @@ import (
// response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload> // response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload>
func (s *Service) chunkBlockWriter(stream libp2pcore.Stream, blk interfaces.ReadOnlySignedBeaconBlock) error { func (s *Service) chunkBlockWriter(stream libp2pcore.Stream, blk interfaces.ReadOnlySignedBeaconBlock) error {
SetStreamWriteDeadline(stream, defaultWriteDuration) SetStreamWriteDeadline(stream, defaultWriteDuration)
return WriteBlockChunk(stream, s.cfg.chain, s.cfg.p2p.Encoding(), blk) return WriteBlockChunk(stream, s.cfg.clock, s.cfg.p2p.Encoding(), blk)
} }
// WriteBlockChunk writes block chunk object to stream. // WriteBlockChunk writes block chunk object to stream.
// response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload> // response_chunk ::= <result> | <context-bytes> | <encoding-dependent-header> | <encoded-payload>
func WriteBlockChunk(stream libp2pcore.Stream, chain blockchain.ChainInfoFetcher, encoding encoder.NetworkEncoding, blk interfaces.ReadOnlySignedBeaconBlock) error { func WriteBlockChunk(stream libp2pcore.Stream, tor blockchain.TemporalOracle, encoding encoder.NetworkEncoding, blk interfaces.ReadOnlySignedBeaconBlock) error {
if _, err := stream.Write([]byte{responseCodeSuccess}); err != nil { if _, err := stream.Write([]byte{responseCodeSuccess}); err != nil {
return err return err
} }
var obtainedCtx []byte var obtainedCtx []byte
valRoot := tor.GenesisValidatorsRoot()
switch blk.Version() { switch blk.Version() {
case version.Phase0: case version.Phase0:
valRoot := chain.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().GenesisEpoch, valRoot[:]) digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().GenesisEpoch, valRoot[:])
if err != nil { if err != nil {
return err return err
} }
obtainedCtx = digest[:] obtainedCtx = digest[:]
case version.Altair: case version.Altair:
valRoot := chain.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, valRoot[:]) digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().AltairForkEpoch, valRoot[:])
if err != nil { if err != nil {
return err return err
} }
obtainedCtx = digest[:] obtainedCtx = digest[:]
case version.Bellatrix: case version.Bellatrix:
valRoot := chain.GenesisValidatorsRoot()
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().BellatrixForkEpoch, valRoot[:]) digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().BellatrixForkEpoch, valRoot[:])
if err != nil { if err != nil {
return err return err
} }
obtainedCtx = digest[:] obtainedCtx = digest[:]
case version.Capella:
digest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().CapellaForkEpoch, valRoot[:])
if err != nil {
return err
}
obtainedCtx = digest[:]
default:
return errors.Wrapf(ErrUnrecognizedVersion, "block version %d is not recognized", blk.Version())
} }
if err := writeContextToStream(obtainedCtx, stream, chain); err != nil { if err := writeContextToStream(obtainedCtx, stream); err != nil {
return err return err
} }
_, err := encoding.EncodeWithMaxLength(stream, blk) _, err := encoding.EncodeWithMaxLength(stream, blk)
@@ -64,18 +70,18 @@ func WriteBlockChunk(stream libp2pcore.Stream, chain blockchain.ChainInfoFetcher
// ReadChunkedBlock handles each response chunk that is sent by the // ReadChunkedBlock handles each response chunk that is sent by the
// peer and converts it into a beacon block. // peer and converts it into a beacon block.
func ReadChunkedBlock(stream libp2pcore.Stream, chain blockchain.ForkFetcher, p2p p2p.EncodingProvider, isFirstChunk bool) (interfaces.ReadOnlySignedBeaconBlock, error) { func ReadChunkedBlock(stream libp2pcore.Stream, tor blockchain.TemporalOracle, p2p p2p.EncodingProvider, isFirstChunk bool) (interfaces.ReadOnlySignedBeaconBlock, error) {
// Handle deadlines differently for first chunk // Handle deadlines differently for first chunk
if isFirstChunk { if isFirstChunk {
return readFirstChunkedBlock(stream, chain, p2p) return readFirstChunkedBlock(stream, tor, p2p)
} }
return readResponseChunk(stream, chain, p2p) return readResponseChunk(stream, tor, p2p)
} }
// readFirstChunkedBlock reads the first chunked block and applies the appropriate deadlines to // readFirstChunkedBlock reads the first chunked block and applies the appropriate deadlines to
// it. // it.
func readFirstChunkedBlock(stream libp2pcore.Stream, chain blockchain.ForkFetcher, p2p p2p.EncodingProvider) (interfaces.ReadOnlySignedBeaconBlock, error) { func readFirstChunkedBlock(stream libp2pcore.Stream, tor blockchain.TemporalOracle, p2p p2p.EncodingProvider) (interfaces.ReadOnlySignedBeaconBlock, error) {
code, errMsg, err := ReadStatusCode(stream, p2p.Encoding()) code, errMsg, err := ReadStatusCode(stream, p2p.Encoding())
if err != nil { if err != nil {
return nil, err return nil, err
@@ -83,11 +89,11 @@ func readFirstChunkedBlock(stream libp2pcore.Stream, chain blockchain.ForkFetche
if code != 0 { if code != 0 {
return nil, errors.New(errMsg) return nil, errors.New(errMsg)
} }
rpcCtx, err := readContextFromStream(stream, chain) rpcCtx, err := readContextFromStream(stream)
if err != nil { if err != nil {
return nil, err return nil, err
} }
blk, err := extractBlockDataType(rpcCtx, chain) blk, err := extractBlockDataType(rpcCtx, tor)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -97,7 +103,7 @@ func readFirstChunkedBlock(stream libp2pcore.Stream, chain blockchain.ForkFetche
// readResponseChunk reads the response from the stream and decodes it into the // readResponseChunk reads the response from the stream and decodes it into the
// provided message type. // provided message type.
func readResponseChunk(stream libp2pcore.Stream, chain blockchain.ForkFetcher, p2p p2p.EncodingProvider) (interfaces.ReadOnlySignedBeaconBlock, error) { func readResponseChunk(stream libp2pcore.Stream, tor blockchain.TemporalOracle, p2p p2p.EncodingProvider) (interfaces.ReadOnlySignedBeaconBlock, error) {
SetStreamReadDeadline(stream, respTimeout) SetStreamReadDeadline(stream, respTimeout)
code, errMsg, err := readStatusCodeNoDeadline(stream, p2p.Encoding()) code, errMsg, err := readStatusCodeNoDeadline(stream, p2p.Encoding())
if err != nil { if err != nil {
@@ -107,11 +113,11 @@ func readResponseChunk(stream libp2pcore.Stream, chain blockchain.ForkFetcher, p
return nil, errors.New(errMsg) return nil, errors.New(errMsg)
} }
// No-op for now with the rpc context. // No-op for now with the rpc context.
rpcCtx, err := readContextFromStream(stream, chain) rpcCtx, err := readContextFromStream(stream)
if err != nil { if err != nil {
return nil, err return nil, err
} }
blk, err := extractBlockDataType(rpcCtx, chain) blk, err := extractBlockDataType(rpcCtx, tor)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -119,7 +125,7 @@ func readResponseChunk(stream libp2pcore.Stream, chain blockchain.ForkFetcher, p
return blk, err return blk, err
} }
func extractBlockDataType(digest []byte, chain blockchain.ForkFetcher) (interfaces.ReadOnlySignedBeaconBlock, error) { func extractBlockDataType(digest []byte, tor blockchain.TemporalOracle) (interfaces.ReadOnlySignedBeaconBlock, error) {
if len(digest) == 0 { if len(digest) == 0 {
bFunc, ok := types.BlockMap[bytesutil.ToBytes4(params.BeaconConfig().GenesisForkVersion)] bFunc, ok := types.BlockMap[bytesutil.ToBytes4(params.BeaconConfig().GenesisForkVersion)]
if !ok { if !ok {
@@ -130,7 +136,7 @@ func extractBlockDataType(digest []byte, chain blockchain.ForkFetcher) (interfac
if len(digest) != forkDigestLength { if len(digest) != forkDigestLength {
return nil, errors.Errorf("invalid digest returned, wanted a length of %d but received %d", forkDigestLength, len(digest)) return nil, errors.Errorf("invalid digest returned, wanted a length of %d but received %d", forkDigestLength, len(digest))
} }
vRoot := chain.GenesisValidatorsRoot() vRoot := tor.GenesisValidatorsRoot()
for k, blkFunc := range types.BlockMap { for k, blkFunc := range types.BlockMap {
rDigest, err := signing.ComputeForkDigest(k[:], vRoot[:]) rDigest, err := signing.ComputeForkDigest(k[:], vRoot[:])
if err != nil { if err != nil {
@@ -140,5 +146,5 @@ func extractBlockDataType(digest []byte, chain blockchain.ForkFetcher) (interfac
return blkFunc() return blkFunc()
} }
} }
return nil, errors.New("no valid digest matched") return nil, errors.Wrapf(ErrNoValidDigest, "could not extract block data type, saw digest=%#x, genesis=%v, vr=%#x", digest, tor.GenesisTime(), tor.GenesisValidatorsRoot())
} }

View File

@@ -96,7 +96,7 @@ func (s *Service) sendGoodByeMessage(ctx context.Context, code p2ptypes.RPCGoodb
ctx, cancel := context.WithTimeout(ctx, respTimeout) ctx, cancel := context.WithTimeout(ctx, respTimeout)
defer cancel() defer cancel()
topic, err := p2p.TopicFromMessage(p2p.GoodbyeMessageName, slots.ToEpoch(s.cfg.chain.CurrentSlot())) topic, err := p2p.TopicFromMessage(p2p.GoodbyeMessageName, slots.ToEpoch(s.cfg.clock.CurrentSlot()))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -12,6 +12,7 @@ import (
db "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" db "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types" p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
leakybucket "github.com/prysmaticlabs/prysm/v4/container/leaky-bucket" leakybucket "github.com/prysmaticlabs/prysm/v4/container/leaky-bucket"
@@ -153,11 +154,13 @@ func TestSendGoodbye_SendsMessage(t *testing.T) {
// Set up a head state in the database with data we expect. // Set up a head state in the database with data we expect.
d := db.SetupDB(t) d := db.SetupDB(t)
chain := &mock.ChainService{ValidatorsRoot: [32]byte{}, Genesis: time.Now()}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
beaconDB: d, beaconDB: d,
p2p: p1, p2p: p1,
chain: &mock.ChainService{ValidatorsRoot: [32]byte{}, Genesis: time.Now()}, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
}, },
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }
@@ -198,11 +201,13 @@ func TestSendGoodbye_DisconnectWithPeer(t *testing.T) {
// Set up a head state in the database with data we expect. // Set up a head state in the database with data we expect.
d := db.SetupDB(t) d := db.SetupDB(t)
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
beaconDB: d, beaconDB: d,
p2p: p1, p2p: p1,
chain: &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
}, },
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }

View File

@@ -89,7 +89,7 @@ func (s *Service) sendMetaDataRequest(ctx context.Context, id peer.ID) (metadata
ctx, cancel := context.WithTimeout(ctx, respTimeout) ctx, cancel := context.WithTimeout(ctx, respTimeout)
defer cancel() defer cancel()
topic, err := p2p.TopicFromMessage(p2p.MetadataMessageName, slots.ToEpoch(s.cfg.chain.CurrentSlot())) topic, err := p2p.TopicFromMessage(p2p.MetadataMessageName, slots.ToEpoch(s.cfg.clock.CurrentSlot()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -107,12 +107,12 @@ func (s *Service) sendMetaDataRequest(ctx context.Context, id peer.ID) (metadata
s.cfg.p2p.Peers().Scorers().BadResponsesScorer().Increment(stream.Conn().RemotePeer()) s.cfg.p2p.Peers().Scorers().BadResponsesScorer().Increment(stream.Conn().RemotePeer())
return nil, errors.New(errMsg) return nil, errors.New(errMsg)
} }
valRoot := s.cfg.chain.GenesisValidatorsRoot() valRoot := s.cfg.clock.GenesisValidatorsRoot()
rpcCtx, err := forks.ForkDigestFromEpoch(slots.ToEpoch(s.cfg.chain.CurrentSlot()), valRoot[:]) rpcCtx, err := forks.ForkDigestFromEpoch(slots.ToEpoch(s.cfg.clock.CurrentSlot()), valRoot[:])
if err != nil { if err != nil {
return nil, err return nil, err
} }
msg, err := extractMetaDataType(rpcCtx[:], s.cfg.chain) msg, err := extractMetaDataType(rpcCtx[:], s.cfg.clock)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -134,7 +134,7 @@ func (s *Service) sendMetaDataRequest(ctx context.Context, id peer.ID) (metadata
return msg, nil return msg, nil
} }
func extractMetaDataType(digest []byte, chain blockchain.ChainInfoFetcher) (metadata.Metadata, error) { func extractMetaDataType(digest []byte, tor blockchain.TemporalOracle) (metadata.Metadata, error) {
if len(digest) == 0 { if len(digest) == 0 {
mdFunc, ok := types.MetaDataMap[bytesutil.ToBytes4(params.BeaconConfig().GenesisForkVersion)] mdFunc, ok := types.MetaDataMap[bytesutil.ToBytes4(params.BeaconConfig().GenesisForkVersion)]
if !ok { if !ok {
@@ -145,7 +145,7 @@ func extractMetaDataType(digest []byte, chain blockchain.ChainInfoFetcher) (meta
if len(digest) != forkDigestLength { if len(digest) != forkDigestLength {
return nil, errors.Errorf("invalid digest returned, wanted a length of %d but received %d", forkDigestLength, len(digest)) return nil, errors.Errorf("invalid digest returned, wanted a length of %d but received %d", forkDigestLength, len(digest))
} }
vRoot := chain.GenesisValidatorsRoot() vRoot := tor.GenesisValidatorsRoot()
for k, mdFunc := range types.MetaDataMap { for k, mdFunc := range types.MetaDataMap {
rDigest, err := signing.ComputeForkDigest(k[:], vRoot[:]) rDigest, err := signing.ComputeForkDigest(k[:], vRoot[:])
if err != nil { if err != nil {
@@ -155,5 +155,5 @@ func extractMetaDataType(digest []byte, chain blockchain.ChainInfoFetcher) (meta
return mdFunc(), nil return mdFunc(), nil
} }
} }
return nil, errors.New("no valid digest matched") return nil, errors.Wrapf(ErrNoValidDigest, "could not extract metadata type, saw digest=%#x, genesis=%v, vr=%#x", digest, tor.GenesisTime(), tor.GenesisValidatorsRoot())
} }

View File

@@ -15,6 +15,7 @@ import (
db "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" db "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/wrapper" "github.com/prysmaticlabs/prysm/v4/consensus-types/wrapper"
leakybucket "github.com/prysmaticlabs/prysm/v4/container/leaky-bucket" leakybucket "github.com/prysmaticlabs/prysm/v4/container/leaky-bucket"
@@ -90,12 +91,14 @@ func TestMetadataRPCHandler_SendsMetadata(t *testing.T) {
}) })
// Set up a head state in the database with data we expect. // Set up a head state in the database with data we expect.
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
d := db.SetupDB(t) d := db.SetupDB(t)
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
beaconDB: d, beaconDB: d,
p2p: p1, p2p: p1,
chain: &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
}, },
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }
@@ -158,20 +161,24 @@ func TestMetadataRPCHandler_SendsMetadataAltair(t *testing.T) {
// Set up a head state in the database with data we expect. // Set up a head state in the database with data we expect.
d := db.SetupDB(t) d := db.SetupDB(t)
chain := &mock.ChainService{Genesis: time.Now().Add(-5 * oneEpoch()), ValidatorsRoot: [32]byte{}}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
beaconDB: d, beaconDB: d,
p2p: p1, p2p: p1,
chain: &mock.ChainService{Genesis: time.Now().Add(-5 * oneEpoch()), ValidatorsRoot: [32]byte{}}, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
}, },
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }
chain2 := &mock.ChainService{Genesis: time.Now().Add(-5 * oneEpoch()), ValidatorsRoot: [32]byte{}}
r2 := &Service{ r2 := &Service{
cfg: &config{ cfg: &config{
beaconDB: d, beaconDB: d,
p2p: p2, p2p: p2,
chain: &mock.ChainService{Genesis: time.Now().Add(-5 * oneEpoch()), ValidatorsRoot: [32]byte{}}, chain: chain2,
clock: startup.NewClock(chain2.Genesis, chain2.ValidatorsRoot),
}, },
rateLimiter: newRateLimiter(p2), rateLimiter: newRateLimiter(p2),
} }
@@ -236,7 +243,7 @@ func TestExtractMetaDataType(t *testing.T) {
type args struct { type args struct {
digest []byte digest []byte
chain blockchain.ChainInfoFetcher clock blockchain.TemporalOracle
} }
tests := []struct { tests := []struct {
name string name string
@@ -248,7 +255,7 @@ func TestExtractMetaDataType(t *testing.T) {
name: "no digest", name: "no digest",
args: args{ args: args{
digest: []byte{}, digest: []byte{},
chain: &mock.ChainService{ValidatorsRoot: [32]byte{}}, clock: startup.NewClock(time.Now(), [32]byte{}),
}, },
want: wrapper.WrappedMetadataV0(&pb.MetaDataV0{}), want: wrapper.WrappedMetadataV0(&pb.MetaDataV0{}),
wantErr: false, wantErr: false,
@@ -257,7 +264,7 @@ func TestExtractMetaDataType(t *testing.T) {
name: "invalid digest", name: "invalid digest",
args: args{ args: args{
digest: []byte{0x00, 0x01}, digest: []byte{0x00, 0x01},
chain: &mock.ChainService{ValidatorsRoot: [32]byte{}}, clock: startup.NewClock(time.Now(), [32]byte{}),
}, },
want: nil, want: nil,
wantErr: true, wantErr: true,
@@ -266,7 +273,7 @@ func TestExtractMetaDataType(t *testing.T) {
name: "non existent digest", name: "non existent digest",
args: args{ args: args{
digest: []byte{0x00, 0x01, 0x02, 0x03}, digest: []byte{0x00, 0x01, 0x02, 0x03},
chain: &mock.ChainService{ValidatorsRoot: [32]byte{}}, clock: startup.NewClock(time.Now(), [32]byte{}),
}, },
want: nil, want: nil,
wantErr: true, wantErr: true,
@@ -275,7 +282,7 @@ func TestExtractMetaDataType(t *testing.T) {
name: "genesis fork version", name: "genesis fork version",
args: args{ args: args{
digest: genDigest[:], digest: genDigest[:],
chain: &mock.ChainService{ValidatorsRoot: [32]byte{}}, clock: startup.NewClock(time.Now(), [32]byte{}),
}, },
want: wrapper.WrappedMetadataV0(&pb.MetaDataV0{}), want: wrapper.WrappedMetadataV0(&pb.MetaDataV0{}),
wantErr: false, wantErr: false,
@@ -284,7 +291,7 @@ func TestExtractMetaDataType(t *testing.T) {
name: "altair fork version", name: "altair fork version",
args: args{ args: args{
digest: altairDigest[:], digest: altairDigest[:],
chain: &mock.ChainService{ValidatorsRoot: [32]byte{}}, clock: startup.NewClock(time.Now(), [32]byte{}),
}, },
want: wrapper.WrappedMetadataV1(&pb.MetaDataV1{}), want: wrapper.WrappedMetadataV1(&pb.MetaDataV1{}),
wantErr: false, wantErr: false,
@@ -292,7 +299,7 @@ func TestExtractMetaDataType(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := extractMetaDataType(tt.args.digest, tt.args.chain) got, err := extractMetaDataType(tt.args.digest, tt.args.clock)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("extractMetaDataType() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("extractMetaDataType() error = %v, wantErr %v", err, tt.wantErr)
return return

View File

@@ -78,7 +78,7 @@ func (s *Service) sendPingRequest(ctx context.Context, id peer.ID) error {
defer cancel() defer cancel()
metadataSeq := primitives.SSZUint64(s.cfg.p2p.MetadataSeq()) metadataSeq := primitives.SSZUint64(s.cfg.p2p.MetadataSeq())
topic, err := p2p.TopicFromMessage(p2p.PingMessageName, slots.ToEpoch(s.cfg.chain.CurrentSlot())) topic, err := p2p.TopicFromMessage(p2p.PingMessageName, slots.ToEpoch(s.cfg.clock.CurrentSlot()))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -14,6 +14,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types" p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/consensus-types/wrapper" "github.com/prysmaticlabs/prysm/v4/consensus-types/wrapper"
leakybucket "github.com/prysmaticlabs/prysm/v4/container/leaky-bucket" leakybucket "github.com/prysmaticlabs/prysm/v4/container/leaky-bucket"
@@ -97,11 +98,13 @@ func TestPingRPCHandler_SendsPing(t *testing.T) {
// Set up a head state in the database with data we expect. // Set up a head state in the database with data we expect.
d := db.SetupDB(t) d := db.SetupDB(t)
chain := &mock.ChainService{ValidatorsRoot: [32]byte{}, Genesis: time.Now()}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
beaconDB: d, beaconDB: d,
p2p: p1, p2p: p1,
chain: &mock.ChainService{ValidatorsRoot: [32]byte{}, Genesis: time.Now()}, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
}, },
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }
@@ -112,11 +115,13 @@ func TestPingRPCHandler_SendsPing(t *testing.T) {
p2.Peers().Add(new(enr.Record), p1.BHost.ID(), p1.BHost.Addrs()[0], network.DirUnknown) p2.Peers().Add(new(enr.Record), p1.BHost.ID(), p1.BHost.Addrs()[0], network.DirUnknown)
p2.Peers().SetMetadata(p1.BHost.ID(), p1.LocalMetadata) p2.Peers().SetMetadata(p1.BHost.ID(), p1.LocalMetadata)
chain2 := &mock.ChainService{ValidatorsRoot: [32]byte{}, Genesis: time.Now()}
r2 := &Service{ r2 := &Service{
cfg: &config{ cfg: &config{
beaconDB: d, beaconDB: d,
p2p: p2, p2p: p2,
chain: &mock.ChainService{ValidatorsRoot: [32]byte{}, Genesis: time.Now()}, chain: chain2,
clock: startup.NewClock(chain2.Genesis, chain.ValidatorsRoot),
}, },
rateLimiter: newRateLimiter(p2), rateLimiter: newRateLimiter(p2),
} }

View File

@@ -25,10 +25,10 @@ type BeaconBlockProcessor func(block interfaces.ReadOnlySignedBeaconBlock) error
// SendBeaconBlocksByRangeRequest sends BeaconBlocksByRange and returns fetched blocks, if any. // SendBeaconBlocksByRangeRequest sends BeaconBlocksByRange and returns fetched blocks, if any.
func SendBeaconBlocksByRangeRequest( func SendBeaconBlocksByRangeRequest(
ctx context.Context, chain blockchain.ForkFetcher, p2pProvider p2p.SenderEncoder, pid peer.ID, ctx context.Context, tor blockchain.TemporalOracle, p2pProvider p2p.SenderEncoder, pid peer.ID,
req *pb.BeaconBlocksByRangeRequest, blockProcessor BeaconBlockProcessor, req *pb.BeaconBlocksByRangeRequest, blockProcessor BeaconBlockProcessor,
) ([]interfaces.ReadOnlySignedBeaconBlock, error) { ) ([]interfaces.ReadOnlySignedBeaconBlock, error) {
topic, err := p2p.TopicFromMessage(p2p.BeaconBlocksByRangeMessageName, slots.ToEpoch(chain.CurrentSlot())) topic, err := p2p.TopicFromMessage(p2p.BeaconBlocksByRangeMessageName, slots.ToEpoch(tor.CurrentSlot()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -50,7 +50,7 @@ func SendBeaconBlocksByRangeRequest(
var prevSlot primitives.Slot var prevSlot primitives.Slot
for i := uint64(0); ; i++ { for i := uint64(0); ; i++ {
isFirstChunk := i == 0 isFirstChunk := i == 0
blk, err := ReadChunkedBlock(stream, chain, p2pProvider, isFirstChunk) blk, err := ReadChunkedBlock(stream, tor, p2pProvider, isFirstChunk)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
break break
} }
@@ -87,10 +87,10 @@ func SendBeaconBlocksByRangeRequest(
// SendBeaconBlocksByRootRequest sends BeaconBlocksByRoot and returns fetched blocks, if any. // SendBeaconBlocksByRootRequest sends BeaconBlocksByRoot and returns fetched blocks, if any.
func SendBeaconBlocksByRootRequest( func SendBeaconBlocksByRootRequest(
ctx context.Context, chain blockchain.ChainInfoFetcher, p2pProvider p2p.P2P, pid peer.ID, ctx context.Context, clock blockchain.TemporalOracle, p2pProvider p2p.P2P, pid peer.ID,
req *p2ptypes.BeaconBlockByRootsReq, blockProcessor BeaconBlockProcessor, req *p2ptypes.BeaconBlockByRootsReq, blockProcessor BeaconBlockProcessor,
) ([]interfaces.ReadOnlySignedBeaconBlock, error) { ) ([]interfaces.ReadOnlySignedBeaconBlock, error) {
topic, err := p2p.TopicFromMessage(p2p.BeaconBlocksByRootsMessageName, slots.ToEpoch(chain.CurrentSlot())) topic, err := p2p.TopicFromMessage(p2p.BeaconBlocksByRootsMessageName, slots.ToEpoch(clock.CurrentSlot()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -115,7 +115,7 @@ func SendBeaconBlocksByRootRequest(
break break
} }
isFirstChunk := i == 0 isFirstChunk := i == 0
blk, err := ReadChunkedBlock(stream, chain, p2pProvider, isFirstChunk) blk, err := ReadChunkedBlock(stream, clock, p2pProvider, isFirstChunk)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
break break
} }

View File

@@ -9,10 +9,10 @@ import (
"time" "time"
"github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/network"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
p2pTypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types" p2pTypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
@@ -35,8 +35,7 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
p1.Connect(bogusPeer) p1.Connect(bogusPeer)
req := &ethpb.BeaconBlocksByRangeRequest{} req := &ethpb.BeaconBlocksByRangeRequest{}
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} _, err := SendBeaconBlocksByRangeRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, bogusPeer.PeerID(), req, nil)
_, err := SendBeaconBlocksByRangeRequest(ctx, chain, p1, bogusPeer.PeerID(), req, nil)
assert.ErrorContains(t, "protocols not supported", err) assert.ErrorContains(t, "protocols not supported", err)
}) })
@@ -83,10 +82,9 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
if uint64(i) >= uint64(len(knownBlocks)) { if uint64(i) >= uint64(len(knownBlocks)) {
break break
} }
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
wsb, err := blocks.NewSignedBeaconBlock(knownBlocks[i]) wsb, err := blocks.NewSignedBeaconBlock(knownBlocks[i])
require.NoError(t, err) require.NoError(t, err)
err = WriteBlockChunk(stream, chain, p2pProvider.Encoding(), wsb) err = WriteBlockChunk(stream, startup.NewClock(time.Now(), [32]byte{}), p2pProvider.Encoding(), wsb)
if err != nil && err.Error() != network.ErrReset.Error() { if err != nil && err.Error() != network.ErrReset.Error() {
require.NoError(t, err) require.NoError(t, err)
} }
@@ -105,8 +103,7 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
Count: 128, Count: 128,
Step: 1, Step: 1,
} }
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRangeRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, nil)
blocks, err := SendBeaconBlocksByRangeRequest(ctx, chain, p1, p2.PeerID(), req, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 128, len(blocks)) assert.Equal(t, 128, len(blocks))
}) })
@@ -124,8 +121,7 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
Step: 1, Step: 1,
} }
blocksFromProcessor := make([]interfaces.ReadOnlySignedBeaconBlock, 0) blocksFromProcessor := make([]interfaces.ReadOnlySignedBeaconBlock, 0)
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRangeRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
blocks, err := SendBeaconBlocksByRangeRequest(ctx, chain, p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
blocksFromProcessor = append(blocksFromProcessor, block) blocksFromProcessor = append(blocksFromProcessor, block)
return nil return nil
}) })
@@ -147,8 +143,7 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
Step: 1, Step: 1,
} }
errFromProcessor := errors.New("processor error") errFromProcessor := errors.New("processor error")
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} _, err := SendBeaconBlocksByRangeRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
_, err := SendBeaconBlocksByRangeRequest(ctx, chain, p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
return errFromProcessor return errFromProcessor
}) })
assert.ErrorContains(t, errFromProcessor.Error(), err) assert.ErrorContains(t, errFromProcessor.Error(), err)
@@ -166,8 +161,7 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
Count: 128, Count: 128,
Step: 1, Step: 1,
} }
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRangeRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, nil)
blocks, err := SendBeaconBlocksByRangeRequest(ctx, chain, p1, p2.PeerID(), req, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 128, len(blocks)) assert.Equal(t, 128, len(blocks))
@@ -178,7 +172,7 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
cfg.MaxRequestBlocks = maxRequestBlocks cfg.MaxRequestBlocks = maxRequestBlocks
params.OverrideBeaconNetworkConfig(cfg) params.OverrideBeaconNetworkConfig(cfg)
}() }()
blocks, err = SendBeaconBlocksByRangeRequest(ctx, chain, p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error { blocks, err = SendBeaconBlocksByRangeRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
// Since ssz checks the boundaries, and doesn't normally allow to send requests bigger than // Since ssz checks the boundaries, and doesn't normally allow to send requests bigger than
// the max request size, we are updating max request size dynamically. Even when updated dynamically, // the max request size, we are updating max request size dynamically. Even when updated dynamically,
// no more than max request size of blocks is expected on return. // no more than max request size of blocks is expected on return.
@@ -209,8 +203,7 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
Count: 128, Count: 128,
Step: 1, Step: 1,
} }
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRangeRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, nil)
blocks, err := SendBeaconBlocksByRangeRequest(ctx, chain, p1, p2.PeerID(), req, nil)
assert.ErrorContains(t, expectedErr.Error(), err) assert.ErrorContains(t, expectedErr.Error(), err)
assert.Equal(t, 0, len(blocks)) assert.Equal(t, 0, len(blocks))
}) })
@@ -238,9 +231,8 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
if uint64(i) >= uint64(len(knownBlocks)) { if uint64(i) >= uint64(len(knownBlocks)) {
break break
} }
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
wsb, err := blocks.NewSignedBeaconBlock(knownBlocks[i]) wsb, err := blocks.NewSignedBeaconBlock(knownBlocks[i])
err = WriteBlockChunk(stream, chain, p2.Encoding(), wsb) err = WriteBlockChunk(stream, startup.NewClock(time.Now(), [32]byte{}), p2.Encoding(), wsb)
if err != nil && err.Error() != network.ErrReset.Error() { if err != nil && err.Error() != network.ErrReset.Error() {
require.NoError(t, err) require.NoError(t, err)
} }
@@ -252,8 +244,7 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
Count: 128, Count: 128,
Step: 1, Step: 1,
} }
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRangeRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, nil)
blocks, err := SendBeaconBlocksByRangeRequest(ctx, chain, p1, p2.PeerID(), req, nil)
assert.ErrorContains(t, ErrInvalidFetchedData.Error(), err) assert.ErrorContains(t, ErrInvalidFetchedData.Error(), err)
assert.Equal(t, 0, len(blocks)) assert.Equal(t, 0, len(blocks))
@@ -282,10 +273,9 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
if uint64(i) >= uint64(len(knownBlocks)) { if uint64(i) >= uint64(len(knownBlocks)) {
break break
} }
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}}
wsb, err := blocks.NewSignedBeaconBlock(knownBlocks[i]) wsb, err := blocks.NewSignedBeaconBlock(knownBlocks[i])
require.NoError(t, err) require.NoError(t, err)
err = WriteBlockChunk(stream, chain, p2.Encoding(), wsb) err = WriteBlockChunk(stream, startup.NewClock(time.Now(), [32]byte{}), p2.Encoding(), wsb)
if err != nil && err.Error() != network.ErrReset.Error() { if err != nil && err.Error() != network.ErrReset.Error() {
require.NoError(t, err) require.NoError(t, err)
} }
@@ -297,8 +287,7 @@ func TestSendRequest_SendBeaconBlocksByRangeRequest(t *testing.T) {
Count: 128, Count: 128,
Step: 10, Step: 10,
} }
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRangeRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, nil)
blocks, err := SendBeaconBlocksByRangeRequest(ctx, chain, p1, p2.PeerID(), req, nil)
assert.ErrorContains(t, ErrInvalidFetchedData.Error(), err) assert.ErrorContains(t, ErrInvalidFetchedData.Error(), err)
assert.Equal(t, 0, len(blocks)) assert.Equal(t, 0, len(blocks))
@@ -327,8 +316,7 @@ func TestSendRequest_SendBeaconBlocksByRootRequest(t *testing.T) {
p1.Connect(bogusPeer) p1.Connect(bogusPeer)
req := &p2pTypes.BeaconBlockByRootsReq{} req := &p2pTypes.BeaconBlockByRootsReq{}
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} _, err := SendBeaconBlocksByRootRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, bogusPeer.PeerID(), req, nil)
_, err := SendBeaconBlocksByRootRequest(ctx, chain, p1, bogusPeer.PeerID(), req, nil)
assert.ErrorContains(t, "protocols not supported", err) assert.ErrorContains(t, "protocols not supported", err)
}) })
@@ -377,8 +365,7 @@ func TestSendRequest_SendBeaconBlocksByRootRequest(t *testing.T) {
p2.SetStreamHandler(pcl, knownBlocksProvider(p2, nil)) p2.SetStreamHandler(pcl, knownBlocksProvider(p2, nil))
req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1]} req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1]}
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRootRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, nil)
blocks, err := SendBeaconBlocksByRootRequest(ctx, chain, p1, p2.PeerID(), req, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 2, len(blocks)) assert.Equal(t, 2, len(blocks))
}) })
@@ -392,8 +379,7 @@ func TestSendRequest_SendBeaconBlocksByRootRequest(t *testing.T) {
// No error from block processor. // No error from block processor.
req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1]} req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1]}
blocksFromProcessor := make([]interfaces.ReadOnlySignedBeaconBlock, 0) blocksFromProcessor := make([]interfaces.ReadOnlySignedBeaconBlock, 0)
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRootRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
blocks, err := SendBeaconBlocksByRootRequest(ctx, chain, p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
blocksFromProcessor = append(blocksFromProcessor, block) blocksFromProcessor = append(blocksFromProcessor, block)
return nil return nil
}) })
@@ -411,8 +397,7 @@ func TestSendRequest_SendBeaconBlocksByRootRequest(t *testing.T) {
// Send error from block processor. // Send error from block processor.
req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1]} req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1]}
errFromProcessor := errors.New("processor error") errFromProcessor := errors.New("processor error")
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} _, err := SendBeaconBlocksByRootRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
_, err := SendBeaconBlocksByRootRequest(ctx, chain, p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
return errFromProcessor return errFromProcessor
}) })
assert.ErrorContains(t, errFromProcessor.Error(), err) assert.ErrorContains(t, errFromProcessor.Error(), err)
@@ -426,8 +411,8 @@ func TestSendRequest_SendBeaconBlocksByRootRequest(t *testing.T) {
// No cap on max roots. // No cap on max roots.
req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1], knownRoots[2], knownRoots[3]} req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1], knownRoots[2], knownRoots[3]}
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} clock := startup.NewClock(time.Now(), [32]byte{})
blocks, err := SendBeaconBlocksByRootRequest(ctx, chain, p1, p2.PeerID(), req, nil) blocks, err := SendBeaconBlocksByRootRequest(ctx, clock, p1, p2.PeerID(), req, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 4, len(blocks)) assert.Equal(t, 4, len(blocks))
@@ -438,7 +423,7 @@ func TestSendRequest_SendBeaconBlocksByRootRequest(t *testing.T) {
cfg.MaxRequestBlocks = maxRequestBlocks cfg.MaxRequestBlocks = maxRequestBlocks
params.OverrideBeaconNetworkConfig(cfg) params.OverrideBeaconNetworkConfig(cfg)
}() }()
blocks, err = SendBeaconBlocksByRootRequest(ctx, chain, p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error { blocks, err = SendBeaconBlocksByRootRequest(ctx, clock, p1, p2.PeerID(), req, func(block interfaces.ReadOnlySignedBeaconBlock) error {
// Since ssz checks the boundaries, and doesn't normally allow to send requests bigger than // Since ssz checks the boundaries, and doesn't normally allow to send requests bigger than
// the max request size, we are updating max request size dynamically. Even when updated dynamically, // the max request size, we are updating max request size dynamically. Even when updated dynamically,
// no more than max request size of blocks is expected on return. // no more than max request size of blocks is expected on return.
@@ -465,8 +450,7 @@ func TestSendRequest_SendBeaconBlocksByRootRequest(t *testing.T) {
})) }))
req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1], knownRoots[2], knownRoots[3]} req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1], knownRoots[2], knownRoots[3]}
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRootRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, nil)
blocks, err := SendBeaconBlocksByRootRequest(ctx, chain, p1, p2.PeerID(), req, nil)
assert.ErrorContains(t, expectedErr.Error(), err) assert.ErrorContains(t, expectedErr.Error(), err)
assert.Equal(t, 0, len(blocks)) assert.Equal(t, 0, len(blocks))
}) })
@@ -486,8 +470,7 @@ func TestSendRequest_SendBeaconBlocksByRootRequest(t *testing.T) {
})) }))
req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1], knownRoots[2], knownRoots[3]} req := &p2pTypes.BeaconBlockByRootsReq{knownRoots[0], knownRoots[1], knownRoots[2], knownRoots[3]}
chain := &mock.ChainService{Genesis: time.Now(), ValidatorsRoot: [32]byte{}} blocks, err := SendBeaconBlocksByRootRequest(ctx, startup.NewClock(time.Now(), [32]byte{}), p1, p2.PeerID(), req, nil)
blocks, err := SendBeaconBlocksByRootRequest(ctx, chain, p1, p2.PeerID(), req, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 3, len(blocks)) assert.Equal(t, 3, len(blocks))
}) })

View File

@@ -93,7 +93,7 @@ func (s *Service) resyncIfBehind() {
// Check if the current node is more than 1 epoch behind. // Check if the current node is more than 1 epoch behind.
if highestEpoch > (syncedEpoch + 1) { if highestEpoch > (syncedEpoch + 1) {
log.WithFields(logrus.Fields{ log.WithFields(logrus.Fields{
"currentEpoch": slots.ToEpoch(s.cfg.chain.CurrentSlot()), "currentEpoch": slots.ToEpoch(s.cfg.clock.CurrentSlot()),
"syncedEpoch": syncedEpoch, "syncedEpoch": syncedEpoch,
"peersEpoch": highestEpoch, "peersEpoch": highestEpoch,
}).Info("Fallen behind peers; reverting to initial sync to catch up") }).Info("Fallen behind peers; reverting to initial sync to catch up")
@@ -110,7 +110,7 @@ func (s *Service) resyncIfBehind() {
// shouldReSync returns true if the node is not syncing and falls behind two epochs. // shouldReSync returns true if the node is not syncing and falls behind two epochs.
func (s *Service) shouldReSync() bool { func (s *Service) shouldReSync() bool {
syncedEpoch := slots.ToEpoch(s.cfg.chain.HeadSlot()) syncedEpoch := slots.ToEpoch(s.cfg.chain.HeadSlot())
currentEpoch := slots.ToEpoch(s.cfg.chain.CurrentSlot()) currentEpoch := slots.ToEpoch(s.cfg.clock.CurrentSlot())
prevEpoch := primitives.Epoch(0) prevEpoch := primitives.Epoch(0)
if currentEpoch > 1 { if currentEpoch > 1 {
prevEpoch = currentEpoch - 1 prevEpoch = currentEpoch - 1
@@ -140,7 +140,7 @@ func (s *Service) sendRPCStatusRequest(ctx context.Context, id peer.ID) error {
HeadRoot: headRoot, HeadRoot: headRoot,
HeadSlot: s.cfg.chain.HeadSlot(), HeadSlot: s.cfg.chain.HeadSlot(),
} }
topic, err := p2p.TopicFromMessage(p2p.StatusMessageName, slots.ToEpoch(s.cfg.chain.CurrentSlot())) topic, err := p2p.TopicFromMessage(p2p.StatusMessageName, slots.ToEpoch(s.cfg.clock.CurrentSlot()))
if err != nil { if err != nil {
return err return err
} }
@@ -288,7 +288,7 @@ func (s *Service) validateStatusMessage(ctx context.Context, msg *pb.Status) err
if !bytes.Equal(forkDigest[:], msg.ForkDigest) { if !bytes.Equal(forkDigest[:], msg.ForkDigest) {
return p2ptypes.ErrWrongForkDigestVersion return p2ptypes.ErrWrongForkDigestVersion
} }
genesis := s.cfg.chain.GenesisTime() genesis := s.cfg.clock.GenesisTime()
cp := s.cfg.chain.FinalizedCheckpt() cp := s.cfg.chain.FinalizedCheckpt()
finalizedEpoch := cp.Epoch finalizedEpoch := cp.Epoch
maxEpoch := slots.EpochsSinceGenesis(genesis) maxEpoch := slots.EpochsSinceGenesis(genesis)

View File

@@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
"github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/protocol" "github.com/libp2p/go-libp2p/core/protocol"
"github.com/prysmaticlabs/prysm/v4/async/abool"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db/kv" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/kv"
@@ -17,6 +18,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/peers"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types" p2ptypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native" state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -41,6 +43,8 @@ func TestStatusRPCHandler_Disconnects_OnForkVersionMismatch(t *testing.T) {
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
root := [32]byte{'C'} root := [32]byte{'C'}
gt := time.Now()
vr := [32]byte{'A'}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
@@ -53,10 +57,11 @@ func TestStatusRPCHandler_Disconnects_OnForkVersionMismatch(t *testing.T) {
Epoch: 0, Epoch: 0,
Root: root[:], Root: root[:],
}, },
Genesis: time.Now(), Genesis: gt,
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
Root: make([]byte, 32), Root: make([]byte, 32),
}, },
clock: startup.NewClock(gt, vr),
}, },
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }
@@ -109,6 +114,8 @@ func TestStatusRPCHandler_ConnectsOnGenesis(t *testing.T) {
assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected") assert.Equal(t, 1, len(p1.BHost.Network().Peers()), "Expected peers to be connected")
var root [32]byte var root [32]byte
gt := time.Now()
vr := [32]byte{'A'}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
@@ -121,10 +128,11 @@ func TestStatusRPCHandler_ConnectsOnGenesis(t *testing.T) {
Epoch: 0, Epoch: 0,
Root: params.BeaconConfig().ZeroHash[:], Root: params.BeaconConfig().ZeroHash[:],
}, },
Genesis: time.Now(), Genesis: gt,
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
Root: make([]byte, 32), Root: make([]byte, 32),
}, },
clock: startup.NewClock(gt, vr),
}, },
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }
@@ -187,6 +195,8 @@ func TestStatusRPCHandler_ReturnsHelloMessage(t *testing.T) {
totalSec := int64(params.BeaconConfig().SlotsPerEpoch.Mul(5 * params.BeaconConfig().SecondsPerSlot)) totalSec := int64(params.BeaconConfig().SlotsPerEpoch.Mul(5 * params.BeaconConfig().SecondsPerSlot))
genTime := time.Now().Unix() - totalSec genTime := time.Now().Unix() - totalSec
gt := time.Unix(genTime, 0)
vr := [32]byte{'A'}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
@@ -198,12 +208,13 @@ func TestStatusRPCHandler_ReturnsHelloMessage(t *testing.T) {
PreviousVersion: params.BeaconConfig().GenesisForkVersion, PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion, CurrentVersion: params.BeaconConfig().GenesisForkVersion,
}, },
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
Genesis: time.Unix(genTime, 0), Genesis: gt,
FinalizedRoots: map[[32]byte]bool{ FinalizedRoots: map[[32]byte]bool{
finalizedRoot: true, finalizedRoot: true,
}, },
}, },
clock: startup.NewClock(gt, vr),
beaconDB: db, beaconDB: db,
}, },
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
@@ -249,6 +260,10 @@ func TestStatusRPCHandler_ReturnsHelloMessage(t *testing.T) {
} }
func TestHandshakeHandlers_Roundtrip(t *testing.T) { func TestHandshakeHandlers_Roundtrip(t *testing.T) {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// Scenario is that p1 and p2 connect, exchange handshakes. // Scenario is that p1 and p2 connect, exchange handshakes.
// p2 disconnects and p1 should forget the handshake status. // p2 disconnects and p1 should forget the handshake status.
p1 := p2ptest.NewTestP2P(t) p1 := p2ptest.NewTestP2P(t)
@@ -271,48 +286,56 @@ func TestHandshakeHandlers_Roundtrip(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
blk := util.NewBeaconBlock() blk := util.NewBeaconBlock()
blk.Block.Slot = 0 blk.Block.Slot = 0
util.SaveBlock(t, context.Background(), db, blk) util.SaveBlock(t, ctx, db, blk)
finalizedRoot, err := blk.Block.HashTreeRoot() finalizedRoot, err := blk.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, db.SaveGenesisBlockRoot(context.Background(), finalizedRoot)) require.NoError(t, db.SaveGenesisBlockRoot(ctx, finalizedRoot))
chain := &mock.ChainService{
State: st,
FinalizedCheckPoint: &ethpb.Checkpoint{Epoch: 0, Root: finalizedRoot[:]},
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
Root: make([]byte, 32),
FinalizedRoots: map[[32]byte]bool{
finalizedRoot: true,
},
}
cw := startup.NewClockSynchronizer()
r := &Service{ r := &Service{
ctx: ctx,
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
chain: &mock.ChainService{ chain: chain,
State: st, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
FinalizedCheckPoint: &ethpb.Checkpoint{Epoch: 0, Root: finalizedRoot[:]},
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
Root: make([]byte, 32),
FinalizedRoots: map[[32]byte]bool{
finalizedRoot: true,
},
},
beaconDB: db, beaconDB: db,
}, },
ctx: context.Background(), rateLimiter: newRateLimiter(p1),
rateLimiter: newRateLimiter(p1), clockWaiter: cw,
chainStarted: abool.New(),
} }
p1.Digest, err = r.currentForkDigest() p1.Digest, err = r.currentForkDigest()
require.NoError(t, err) require.NoError(t, err)
chain2 := &mock.ChainService{
FinalizedCheckPoint: &ethpb.Checkpoint{Epoch: 0, Root: finalizedRoot[:]},
}
r2 := &Service{ r2 := &Service{
ctx: ctx,
cfg: &config{ cfg: &config{
chain: &mock.ChainService{ chain: chain2,
FinalizedCheckPoint: &ethpb.Checkpoint{Epoch: 0, Root: finalizedRoot[:]}, clock: startup.NewClock(chain2.Genesis, chain2.ValidatorsRoot),
}, p2p: p2,
p2p: p2,
}, },
rateLimiter: newRateLimiter(p2), rateLimiter: newRateLimiter(p2),
} }
p2.Digest, err = r.currentForkDigest() p2.Digest, err = r.currentForkDigest()
require.NoError(t, err) require.NoError(t, err)
r.Start() go r.Start()
// Setup streams // Setup streams
pcl := protocol.ID("/eth2/beacon_chain/req/status/1/ssz_snappy") pcl := protocol.ID("/eth2/beacon_chain/req/status/1/ssz_snappy")
@@ -347,13 +370,14 @@ func TestHandshakeHandlers_Roundtrip(t *testing.T) {
out := new(primitives.SSZUint64) out := new(primitives.SSZUint64)
assert.NoError(t, r.cfg.p2p.Encoding().DecodeWithMaxLength(stream, out)) assert.NoError(t, r.cfg.p2p.Encoding().DecodeWithMaxLength(stream, out))
assert.Equal(t, uint64(2), uint64(*out)) assert.Equal(t, uint64(2), uint64(*out))
assert.NoError(t, r2.pingHandler(context.Background(), out, stream)) assert.NoError(t, r2.pingHandler(ctx, out, stream))
assert.NoError(t, stream.Close()) assert.NoError(t, stream.Close())
}) })
numInactive1 := len(p1.Peers().Inactive()) numInactive1 := len(p1.Peers().Inactive())
numActive1 := len(p1.Peers().Active()) numActive1 := len(p1.Peers().Active())
require.NoError(t, cw.SetClock(startup.NewClock(chain.Genesis, chain.ValidatorsRoot)))
p1.Connect(p2) p1.Connect(p2)
p1.Peers().Add(new(enr.Record), p2.BHost.ID(), p2.BHost.Addrs()[0], network.DirUnknown) p1.Peers().Add(new(enr.Record), p2.BHost.ID(), p2.BHost.Addrs()[0], network.DirUnknown)
@@ -412,20 +436,22 @@ func TestStatusRPCRequest_RequestSent(t *testing.T) {
Root: finalizedRoot[:], Root: finalizedRoot[:],
} }
chain := &mock.ChainService{
State: genesisState,
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
chain: &mock.ChainService{ chain: chain,
State: genesisState, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
},
}, },
ctx: context.Background(), ctx: context.Background(),
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
@@ -494,45 +520,48 @@ func TestStatusRPCRequest_FinalizedBlockExists(t *testing.T) {
} }
totalSec := int64(params.BeaconConfig().SlotsPerEpoch.Mul(5 * params.BeaconConfig().SecondsPerSlot)) totalSec := int64(params.BeaconConfig().SlotsPerEpoch.Mul(5 * params.BeaconConfig().SecondsPerSlot))
genTime := time.Now().Unix() - totalSec genTime := time.Now().Unix() - totalSec
chain := &mock.ChainService{
State: genesisState,
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Unix(genTime, 0),
ValidatorsRoot: [32]byte{'A'},
FinalizedRoots: map[[32]byte]bool{
finalizedRoot: true,
},
}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
chain: &mock.ChainService{ chain: chain,
State: genesisState, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Unix(genTime, 0),
ValidatorsRoot: [32]byte{'A'},
FinalizedRoots: map[[32]byte]bool{
finalizedRoot: true,
},
},
}, },
ctx: context.Background(), ctx: context.Background(),
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }
chain2 := &mock.ChainService{
State: genesisState,
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Unix(genTime, 0),
ValidatorsRoot: [32]byte{'A'},
FinalizedRoots: map[[32]byte]bool{
finalizedRoot: true,
},
}
r2 := &Service{ r2 := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
chain: &mock.ChainService{ chain: chain2,
State: genesisState, clock: startup.NewClock(chain2.Genesis, chain2.ValidatorsRoot),
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Unix(genTime, 0),
ValidatorsRoot: [32]byte{'A'},
FinalizedRoots: map[[32]byte]bool{
finalizedRoot: true,
},
},
beaconDB: db, beaconDB: db,
}, },
ctx: context.Background(), ctx: context.Background(),
@@ -674,48 +703,52 @@ func TestStatusRPCRequest_FinalizedBlockSkippedSlots(t *testing.T) {
epoch := expectedFinalizedEpoch.Add(2) epoch := expectedFinalizedEpoch.Add(2)
totalSec := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch) * params.BeaconConfig().SecondsPerSlot)) totalSec := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch) * params.BeaconConfig().SecondsPerSlot))
genTime := time.Now().Unix() - int64(totalSec) gt := time.Unix(time.Now().Unix()-int64(totalSec), 0)
vr := [32]byte{'A'}
chain := &mock.ChainService{
State: nState,
FinalizedCheckPoint: remoteFinalizedChkpt,
Root: rHeadRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: gt,
ValidatorsRoot: vr,
FinalizedRoots: map[[32]byte]bool{
tt.expectedFinalizedRoot: true,
tt.remoteFinalizedRoot: true,
},
}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
chain: &mock.ChainService{ chain: chain,
State: nState, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
FinalizedCheckPoint: remoteFinalizedChkpt,
Root: rHeadRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Unix(genTime, 0),
ValidatorsRoot: [32]byte{'A'},
FinalizedRoots: map[[32]byte]bool{
tt.expectedFinalizedRoot: true,
tt.remoteFinalizedRoot: true,
},
},
}, },
ctx: context.Background(), ctx: context.Background(),
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
} }
chain2 := &mock.ChainService{
State: nState,
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: gt,
ValidatorsRoot: vr,
FinalizedRoots: map[[32]byte]bool{
tt.expectedFinalizedRoot: true,
tt.remoteFinalizedRoot: true,
},
}
r2 := &Service{ r2 := &Service{
cfg: &config{ cfg: &config{
p2p: p2, p2p: p2,
chain: &mock.ChainService{ chain: chain2,
State: nState, clock: startup.NewClock(chain2.Genesis, chain2.ValidatorsRoot),
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Unix(genTime, 0),
ValidatorsRoot: [32]byte{'A'},
FinalizedRoots: map[[32]byte]bool{
tt.expectedFinalizedRoot: true,
tt.remoteFinalizedRoot: true,
},
},
beaconDB: db, beaconDB: db,
}, },
@@ -750,6 +783,10 @@ func TestStatusRPCRequest_FinalizedBlockSkippedSlots(t *testing.T) {
} }
func TestStatusRPCRequest_BadPeerHandshake(t *testing.T) { func TestStatusRPCRequest_BadPeerHandshake(t *testing.T) {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
p1 := p2ptest.NewTestP2P(t) p1 := p2ptest.NewTestP2P(t)
p2 := p2ptest.NewTestP2P(t) p2 := p2ptest.NewTestP2P(t)
@@ -761,7 +798,7 @@ func TestStatusRPCRequest_BadPeerHandshake(t *testing.T) {
finalized := util.NewBeaconBlock() finalized := util.NewBeaconBlock()
finalizedRoot, err := finalized.Block.HashTreeRoot() finalizedRoot, err := finalized.Block.HashTreeRoot()
require.NoError(t, err) require.NoError(t, err)
genesisState, err := transition.GenesisBeaconState(context.Background(), nil, 0, &ethpb.Eth1Data{}) genesisState, err := transition.GenesisBeaconState(ctx, nil, 0, &ethpb.Eth1Data{})
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, genesisState.SetSlot(111)) require.NoError(t, genesisState.SetSlot(111))
require.NoError(t, genesisState.UpdateBlockRootAtIndex(111%uint64(params.BeaconConfig().SlotsPerHistoricalRoot), headRoot)) require.NoError(t, genesisState.UpdateBlockRootAtIndex(111%uint64(params.BeaconConfig().SlotsPerHistoricalRoot), headRoot))
@@ -769,28 +806,32 @@ func TestStatusRPCRequest_BadPeerHandshake(t *testing.T) {
Epoch: 5, Epoch: 5,
Root: finalizedRoot[:], Root: finalizedRoot[:],
} }
chain := &mock.ChainService{
State: genesisState,
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
}
cw := startup.NewClockSynchronizer()
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p1, p2p: p1,
chain: &mock.ChainService{ chain: chain,
State: genesisState,
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
},
}, },
ctx: context.Background(), ctx: ctx,
rateLimiter: newRateLimiter(p1), rateLimiter: newRateLimiter(p1),
clockWaiter: cw,
chainStarted: abool.New(),
} }
r.Start() go r.Start()
// Setup streams // Setup streams
pcl := protocol.ID("/eth2/beacon_chain/req/status/1/ssz_snappy") pcl := protocol.ID("/eth2/beacon_chain/req/status/1/ssz_snappy")
@@ -816,6 +857,8 @@ func TestStatusRPCRequest_BadPeerHandshake(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
}) })
require.NoError(t, cw.SetClock(startup.NewClock(chain.Genesis, chain.ValidatorsRoot)))
assert.Equal(t, false, p1.Peers().Scorers().IsBadPeer(p2.PeerID()), "Peer is marked as bad") assert.Equal(t, false, p1.Peers().Scorers().IsBadPeer(p2.PeerID()), "Peer is marked as bad")
p1.Connect(p2) p1.Connect(p2)
@@ -850,19 +893,21 @@ func TestStatusRPC_ValidGenesisMessage(t *testing.T) {
Epoch: 5, Epoch: 5,
Root: finalizedRoot[:], Root: finalizedRoot[:],
} }
chain := &mock.ChainService{
State: genesisState,
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
chain: &mock.ChainService{ chain: chain,
State: genesisState, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
FinalizedCheckPoint: finalizedCheckpt,
Root: headRoot[:],
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
},
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
},
}, },
ctx: context.Background(), ctx: context.Background(),
} }
@@ -932,12 +977,14 @@ func TestShouldResync(t *testing.T) {
headState, err := transition.GenesisBeaconState(context.Background(), nil, 0, &ethpb.Eth1Data{}) headState, err := transition.GenesisBeaconState(context.Background(), nil, 0, &ethpb.Eth1Data{})
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, headState.SetSlot(tt.args.headSlot)) require.NoError(t, headState.SetSlot(tt.args.headSlot))
chain := &mock.ChainService{
State: headState,
Genesis: tt.args.genesis,
}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
chain: &mock.ChainService{ chain: chain,
State: headState, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
Genesis: tt.args.genesis,
},
initialSync: &mockSync.Sync{IsSyncing: tt.args.syncing}, initialSync: &mockSync.Sync{IsSyncing: tt.args.syncing},
}, },
ctx: context.Background(), ctx: context.Background(),

View File

@@ -19,10 +19,8 @@ import (
"github.com/prysmaticlabs/prysm/v4/async/abool" "github.com/prysmaticlabs/prysm/v4/async/abool"
"github.com/prysmaticlabs/prysm/v4/async/event" "github.com/prysmaticlabs/prysm/v4/async/event"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain" "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
blockfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/block" blockfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/block"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/operation" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/operation"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db" "github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/execution" "github.com/prysmaticlabs/prysm/v4/beacon-chain/execution"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
@@ -31,6 +29,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/synccommittee"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/voluntaryexits"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru" lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -79,13 +78,13 @@ type config struct {
blsToExecPool blstoexec.PoolManager blsToExecPool blstoexec.PoolManager
chain blockchainService chain blockchainService
initialSync Checker initialSync Checker
stateNotifier statefeed.Notifier
blockNotifier blockfeed.Notifier blockNotifier blockfeed.Notifier
operationNotifier operation.Notifier operationNotifier operation.Notifier
executionPayloadReconstructor execution.ExecutionPayloadReconstructor executionPayloadReconstructor execution.ExecutionPayloadReconstructor
stateGen *stategen.State stateGen *stategen.State
slasherAttestationsFeed *event.Feed slasherAttestationsFeed *event.Feed
slasherBlockHeadersFeed *event.Feed slasherBlockHeadersFeed *event.Feed
clock *startup.Clock
} }
// This defines the interface for interacting with block chain service // This defines the interface for interacting with block chain service
@@ -139,6 +138,8 @@ type Service struct {
syncContributionBitsOverlapLock sync.RWMutex syncContributionBitsOverlapLock sync.RWMutex
syncContributionBitsOverlapCache *lru.Cache syncContributionBitsOverlapCache *lru.Cache
signatureChan chan *signatureVerifier signatureChan chan *signatureVerifier
clockWaiter startup.ClockWaiter
initialSyncComplete chan struct{}
} }
// NewService initializes new regular sync service. // NewService initializes new regular sync service.
@@ -164,14 +165,14 @@ func NewService(ctx context.Context, opts ...Option) *Service {
r.rateLimiter = newRateLimiter(r.cfg.p2p) r.rateLimiter = newRateLimiter(r.cfg.p2p)
r.initCaches() r.initCaches()
go r.registerHandlers()
go r.verifierRoutine()
return r return r
} }
// Start the regular sync service. // Start the regular sync service.
func (s *Service) Start() { func (s *Service) Start() {
go s.verifierRoutine()
go s.registerHandlers()
s.cfg.p2p.AddConnectionHandler(s.reValidatePeer, s.sendGoodbye) s.cfg.p2p.AddConnectionHandler(s.reValidatePeer, s.sendGoodbye)
s.cfg.p2p.AddDisconnectionHandler(func(_ context.Context, _ peer.ID) error { s.cfg.p2p.AddDisconnectionHandler(func(_ context.Context, _ peer.ID) error {
// no-op // no-op
@@ -210,7 +211,7 @@ func (s *Service) Stop() error {
func (s *Service) Status() error { func (s *Service) Status() error {
// If our head slot is on a previous epoch and our peers are reporting their head block are // If our head slot is on a previous epoch and our peers are reporting their head block are
// in the most recent epoch, then we might be out of sync. // in the most recent epoch, then we might be out of sync.
if headEpoch := slots.ToEpoch(s.cfg.chain.HeadSlot()); headEpoch+1 < slots.ToEpoch(s.cfg.chain.CurrentSlot()) && if headEpoch := slots.ToEpoch(s.cfg.chain.HeadSlot()); headEpoch+1 < slots.ToEpoch(s.cfg.clock.CurrentSlot()) &&
headEpoch+1 < s.cfg.p2p.Peers().HighestEpoch() { headEpoch+1 < s.cfg.p2p.Peers().HighestEpoch() {
return errors.New("out of sync") return errors.New("out of sync")
} }
@@ -232,58 +233,42 @@ func (s *Service) initCaches() {
s.badBlockCache = lruwrpr.New(badBlockSize) s.badBlockCache = lruwrpr.New(badBlockSize)
} }
func (s *Service) registerHandlers() { func (s *Service) waitForChainStart() {
// Wait until chain start. clock, err := s.clockWaiter.WaitForClock(s.ctx)
stateChannel := make(chan *feed.Event, 1) if err != nil {
stateSub := s.cfg.stateNotifier.StateFeed().Subscribe(stateChannel) log.WithError(err).Error("sync service failed to receive genesis data")
defer stateSub.Unsubscribe() return
for { }
select { s.cfg.clock = clock
case e := <-stateChannel: startTime := clock.GenesisTime()
switch e.Type { log.WithField("starttime", startTime).Debug("Received state initialized event")
case statefeed.Initialized: // Register respective rpc handlers at state initialized event.
data, ok := e.Data.(*statefeed.InitializedData) s.registerRPCHandlers()
if !ok { // Wait for chainstart in separate routine.
log.Error("Event feed data is not type *statefeed.InitializedData") if startTime.After(prysmTime.Now()) {
return time.Sleep(prysmTime.Until(startTime))
} }
startTime := data.StartTime log.WithField("starttime", startTime).Debug("Chain started in sync service")
log.WithField("starttime", startTime).Debug("Received state initialized event") s.markForChainStart()
}
// Register respective rpc handlers at state initialized event. func (s *Service) registerHandlers() {
s.registerRPCHandlers() s.waitForChainStart()
// Wait for chainstart in separate routine. select {
go func() { case <-s.initialSyncComplete:
if startTime.After(prysmTime.Now()) { // Register respective pubsub handlers at state synced event.
time.Sleep(prysmTime.Until(startTime)) digest, err := s.currentForkDigest()
} if err != nil {
log.WithField("starttime", startTime).Debug("Chain started in sync service") log.WithError(err).Error("Could not retrieve current fork digest")
s.markForChainStart()
}()
case statefeed.Synced:
_, ok := e.Data.(*statefeed.SyncedData)
if !ok {
log.Error("Event feed data is not type *statefeed.SyncedData")
return
}
// Register respective pubsub handlers at state synced event.
digest, err := s.currentForkDigest()
if err != nil {
log.WithError(err).Error("Could not retrieve current fork digest")
return
}
currentEpoch := slots.ToEpoch(slots.CurrentSlot(uint64(s.cfg.chain.GenesisTime().Unix())))
s.registerSubscribers(currentEpoch, digest)
go s.forkWatcher()
return
}
case <-s.ctx.Done():
log.Debug("Context closed, exiting goroutine")
return
case err := <-stateSub.Err():
log.WithError(err).Error("Could not subscribe to state notifier")
return return
} }
currentEpoch := slots.ToEpoch(slots.CurrentSlot(uint64(s.cfg.clock.GenesisTime().Unix())))
s.registerSubscribers(currentEpoch, digest)
go s.forkWatcher()
return
case <-s.ctx.Done():
log.Debug("Context closed, exiting goroutine")
return
} }
} }
@@ -292,6 +277,10 @@ func (s *Service) markForChainStart() {
s.chainStarted.Set() s.chainStarted.Set()
} }
func (s *Service) chainIsStarted() bool {
return s.chainStarted.IsSet()
}
// Checker defines a struct which can verify whether a node is currently // Checker defines a struct which can verify whether a node is currently
// synchronizing a chain with the rest of peers in the network. // synchronizing a chain with the rest of peers in the network.
type Checker interface { type Checker interface {

View File

@@ -9,9 +9,9 @@ import (
"github.com/prysmaticlabs/prysm/v4/async/abool" "github.com/prysmaticlabs/prysm/v4/async/abool"
mockChain "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing" mockChain "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
dbTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" dbTest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native" state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
"github.com/prysmaticlabs/prysm/v4/crypto/bls" "github.com/prysmaticlabs/prysm/v4/crypto/bls"
@@ -25,14 +25,16 @@ import (
func TestService_StatusZeroEpoch(t *testing.T) { func TestService_StatusZeroEpoch(t *testing.T) {
bState, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{Slot: 0}) bState, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{Slot: 0})
require.NoError(t, err) require.NoError(t, err)
chain := &mockChain.ChainService{
Genesis: time.Now(),
State: bState,
}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p2ptest.NewTestP2P(t), p2p: p2ptest.NewTestP2P(t),
initialSync: new(mockSync.Sync), initialSync: new(mockSync.Sync),
chain: &mockChain.ChainService{ chain: chain,
Genesis: time.Now(), clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
State: bState,
},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
} }
@@ -47,29 +49,25 @@ func TestSyncHandlers_WaitToSync(t *testing.T) {
Genesis: time.Now(), Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: [32]byte{'A'},
} }
gs := startup.NewClockSynchronizer()
r := Service{ r := Service{
ctx: context.Background(), ctx: context.Background(),
cfg: &config{ cfg: &config{
p2p: p2p, p2p: p2p,
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(), initialSync: &mockSync.Sync{IsSyncing: false},
initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
clockWaiter: gs,
} }
topic := "/eth2/%x/beacon_block" topic := "/eth2/%x/beacon_block"
go r.registerHandlers() go r.registerHandlers()
go r.waitForChainStart()
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
i := r.cfg.stateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized, var vr [32]byte
Data: &statefeed.InitializedData{ require.NoError(t, gs.SetClock(startup.NewClock(time.Now(), vr)))
StartTime: time.Now(),
},
})
if i == 0 {
t.Fatal("didn't send genesis time to subscribers")
}
b := []byte("sk") b := []byte("sk")
b32 := bytesutil.ToBytes32(b) b32 := bytesutil.ToBytes32(b)
sk, err := bls.SecretKeyFromBytes(b32[:]) sk, err := bls.SecretKeyFromBytes(b32[:])
@@ -90,33 +88,24 @@ func TestSyncHandlers_WaitForChainStart(t *testing.T) {
Genesis: time.Now(), Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: [32]byte{'A'},
} }
gs := startup.NewClockSynchronizer()
r := Service{ r := Service{
ctx: context.Background(), ctx: context.Background(),
cfg: &config{ cfg: &config{
p2p: p2p, p2p: p2p,
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(), initialSync: &mockSync.Sync{IsSyncing: false},
initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), slotToPendingBlocks: gcache.New(time.Second, 2*time.Second),
clockWaiter: gs,
} }
go r.registerHandlers() go r.registerHandlers()
time.Sleep(100 * time.Millisecond) var vr [32]byte
i := r.cfg.stateNotifier.StateFeed().Send(&feed.Event{ require.NoError(t, gs.SetClock(startup.NewClock(time.Now(), vr)))
Type: statefeed.Initialized, r.waitForChainStart()
Data: &statefeed.InitializedData{
StartTime: time.Now().Add(2 * time.Second),
},
})
if i == 0 {
t.Fatal("didn't send genesis time to subscribers")
}
require.Equal(t, false, r.chainStarted.IsSet(), "Chainstart was marked prematurely")
// wait for chainstart to be sent
time.Sleep(3 * time.Second)
require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.") require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.")
} }
@@ -128,18 +117,20 @@ func TestSyncHandlers_WaitTillSynced(t *testing.T) {
} }
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() defer cancel()
gs := startup.NewClockSynchronizer()
r := Service{ r := Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
p2p: p2p, p2p: p2p,
beaconDB: dbTest.SetupDB(t), beaconDB: dbTest.SetupDB(t),
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(),
blockNotifier: chainService.BlockNotifier(), blockNotifier: chainService.BlockNotifier(),
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
clockWaiter: gs,
initialSyncComplete: make(chan struct{}),
} }
r.initCaches() r.initCaches()
@@ -148,19 +139,9 @@ func TestSyncHandlers_WaitTillSynced(t *testing.T) {
r.registerHandlers() r.registerHandlers()
syncCompleteCh <- true syncCompleteCh <- true
}() }()
for i := 0; i == 0; { var vr [32]byte
assert.NoError(t, ctx.Err()) require.NoError(t, gs.SetClock(startup.NewClock(time.Now(), vr)))
i = r.cfg.stateNotifier.StateFeed().Send(&feed.Event{ r.waitForChainStart()
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
StartTime: time.Now(),
},
})
}
for !r.chainStarted.IsSet() {
assert.NoError(t, ctx.Err())
time.Sleep(time.Millisecond)
}
require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.") require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.")
blockChan := make(chan *feed.Event, 1) blockChan := make(chan *feed.Event, 1)
@@ -184,15 +165,7 @@ func TestSyncHandlers_WaitTillSynced(t *testing.T) {
p2p.ReceivePubSub(topic, msg) p2p.ReceivePubSub(topic, msg)
assert.Equal(t, 0, len(blockChan), "block was received by sync service despite not being fully synced") assert.Equal(t, 0, len(blockChan), "block was received by sync service despite not being fully synced")
for i := 0; i == 0; { close(r.initialSyncComplete)
assert.NoError(t, ctx.Err())
i = r.cfg.stateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Synced,
Data: &statefeed.SyncedData{
StartTime: time.Now(),
},
})
}
<-syncCompleteCh <-syncCompleteCh
p2p.ReceivePubSub(topic, msg) p2p.ReceivePubSub(topic, msg)
@@ -211,30 +184,25 @@ func TestSyncService_StopCleanly(t *testing.T) {
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: [32]byte{'A'},
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
gs := startup.NewClockSynchronizer()
r := Service{ r := Service{
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
cfg: &config{ cfg: &config{
p2p: p2p, p2p: p2p,
chain: chainService, chain: chainService,
stateNotifier: chainService.StateNotifier(), initialSync: &mockSync.Sync{IsSyncing: false},
initialSync: &mockSync.Sync{IsSyncing: false},
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
clockWaiter: gs,
initialSyncComplete: make(chan struct{}),
} }
go r.registerHandlers() go r.registerHandlers()
time.Sleep(100 * time.Millisecond) var vr [32]byte
i := r.cfg.stateNotifier.StateFeed().Send(&feed.Event{ require.NoError(t, gs.SetClock(startup.NewClock(time.Now(), vr)))
Type: statefeed.Initialized, r.waitForChainStart()
Data: &statefeed.InitializedData{
StartTime: time.Now(),
},
})
if i == 0 {
t.Fatal("didn't send genesis time to subscribers")
}
var err error var err error
p2p.Digest, err = r.currentForkDigest() p2p.Digest, err = r.currentForkDigest()
@@ -244,16 +212,7 @@ func TestSyncService_StopCleanly(t *testing.T) {
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.") require.Equal(t, true, r.chainStarted.IsSet(), "Did not receive chain start event.")
i = r.cfg.stateNotifier.StateFeed().Send(&feed.Event{ close(r.initialSyncComplete)
Type: statefeed.Synced,
Data: &statefeed.SyncedData{
StartTime: time.Now(),
},
})
if i == 0 {
t.Fatal("didn't send genesis time to sync event subscribers")
}
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
require.NotEqual(t, 0, len(r.cfg.p2p.PubSub().GetTopics())) require.NotEqual(t, 0, len(r.cfg.p2p.PubSub().GetTopics()))

View File

@@ -135,7 +135,7 @@ func (s *Service) registerSubscribers(epoch primitives.Epoch, digest [4]byte) {
// subscribe to a given topic with a given validator and subscription handler. // subscribe to a given topic with a given validator and subscription handler.
// The base protobuf message is used to initialize new messages for decoding. // The base protobuf message is used to initialize new messages for decoding.
func (s *Service) subscribe(topic string, validator wrappedVal, handle subHandler, digest [4]byte) *pubsub.Subscription { func (s *Service) subscribe(topic string, validator wrappedVal, handle subHandler, digest [4]byte) *pubsub.Subscription {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
_, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:]) _, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:])
if err != nil { if err != nil {
// Impossible condition as it would mean digest does not exist. // Impossible condition as it would mean digest does not exist.
@@ -301,7 +301,7 @@ func (s *Service) wrapAndReportValidation(topic string, v wrappedVal) (string, p
// subscribe to a static subnet with the given topic and index.A given validator and subscription handler is // subscribe to a static subnet with the given topic and index.A given validator and subscription handler is
// used to handle messages from the subnet. The base protobuf message is used to initialize new messages for decoding. // used to handle messages from the subnet. The base protobuf message is used to initialize new messages for decoding.
func (s *Service) subscribeStaticWithSubnets(topic string, validator wrappedVal, handle subHandler, digest [4]byte) { func (s *Service) subscribeStaticWithSubnets(topic string, validator wrappedVal, handle subHandler, digest [4]byte) {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
_, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:]) _, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:])
if err != nil { if err != nil {
// Impossible condition as it would mean digest does not exist. // Impossible condition as it would mean digest does not exist.
@@ -315,7 +315,7 @@ func (s *Service) subscribeStaticWithSubnets(topic string, validator wrappedVal,
for i := uint64(0); i < params.BeaconNetworkConfig().AttestationSubnetCount; i++ { for i := uint64(0); i < params.BeaconNetworkConfig().AttestationSubnetCount; i++ {
s.subscribeWithBase(s.addDigestAndIndexToTopic(topic, digest, i), validator, handle) s.subscribeWithBase(s.addDigestAndIndexToTopic(topic, digest, i), validator, handle)
} }
genesis := s.cfg.chain.GenesisTime() genesis := s.cfg.clock.GenesisTime()
ticker := slots.NewSlotTicker(genesis, params.BeaconConfig().SecondsPerSlot) ticker := slots.NewSlotTicker(genesis, params.BeaconConfig().SecondsPerSlot)
go func() { go func() {
@@ -374,7 +374,7 @@ func (s *Service) subscribeDynamicWithSubnets(
handle subHandler, handle subHandler,
digest [4]byte, digest [4]byte,
) { ) {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
_, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:]) _, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:])
if err != nil { if err != nil {
// Impossible condition as it would mean digest does not exist. // Impossible condition as it would mean digest does not exist.
@@ -385,7 +385,7 @@ func (s *Service) subscribeDynamicWithSubnets(
panic(fmt.Sprintf("%s is not mapped to any message in GossipTopicMappings", topicFormat)) panic(fmt.Sprintf("%s is not mapped to any message in GossipTopicMappings", topicFormat))
} }
subscriptions := make(map[uint64]*pubsub.Subscription, params.BeaconConfig().MaxCommitteesPerSlot) subscriptions := make(map[uint64]*pubsub.Subscription, params.BeaconConfig().MaxCommitteesPerSlot)
genesis := s.cfg.chain.GenesisTime() genesis := s.cfg.clock.GenesisTime()
ticker := slots.NewSlotTicker(genesis, params.BeaconConfig().SecondsPerSlot) ticker := slots.NewSlotTicker(genesis, params.BeaconConfig().SecondsPerSlot)
go func() { go func() {
@@ -503,7 +503,7 @@ func (s *Service) subscribeSyncSubnet(
// subscribe to a static subnet with the given topic and index. A given validator and subscription handler is // subscribe to a static subnet with the given topic and index. A given validator and subscription handler is
// used to handle messages from the subnet. The base protobuf message is used to initialize new messages for decoding. // used to handle messages from the subnet. The base protobuf message is used to initialize new messages for decoding.
func (s *Service) subscribeStaticWithSyncSubnets(topic string, validator wrappedVal, handle subHandler, digest [4]byte) { func (s *Service) subscribeStaticWithSyncSubnets(topic string, validator wrappedVal, handle subHandler, digest [4]byte) {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
_, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:]) _, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:])
if err != nil { if err != nil {
panic(err) panic(err)
@@ -515,7 +515,7 @@ func (s *Service) subscribeStaticWithSyncSubnets(topic string, validator wrapped
for i := uint64(0); i < params.BeaconConfig().SyncCommitteeSubnetCount; i++ { for i := uint64(0); i < params.BeaconConfig().SyncCommitteeSubnetCount; i++ {
s.subscribeWithBase(s.addDigestAndIndexToTopic(topic, digest, i), validator, handle) s.subscribeWithBase(s.addDigestAndIndexToTopic(topic, digest, i), validator, handle)
} }
genesis := s.cfg.chain.GenesisTime() genesis := s.cfg.clock.GenesisTime()
ticker := slots.NewSlotTicker(genesis, params.BeaconConfig().SecondsPerSlot) ticker := slots.NewSlotTicker(genesis, params.BeaconConfig().SecondsPerSlot)
go func() { go func() {
@@ -574,7 +574,7 @@ func (s *Service) subscribeDynamicWithSyncSubnets(
handle subHandler, handle subHandler,
digest [4]byte, digest [4]byte,
) { ) {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
_, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:]) _, e, err := forks.RetrieveForkDataFromDigest(digest, genRoot[:])
if err != nil { if err != nil {
panic(err) panic(err)
@@ -584,7 +584,7 @@ func (s *Service) subscribeDynamicWithSyncSubnets(
panic(fmt.Sprintf("%s is not mapped to any message in GossipTopicMappings", topicFormat)) panic(fmt.Sprintf("%s is not mapped to any message in GossipTopicMappings", topicFormat))
} }
subscriptions := make(map[uint64]*pubsub.Subscription, params.BeaconConfig().SyncCommitteeSubnetCount) subscriptions := make(map[uint64]*pubsub.Subscription, params.BeaconConfig().SyncCommitteeSubnetCount)
genesis := s.cfg.chain.GenesisTime() genesis := s.cfg.clock.GenesisTime()
ticker := slots.NewSlotTicker(genesis, params.BeaconConfig().SecondsPerSlot) ticker := slots.NewSlotTicker(genesis, params.BeaconConfig().SecondsPerSlot)
go func() { go func() {
@@ -686,7 +686,7 @@ func (s *Service) filterNeededPeers(pids []peer.ID) []peer.ID {
log.WithError(err).Error("Could not compute fork digest") log.WithError(err).Error("Could not compute fork digest")
return pids return pids
} }
currSlot := s.cfg.chain.CurrentSlot() currSlot := s.cfg.clock.CurrentSlot()
wantedSubs := s.retrievePersistentSubs(currSlot) wantedSubs := s.retrievePersistentSubs(currSlot)
wantedSubs = slice.SetUint64(append(wantedSubs, s.attesterSubnetIndices(currSlot)...)) wantedSubs = slice.SetUint64(append(wantedSubs, s.attesterSubnetIndices(currSlot)...))
topic := p2p.GossipTypeMapping[reflect.TypeOf(&ethpb.Attestation{})] topic := p2p.GossipTypeMapping[reflect.TypeOf(&ethpb.Attestation{})]
@@ -740,8 +740,8 @@ func (_ *Service) addDigestAndIndexToTopic(topic string, digest [4]byte, idx uin
} }
func (s *Service) currentForkDigest() ([4]byte, error) { func (s *Service) currentForkDigest() ([4]byte, error) {
genRoot := s.cfg.chain.GenesisValidatorsRoot() genRoot := s.cfg.clock.GenesisValidatorsRoot()
return forks.CreateForkDigest(s.cfg.chain.GenesisTime(), genRoot[:]) return forks.CreateForkDigest(s.cfg.clock.GenesisTime(), genRoot[:])
} }
// Checks if the provided digest matches up with the current supposed digest. // Checks if the provided digest matches up with the current supposed digest.

View File

@@ -20,6 +20,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/encoder"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru" lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru"
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags" "github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
@@ -39,15 +40,18 @@ import (
func TestSubscribe_ReceivesValidMessage(t *testing.T) { func TestSubscribe_ReceivesValidMessage(t *testing.T) {
p2pService := p2ptest.NewTestP2P(t) p2pService := p2ptest.NewTestP2P(t)
gt := time.Now()
vr := [32]byte{'A'}
r := Service{ r := Service{
ctx: context.Background(), ctx: context.Background(),
cfg: &config{ cfg: &config{
p2p: p2pService, p2p: p2pService,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
chain: &mockChain.ChainService{ chain: &mockChain.ChainService{
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
Genesis: time.Now(), Genesis: gt,
}, },
clock: startup.NewClock(gt, vr),
}, },
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
chainStarted: abool.New(), chainStarted: abool.New(),
@@ -79,15 +83,18 @@ func TestSubscribe_ReceivesValidMessage(t *testing.T) {
func TestSubscribe_UnsubscribeTopic(t *testing.T) { func TestSubscribe_UnsubscribeTopic(t *testing.T) {
p2pService := p2ptest.NewTestP2P(t) p2pService := p2ptest.NewTestP2P(t)
gt := time.Now()
vr := [32]byte{'A'}
r := Service{ r := Service{
ctx: context.Background(), ctx: context.Background(),
cfg: &config{ cfg: &config{
p2p: p2pService, p2p: p2pService,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
chain: &mockChain.ChainService{ chain: &mockChain.ChainService{
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
Genesis: time.Now(), Genesis: gt,
}, },
clock: startup.NewClock(gt, vr),
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -123,9 +130,11 @@ func TestSubscribe_ReceivesAttesterSlashing(t *testing.T) {
p2pService := p2ptest.NewTestP2P(t) p2pService := p2ptest.NewTestP2P(t)
ctx := context.Background() ctx := context.Background()
d := db.SetupDB(t) d := db.SetupDB(t)
gt := time.Now()
vr := [32]byte{'A'}
chainService := &mockChain.ChainService{ chainService := &mockChain.ChainService{
Genesis: time.Now(), Genesis: gt,
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
} }
r := Service{ r := Service{
ctx: ctx, ctx: ctx,
@@ -134,6 +143,7 @@ func TestSubscribe_ReceivesAttesterSlashing(t *testing.T) {
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
slashingPool: slashings.NewPool(), slashingPool: slashings.NewPool(),
chain: chainService, chain: chainService,
clock: startup.NewClock(gt, vr),
beaconDB: d, beaconDB: d,
}, },
seenAttesterSlashingCache: make(map[uint64]bool), seenAttesterSlashingCache: make(map[uint64]bool),
@@ -187,6 +197,7 @@ func TestSubscribe_ReceivesProposerSlashing(t *testing.T) {
slashingPool: slashings.NewPool(), slashingPool: slashings.NewPool(),
chain: chainService, chain: chainService,
beaconDB: d, beaconDB: d,
clock: startup.NewClock(chainService.Genesis, chainService.ValidatorsRoot),
}, },
seenProposerSlashingCache: lruwrpr.New(10), seenProposerSlashingCache: lruwrpr.New(10),
chainStarted: abool.New(), chainStarted: abool.New(),
@@ -226,14 +237,16 @@ func TestSubscribe_ReceivesProposerSlashing(t *testing.T) {
func TestSubscribe_HandlesPanic(t *testing.T) { func TestSubscribe_HandlesPanic(t *testing.T) {
p := p2ptest.NewTestP2P(t) p := p2ptest.NewTestP2P(t)
chain := &mockChain.ChainService{
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
}
r := Service{ r := Service{
ctx: context.Background(), ctx: context.Background(),
cfg: &config{ cfg: &config{
chain: &mockChain.ChainService{ chain: chain,
Genesis: time.Now(), clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
ValidatorsRoot: [32]byte{'A'}, p2p: p,
},
p2p: p,
}, },
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
chainStarted: abool.New(), chainStarted: abool.New(),
@@ -261,14 +274,16 @@ func TestSubscribe_HandlesPanic(t *testing.T) {
func TestRevalidateSubscription_CorrectlyFormatsTopic(t *testing.T) { func TestRevalidateSubscription_CorrectlyFormatsTopic(t *testing.T) {
p := p2ptest.NewTestP2P(t) p := p2ptest.NewTestP2P(t)
hook := logTest.NewGlobal() hook := logTest.NewGlobal()
chain := &mockChain.ChainService{
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
}
r := Service{ r := Service{
ctx: context.Background(), ctx: context.Background(),
cfg: &config{ cfg: &config{
chain: &mockChain.ChainService{ chain: chain,
Genesis: time.Now(), clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
ValidatorsRoot: [32]byte{'A'}, p2p: p,
},
p2p: p,
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -300,14 +315,16 @@ func TestRevalidateSubscription_CorrectlyFormatsTopic(t *testing.T) {
func TestStaticSubnets(t *testing.T) { func TestStaticSubnets(t *testing.T) {
p := p2ptest.NewTestP2P(t) p := p2ptest.NewTestP2P(t)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
chain := &mockChain.ChainService{
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
}
r := Service{ r := Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
chain: &mockChain.ChainService{ chain: chain,
Genesis: time.Now(), clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
ValidatorsRoot: [32]byte{'A'}, p2p: p,
},
p2p: p,
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -427,6 +444,7 @@ func Test_wrapAndReportValidation(t *testing.T) {
chainStarted: chainStarted, chainStarted: chainStarted,
cfg: &config{ cfg: &config{
chain: mChain, chain: mChain,
clock: startup.NewClock(mChain.Genesis, mChain.ValidatorsRoot),
}, },
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
} }
@@ -452,19 +470,28 @@ func TestFilterSubnetPeers(t *testing.T) {
defer flags.Init(new(flags.GlobalFlags)) defer flags.Init(new(flags.GlobalFlags))
p := p2ptest.NewTestP2P(t) p := p2ptest.NewTestP2P(t)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel()
currSlot := primitives.Slot(100) currSlot := primitives.Slot(100)
gt := time.Now()
genPlus100 := func() time.Time {
return gt.Add(time.Second * time.Duration(uint64(currSlot)*params.BeaconConfig().SecondsPerSlot))
}
chain := &mockChain.ChainService{
Genesis: gt,
ValidatorsRoot: [32]byte{'A'},
FinalizedRoots: map[[32]byte]bool{
{}: true,
},
}
clock := startup.NewClock(chain.Genesis, chain.ValidatorsRoot, startup.WithNower(genPlus100))
require.Equal(t, currSlot, clock.CurrentSlot())
r := Service{ r := Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
chain: &mockChain.ChainService{ chain: chain,
Genesis: time.Now(), clock: clock,
ValidatorsRoot: [32]byte{'A'}, p2p: p,
Slot: &currSlot,
FinalizedRoots: map[[32]byte]bool{
{}: true,
},
},
p2p: p,
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -509,9 +536,7 @@ func TestFilterSubnetPeers(t *testing.T) {
} }
recPeers = r.filterNeededPeers(wantedPeers) recPeers = r.filterNeededPeers(wantedPeers)
assert.DeepEqual(t, 1, len(recPeers), "expected at least 1 suitable peer to prune") assert.Equal(t, 1, len(recPeers), "expected at least 1 suitable peer to prune")
cancel()
} }
func TestSubscribeWithSyncSubnets_StaticOK(t *testing.T) { func TestSubscribeWithSyncSubnets_StaticOK(t *testing.T) {
@@ -522,16 +547,16 @@ func TestSubscribeWithSyncSubnets_StaticOK(t *testing.T) {
p := p2ptest.NewTestP2P(t) p := p2ptest.NewTestP2P(t)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
currSlot := primitives.Slot(100) chain := &mockChain.ChainService{
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
}
r := Service{ r := Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
chain: &mockChain.ChainService{ chain: chain,
Genesis: time.Now(), clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
ValidatorsRoot: [32]byte{'A'}, p2p: p,
Slot: &currSlot,
},
p2p: p,
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -553,23 +578,24 @@ func TestSubscribeWithSyncSubnets_DynamicOK(t *testing.T) {
p := p2ptest.NewTestP2P(t) p := p2ptest.NewTestP2P(t)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
currSlot := primitives.Slot(100) gt := time.Now()
vr := [32]byte{'A'}
r := Service{ r := Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
chain: &mockChain.ChainService{ chain: &mockChain.ChainService{
Genesis: time.Now(), Genesis: gt,
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
Slot: &currSlot,
}, },
p2p: p, p2p: p,
clock: startup.NewClock(gt, vr),
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
} }
// Empty cache at the end of the test. // Empty cache at the end of the test.
defer cache.SyncSubnetIDs.EmptyAllCaches() defer cache.SyncSubnetIDs.EmptyAllCaches()
slot := r.cfg.chain.CurrentSlot() slot := r.cfg.clock.CurrentSlot()
currEpoch := slots.ToEpoch(slot) currEpoch := slots.ToEpoch(slot)
cache.SyncSubnetIDs.AddSyncCommitteeSubnets([]byte("pubkey"), currEpoch, []uint64{0, 1}, 10*time.Second) cache.SyncSubnetIDs.AddSyncCommitteeSubnets([]byte("pubkey"), currEpoch, []uint64{0, 1}, 10*time.Second)
digest, err := r.currentForkDigest() digest, err := r.currentForkDigest()
@@ -599,22 +625,24 @@ func TestSubscribeWithSyncSubnets_StaticSwitchFork(t *testing.T) {
params.BeaconConfig().InitializeForkSchedule() params.BeaconConfig().InitializeForkSchedule()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
currSlot := primitives.Slot(100) currSlot := primitives.Slot(100)
chain := &mockChain.ChainService{
Genesis: time.Now().Add(-time.Duration(uint64(params.BeaconConfig().SlotsPerEpoch)*params.BeaconConfig().SecondsPerSlot) * time.Second),
ValidatorsRoot: [32]byte{'A'},
Slot: &currSlot,
}
r := Service{ r := Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
chain: &mockChain.ChainService{ chain: chain,
Genesis: time.Now().Add(-time.Duration(uint64(params.BeaconConfig().SlotsPerEpoch)*params.BeaconConfig().SecondsPerSlot) * time.Second), clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
ValidatorsRoot: [32]byte{'A'}, p2p: p,
Slot: &currSlot,
},
p2p: p,
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
} }
// Empty cache at the end of the test. // Empty cache at the end of the test.
defer cache.SyncSubnetIDs.EmptyAllCaches() defer cache.SyncSubnetIDs.EmptyAllCaches()
genRoot := r.cfg.chain.GenesisValidatorsRoot() genRoot := r.cfg.clock.GenesisValidatorsRoot()
digest, err := signing.ComputeForkDigest(params.BeaconConfig().GenesisForkVersion, genRoot[:]) digest, err := signing.ComputeForkDigest(params.BeaconConfig().GenesisForkVersion, genRoot[:])
assert.NoError(t, err) assert.NoError(t, err)
r.subscribeStaticWithSyncSubnets(p2p.SyncCommitteeSubnetTopicFormat, nil, nil, digest) r.subscribeStaticWithSyncSubnets(p2p.SyncCommitteeSubnetTopicFormat, nil, nil, digest)
@@ -638,15 +666,18 @@ func TestSubscribeWithSyncSubnets_DynamicSwitchFork(t *testing.T) {
params.BeaconConfig().InitializeForkSchedule() params.BeaconConfig().InitializeForkSchedule()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
currSlot := primitives.Slot(100) currSlot := primitives.Slot(100)
gt := time.Now().Add(-time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second)
vr := [32]byte{'A'}
r := Service{ r := Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
chain: &mockChain.ChainService{ chain: &mockChain.ChainService{
Genesis: time.Now().Add(-time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second), Genesis: gt,
ValidatorsRoot: [32]byte{'A'}, ValidatorsRoot: vr,
Slot: &currSlot, Slot: &currSlot,
}, },
p2p: p, clock: startup.NewClock(gt, vr),
p2p: p,
}, },
chainStarted: abool.New(), chainStarted: abool.New(),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -654,7 +685,7 @@ func TestSubscribeWithSyncSubnets_DynamicSwitchFork(t *testing.T) {
// Empty cache at the end of the test. // Empty cache at the end of the test.
defer cache.SyncSubnetIDs.EmptyAllCaches() defer cache.SyncSubnetIDs.EmptyAllCaches()
cache.SyncSubnetIDs.AddSyncCommitteeSubnets([]byte("pubkey"), 0, []uint64{0, 1}, 10*time.Second) cache.SyncSubnetIDs.AddSyncCommitteeSubnets([]byte("pubkey"), 0, []uint64{0, 1}, 10*time.Second)
genRoot := r.cfg.chain.GenesisValidatorsRoot() genRoot := r.cfg.clock.GenesisValidatorsRoot()
digest, err := signing.ComputeForkDigest(params.BeaconConfig().GenesisForkVersion, genRoot[:]) digest, err := signing.ComputeForkDigest(params.BeaconConfig().GenesisForkVersion, genRoot[:])
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -20,6 +20,7 @@ import (
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree" doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru" lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru"
@@ -67,6 +68,7 @@ func FuzzValidateBeaconBlockPubSub_Phase0(f *testing.F) {
p2p: p, p2p: p,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
chain: chainService, chain: chainService,
clock: startup.NewClock(chainService.Genesis, chainService.ValidatorsRoot),
blockNotifier: chainService.BlockNotifier(), blockNotifier: chainService.BlockNotifier(),
stateGen: stateGen, stateGen: stateGen,
}, },
@@ -150,6 +152,7 @@ func FuzzValidateBeaconBlockPubSub_Altair(f *testing.F) {
chain: chainService, chain: chainService,
blockNotifier: chainService.BlockNotifier(), blockNotifier: chainService.BlockNotifier(),
stateGen: stateGen, stateGen: stateGen,
clock: startup.NewClock(chainService.Genesis, chainService.ValidatorsRoot),
}, },
seenBlockCache: lruwrpr.New(10), seenBlockCache: lruwrpr.New(10),
badBlockCache: lruwrpr.New(10), badBlockCache: lruwrpr.New(10),
@@ -229,6 +232,7 @@ func FuzzValidateBeaconBlockPubSub_Bellatrix(f *testing.F) {
p2p: p, p2p: p,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
chain: chainService, chain: chainService,
clock: startup.NewClock(chainService.Genesis, chainService.ValidatorsRoot),
blockNotifier: chainService.BlockNotifier(), blockNotifier: chainService.BlockNotifier(),
stateGen: stateGen, stateGen: stateGen,
}, },

View File

@@ -80,7 +80,7 @@ func (s *Service) validateAggregateAndProof(ctx context.Context, pid peer.ID, ms
// processing tolerance. // processing tolerance.
if err := helpers.ValidateAttestationTime( if err := helpers.ValidateAttestationTime(
m.Message.Aggregate.Data.Slot, m.Message.Aggregate.Data.Slot,
s.cfg.chain.GenesisTime(), s.cfg.clock.GenesisTime(),
earlyAttestationProcessingTolerance, earlyAttestationProcessingTolerance,
); err != nil { ); err != nil {
tracing.AnnotateError(span, err) tracing.AnnotateError(span, err)

View File

@@ -17,6 +17,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations" "github.com/prysmaticlabs/prysm/v4/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru" lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
@@ -355,21 +356,23 @@ func TestValidateAggregateAndProof_CanValidate(t *testing.T) {
require.NoError(t, beaconState.SetGenesisTime(uint64(time.Now().Unix()))) require.NoError(t, beaconState.SetGenesisTime(uint64(time.Now().Unix())))
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
chain := &mock.ChainService{Genesis: time.Now().Add(-oneEpoch()),
Optimistic: true,
DB: db,
State: beaconState,
ValidAttestation: true,
FinalizedCheckPoint: &ethpb.Checkpoint{
Epoch: 0,
Root: att.Data.BeaconBlockRoot,
}}
r := &Service{ r := &Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
p2p: p, p2p: p,
beaconDB: db, beaconDB: db,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
chain: &mock.ChainService{Genesis: time.Now().Add(-oneEpoch()), chain: chain,
Optimistic: true, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
DB: db,
State: beaconState,
ValidAttestation: true,
FinalizedCheckPoint: &ethpb.Checkpoint{
Epoch: 0,
Root: att.Data.BeaconBlockRoot,
}},
attPool: attestations.NewPool(), attPool: attestations.NewPool(),
attestationNotifier: (&mock.ChainService{}).OperationNotifier(), attestationNotifier: (&mock.ChainService{}).OperationNotifier(),
}, },
@@ -456,22 +459,23 @@ func TestVerifyIndexInCommittee_SeenAggregatorEpoch(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
chain := &mock.ChainService{Genesis: time.Now().Add(-oneEpoch()),
DB: db,
ValidatorsRoot: [32]byte{'A'},
State: beaconState,
ValidAttestation: true,
FinalizedCheckPoint: &ethpb.Checkpoint{
Epoch: 0,
Root: signedAggregateAndProof.Message.Aggregate.Data.BeaconBlockRoot,
}}
r := &Service{ r := &Service{
ctx: ctx, ctx: ctx,
cfg: &config{ cfg: &config{
p2p: p, p2p: p,
beaconDB: db, beaconDB: db,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
chain: &mock.ChainService{Genesis: time.Now().Add(-oneEpoch()), chain: chain,
DB: db, clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
ValidatorsRoot: [32]byte{'A'},
State: beaconState,
ValidAttestation: true,
FinalizedCheckPoint: &ethpb.Checkpoint{
Epoch: 0,
Root: signedAggregateAndProof.Message.Aggregate.Data.BeaconBlockRoot,
}},
attPool: attestations.NewPool(), attPool: attestations.NewPool(),
attestationNotifier: (&mock.ChainService{}).OperationNotifier(), attestationNotifier: (&mock.ChainService{}).OperationNotifier(),
}, },

View File

@@ -14,6 +14,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state" "github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
@@ -80,10 +81,12 @@ func TestValidateAttesterSlashing_ValidSlashing(t *testing.T) {
slashing, s := setupValidAttesterSlashing(t) slashing, s := setupValidAttesterSlashing(t)
chain := &mock.ChainService{State: s, Genesis: time.Now()}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p, p2p: p,
chain: &mock.ChainService{State: s, Genesis: time.Now()}, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
seenAttesterSlashingCache: make(map[uint64]bool), seenAttesterSlashingCache: make(map[uint64]bool),
@@ -123,10 +126,12 @@ func TestValidateAttesterSlashing_InvalidSlashing_WithdrawableEpoch(t *testing.T
require.NoError(t, s.SetValidators(vals)) require.NoError(t, s.SetValidators(vals))
chain := &mock.ChainService{State: s, Genesis: time.Now()}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p, p2p: p,
chain: &mock.ChainService{State: s, Genesis: time.Now()}, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
seenAttesterSlashingCache: make(map[uint64]bool), seenAttesterSlashingCache: make(map[uint64]bool),
@@ -171,11 +176,13 @@ func TestValidateAttesterSlashing_CanFilter(t *testing.T) {
p := p2ptest.NewTestP2P(t) p := p2ptest.NewTestP2P(t)
ctx := context.Background() ctx := context.Background()
chain := &mock.ChainService{Genesis: time.Now()}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p, p2p: p,
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
chain: &mock.ChainService{Genesis: time.Now()}, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
}, },
seenAttesterSlashingCache: make(map[uint64]bool), seenAttesterSlashingCache: make(map[uint64]bool),
subHandler: newSubTopicHandler(), subHandler: newSubTopicHandler(),
@@ -240,10 +247,12 @@ func TestValidateAttesterSlashing_ContextTimeout(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel() defer cancel()
chain := &mock.ChainService{State: s}
r := &Service{ r := &Service{
cfg: &config{ cfg: &config{
p2p: p, p2p: p,
chain: &mock.ChainService{State: s}, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
initialSync: &mockSync.Sync{IsSyncing: false}, initialSync: &mockSync.Sync{IsSyncing: false},
}, },
seenAttesterSlashingCache: make(map[uint64]bool), seenAttesterSlashingCache: make(map[uint64]bool),

View File

@@ -78,7 +78,7 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
// Attestation's slot is within ATTESTATION_PROPAGATION_SLOT_RANGE and early attestation // Attestation's slot is within ATTESTATION_PROPAGATION_SLOT_RANGE and early attestation
// processing tolerance. // processing tolerance.
if err := helpers.ValidateAttestationTime(att.Data.Slot, s.cfg.chain.GenesisTime(), if err := helpers.ValidateAttestationTime(att.Data.Slot, s.cfg.clock.GenesisTime(),
earlyAttestationProcessingTolerance); err != nil { earlyAttestationProcessingTolerance); err != nil {
tracing.AnnotateError(span, err) tracing.AnnotateError(span, err)
return pubsub.ValidationIgnore, err return pubsub.ValidationIgnore, err

View File

@@ -15,6 +15,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing" "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing"
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing" dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru" lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
@@ -46,6 +47,7 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) {
p2p: p, p2p: p,
beaconDB: db, beaconDB: db,
chain: chain, chain: chain,
clock: startup.NewClock(chain.Genesis, chain.ValidatorsRoot),
attestationNotifier: (&mockChain.ChainService{}).OperationNotifier(), attestationNotifier: (&mockChain.ChainService{}).OperationNotifier(),
}, },
blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof), blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof),
@@ -305,11 +307,7 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) {
} }
func TestService_setSeenCommitteeIndicesSlot(t *testing.T) { func TestService_setSeenCommitteeIndicesSlot(t *testing.T) {
chainService := &mockChain.ChainService{ s := NewService(context.Background(), WithP2P(p2ptest.NewTestP2P(t)))
Genesis: time.Now(),
ValidatorsRoot: [32]byte{'A'},
}
s := NewService(context.Background(), WithP2P(p2ptest.NewTestP2P(t)), WithStateNotifier(chainService.StateNotifier()))
s.initCaches() s.initCaches()
// Empty cache // Empty cache

View File

@@ -122,7 +122,7 @@ func (s *Service) validateBeaconBlockPubSub(ctx context.Context, pid peer.ID, ms
// Be lenient in handling early blocks. Instead of discarding blocks arriving later than // Be lenient in handling early blocks. Instead of discarding blocks arriving later than
// MAXIMUM_GOSSIP_CLOCK_DISPARITY in future, we tolerate blocks arriving at max two slots // MAXIMUM_GOSSIP_CLOCK_DISPARITY in future, we tolerate blocks arriving at max two slots
// earlier (SECONDS_PER_SLOT * 2 seconds). Queue such blocks and process them at the right slot. // earlier (SECONDS_PER_SLOT * 2 seconds). Queue such blocks and process them at the right slot.
genesisTime := uint64(s.cfg.chain.GenesisTime().Unix()) genesisTime := uint64(s.cfg.clock.GenesisTime().Unix())
if err := slots.VerifyTime(genesisTime, blk.Block().Slot(), earlyBlockProcessingTolerance); err != nil { if err := slots.VerifyTime(genesisTime, blk.Block().Slot(), earlyBlockProcessingTolerance); err != nil {
log.WithError(err).WithFields(getBlockFields(blk)).Debug("Ignored block: could not verify slot time") log.WithError(err).WithFields(getBlockFields(blk)).Debug("Ignored block: could not verify slot time")
return pubsub.ValidationIgnore, nil return pubsub.ValidationIgnore, nil
@@ -156,7 +156,7 @@ func (s *Service) validateBeaconBlockPubSub(ctx context.Context, pid peer.ID, ms
return pubsub.ValidationIgnore, err return pubsub.ValidationIgnore, err
} }
s.pendingQueueLock.Unlock() s.pendingQueueLock.Unlock()
err := fmt.Errorf("early block, with current slot %d < block slot %d", s.cfg.chain.CurrentSlot(), blk.Block().Slot()) err := fmt.Errorf("early block, with current slot %d < block slot %d", s.cfg.clock.CurrentSlot(), blk.Block().Slot())
log.WithError(err).WithFields(getBlockFields(blk)).Debug("Could not process early block") log.WithError(err).WithFields(getBlockFields(blk)).Debug("Could not process early block")
return pubsub.ValidationIgnore, err return pubsub.ValidationIgnore, err
} }

Some files were not shown because too many files have changed in this diff Show More