prysm-pulse/beacon-chain/rpc/beacon_server.go
terence tsao 1b5b8a57e0 Remove unused proto schemas (#3005)
* Update io_kubernetes_build commit hash to 1246899

* Update dependency build_bazel_rules_nodejs to v0.33.1

* Update dependency com_github_hashicorp_golang_lru to v0.5.1

* Update libp2p

* Update io_bazel_rules_k8s commit hash to e68d5d7

* Starting to remove old protos

* Bazel build proto passes

* Fixing pb version

* Cleaned up core package

* Fixing tests

* 6 tests failing

* Update proto bugs

* Fixed incorrect validator ordering proto

* Sync with master

* Update go-ssz commit

* Removed bad copies from v1alpha1 folder

* add json spec json to pb handler

* add nested proto example

* proto/testing test works

* fix refactoring build failures

* use merged ssz

* push latest changes

* used forked json encoding

* used forked json encoding

* fix warning

* fix build issues

* fix test and lint

* fix build

* lint
2019-07-22 10:03:57 -04:00

224 lines
7.1 KiB
Go

package rpc
import (
"context"
"errors"
"fmt"
"time"
ptypes "github.com/gogo/protobuf/types"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/trieutil"
)
// BeaconServer defines a server implementation of the gRPC Beacon service,
// providing RPC endpoints for obtaining the canonical beacon chain head,
// fetching latest observed attestations, and more.
type BeaconServer struct {
beaconDB *db.BeaconDB
ctx context.Context
powChainService powChainService
chainService chainService
targetsFetcher blockchain.TargetsFetcher
operationService operationService
incomingAttestation chan *ethpb.Attestation
canonicalStateChan chan *pbp2p.BeaconState
chainStartChan chan time.Time
}
// WaitForChainStart queries the logs of the Deposit Contract in order to verify the beacon chain
// has started its runtime and validators begin their responsibilities. If it has not, it then
// subscribes to an event stream triggered by the powchain service whenever the ChainStart log does
// occur in the Deposit Contract on ETH 1.0.
func (bs *BeaconServer) WaitForChainStart(req *ptypes.Empty, stream pb.BeaconService_WaitForChainStartServer) error {
ok := bs.powChainService.HasChainStarted()
if ok {
genesisTime := bs.powChainService.ETH2GenesisTime()
res := &pb.ChainStartResponse{
Started: true,
GenesisTime: genesisTime,
}
return stream.Send(res)
}
sub := bs.chainService.StateInitializedFeed().Subscribe(bs.chainStartChan)
defer sub.Unsubscribe()
for {
select {
case chainStartTime := <-bs.chainStartChan:
log.Info("Sending ChainStart log and genesis time to connected validator clients")
res := &pb.ChainStartResponse{
Started: true,
GenesisTime: uint64(chainStartTime.Unix()),
}
return stream.Send(res)
case <-sub.Err():
return errors.New("subscriber closed, exiting goroutine")
case <-bs.ctx.Done():
return errors.New("rpc context closed, exiting goroutine")
}
}
}
// CanonicalHead of the current beacon chain. This method is requested on-demand
// by a validator when it is their time to propose or attest.
func (bs *BeaconServer) CanonicalHead(ctx context.Context, req *ptypes.Empty) (*ethpb.BeaconBlock, error) {
block, err := bs.beaconDB.ChainHead()
if err != nil {
return nil, fmt.Errorf("could not get canonical head block: %v", err)
}
return block, nil
}
// BlockTree returns the current tree of saved blocks and their votes starting from the justified state.
func (bs *BeaconServer) BlockTree(ctx context.Context, _ *ptypes.Empty) (*pb.BlockTreeResponse, error) {
justifiedState, err := bs.beaconDB.JustifiedState()
if err != nil {
return nil, fmt.Errorf("could not retrieve justified state: %v", err)
}
attestationTargets, err := bs.targetsFetcher.AttestationTargets(justifiedState)
if err != nil {
return nil, fmt.Errorf("could not retrieve attestation target: %v", err)
}
justifiedBlock, err := bs.beaconDB.JustifiedBlock()
if err != nil {
return nil, err
}
highestSlot := bs.beaconDB.HighestBlockSlot()
fullBlockTree := []*ethpb.BeaconBlock{}
for i := justifiedBlock.Slot + 1; i < highestSlot; i++ {
if ctx.Err() != nil {
return nil, ctx.Err()
}
nextLayer, err := bs.beaconDB.BlocksBySlot(ctx, i)
if err != nil {
return nil, err
}
fullBlockTree = append(fullBlockTree, nextLayer...)
}
tree := []*pb.BlockTreeResponse_TreeNode{}
for _, kid := range fullBlockTree {
if ctx.Err() != nil {
return nil, ctx.Err()
}
participatedVotes, err := blockchain.VoteCount(kid, justifiedState, attestationTargets, bs.beaconDB)
if err != nil {
return nil, err
}
blockRoot, err := ssz.SigningRoot(kid)
if err != nil {
return nil, err
}
tree = append(tree, &pb.BlockTreeResponse_TreeNode{
BlockRoot: blockRoot[:],
Block: kid,
ParticipatedVotes: uint64(participatedVotes),
})
}
return &pb.BlockTreeResponse{
Tree: tree,
}, nil
}
// BlockTreeBySlots returns the current tree of saved blocks and their
// votes starting from the justified state.
func (bs *BeaconServer) BlockTreeBySlots(ctx context.Context, req *pb.TreeBlockSlotRequest) (*pb.BlockTreeResponse, error) {
justifiedState, err := bs.beaconDB.JustifiedState()
if err != nil {
return nil, fmt.Errorf("could not retrieve justified state: %v", err)
}
attestationTargets, err := bs.targetsFetcher.AttestationTargets(justifiedState)
if err != nil {
return nil, fmt.Errorf("could not retrieve attestation target: %v", err)
}
justifiedBlock, err := bs.beaconDB.JustifiedBlock()
if err != nil {
return nil, err
}
if req == nil {
return nil, errors.New("argument 'TreeBlockSlotRequest' cannot be nil")
}
if !(req.SlotFrom <= req.SlotTo) {
return nil, fmt.Errorf("upper limit (%d) of slot range cannot be lower than the lower limit (%d)", req.SlotTo, req.SlotFrom)
}
highestSlot := bs.beaconDB.HighestBlockSlot()
fullBlockTree := []*ethpb.BeaconBlock{}
for i := justifiedBlock.Slot + 1; i < highestSlot; i++ {
if ctx.Err() != nil {
return nil, ctx.Err()
}
if i >= req.SlotFrom && i <= req.SlotTo {
nextLayer, err := bs.beaconDB.BlocksBySlot(ctx, i)
if err != nil {
return nil, err
}
if nextLayer != nil {
fullBlockTree = append(fullBlockTree, nextLayer...)
}
}
if i > req.SlotTo {
break
}
}
tree := []*pb.BlockTreeResponse_TreeNode{}
for _, kid := range fullBlockTree {
if ctx.Err() != nil {
return nil, ctx.Err()
}
participatedVotes, err := blockchain.VoteCount(kid, justifiedState, attestationTargets, bs.beaconDB)
if err != nil {
return nil, err
}
blockRoot, err := ssz.SigningRoot(kid)
if err != nil {
return nil, err
}
hState, err := bs.beaconDB.HistoricalStateFromSlot(ctx, kid.Slot, blockRoot)
if err != nil {
return nil, err
}
if kid.Slot >= req.SlotFrom && kid.Slot <= req.SlotTo {
activeValidatorIndices, err := helpers.ActiveValidatorIndices(hState, helpers.CurrentEpoch(hState))
if err != nil {
return nil, err
}
totalVotes := helpers.TotalBalance(hState, activeValidatorIndices)
tree = append(tree, &pb.BlockTreeResponse_TreeNode{
BlockRoot: blockRoot[:],
Block: kid,
ParticipatedVotes: uint64(participatedVotes),
TotalVotes: uint64(totalVotes),
})
}
}
return &pb.BlockTreeResponse{
Tree: tree,
}, nil
}
func constructMerkleProof(trie *trieutil.MerkleTrie, index int, deposit *ethpb.Deposit) (*ethpb.Deposit, error) {
proof, err := trie.MerkleProof(index)
if err != nil {
return nil, fmt.Errorf(
"could not generate merkle proof for deposit at index %d: %v",
index,
err,
)
}
// For every deposit, we construct a Merkle proof using the powchain service's
// in-memory deposits trie, which is updated only once the state's LatestETH1Data
// property changes during a state transition after a voting period.
deposit.Proof = proof
return deposit, nil
}