mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
Do Not Subscribe to Blocks in Initial Sync (#2524)
* only sub to block batches * batch sub remove * tests * fix lint * gazelle * delete old im mem blocks code
This commit is contained in:
@@ -45,7 +45,6 @@ go_test(
|
||||
"//shared/p2p:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_peer//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
|
||||
@@ -36,16 +36,14 @@ var debugError = "debug:"
|
||||
// Config defines the configurable properties of InitialSync.
|
||||
//
|
||||
type Config struct {
|
||||
SyncPollingInterval time.Duration
|
||||
BlockBufferSize int
|
||||
BlockAnnounceBufferSize int
|
||||
BatchedBlockBufferSize int
|
||||
StateBufferSize int
|
||||
BeaconDB *db.BeaconDB
|
||||
P2P p2pAPI
|
||||
SyncService syncService
|
||||
ChainService chainService
|
||||
PowChain powChainService
|
||||
SyncPollingInterval time.Duration
|
||||
BatchedBlockBufferSize int
|
||||
StateBufferSize int
|
||||
BeaconDB *db.BeaconDB
|
||||
P2P p2pAPI
|
||||
SyncService syncService
|
||||
ChainService chainService
|
||||
PowChain powChainService
|
||||
}
|
||||
|
||||
// DefaultConfig provides the default configuration for a sync service.
|
||||
@@ -54,11 +52,9 @@ type Config struct {
|
||||
// StateBufferSize determines the buffer size of the `stateBuf` channel.
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
SyncPollingInterval: time.Duration(params.BeaconConfig().SyncPollingInterval) * time.Second,
|
||||
BlockBufferSize: params.BeaconConfig().DefaultBufferSize,
|
||||
BatchedBlockBufferSize: params.BeaconConfig().DefaultBufferSize,
|
||||
BlockAnnounceBufferSize: params.BeaconConfig().DefaultBufferSize,
|
||||
StateBufferSize: params.BeaconConfig().DefaultBufferSize,
|
||||
SyncPollingInterval: time.Duration(params.BeaconConfig().SyncPollingInterval) * time.Second,
|
||||
BatchedBlockBufferSize: params.BeaconConfig().DefaultBufferSize,
|
||||
StateBufferSize: params.BeaconConfig().DefaultBufferSize,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,16 +89,13 @@ type InitialSync struct {
|
||||
chainService chainService
|
||||
db *db.BeaconDB
|
||||
powchain powChainService
|
||||
blockAnnounceBuf chan p2p.Message
|
||||
batchedBlockBuf chan p2p.Message
|
||||
blockBuf chan p2p.Message
|
||||
stateBuf chan p2p.Message
|
||||
currentSlot uint64
|
||||
highestObservedSlot uint64
|
||||
highestObservedRoot [32]byte
|
||||
beaconStateSlot uint64
|
||||
syncPollingInterval time.Duration
|
||||
inMemoryBlocks map[uint64]*pb.BeaconBlock
|
||||
syncedFeed *event.Feed
|
||||
stateReceived bool
|
||||
lastRequestedSlot uint64
|
||||
@@ -119,9 +112,7 @@ func NewInitialSyncService(ctx context.Context,
|
||||
) *InitialSync {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
blockBuf := make(chan p2p.Message, cfg.BlockBufferSize)
|
||||
stateBuf := make(chan p2p.Message, cfg.StateBufferSize)
|
||||
blockAnnounceBuf := make(chan p2p.Message, cfg.BlockAnnounceBufferSize)
|
||||
batchedBlockBuf := make(chan p2p.Message, cfg.BatchedBlockBufferSize)
|
||||
|
||||
return &InitialSync{
|
||||
@@ -135,12 +126,9 @@ func NewInitialSyncService(ctx context.Context,
|
||||
currentSlot: params.BeaconConfig().GenesisSlot,
|
||||
highestObservedSlot: params.BeaconConfig().GenesisSlot,
|
||||
beaconStateSlot: params.BeaconConfig().GenesisSlot,
|
||||
blockBuf: blockBuf,
|
||||
stateBuf: stateBuf,
|
||||
batchedBlockBuf: batchedBlockBuf,
|
||||
blockAnnounceBuf: blockAnnounceBuf,
|
||||
syncPollingInterval: cfg.SyncPollingInterval,
|
||||
inMemoryBlocks: map[uint64]*pb.BeaconBlock{},
|
||||
syncedFeed: new(event.Feed),
|
||||
stateReceived: false,
|
||||
mutex: new(sync.Mutex),
|
||||
@@ -155,7 +143,6 @@ func (s *InitialSync) Start() {
|
||||
}
|
||||
s.currentSlot = cHead.Slot
|
||||
go s.run()
|
||||
go s.checkInMemoryBlocks()
|
||||
}
|
||||
|
||||
// Stop kills the initial sync goroutine.
|
||||
@@ -259,40 +246,16 @@ func (s *InitialSync) exitInitialSync(ctx context.Context, block *pb.BeaconBlock
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkInMemoryBlocks is another routine which will run concurrently with the
|
||||
// main routine for initial sync, where it checks the blocks saved in memory regularly
|
||||
// to see if the blocks are valid enough to be processed.
|
||||
func (s *InitialSync) checkInMemoryBlocks() {
|
||||
for {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
default:
|
||||
if s.currentSlot == s.highestObservedSlot {
|
||||
return
|
||||
}
|
||||
s.mutex.Lock()
|
||||
if block, ok := s.inMemoryBlocks[s.currentSlot+1]; ok && s.currentSlot+1 <= s.highestObservedSlot {
|
||||
s.processBlock(s.ctx, block)
|
||||
}
|
||||
s.mutex.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run is the main goroutine for the initial sync service.
|
||||
// delayChan is explicitly passed into this function to facilitate tests that don't require a timeout.
|
||||
// It is assumed that the goroutine `run` is only called once per instance.
|
||||
func (s *InitialSync) run() {
|
||||
blockSub := s.p2p.Subscribe(&pb.BeaconBlockResponse{}, s.blockBuf)
|
||||
batchedBlocksub := s.p2p.Subscribe(&pb.BatchedBeaconBlockResponse{}, s.batchedBlockBuf)
|
||||
beaconStateSub := s.p2p.Subscribe(&pb.BeaconStateResponse{}, s.stateBuf)
|
||||
defer func() {
|
||||
blockSub.Unsubscribe()
|
||||
beaconStateSub.Unsubscribe()
|
||||
batchedBlocksub.Unsubscribe()
|
||||
close(s.batchedBlockBuf)
|
||||
close(s.blockBuf)
|
||||
close(s.stateBuf)
|
||||
}()
|
||||
|
||||
@@ -306,11 +269,6 @@ func (s *InitialSync) run() {
|
||||
case <-s.ctx.Done():
|
||||
log.Debug("Exiting goroutine")
|
||||
return
|
||||
case msg := <-s.blockBuf:
|
||||
safelyHandleMessage(func(message p2p.Message) {
|
||||
data := message.Data.(*pb.BeaconBlockResponse)
|
||||
s.processBlock(message.Ctx, data.Block)
|
||||
}, msg)
|
||||
case msg := <-s.stateBuf:
|
||||
safelyHandleMessage(s.processState, msg)
|
||||
case msg := <-s.batchedBlockBuf:
|
||||
|
||||
@@ -2,11 +2,9 @@ package initialsync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
peer "github.com/libp2p/go-libp2p-peer"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
@@ -51,12 +49,6 @@ func (ms *mockSyncService) ResumeSync() {
|
||||
|
||||
}
|
||||
|
||||
type mockPowchain struct{}
|
||||
|
||||
func (mp *mockPowchain) BlockExists(ctx context.Context, hash common.Hash) (bool, *big.Int, error) {
|
||||
return true, nil, nil
|
||||
}
|
||||
|
||||
type mockChainService struct{}
|
||||
|
||||
func (ms *mockChainService) CanonicalBlockFeed() *event.Feed {
|
||||
@@ -114,125 +106,6 @@ func setUpGenesisStateAndBlock(beaconDB *db.BeaconDB, t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSavingBlock_InSync(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
db := internal.SetupDB(t)
|
||||
setUpGenesisStateAndBlock(db, t)
|
||||
|
||||
cfg := &Config{
|
||||
P2P: &mockP2P{},
|
||||
SyncService: &mockSyncService{},
|
||||
ChainService: &mockChainService{},
|
||||
BeaconDB: db,
|
||||
PowChain: &mockPowchain{},
|
||||
}
|
||||
ss := NewInitialSyncService(context.Background(), cfg)
|
||||
|
||||
exitRoutine := make(chan bool)
|
||||
|
||||
defer func() {
|
||||
close(exitRoutine)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
ss.run()
|
||||
exitRoutine <- true
|
||||
}()
|
||||
|
||||
genericHash := make([]byte, 32)
|
||||
genericHash[0] = 'a'
|
||||
|
||||
fState := &pb.BeaconState{
|
||||
FinalizedEpoch: params.BeaconConfig().GenesisEpoch + 1,
|
||||
LatestBlock: &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + params.BeaconConfig().SlotsPerEpoch,
|
||||
},
|
||||
LatestEth1Data: &pb.Eth1Data{
|
||||
BlockHash32: []byte{},
|
||||
},
|
||||
}
|
||||
|
||||
stateResponse := &pb.BeaconStateResponse{
|
||||
FinalizedState: fState,
|
||||
}
|
||||
|
||||
incorrectState := &pb.BeaconState{
|
||||
FinalizedEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
JustifiedEpoch: params.BeaconConfig().GenesisEpoch + 1,
|
||||
LatestBlock: &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 4*params.BeaconConfig().SlotsPerEpoch,
|
||||
},
|
||||
LatestEth1Data: &pb.Eth1Data{
|
||||
BlockHash32: []byte{},
|
||||
},
|
||||
}
|
||||
|
||||
incorrectStateResponse := &pb.BeaconStateResponse{
|
||||
FinalizedState: incorrectState,
|
||||
}
|
||||
|
||||
stateRoot, err := hashutil.HashProto(fState)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to tree hash state: %v", err)
|
||||
}
|
||||
beaconStateRootHash32 := stateRoot
|
||||
|
||||
getBlockResponseMsg := func(Slot uint64) p2p.Message {
|
||||
block := &pb.BeaconBlock{
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{1, 2, 3},
|
||||
BlockHash32: []byte{4, 5, 6},
|
||||
},
|
||||
ParentRootHash32: genericHash,
|
||||
Slot: Slot,
|
||||
StateRootHash32: beaconStateRootHash32[:],
|
||||
}
|
||||
|
||||
blockResponse := &pb.BeaconBlockResponse{
|
||||
Block: block,
|
||||
}
|
||||
|
||||
return p2p.Message{
|
||||
Peer: "",
|
||||
Data: blockResponse,
|
||||
Ctx: context.Background(),
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to hash block %v", err)
|
||||
}
|
||||
|
||||
msg1 := getBlockResponseMsg(params.BeaconConfig().GenesisSlot + 1)
|
||||
|
||||
// saving genesis block
|
||||
ss.blockBuf <- msg1
|
||||
|
||||
msg2 := p2p.Message{
|
||||
Peer: "",
|
||||
Data: incorrectStateResponse,
|
||||
Ctx: context.Background(),
|
||||
}
|
||||
|
||||
ss.stateBuf <- msg2
|
||||
|
||||
msg2.Data = stateResponse
|
||||
|
||||
ss.stateBuf <- msg2
|
||||
|
||||
msg1 = getBlockResponseMsg(params.BeaconConfig().GenesisSlot + 1)
|
||||
ss.blockBuf <- msg1
|
||||
|
||||
msg1 = getBlockResponseMsg(params.BeaconConfig().GenesisSlot + 2)
|
||||
ss.blockBuf <- msg1
|
||||
|
||||
ss.cancel()
|
||||
<-exitRoutine
|
||||
|
||||
hook.Reset()
|
||||
internal.TeardownDB(t, db)
|
||||
}
|
||||
|
||||
func TestProcessingBatchedBlocks_OK(t *testing.T) {
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
|
||||
@@ -36,29 +36,6 @@ func (s *InitialSync) processBlock(ctx context.Context, block *pb.BeaconBlock) {
|
||||
return
|
||||
}
|
||||
|
||||
// if it isn't the block in the next slot we check if it is a skipped slot.
|
||||
// if it isn't skipped we save it in memory.
|
||||
if block.Slot != (s.currentSlot + 1) {
|
||||
// if parent exists we validate the block.
|
||||
if s.doesParentExist(block) {
|
||||
if err := s.validateAndSaveNextBlock(ctx, block); err != nil {
|
||||
// Debug error so as not to have noisy error logs
|
||||
if strings.HasPrefix(err.Error(), debugError) {
|
||||
log.Debug(strings.TrimPrefix(err.Error(), debugError))
|
||||
return
|
||||
}
|
||||
log.Errorf("Unable to save block: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
if _, ok := s.inMemoryBlocks[block.Slot]; !ok {
|
||||
s.inMemoryBlocks[block.Slot] = block
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.validateAndSaveNextBlock(ctx, block); err != nil {
|
||||
// Debug error so as not to have noisy error logs
|
||||
if strings.HasPrefix(err.Error(), debugError) {
|
||||
@@ -148,10 +125,6 @@ func (s *InitialSync) validateAndSaveNextBlock(ctx context.Context, block *pb.Be
|
||||
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
// delete block from memory.
|
||||
if _, ok := s.inMemoryBlocks[block.Slot]; ok {
|
||||
delete(s.inMemoryBlocks, block.Slot)
|
||||
}
|
||||
state, err := s.db.HeadState(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user