2019-02-05 13:47:25 +00:00
|
|
|
// Package client represents the functionality to act as a validator.
|
2019-01-23 02:52:39 +00:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-01-30 12:28:53 +00:00
|
|
|
"io"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
ptypes "github.com/gogo/protobuf/types"
|
2019-01-23 02:52:39 +00:00
|
|
|
|
|
|
|
"github.com/opentracing/opentracing-go"
|
|
|
|
|
2019-02-05 13:47:25 +00:00
|
|
|
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
2019-01-23 02:52:39 +00:00
|
|
|
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
2019-01-31 02:53:58 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
2019-01-23 02:52:39 +00:00
|
|
|
)
|
|
|
|
|
2019-02-05 13:47:25 +00:00
|
|
|
// AttestationPool STUB interface. Final attestation pool pending design.
|
|
|
|
// TODO(1323): Replace with actual attestation pool.
|
|
|
|
type AttestationPool interface {
|
|
|
|
PendingAttestations() []*pbp2p.Attestation
|
|
|
|
}
|
|
|
|
|
2019-01-23 02:52:39 +00:00
|
|
|
// validator
|
|
|
|
//
|
|
|
|
// WIP - not done.
|
|
|
|
type validator struct {
|
2019-01-30 12:28:53 +00:00
|
|
|
genesisTime uint64
|
2019-01-31 02:53:58 +00:00
|
|
|
ticker *slotutil.SlotTicker
|
2019-01-30 12:28:53 +00:00
|
|
|
assignment *pb.Assignment
|
2019-02-05 13:47:25 +00:00
|
|
|
proposerClient pb.ProposerServiceClient
|
2019-01-25 03:26:03 +00:00
|
|
|
validatorClient pb.ValidatorServiceClient
|
2019-01-30 12:28:53 +00:00
|
|
|
beaconClient pb.BeaconServiceClient
|
2019-01-29 12:56:14 +00:00
|
|
|
pubKey []byte
|
2019-02-05 13:47:25 +00:00
|
|
|
attestationPool AttestationPool
|
2019-01-23 02:52:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Done cleans up the validator.
|
|
|
|
func (v *validator) Done() {
|
|
|
|
v.ticker.Done()
|
|
|
|
}
|
|
|
|
|
2019-01-30 12:28:53 +00:00
|
|
|
// WaitForChainStart checks whether the beacon node has started its runtime. That is,
|
|
|
|
// it calls to the beacon node which then verifies the ETH1.0 deposit contract logs to check
|
|
|
|
// for the ChainStart log to have been emitted. If so, it starts a ticker based on the ChainStart
|
|
|
|
// unix timestamp which will be used to keep track of time within the validator client.
|
|
|
|
func (v *validator) WaitForChainStart(ctx context.Context) {
|
|
|
|
span, ctx := opentracing.StartSpanFromContext(ctx, "validator.WaitForChainStart")
|
|
|
|
defer span.Finish()
|
|
|
|
// First, check if the beacon chain has started.
|
|
|
|
stream, err := v.beaconClient.WaitForChainStart(ctx, &ptypes.Empty{})
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Could not setup beacon chain ChainStart streaming client: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for {
|
|
|
|
log.Info("Waiting for beacon chain start log from the ETH 1.0 deposit contract...")
|
|
|
|
chainStartRes, err := stream.Recv()
|
|
|
|
// If the stream is closed, we stop the loop.
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// If context is canceled we stop the loop.
|
|
|
|
if ctx.Err() == context.Canceled {
|
|
|
|
log.Debugf("Context has been canceled so shutting down the loop: %v", ctx.Err())
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("Could not receive ChainStart from stream: %v", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
v.genesisTime = chainStartRes.GenesisTime
|
|
|
|
break
|
|
|
|
}
|
|
|
|
log.Infof("Beacon chain initialized at unix time: %v", time.Unix(int64(v.genesisTime), 0))
|
|
|
|
// Once the ChainStart log is received, we update the genesis time of the validator client
|
|
|
|
// and begin a slot ticker used to track the current slot the beacon node is in.
|
2019-01-31 02:53:58 +00:00
|
|
|
v.ticker = slotutil.GetSlotTicker(time.Unix(int64(v.genesisTime), 0), params.BeaconConfig().SlotDuration)
|
2019-01-30 12:28:53 +00:00
|
|
|
}
|
|
|
|
|
2019-01-23 02:52:39 +00:00
|
|
|
// WaitForActivation checks whether the validator pubkey is in the active
|
2019-01-30 12:28:53 +00:00
|
|
|
// validator set. If not, this operation will block until an activation message is
|
2019-01-23 02:52:39 +00:00
|
|
|
// received.
|
|
|
|
//
|
|
|
|
// WIP - not done.
|
|
|
|
func (v *validator) WaitForActivation(ctx context.Context) {
|
|
|
|
span, ctx := opentracing.StartSpanFromContext(ctx, "validator.WaitForActivation")
|
|
|
|
defer span.Finish()
|
2019-01-30 12:28:53 +00:00
|
|
|
// First, check if the validator has deposited into the Deposit Contract.
|
|
|
|
// If the validator has deposited, subscribe to a stream receiving the activation status.
|
|
|
|
// of the validator until a final ACTIVATED check if received, then this function can return.
|
2019-01-23 02:52:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NextSlot emits the next slot number at the start time of that slot.
|
|
|
|
func (v *validator) NextSlot() <-chan uint64 {
|
|
|
|
return v.ticker.C()
|
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateAssignments checks the slot number to determine if the validator's
|
|
|
|
// list of upcoming assignments needs to be updated. For example, at the
|
|
|
|
// beginning of a new epoch.
|
2019-01-25 03:26:03 +00:00
|
|
|
func (v *validator) UpdateAssignments(ctx context.Context, slot uint64) error {
|
2019-01-23 02:52:39 +00:00
|
|
|
span, ctx := opentracing.StartSpanFromContext(ctx, "validator.UpdateAssignments")
|
|
|
|
defer span.Finish()
|
|
|
|
|
2019-01-25 03:26:03 +00:00
|
|
|
if slot%params.BeaconConfig().EpochLength != 0 {
|
|
|
|
// Do nothing if not epoch start.
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
req := &pb.ValidatorEpochAssignmentsRequest{
|
|
|
|
EpochStart: slot,
|
|
|
|
PublicKey: v.pubKey,
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := v.validatorClient.ValidatorEpochAssignments(ctx, req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-29 12:56:14 +00:00
|
|
|
v.assignment = resp.Assignment
|
2019-01-25 03:26:03 +00:00
|
|
|
return nil
|
2019-01-23 02:52:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// RoleAt slot returns the validator role at the given slot. Returns nil if the
|
|
|
|
// validator is known to not have a role at the at slot. Returns UNKNOWN if the
|
|
|
|
// validator assignments are unknown. Otherwise returns a valid ValidatorRole.
|
|
|
|
func (v *validator) RoleAt(slot uint64) pb.ValidatorRole {
|
2019-01-29 12:56:14 +00:00
|
|
|
if v.assignment == nil {
|
2019-01-23 02:52:39 +00:00
|
|
|
return pb.ValidatorRole_UNKNOWN
|
|
|
|
}
|
2019-01-29 12:56:14 +00:00
|
|
|
if v.assignment.AttesterSlot == slot {
|
|
|
|
return pb.ValidatorRole_ATTESTER
|
|
|
|
} else if v.assignment.ProposerSlot == slot {
|
|
|
|
return pb.ValidatorRole_PROPOSER
|
2019-01-25 03:26:03 +00:00
|
|
|
}
|
2019-01-29 12:56:14 +00:00
|
|
|
return pb.ValidatorRole_UNKNOWN
|
2019-01-23 02:52:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// AttestToBlockHead
|
|
|
|
//
|
|
|
|
// WIP - not done.
|
|
|
|
func (v *validator) AttestToBlockHead(ctx context.Context, slot uint64) {
|
|
|
|
span, ctx := opentracing.StartSpanFromContext(ctx, "validator.AttestToBlockHead")
|
|
|
|
defer span.Finish()
|
|
|
|
}
|