mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-27 05:38:55 +00:00
79a04cac83
* request parents recursively begin code * recursive call * writing tests for recursively processing child blocks * tests for parent root requests * expecting blcoks awaiting processing to be empty after recursive calls * finishing touches to get tests to pass * first test pass * gazelle * rem outdated test * tests done * 50 requested parents recursively pass * recursive parent fetching depth of 100 * recursive parent fetching depth of 50 * lint * fix failing test * fix item * add db to mock chain
149 lines
5.1 KiB
Go
149 lines
5.1 KiB
Go
package sync
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
|
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
|
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
|
"github.com/prysmaticlabs/prysm/shared/p2p"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
"go.opencensus.io/trace"
|
|
)
|
|
|
|
// receiveBlockAnnounce accepts a block hash, determines if we do not contain
|
|
// the block in our local DB, and then request the full block data.
|
|
func (rs *RegularSync) receiveBlockAnnounce(msg p2p.Message) error {
|
|
ctx, span := trace.StartSpan(msg.Ctx, "beacon-chain.sync.receiveBlockAnnounce")
|
|
defer span.End()
|
|
recBlockAnnounce.Inc()
|
|
|
|
data := msg.Data.(*pb.BeaconBlockAnnounce)
|
|
h := bytesutil.ToBytes32(data.Hash[:32])
|
|
|
|
hasBlock := rs.db.HasBlock(h)
|
|
span.AddAttributes(trace.BoolAttribute("hasBlock", hasBlock))
|
|
|
|
if hasBlock {
|
|
log.Debugf("Received a root for a block that has already been processed: %#x", h)
|
|
return nil
|
|
}
|
|
|
|
log.WithField("blockRoot", fmt.Sprintf("%#x", h)).Debug("Received incoming block root, requesting full block data from sender")
|
|
// Request the full block data from peer that sent the block hash.
|
|
if err := rs.p2p.Send(ctx, &pb.BeaconBlockRequest{Hash: h[:]}, msg.Peer); err != nil {
|
|
log.Error(err)
|
|
return err
|
|
}
|
|
sentBlockReq.Inc()
|
|
return nil
|
|
}
|
|
|
|
// receiveBlock processes a block message from the p2p layer and requests for its
|
|
// parents recursively if they are not yet contained in the local node's persistent storage.
|
|
func (rs *RegularSync) receiveBlock(msg p2p.Message) error {
|
|
ctx, span := trace.StartSpan(msg.Ctx, "beacon-chain.sync.receiveBlock")
|
|
defer span.End()
|
|
recBlock.Inc()
|
|
|
|
response := msg.Data.(*pb.BeaconBlockResponse)
|
|
block := response.Block
|
|
blockRoot, err := hashutil.HashBeaconBlock(block)
|
|
if err != nil {
|
|
log.Errorf("Could not hash received block: %v", err)
|
|
return err
|
|
}
|
|
|
|
log.Debugf("Processing response to block request: %#x", blockRoot)
|
|
hasBlock := rs.db.HasBlock(blockRoot)
|
|
span.AddAttributes(trace.BoolAttribute("hasBlock", hasBlock))
|
|
if hasBlock {
|
|
log.Debug("Received a block that already exists. Exiting...")
|
|
return nil
|
|
}
|
|
|
|
beaconState, err := rs.db.State(ctx)
|
|
if err != nil {
|
|
log.Errorf("Failed to get beacon state: %v", err)
|
|
return err
|
|
}
|
|
|
|
span.AddAttributes(
|
|
trace.Int64Attribute("block.Slot", int64(block.Slot)),
|
|
trace.Int64Attribute("finalized slot", int64(beaconState.FinalizedEpoch*params.BeaconConfig().SlotsPerEpoch)),
|
|
)
|
|
if block.Slot < beaconState.FinalizedEpoch*params.BeaconConfig().SlotsPerEpoch {
|
|
log.Debug("Discarding received block with a slot number smaller than the last finalized slot")
|
|
return nil
|
|
}
|
|
|
|
// We check if we have the block's parents saved locally.
|
|
parentRoot := bytesutil.ToBytes32(block.ParentRootHash32)
|
|
hasParent := rs.db.HasBlock(parentRoot)
|
|
span.AddAttributes(trace.BoolAttribute("hasParent", hasParent))
|
|
|
|
if !hasParent {
|
|
// If we do not have the parent, we insert it into a pending block's map.
|
|
rs.insertPendingBlock(ctx, parentRoot, msg)
|
|
// We update the last observed slot to the received canonical block's slot.
|
|
if block.Slot > rs.highestObservedSlot {
|
|
rs.highestObservedSlot = block.Slot
|
|
}
|
|
return nil
|
|
}
|
|
|
|
log.WithField("blockRoot", fmt.Sprintf("%#x", blockRoot)).Debug("Sending newly received block to chain service")
|
|
// We then process the block by passing it through the ChainService and running
|
|
// a fork choice rule.
|
|
beaconState, err = rs.chainService.ReceiveBlock(ctx, block)
|
|
if err != nil {
|
|
log.Errorf("Could not process beacon block: %v", err)
|
|
return err
|
|
}
|
|
if err := rs.chainService.ApplyForkChoiceRule(ctx, block, beaconState); err != nil {
|
|
log.Errorf("could not apply fork choice rule: %v", err)
|
|
return err
|
|
}
|
|
|
|
// We clear the block root from the pending processing map.
|
|
rs.clearPendingBlock(blockRoot)
|
|
sentBlocks.Inc()
|
|
|
|
// We update the last observed slot to the received canonical block's slot.
|
|
if block.Slot > rs.highestObservedSlot {
|
|
rs.highestObservedSlot = block.Slot
|
|
}
|
|
span.AddAttributes(trace.Int64Attribute("highestObservedSlot", int64(rs.highestObservedSlot)))
|
|
|
|
// If the block has a child, we then clear it from the blocks pending processing
|
|
// and call receiveBlock recursively. The recursive function call will stop once
|
|
// the block we process no longer has children.
|
|
if child, ok := rs.hasChild(blockRoot); ok {
|
|
return rs.receiveBlock(child)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (rs *RegularSync) insertPendingBlock(ctx context.Context, blockRoot [32]byte, blockMsg p2p.Message) {
|
|
rs.blocksAwaitingProcessingLock.Lock()
|
|
defer rs.blocksAwaitingProcessingLock.Unlock()
|
|
rs.blocksAwaitingProcessing[blockRoot] = blockMsg
|
|
blocksAwaitingProcessingGauge.Inc()
|
|
rs.p2p.Broadcast(ctx, &pb.BeaconBlockRequest{Hash: blockRoot[:]})
|
|
}
|
|
|
|
func (rs *RegularSync) clearPendingBlock(blockRoot [32]byte) {
|
|
rs.blocksAwaitingProcessingLock.Lock()
|
|
defer rs.blocksAwaitingProcessingLock.Unlock()
|
|
delete(rs.blocksAwaitingProcessing, blockRoot)
|
|
blocksAwaitingProcessingGauge.Dec()
|
|
}
|
|
|
|
func (rs *RegularSync) hasChild(blockRoot [32]byte) (p2p.Message, bool) {
|
|
rs.blocksAwaitingProcessingLock.Lock()
|
|
defer rs.blocksAwaitingProcessingLock.Unlock()
|
|
child, ok := rs.blocksAwaitingProcessing[blockRoot]
|
|
return child, ok
|
|
}
|