mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-04 16:54:28 +00:00
1b5b8a57e0
* 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
224 lines
7.1 KiB
Go
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
|
|
}
|