2019-08-20 19:06:49 +00:00
|
|
|
package sync
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
libp2pcore "github.com/libp2p/go-libp2p-core"
|
|
|
|
"github.com/pkg/errors"
|
2019-10-29 15:14:17 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
2019-08-20 19:06:49 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
|
|
|
|
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
2019-10-29 15:14:17 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/traceutil"
|
|
|
|
"go.opencensus.io/trace"
|
2019-08-20 19:06:49 +00:00
|
|
|
)
|
|
|
|
|
2019-09-20 06:27:28 +00:00
|
|
|
// beaconBlocksByRangeRPCHandler looks up the request blocks from the database from a given start block.
|
|
|
|
func (r *RegularSync) beaconBlocksByRangeRPCHandler(ctx context.Context, msg interface{}, stream libp2pcore.Stream) error {
|
2019-10-29 15:14:17 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "sync.BeaconBlocksByRangeHandler")
|
|
|
|
defer span.End()
|
2019-08-20 19:06:49 +00:00
|
|
|
defer stream.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
setRPCStreamDeadlines(stream)
|
2019-09-20 06:27:28 +00:00
|
|
|
log := log.WithField("handler", "beacon_blocks_by_range")
|
2019-08-20 19:06:49 +00:00
|
|
|
|
2019-09-20 06:27:28 +00:00
|
|
|
m := msg.(*pb.BeaconBlocksByRangeRequest)
|
2019-08-20 19:06:49 +00:00
|
|
|
|
2019-09-20 06:27:28 +00:00
|
|
|
startSlot := m.StartSlot
|
2019-11-19 03:56:37 +00:00
|
|
|
endSlot := startSlot + (m.Step * (m.Count-1))
|
2019-08-20 19:06:49 +00:00
|
|
|
|
2019-10-29 15:14:17 +00:00
|
|
|
span.AddAttributes(
|
|
|
|
trace.Int64Attribute("start", int64(startSlot)),
|
|
|
|
trace.Int64Attribute("end", int64(endSlot)),
|
|
|
|
trace.Int64Attribute("step", int64(m.Step)),
|
|
|
|
trace.Int64Attribute("count", int64(m.Count)),
|
|
|
|
trace.StringAttribute("peer", stream.Conn().RemotePeer().Pretty()),
|
|
|
|
)
|
|
|
|
|
2019-08-20 19:06:49 +00:00
|
|
|
// TODO(3147): Update this with reasonable constraints.
|
|
|
|
if endSlot-startSlot > 1000 || m.Step == 0 {
|
|
|
|
resp, err := r.generateErrorResponse(responseCodeInvalidRequest, "invalid range or step")
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Error("Failed to generate a response error")
|
|
|
|
} else {
|
|
|
|
if _, err := stream.Write(resp); err != nil {
|
|
|
|
log.WithError(err).Errorf("Failed to write to stream")
|
|
|
|
}
|
|
|
|
}
|
2019-10-29 15:14:17 +00:00
|
|
|
err = errors.New("invalid range or step")
|
|
|
|
traceutil.AnnotateError(span, err)
|
|
|
|
return err
|
2019-08-20 19:06:49 +00:00
|
|
|
}
|
|
|
|
|
2019-10-29 15:14:17 +00:00
|
|
|
var errResponse = func() {
|
2019-08-20 19:06:49 +00:00
|
|
|
resp, err := r.generateErrorResponse(responseCodeServerError, genericError)
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Error("Failed to generate a response error")
|
|
|
|
} else {
|
|
|
|
if _, err := stream.Write(resp); err != nil {
|
|
|
|
log.WithError(err).Errorf("Failed to write to stream")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-29 15:14:17 +00:00
|
|
|
filter := filters.NewFilter().SetStartSlot(startSlot).SetEndSlot(endSlot)
|
|
|
|
blks, err := r.db.Blocks(ctx, filter)
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Error("Failed to retrieve blocks")
|
|
|
|
errResponse()
|
|
|
|
traceutil.AnnotateError(span, err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
roots, err := r.db.BlockRoots(ctx, filter)
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Error("Failed to retrieve block roots")
|
|
|
|
errResponse()
|
|
|
|
traceutil.AnnotateError(span, err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
checkpoint, err := r.db.FinalizedCheckpoint(ctx)
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Error("Failed to retrieve finalized checkpoint")
|
|
|
|
errResponse()
|
|
|
|
traceutil.AnnotateError(span, err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for i, blk := range blks {
|
2019-11-08 03:00:47 +00:00
|
|
|
if blk == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
isRequestedSlotStep := (blk.Slot-startSlot)%m.Step == 0
|
|
|
|
isRecentUnfinalizedSlot := blk.Slot >= helpers.StartSlot(checkpoint.Epoch+1) || checkpoint.Epoch == 0
|
|
|
|
if isRequestedSlotStep && (isRecentUnfinalizedSlot || r.db.IsFinalizedBlock(ctx, roots[i])) {
|
2019-09-24 14:56:50 +00:00
|
|
|
if err := r.chunkWriter(stream, blk); err != nil {
|
|
|
|
log.WithError(err).Error("Failed to send a chunked response")
|
|
|
|
return err
|
|
|
|
}
|
2019-08-20 19:06:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|