mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-29 06:37:17 +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
177 lines
5.5 KiB
Go
177 lines
5.5 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/prysmaticlabs/go-ssz"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
|
"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/bytesutil"
|
|
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
|
"github.com/prysmaticlabs/prysm/shared/p2p"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
)
|
|
|
|
// AttesterServer defines a server implementation of the gRPC Attester service,
|
|
// providing RPC methods for validators acting as attesters to broadcast votes on beacon blocks.
|
|
type AttesterServer struct {
|
|
p2p p2p.Broadcaster
|
|
beaconDB *db.BeaconDB
|
|
operationService operationService
|
|
cache *cache.AttestationCache
|
|
}
|
|
|
|
// SubmitAttestation is a function called by an attester in a sharding validator to vote
|
|
// on a block via an attestation object as defined in the Ethereum Serenity specification.
|
|
func (as *AttesterServer) SubmitAttestation(ctx context.Context, att *ethpb.Attestation) (*pb.AttestResponse, error) {
|
|
h, err := hashutil.HashProto(att)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not hash attestation: %v", err)
|
|
}
|
|
|
|
if err := as.operationService.HandleAttestations(ctx, att); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
headState, err := as.beaconDB.HeadState(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
slot, err := helpers.AttestationDataSlot(headState, att.Data)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get attestation slot: %v", err)
|
|
}
|
|
|
|
// Update attestation target for RPC server to run necessary fork choice.
|
|
// We need to retrieve the head block to get its parent root.
|
|
head, err := as.beaconDB.Block(bytesutil.ToBytes32(att.Data.BeaconBlockRoot))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// If the head block is nil, we can't save the attestation target.
|
|
if head == nil {
|
|
return nil, fmt.Errorf("could not find head %#x in db", bytesutil.Trunc(att.Data.BeaconBlockRoot))
|
|
}
|
|
attTarget := &pbp2p.AttestationTarget{
|
|
Slot: slot,
|
|
BeaconBlockRoot: att.Data.BeaconBlockRoot,
|
|
ParentRoot: head.ParentRoot,
|
|
}
|
|
if err := as.beaconDB.SaveAttestationTarget(ctx, attTarget); err != nil {
|
|
return nil, fmt.Errorf("could not save attestation target")
|
|
}
|
|
|
|
as.p2p.Broadcast(ctx, &pbp2p.AttestationAnnounce{
|
|
Hash: h[:],
|
|
})
|
|
|
|
return &pb.AttestResponse{Root: h[:]}, nil
|
|
}
|
|
|
|
// RequestAttestation requests that the beacon node produce an IndexedAttestation,
|
|
// with a blank signature field, which the validator will then sign.
|
|
func (as *AttesterServer) RequestAttestation(ctx context.Context, req *pb.AttestationRequest) (*ethpb.AttestationData, error) {
|
|
res, err := as.cache.Get(ctx, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if res != nil {
|
|
return res, nil
|
|
}
|
|
|
|
if err := as.cache.MarkInProgress(req); err != nil {
|
|
if err == cache.ErrAlreadyInProgress {
|
|
res, err := as.cache.Get(ctx, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if res == nil {
|
|
return nil, errors.New("a request was in progress and resolved to nil")
|
|
}
|
|
return res, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
defer func() {
|
|
if err := as.cache.MarkNotInProgress(req); err != nil {
|
|
log.WithError(err).Error("Failed to mark cache not in progress")
|
|
}
|
|
}()
|
|
|
|
// Set the attestation data's beacon block root = hash_tree_root(head) where head
|
|
// is the validator's view of the head block of the beacon chain during the slot.
|
|
headBlock, err := as.beaconDB.ChainHead()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to retrieve chain head: %v", err)
|
|
}
|
|
headRoot, err := ssz.SigningRoot(headBlock)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not tree hash beacon block: %v", err)
|
|
}
|
|
|
|
// Let head state be the state of head block processed through empty slots up to assigned slot.
|
|
headState, err := as.beaconDB.HeadState(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not fetch head state: %v", err)
|
|
}
|
|
|
|
headState, err = state.ProcessSlots(ctx, headState, req.Slot)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not process slot: %v", err)
|
|
}
|
|
|
|
targetEpoch := helpers.CurrentEpoch(headState)
|
|
epochStartSlot := helpers.StartSlot(targetEpoch)
|
|
targetRoot := make([]byte, 32)
|
|
if epochStartSlot == headState.Slot {
|
|
targetRoot = headRoot[:]
|
|
} else {
|
|
targetRoot, err = helpers.BlockRootAtSlot(headState, epochStartSlot)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get target block for slot %d: %v",
|
|
epochStartSlot, err)
|
|
}
|
|
}
|
|
|
|
startEpoch := headState.CurrentCrosslinks[req.Shard].EndEpoch
|
|
endEpoch := startEpoch + params.BeaconConfig().MaxEpochsPerCrosslink
|
|
if endEpoch > targetEpoch {
|
|
endEpoch = targetEpoch
|
|
}
|
|
crosslinkRoot, err := ssz.HashTreeRoot(headState.CurrentCrosslinks[req.Shard])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not tree hash crosslink for shard %d: %v",
|
|
req.Shard, err)
|
|
}
|
|
res = ðpb.AttestationData{
|
|
BeaconBlockRoot: headRoot[:],
|
|
Source: headState.CurrentJustifiedCheckpoint,
|
|
Target: ðpb.Checkpoint{
|
|
Epoch: targetEpoch,
|
|
Root: targetRoot,
|
|
},
|
|
Crosslink: ðpb.Crosslink{
|
|
Shard: req.Shard,
|
|
StartEpoch: startEpoch,
|
|
EndEpoch: endEpoch,
|
|
ParentRoot: crosslinkRoot[:],
|
|
DataRoot: params.BeaconConfig().ZeroHash[:],
|
|
},
|
|
}
|
|
|
|
if err := as.cache.Put(ctx, req, res); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return res, nil
|
|
}
|