mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 05:47:59 -05:00
updating rpc package
This commit is contained in:
@@ -15,7 +15,6 @@ go_library(
|
||||
"//beacon-chain/blockchain:go_default_library",
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/epoch:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/core/state/stateutils:go_default_library",
|
||||
@@ -35,7 +34,6 @@ go_library(
|
||||
"@com_github_grpc_ecosystem_go_grpc_middleware//:go_default_library",
|
||||
"@com_github_grpc_ecosystem_go_grpc_middleware//recovery:go_default_library",
|
||||
"@com_github_grpc_ecosystem_go_grpc_prometheus//:go_default_library",
|
||||
"@com_github_prysmaticlabs_prysm//shared/ssz:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opencensus_go//plugin/ocgrpc:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
@@ -68,13 +66,13 @@ go_test(
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/ssz:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"//shared/trieutil:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_gogo_protobuf//types:go_default_library",
|
||||
"@com_github_golang_mock//gomock:go_default_library",
|
||||
"@com_github_prysmaticlabs_prysm//shared/ssz:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
],
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@@ -131,7 +132,7 @@ func (as *AttesterServer) AttestationDataAtSlot(ctx context.Context, req *pb.Att
|
||||
if epochStartSlot == headState.Slot {
|
||||
epochBoundaryRoot = headRoot[:]
|
||||
} else {
|
||||
epochBoundaryRoot, err = helpers.BlockRootAtSlot(headState, epochStartSlot)
|
||||
epochBoundaryRoot, err = blocks.BlockRoot(headState, epochStartSlot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get epoch boundary block for slot %d: %v",
|
||||
epochStartSlot, err)
|
||||
|
||||
@@ -105,7 +105,7 @@ func TestAttestationDataAtSlot_OK(t *testing.T) {
|
||||
beaconState := &pbp2p.BeaconState{
|
||||
Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
CurrentJustifiedEpoch: 2 + 0,
|
||||
LatestBlockRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
|
||||
LatestBlockRoots: make([][]byte, params.BeaconConfig().LatestBlockRootsLength),
|
||||
CurrentCrosslinks: []*pbp2p.Crosslink{
|
||||
{
|
||||
DataRoot: []byte("A"),
|
||||
@@ -166,16 +166,16 @@ func TestAttestationDataAtSlot_handlesFarAwayJustifiedEpoch(t *testing.T) {
|
||||
//
|
||||
// State slot = 10000
|
||||
// Last justified slot = epoch start of 1500
|
||||
// SlotsPerHistoricalRoot = 8192
|
||||
// LatestBlockRootsLength = 8192
|
||||
//
|
||||
// More background: https://github.com/prysmaticlabs/prysm/issues/2153
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
// Ensure SlotsPerHistoricalRoot matches scenario
|
||||
// Ensure LatestBlockRootsLength matches scenario
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.SlotsPerHistoricalRoot = 8192
|
||||
cfg.LatestBlockRootsLength = 8192
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
block := &pbp2p.BeaconBlock{
|
||||
@@ -202,7 +202,7 @@ func TestAttestationDataAtSlot_handlesFarAwayJustifiedEpoch(t *testing.T) {
|
||||
beaconState := &pbp2p.BeaconState{
|
||||
Slot: 10000,
|
||||
CurrentJustifiedEpoch: helpers.SlotToEpoch(1500),
|
||||
LatestBlockRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
|
||||
LatestBlockRoots: make([][]byte, params.BeaconConfig().LatestBlockRootsLength),
|
||||
CurrentCrosslinks: []*pbp2p.Crosslink{
|
||||
{
|
||||
DataRoot: []byte("A"),
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"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"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
@@ -85,6 +86,127 @@ func (bs *BeaconServer) CanonicalHead(ctx context.Context, req *ptypes.Empty) (*
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// LatestAttestation streams the latest processed attestations to the rpc clients.
|
||||
func (bs *BeaconServer) LatestAttestation(req *ptypes.Empty, stream pb.BeaconService_LatestAttestationServer) error {
|
||||
sub := bs.operationService.IncomingAttFeed().Subscribe(bs.incomingAttestation)
|
||||
defer sub.Unsubscribe()
|
||||
for {
|
||||
select {
|
||||
case attestation := <-bs.incomingAttestation:
|
||||
log.Info("Sending attestation to RPC clients")
|
||||
if err := stream.Send(attestation); err != nil {
|
||||
return err
|
||||
}
|
||||
case <-sub.Err():
|
||||
log.Debug("Subscriber closed, exiting goroutine")
|
||||
return nil
|
||||
case <-bs.ctx.Done():
|
||||
log.Debug("RPC context closed, exiting goroutine")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DomainData fetches the current domain version information from the beacon state.
|
||||
func (bs *BeaconServer) DomainData(ctx context.Context, request *pb.DomainRequest) (*pb.DomainResponse, error) {
|
||||
state, err := bs.beaconDB.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not retrieve beacon state: %v", err)
|
||||
}
|
||||
dv := helpers.DomainVersion(state, request.Epoch, params.BeaconConfig().DomainRandao)
|
||||
return &pb.DomainResponse{
|
||||
SignatureDomain: dv,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
// Eth1Data is a mechanism used by block proposers vote on a recent Ethereum 1.0 block hash and an
|
||||
// associated deposit root found in the Ethereum 1.0 deposit contract. When consensus is formed,
|
||||
// state.latest_eth1_data is updated, and validator deposits up to this root can be processed.
|
||||
// The deposit root can be calculated by calling the get_deposit_root() function of
|
||||
// the deposit contract using the post-state of the block hash.
|
||||
//
|
||||
// TODO(#2307): Refactor for v0.6.
|
||||
func (bs *BeaconServer) Eth1Data(ctx context.Context, _ *ptypes.Empty) (*pb.Eth1DataResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// PendingDeposits returns a list of pending deposits that are ready for
|
||||
// inclusion in the next beacon block.
|
||||
func (bs *BeaconServer) PendingDeposits(ctx context.Context, _ *ptypes.Empty) (*pb.PendingDepositsResponse, error) {
|
||||
bNum := bs.powChainService.LatestBlockHeight()
|
||||
if bNum == nil {
|
||||
return nil, errors.New("latest PoW block number is unknown")
|
||||
}
|
||||
// Only request deposits that have passed the ETH1 follow distance window.
|
||||
bNum = bNum.Sub(bNum, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)))
|
||||
allDeps := bs.beaconDB.AllDeposits(ctx, bNum)
|
||||
if len(allDeps) == 0 {
|
||||
return &pb.PendingDepositsResponse{PendingDeposits: nil}, nil
|
||||
}
|
||||
|
||||
// Need to fetch if the deposits up to the state's latest eth 1 data matches
|
||||
// the number of all deposits in this RPC call. If not, then we return nil.
|
||||
beaconState, err := bs.beaconDB.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not fetch beacon state: %v", err)
|
||||
}
|
||||
h := bytesutil.ToBytes32(beaconState.LatestEth1Data.BlockRoot)
|
||||
_, latestEth1DataHeight, err := bs.powChainService.BlockExists(ctx, h)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not fetch eth1data height: %v", err)
|
||||
}
|
||||
// If the state's latest eth1 data's block hash has a height of 100, we fetch all the deposits up to height 100.
|
||||
// If this doesn't match the number of deposits stored in the cache, the generated trie will not be the same and
|
||||
// root will fail to verify. This can happen in a scenario where we perhaps have a deposit from height 101,
|
||||
// so we want to avoid any possible mismatches in these lengths.
|
||||
upToLatestEth1DataDeposits := bs.beaconDB.AllDeposits(ctx, latestEth1DataHeight)
|
||||
if len(upToLatestEth1DataDeposits) != len(allDeps) {
|
||||
return &pb.PendingDepositsResponse{PendingDeposits: nil}, nil
|
||||
}
|
||||
depositData := [][]byte{}
|
||||
for _, dep := range upToLatestEth1DataDeposits {
|
||||
depHash, err := hashutil.DepositHash(dep.Data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("coulf not hash deposit data %v", err)
|
||||
}
|
||||
depositData = append(depositData, depHash[:])
|
||||
}
|
||||
|
||||
depositTrie, err := trieutil.GenerateTrieFromItems(depositData, int(params.BeaconConfig().DepositContractTreeDepth))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not generate historical deposit trie from deposits: %v", err)
|
||||
}
|
||||
|
||||
allPendingDeps := bs.beaconDB.PendingDeposits(ctx, bNum)
|
||||
|
||||
// Deposits need to be received in order of merkle index root, so this has to make sure
|
||||
// deposits are sorted from lowest to highest.
|
||||
var pendingDeps []*pbp2p.Deposit
|
||||
for _, dep := range allPendingDeps {
|
||||
if dep.Index >= beaconState.DepositIndex {
|
||||
pendingDeps = append(pendingDeps, dep)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range pendingDeps {
|
||||
// Don't construct merkle proof if the number of deposits is more than max allowed in block.
|
||||
if uint64(i) == params.BeaconConfig().MaxDeposits {
|
||||
break
|
||||
}
|
||||
pendingDeps[i], err = constructMerkleProof(depositTrie, pendingDeps[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Limit the return of pending deposits to not be more than max deposits allowed in block.
|
||||
var pendingDeposits []*pbp2p.Deposit
|
||||
for i := 0; i < len(pendingDeps) && i < int(params.BeaconConfig().MaxDeposits); i++ {
|
||||
pendingDeposits = append(pendingDeposits, pendingDeps[i])
|
||||
}
|
||||
return &pb.PendingDepositsResponse{PendingDeposits: pendingDeposits}, 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()
|
||||
@@ -124,25 +246,10 @@ func (bs *BeaconServer) BlockTree(ctx context.Context, _ *ptypes.Empty) (*pb.Blo
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hState, err := bs.beaconDB.HistoricalStateFromSlot(ctx, kid.Slot, blockRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
activeValidatorIndices, err := helpers.ActiveValidatorIndices(hState, helpers.CurrentEpoch(hState))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalVotes, err := helpers.TotalBalance(hState, activeValidatorIndices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tree = append(tree, &pb.BlockTreeResponse_TreeNode{
|
||||
BlockRoot: blockRoot[:],
|
||||
Block: kid,
|
||||
ParticipatedVotes: uint64(participatedVotes),
|
||||
TotalVotes: uint64(totalVotes),
|
||||
})
|
||||
}
|
||||
return &pb.BlockTreeResponse{
|
||||
@@ -150,89 +257,9 @@ func (bs *BeaconServer) BlockTree(ctx context.Context, _ *ptypes.Empty) (*pb.Blo
|
||||
}, 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 := []*pbp2p.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 := hashutil.HashBeaconBlock(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, err := helpers.TotalBalance(hState, activeValidatorIndices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tree = append(tree, &pb.BlockTreeResponse_TreeNode{
|
||||
BlockRoot: blockRoot[:],
|
||||
Block: kid,
|
||||
ParticipatedVotes: uint64(participatedVotes),
|
||||
TotalVotes: uint64(totalVotes),
|
||||
})
|
||||
}
|
||||
}
|
||||
return &pb.BlockTreeResponse{
|
||||
Tree: tree,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO(#2307): Refactor for v0.6.
|
||||
// nolint
|
||||
func (bs *BeaconServer) defaultDataResponse(ctx context.Context, currentHeight *big.Int, eth1FollowDistance int64) (*pbp2p.Eth1Data, error) {
|
||||
func (bs *BeaconServer) defaultDataResponse(ctx context.Context, currentHeight *big.Int, eth1FollowDistance int64) (*pb.Eth1DataResponse, error) {
|
||||
ancestorHeight := big.NewInt(0).Sub(currentHeight, big.NewInt(eth1FollowDistance))
|
||||
blockHash, err := bs.powChainService.BlockHashByHeight(ctx, ancestorHeight)
|
||||
if err != nil {
|
||||
@@ -263,9 +290,11 @@ func (bs *BeaconServer) defaultDataResponse(ctx context.Context, currentHeight *
|
||||
return nil, fmt.Errorf("could not generate historical deposit trie from deposits: %v", err)
|
||||
}
|
||||
depositRoot := depositTrie.Root()
|
||||
return &pbp2p.Eth1Data{
|
||||
DepositRoot: depositRoot[:],
|
||||
BlockRoot: blockHash[:],
|
||||
return &pb.Eth1DataResponse{
|
||||
Eth1Data: &pbp2p.Eth1Data{
|
||||
DepositRoot: depositRoot[:],
|
||||
BlockRoot: blockHash[:],
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,11 +2,8 @@ package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
@@ -17,7 +14,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -32,110 +28,62 @@ type ProposerServer struct {
|
||||
canonicalStateChan chan *pbp2p.BeaconState
|
||||
}
|
||||
|
||||
// RequestBlock is called by a proposer during its assigned slot to request a block to sign
|
||||
// by passing in the slot and the signed randao reveal of the slot.
|
||||
func (ps *ProposerServer) RequestBlock(ctx context.Context, req *pb.BlockRequest) (*pbp2p.BeaconBlock, error) {
|
||||
|
||||
// Retrieve the parent block as the current head of the canonical chain
|
||||
parent, err := ps.beaconDB.ChainHead()
|
||||
// ProposerIndex sends a response to the client which returns the proposer index for a given slot. Validators
|
||||
// are shuffled and assigned slots to attest/propose to. This method will look for the validator that is assigned
|
||||
// to propose a beacon block at the given slot.
|
||||
func (ps *ProposerServer) ProposerIndex(ctx context.Context, req *pb.ProposerIndexRequest) (*pb.ProposerIndexResponse, error) {
|
||||
beaconState, err := ps.beaconDB.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get canonical head block: %v", err)
|
||||
return nil, fmt.Errorf("could not get beacon state: %v", err)
|
||||
}
|
||||
parentRoot, err := ssz.SigningRoot(parent)
|
||||
beaconState.Slot = req.SlotNumber
|
||||
proposerIndex, err := helpers.BeaconProposerIndex(beaconState)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get parent block root: %v", err)
|
||||
return nil, fmt.Errorf("could not get index of previous proposer: %v", err)
|
||||
}
|
||||
|
||||
// Construct block body
|
||||
// Pack ETH1 deposits which have not been included in the beacon chain
|
||||
eth1Data, err := ps.eth1Data(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get ETH1 data: %v", err)
|
||||
}
|
||||
|
||||
// Pack ETH1 deposits which have not been included in the beacon chain.
|
||||
deposits, err := ps.deposits(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get eth1 deposits: %v", err)
|
||||
}
|
||||
|
||||
// Pack aggregated attestations which have not been included in the beacon chain.
|
||||
attestations, err := ps.attestations(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get pending attestations: %v", err)
|
||||
}
|
||||
|
||||
// Use zero hash as stub for state root to compute later.
|
||||
stateRoot := params.BeaconConfig().ZeroHash[:]
|
||||
|
||||
blk := &pbp2p.BeaconBlock{
|
||||
Slot: req.Slot,
|
||||
ParentRoot: parentRoot[:],
|
||||
StateRoot: stateRoot,
|
||||
Body: &pbp2p.BeaconBlockBody{
|
||||
Eth1Data: eth1Data,
|
||||
Deposits: deposits,
|
||||
Attestations: attestations,
|
||||
// TODO(2766): Implement rest of the retrievals for beacon block operations
|
||||
ProposerSlashings: nil,
|
||||
AttesterSlashings: nil,
|
||||
VoluntaryExits: nil,
|
||||
},
|
||||
}
|
||||
|
||||
if !featureconfig.FeatureConfig().EnableComputeStateRoot {
|
||||
// Compute state root with the newly constructed block.
|
||||
stateRoot, err = ps.computeStateRoot(ctx, blk)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get compute state root: %v", err)
|
||||
}
|
||||
blk.StateRoot = stateRoot
|
||||
}
|
||||
|
||||
return blk, nil
|
||||
return &pb.ProposerIndexResponse{
|
||||
Index: proposerIndex,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ProposeBlock is called by a proposer during its assigned slot to create a block in an attempt
|
||||
// to get it processed by the beacon node as the canonical head.
|
||||
func (ps *ProposerServer) ProposeBlock(ctx context.Context, blk *pbp2p.BeaconBlock) (*pb.ProposeResponse, error) {
|
||||
root, err := hashutil.HashBeaconBlock(blk)
|
||||
h, err := hashutil.HashBeaconBlock(blk)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not tree hash block: %v", err)
|
||||
}
|
||||
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(root[:]))).Debugf(
|
||||
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(h[:]))).Debugf(
|
||||
"Block proposal received via RPC")
|
||||
|
||||
beaconState, err := ps.chainService.ReceiveBlock(ctx, blk)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not process beacon block: %v", err)
|
||||
}
|
||||
|
||||
if err := ps.beaconDB.UpdateChainHead(ctx, blk, beaconState); err != nil {
|
||||
return nil, fmt.Errorf("failed to update chain: %v", err)
|
||||
|
||||
}
|
||||
ps.chainService.UpdateCanonicalRoots(blk, root)
|
||||
ps.chainService.UpdateCanonicalRoots(blk, h)
|
||||
log.WithFields(logrus.Fields{
|
||||
"headRoot": fmt.Sprintf("%#x", bytesutil.Trunc(root[:])),
|
||||
"headRoot": fmt.Sprintf("%#x", bytesutil.Trunc(h[:])),
|
||||
"headSlot": blk.Slot,
|
||||
}).Info("Chain head block and state updated")
|
||||
|
||||
return &pb.ProposeResponse{BlockRoot: root[:]}, nil
|
||||
return &pb.ProposeResponse{BlockRootHash32: h[:]}, nil
|
||||
}
|
||||
|
||||
// attestations retrieves aggregated attestations kept in the beacon node's operations pool which have
|
||||
// PendingAttestations retrieves attestations kept in the beacon node's operations pool which have
|
||||
// not yet been included into the beacon chain. Proposers include these pending attestations in their
|
||||
// proposed blocks when performing their responsibility. If desired, callers can choose to filter pending
|
||||
// attestations which are ready for inclusion. That is, attestations that satisfy:
|
||||
// attestation.slot + MIN_ATTESTATION_INCLUSION_DELAY <= state.slot.
|
||||
func (ps *ProposerServer) attestations(ctx context.Context) ([]*pbp2p.Attestation, error) {
|
||||
func (ps *ProposerServer) PendingAttestations(ctx context.Context, req *pb.PendingAttestationsRequest) (*pb.PendingAttestationsResponse, error) {
|
||||
beaconState, err := ps.beaconDB.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not retrieve beacon state: %v", err)
|
||||
}
|
||||
atts, err := ps.operationService.PendingAttestations(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not retrieve pending attest ations from operations service: %v", err)
|
||||
return nil, fmt.Errorf("could not retrieve pending attestations from operations service: %v", err)
|
||||
}
|
||||
beaconState.Slot++
|
||||
|
||||
@@ -157,7 +105,7 @@ func (ps *ProposerServer) attestations(ctx context.Context) ([]*pbp2p.Attestatio
|
||||
return nil, fmt.Errorf("could not get attestation slot: %v", err)
|
||||
}
|
||||
|
||||
if _, err := blocks.ProcessAttestation(beaconState, att, false); err != nil {
|
||||
if _, err := blocks.VerifyAttestation(beaconState, att, false); err != nil {
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
@@ -187,121 +135,40 @@ func (ps *ProposerServer) attestations(ctx context.Context) ([]*pbp2p.Attestatio
|
||||
validAtts = append(validAtts, att)
|
||||
}
|
||||
|
||||
return validAtts, nil
|
||||
return &pb.PendingAttestationsResponse{
|
||||
PendingAttestations: validAtts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Eth1Data is a mechanism used by block proposers vote on a recent Ethereum 1.0 block hash and an
|
||||
// associated deposit root found in the Ethereum 1.0 deposit contract. When consensus is formed,
|
||||
// state.latest_eth1_data is updated, and validator deposits up to this root can be processed.
|
||||
// The deposit root can be calculated by calling the get_deposit_root() function of
|
||||
// the deposit contract using the post-state of the block hash.
|
||||
//
|
||||
// TODO(#2307): Refactor for v0.6.
|
||||
func (ps *ProposerServer) eth1Data(ctx context.Context) (*pbp2p.Eth1Data, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// computeStateRoot computes the state root after a block has been processed through a state transition and
|
||||
// ComputeStateRoot computes the state root after a block has been processed through a state transition and
|
||||
// returns it to the validator client.
|
||||
func (ps *ProposerServer) computeStateRoot(ctx context.Context, block *pbp2p.BeaconBlock) ([]byte, error) {
|
||||
func (ps *ProposerServer) ComputeStateRoot(ctx context.Context, req *pbp2p.BeaconBlock) (*pb.StateRootResponse, error) {
|
||||
if !featureconfig.FeatureConfig().EnableComputeStateRoot {
|
||||
log.Debug("Compute state root disabled, returning no-op result")
|
||||
return &pb.StateRootResponse{StateRoot: []byte("no-op")}, nil
|
||||
}
|
||||
|
||||
beaconState, err := ps.beaconDB.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get beacon state: %v", err)
|
||||
}
|
||||
|
||||
s, err := state.ExecuteStateTransition(
|
||||
beaconState, err = state.ExecuteStateTransition(
|
||||
ctx,
|
||||
beaconState,
|
||||
block,
|
||||
req,
|
||||
state.DefaultConfig(),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not execute state transition for state root %v", err)
|
||||
return nil, fmt.Errorf("could not execute state transition %v", err)
|
||||
}
|
||||
|
||||
root, err := hashutil.HashProto(s)
|
||||
beaconStateHash, err := hashutil.HashProto(beaconState)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not tree hash beacon state: %v", err)
|
||||
}
|
||||
|
||||
log.WithField("beaconStateRoot", fmt.Sprintf("%#x", root)).Debugf("Computed state hash")
|
||||
|
||||
return root[:], nil
|
||||
}
|
||||
|
||||
// deposits returns a list of pending deposits that are ready for
|
||||
// inclusion in the next beacon block.
|
||||
func (ps *ProposerServer) deposits(ctx context.Context) ([]*pbp2p.Deposit, error) {
|
||||
bNum := ps.powChainService.LatestBlockHeight()
|
||||
if bNum == nil {
|
||||
return nil, errors.New("latest PoW block number is unknown")
|
||||
}
|
||||
// Only request deposits that have passed the ETH1 follow distance window.
|
||||
bNum = bNum.Sub(bNum, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)))
|
||||
allDeps := ps.beaconDB.AllDeposits(ctx, bNum)
|
||||
if len(allDeps) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Need to fetch if the deposits up to the state's latest eth 1 data matches
|
||||
// the number of all deposits in this RPC call. If not, then we return nil.
|
||||
beaconState, err := ps.beaconDB.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not fetch beacon state: %v", err)
|
||||
}
|
||||
h := bytesutil.ToBytes32(beaconState.LatestEth1Data.BlockRoot)
|
||||
_, latestEth1DataHeight, err := ps.powChainService.BlockExists(ctx, h)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not fetch eth1data height: %v", err)
|
||||
}
|
||||
// If the state's latest eth1 data's block hash has a height of 100, we fetch all the deposits up to height 100.
|
||||
// If this doesn't match the number of deposits stored in the cache, the generated trie will not be the same and
|
||||
// root will fail to verify. This can happen in a scenario where we perhaps have a deposit from height 101,
|
||||
// so we want to avoid any possible mismatches in these lengths.
|
||||
upToLatestEth1DataDeposits := ps.beaconDB.AllDeposits(ctx, latestEth1DataHeight)
|
||||
if len(upToLatestEth1DataDeposits) != len(allDeps) {
|
||||
return nil, nil
|
||||
}
|
||||
depositData := [][]byte{}
|
||||
for _, dep := range upToLatestEth1DataDeposits {
|
||||
depHash, err := hashutil.DepositHash(dep.Data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("coulf not hash deposit data %v", err)
|
||||
}
|
||||
depositData = append(depositData, depHash[:])
|
||||
}
|
||||
|
||||
depositTrie, err := trieutil.GenerateTrieFromItems(depositData, int(params.BeaconConfig().DepositContractTreeDepth))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not generate historical deposit trie from deposits: %v", err)
|
||||
}
|
||||
|
||||
allPendingDeps := ps.beaconDB.PendingDeposits(ctx, bNum)
|
||||
|
||||
// Deposits need to be received in order of merkle index root, so this has to make sure
|
||||
// deposits are sorted from lowest to highest.
|
||||
var pendingDeps []*pbp2p.Deposit
|
||||
for _, dep := range allPendingDeps {
|
||||
if dep.Index >= beaconState.DepositIndex {
|
||||
pendingDeps = append(pendingDeps, dep)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range pendingDeps {
|
||||
// Don't construct merkle proof if the number of deposits is more than max allowed in block.
|
||||
if uint64(i) == params.BeaconConfig().MaxDeposits {
|
||||
break
|
||||
}
|
||||
pendingDeps[i], err = constructMerkleProof(depositTrie, pendingDeps[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Limit the return of pending deposits to not be more than max deposits allowed in block.
|
||||
var pendingDeposits []*pbp2p.Deposit
|
||||
for i := 0; i < len(pendingDeps) && i < int(params.BeaconConfig().MaxDeposits); i++ {
|
||||
pendingDeposits = append(pendingDeposits, pendingDeps[i])
|
||||
}
|
||||
return pendingDeposits, nil
|
||||
log.WithField("beaconStateHash", fmt.Sprintf("%#x", beaconStateHash)).Debugf("Computed state hash")
|
||||
return &pb.StateRootResponse{
|
||||
StateRoot: beaconStateHash[:],
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/internal"
|
||||
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/ssz"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -128,16 +124,13 @@ func TestComputeStateRoot_OK(t *testing.T) {
|
||||
RandaoReveal: nil,
|
||||
ProposerSlashings: nil,
|
||||
AttesterSlashings: nil,
|
||||
Eth1Data: &pbp2p.Eth1Data{},
|
||||
},
|
||||
}
|
||||
|
||||
_, _ = proposerServer.computeStateRoot(context.Background(), req)
|
||||
_, _ = proposerServer.ComputeStateRoot(context.Background(), req)
|
||||
}
|
||||
|
||||
func TestPendingAttestations_FiltersWithinInclusionDelay(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
@@ -205,11 +198,13 @@ func TestPendingAttestations_FiltersWithinInclusionDelay(t *testing.T) {
|
||||
t.Fatalf("couldnt update chainhead: %v", err)
|
||||
}
|
||||
|
||||
atts, err := proposerServer.attestations(context.Background())
|
||||
res, err := proposerServer.PendingAttestations(context.Background(), &pb.PendingAttestationsRequest{
|
||||
ProposalBlockSlot: blk.Slot + 1,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error fetching pending attestations: %v", err)
|
||||
}
|
||||
if len(atts) == 0 {
|
||||
if len(res.PendingAttestations) == 0 {
|
||||
t.Error("Expected pending attestations list to be non-empty")
|
||||
}
|
||||
}
|
||||
@@ -222,7 +217,7 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
|
||||
// Edge case: current slot is at the end of an epoch. The pending attestation
|
||||
// for the next slot should come from currentSlot + 1.
|
||||
currentSlot := helpers.StartSlot(
|
||||
params.BeaconConfig().GenesisEpoch+10,
|
||||
10,
|
||||
) - 1
|
||||
|
||||
expectedEpoch := uint64(100)
|
||||
@@ -328,15 +323,20 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
|
||||
t.Fatalf("couldnt update chainhead: %v", err)
|
||||
}
|
||||
|
||||
atts, err := proposerServer.attestations(context.Background())
|
||||
res, err := proposerServer.PendingAttestations(
|
||||
context.Background(),
|
||||
&pb.PendingAttestationsRequest{
|
||||
ProposalBlockSlot: currentSlot,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error fetching pending attestations: %v", err)
|
||||
}
|
||||
if len(atts) != expectedNumberOfAttestations {
|
||||
if len(res.PendingAttestations) != expectedNumberOfAttestations {
|
||||
t.Errorf(
|
||||
"Expected pending attestations list length %d, but was %d",
|
||||
expectedNumberOfAttestations,
|
||||
len(atts),
|
||||
len(res.PendingAttestations),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -357,502 +357,7 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
|
||||
Crosslink: &pbp2p.Crosslink{Epoch: 10, DataRoot: params.BeaconConfig().ZeroHash[:], ParentRoot: encoded[:]},
|
||||
}, AggregationBitfield: []byte{0xC0, 0xC0, 0xC0, 0xC0}},
|
||||
}
|
||||
if !reflect.DeepEqual(atts, expectedAtts) {
|
||||
if !reflect.DeepEqual(res.PendingAttestations, expectedAtts) {
|
||||
t.Error("Did not receive expected attestations")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPendingDeposits_UnknownBlockNum(t *testing.T) {
|
||||
p := &mockPOWChainService{
|
||||
latestBlockNumber: nil,
|
||||
}
|
||||
ps := ProposerServer{powChainService: p}
|
||||
|
||||
_, err := ps.deposits(context.Background())
|
||||
if err.Error() != "latest PoW block number is unknown" {
|
||||
t.Errorf("Received unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPendingDeposits_OutsideEth1FollowWindow(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
|
||||
p := &mockPOWChainService{
|
||||
latestBlockNumber: height,
|
||||
hashesByHeight: map[int][]byte{
|
||||
int(height.Int64()): []byte("0x0"),
|
||||
},
|
||||
}
|
||||
d := internal.SetupDB(t)
|
||||
|
||||
beaconState := &pbp2p.BeaconState{
|
||||
LatestEth1Data: &pbp2p.Eth1Data{
|
||||
BlockRoot: []byte("0x0"),
|
||||
},
|
||||
DepositIndex: 2,
|
||||
}
|
||||
if err := d.SaveState(ctx, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var mockSig [96]byte
|
||||
var mockCreds [32]byte
|
||||
|
||||
// Using the merkleTreeIndex as the block number for this test...
|
||||
readyDeposits := []*pbp2p.Deposit{
|
||||
{
|
||||
Index: 0,
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("a"),
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: 1,
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("b"),
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
recentDeposits := []*pbp2p.Deposit{
|
||||
{
|
||||
Index: 2,
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("c"),
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: 3,
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("d"),
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, dp := range append(readyDeposits, recentDeposits...) {
|
||||
d.InsertDeposit(ctx, dp, big.NewInt(int64(dp.Index)))
|
||||
}
|
||||
for _, dp := range recentDeposits {
|
||||
d.InsertPendingDeposit(ctx, dp, big.NewInt(int64(dp.Index)))
|
||||
}
|
||||
|
||||
bs := &ProposerServer{
|
||||
beaconDB: d,
|
||||
powChainService: p,
|
||||
chainService: newMockChainService(),
|
||||
}
|
||||
|
||||
deposits, err := bs.deposits(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(deposits) != 0 {
|
||||
t.Errorf("Received unexpected list of deposits: %+v, wanted: 0", len(deposits))
|
||||
}
|
||||
|
||||
// It should also return the recent deposits after their follow window.
|
||||
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
|
||||
deposits, err = bs.deposits(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(deposits) != len(recentDeposits) {
|
||||
t.Errorf(
|
||||
"Received unexpected number of pending deposits: %d, wanted: %d",
|
||||
len(deposits),
|
||||
len(recentDeposits),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Eth1Data(b *testing.B) {
|
||||
db := internal.SetupDB(b)
|
||||
defer internal.TeardownDB(b, db)
|
||||
ctx := context.Background()
|
||||
|
||||
hashesByHeight := make(map[int][]byte)
|
||||
|
||||
beaconState := &pbp2p.BeaconState{
|
||||
Eth1DataVotes: []*pbp2p.Eth1Data{},
|
||||
LatestEth1Data: &pbp2p.Eth1Data{
|
||||
BlockRoot: []byte("stub"),
|
||||
},
|
||||
}
|
||||
numOfVotes := 1000
|
||||
for i := 0; i < numOfVotes; i++ {
|
||||
blockhash := []byte{'b', 'l', 'o', 'c', 'k', byte(i)}
|
||||
deposit := []byte{'d', 'e', 'p', 'o', 's', 'i', 't', byte(i)}
|
||||
beaconState.Eth1DataVotes = append(beaconState.Eth1DataVotes, &pbp2p.Eth1Data{
|
||||
BlockRoot: blockhash,
|
||||
DepositRoot: deposit,
|
||||
})
|
||||
hashesByHeight[i] = blockhash
|
||||
}
|
||||
hashesByHeight[numOfVotes+1] = []byte("stub")
|
||||
|
||||
if err := db.SaveState(ctx, beaconState); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
currentHeight := params.BeaconConfig().Eth1FollowDistance + 5
|
||||
proposerServer := &ProposerServer{
|
||||
beaconDB: db,
|
||||
powChainService: &mockPOWChainService{
|
||||
latestBlockNumber: big.NewInt(int64(currentHeight)),
|
||||
hashesByHeight: hashesByHeight,
|
||||
},
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := proposerServer.eth1Data(context.Background())
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPendingDeposits_CantReturnBelowStateDepositIndex(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
|
||||
p := &mockPOWChainService{
|
||||
latestBlockNumber: height,
|
||||
hashesByHeight: map[int][]byte{
|
||||
int(height.Int64()): []byte("0x0"),
|
||||
},
|
||||
}
|
||||
d := internal.SetupDB(t)
|
||||
|
||||
beaconState := &pbp2p.BeaconState{
|
||||
LatestEth1Data: &pbp2p.Eth1Data{
|
||||
BlockRoot: []byte("0x0"),
|
||||
},
|
||||
DepositIndex: 10,
|
||||
}
|
||||
if err := d.SaveState(ctx, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var mockSig [96]byte
|
||||
var mockCreds [32]byte
|
||||
|
||||
readyDeposits := []*pbp2p.Deposit{
|
||||
{
|
||||
Index: 0,
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("a"),
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: 1,
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("b"),
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var recentDeposits []*pbp2p.Deposit
|
||||
for i := 2; i < 16; i++ {
|
||||
recentDeposits = append(recentDeposits, &pbp2p.Deposit{
|
||||
Index: uint64(i),
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte{byte(i)},
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for _, dp := range append(readyDeposits, recentDeposits...) {
|
||||
d.InsertDeposit(ctx, dp, big.NewInt(int64(dp.Index)))
|
||||
}
|
||||
for _, dp := range recentDeposits {
|
||||
d.InsertPendingDeposit(ctx, dp, big.NewInt(int64(dp.Index)))
|
||||
}
|
||||
|
||||
bs := &ProposerServer{
|
||||
beaconDB: d,
|
||||
powChainService: p,
|
||||
chainService: newMockChainService(),
|
||||
}
|
||||
|
||||
// It should also return the recent deposits after their follow window.
|
||||
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
|
||||
deposits, err := bs.deposits(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedDeposits := 6
|
||||
if len(deposits) != expectedDeposits {
|
||||
t.Errorf(
|
||||
"Received unexpected number of pending deposits: %d, wanted: %d",
|
||||
len(deposits),
|
||||
expectedDeposits,
|
||||
)
|
||||
}
|
||||
if deposits[0].Index != beaconState.DepositIndex {
|
||||
t.Errorf(
|
||||
"Received unexpected merkle index: %d, wanted: %d",
|
||||
deposits[0].Index,
|
||||
beaconState.DepositIndex,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPendingDeposits_CantReturnMoreThanMax(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
|
||||
p := &mockPOWChainService{
|
||||
latestBlockNumber: height,
|
||||
hashesByHeight: map[int][]byte{
|
||||
int(height.Int64()): []byte("0x0"),
|
||||
},
|
||||
}
|
||||
d := internal.SetupDB(t)
|
||||
|
||||
beaconState := &pbp2p.BeaconState{
|
||||
LatestEth1Data: &pbp2p.Eth1Data{
|
||||
BlockRoot: []byte("0x0"),
|
||||
},
|
||||
DepositIndex: 2,
|
||||
}
|
||||
if err := d.SaveState(ctx, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var mockSig [96]byte
|
||||
var mockCreds [32]byte
|
||||
|
||||
readyDeposits := []*pbp2p.Deposit{
|
||||
{
|
||||
Index: 0,
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("a"),
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
},
|
||||
{
|
||||
Index: 1,
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("b"),
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var recentDeposits []*pbp2p.Deposit
|
||||
for i := 2; i < 22; i++ {
|
||||
recentDeposits = append(recentDeposits, &pbp2p.Deposit{
|
||||
Index: uint64(i),
|
||||
Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte{byte(i)},
|
||||
Signature: mockSig[:],
|
||||
WithdrawalCredentials: mockCreds[:],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
for _, dp := range append(readyDeposits, recentDeposits...) {
|
||||
d.InsertDeposit(ctx, dp, big.NewInt(int64(dp.Index)))
|
||||
}
|
||||
for _, dp := range recentDeposits {
|
||||
d.InsertPendingDeposit(ctx, dp, big.NewInt(int64(dp.Index)))
|
||||
}
|
||||
|
||||
bs := &ProposerServer{
|
||||
beaconDB: d,
|
||||
powChainService: p,
|
||||
chainService: newMockChainService(),
|
||||
}
|
||||
|
||||
// It should also return the recent deposits after their follow window.
|
||||
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
|
||||
deposits, err := bs.deposits(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(deposits) != int(params.BeaconConfig().MaxDeposits) {
|
||||
t.Errorf(
|
||||
"Received unexpected number of pending deposits: %d, wanted: %d",
|
||||
len(deposits),
|
||||
int(params.BeaconConfig().MaxDeposits),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1Data_EmptyVotesFetchBlockHashFailure(t *testing.T) {
|
||||
t.Skip()
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
proposerServer := &ProposerServer{
|
||||
beaconDB: db,
|
||||
powChainService: &faultyPOWChainService{
|
||||
hashesByHeight: make(map[int][]byte),
|
||||
},
|
||||
}
|
||||
|
||||
validators := make([]*pbp2p.Validator, 2*params.BeaconConfig().SlotsPerEpoch)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pbp2p.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
crosslinks := make([]*pbp2p.Crosslink, 2*params.BeaconConfig().SlotsPerEpoch)
|
||||
for i := range crosslinks {
|
||||
crosslinks[i] = &pbp2p.Crosslink{
|
||||
Epoch: params.BeaconConfig().GenesisEpoch + 1,
|
||||
CrosslinkDataRootHash32: params.BeaconConfig().ZeroHash[:],
|
||||
}
|
||||
}
|
||||
beaconState := &pbp2p.BeaconState{
|
||||
LatestEth1Data: &pbp2p.Eth1Data{
|
||||
BlockRoot: []byte{'a'},
|
||||
},
|
||||
Eth1DataVotes: []*pbp2p.Eth1Data{},
|
||||
}
|
||||
if err := proposerServer.beaconDB.SaveState(ctx, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := "could not fetch ETH1_FOLLOW_DISTANCE ancestor"
|
||||
if _, err := proposerServer.eth1Data(context.Background()); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected error %v, received %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1Data_EmptyVotesOk(t *testing.T) {
|
||||
t.Skip()
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
|
||||
deps := []*pbp2p.Deposit{
|
||||
{Index: 0, Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("a"),
|
||||
}},
|
||||
{Index: 1, Data: &pbp2p.DepositData{
|
||||
Pubkey: []byte("b"),
|
||||
}},
|
||||
}
|
||||
depsData := [][]byte{}
|
||||
for _, dp := range deps {
|
||||
db.InsertDeposit(context.Background(), dp, big.NewInt(0))
|
||||
depHash, err := hashutil.DepositHash(dp.Data)
|
||||
if err != nil {
|
||||
t.Errorf("Could not hash deposit")
|
||||
}
|
||||
depsData = append(depsData, depHash[:])
|
||||
}
|
||||
|
||||
depositTrie, err := trieutil.GenerateTrieFromItems(depsData, int(params.BeaconConfig().DepositContractTreeDepth))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
depositRoot := depositTrie.Root()
|
||||
beaconState := &pbp2p.BeaconState{
|
||||
LatestEth1Data: &pbp2p.Eth1Data{
|
||||
BlockRoot: []byte("hash0"),
|
||||
DepositRoot: depositRoot[:],
|
||||
},
|
||||
Eth1DataVotes: []*pbp2p.Eth1Data{},
|
||||
}
|
||||
|
||||
powChainService := &mockPOWChainService{
|
||||
latestBlockNumber: height,
|
||||
hashesByHeight: map[int][]byte{
|
||||
0: []byte("hash0"),
|
||||
1: beaconState.LatestEth1Data.BlockRoot,
|
||||
},
|
||||
}
|
||||
proposerServer := &ProposerServer{
|
||||
beaconDB: db,
|
||||
powChainService: powChainService,
|
||||
}
|
||||
|
||||
if err := proposerServer.beaconDB.SaveState(ctx, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
eth1data, err := proposerServer.eth1Data(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// If the data vote objects are empty, the deposit root should be the one corresponding
|
||||
// to the deposit contract in the powchain service, fetched using powChainService.DepositRoot()
|
||||
if !bytes.Equal(eth1data.DepositRoot, depositRoot[:]) {
|
||||
t.Errorf(
|
||||
"Expected deposit roots to match, received %#x == %#x",
|
||||
eth1data.DepositRoot,
|
||||
depositRoot,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1Data_NonEmptyVotesSelectsBestVote(t *testing.T) {
|
||||
t.Skip()
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
eth1DataVotes := []*pbp2p.Eth1Data{}
|
||||
beaconState := &pbp2p.BeaconState{
|
||||
Eth1DataVotes: eth1DataVotes,
|
||||
LatestEth1Data: &pbp2p.Eth1Data{
|
||||
BlockRoot: []byte("stub"),
|
||||
},
|
||||
}
|
||||
if err := db.SaveState(ctx, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
currentHeight := params.BeaconConfig().Eth1FollowDistance + 5
|
||||
proposerServer := &ProposerServer{
|
||||
beaconDB: db,
|
||||
powChainService: &mockPOWChainService{
|
||||
latestBlockNumber: big.NewInt(int64(currentHeight)),
|
||||
hashesByHeight: map[int][]byte{
|
||||
0: beaconState.LatestEth1Data.BlockRoot,
|
||||
1: beaconState.Eth1DataVotes[0].BlockRoot,
|
||||
2: beaconState.Eth1DataVotes[1].BlockRoot,
|
||||
3: beaconState.Eth1DataVotes[3].BlockRoot,
|
||||
// We will give the hash at index 2 in the beacon state's latest eth1 votes
|
||||
// priority in being selected as the best vote by giving it the highest block number.
|
||||
4: beaconState.Eth1DataVotes[2].BlockRoot,
|
||||
},
|
||||
},
|
||||
}
|
||||
eth1data, err := proposerServer.eth1Data(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Vote at index 2 should have won the best vote selection mechanism as it had the highest block number
|
||||
// despite being tied at vote count with the vote at index 3.
|
||||
if !bytes.Equal(eth1data.BlockRoot, beaconState.Eth1DataVotes[2].BlockRoot) {
|
||||
t.Errorf(
|
||||
"Expected block hashes to match, received %#x == %#x",
|
||||
eth1data.BlockRoot,
|
||||
beaconState.Eth1DataVotes[2].BlockRoot,
|
||||
)
|
||||
}
|
||||
if !bytes.Equal(eth1data.DepositRoot, beaconState.Eth1DataVotes[2].DepositRoot) {
|
||||
t.Errorf(
|
||||
"Expected deposit roots to match, received %#x == %#x",
|
||||
eth1data.DepositRoot,
|
||||
beaconState.Eth1DataVotes[2].DepositRoot,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,28 +101,22 @@ func (vs *ValidatorServer) ValidatorPerformance(
|
||||
return nil, fmt.Errorf("could not retrieve beacon state: %v", err)
|
||||
}
|
||||
|
||||
activeCount, err := helpers.ActiveValidatorCount(head, helpers.SlotToEpoch(req.Slot))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not retrieve active validator count: %v", err)
|
||||
}
|
||||
|
||||
totalActiveBalance, err := helpers.TotalActiveBalance(head)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not retrieve active balance: %v", err)
|
||||
}
|
||||
|
||||
activeIndices := helpers.ActiveValidatorIndices(head, helpers.SlotToEpoch(req.Slot))
|
||||
validatorBalances, err := vs.beaconDB.Balances(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not retrieve validator balances %v", err)
|
||||
}
|
||||
|
||||
avgBalance := float32(totalActiveBalance / activeCount)
|
||||
totalActiveBalance := float32(0)
|
||||
for _, idx := range activeIndices {
|
||||
totalActiveBalance += float32(validatorBalances[idx])
|
||||
}
|
||||
avgBalance := totalActiveBalance / float32(len(activeIndices))
|
||||
balance := validatorBalances[index]
|
||||
return &pb.ValidatorPerformanceResponse{
|
||||
Balance: balance,
|
||||
AverageActiveValidatorBalance: avgBalance,
|
||||
TotalValidators: uint64(len(validatorRegistry)),
|
||||
TotalActiveValidators: uint64(activeCount),
|
||||
TotalActiveValidators: uint64(len(activeIndices)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -213,7 +207,6 @@ func (vs *ValidatorServer) ValidatorStatus(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chainStartKeys := vs.chainStartPubkeys()
|
||||
validatorIndexMap := stateutils.ValidatorIndexMap(beaconState)
|
||||
return vs.validatorStatus(ctx, req.PublicKey, chainStarted, chainStartKeys, validatorIndexMap, beaconState), nil
|
||||
@@ -465,7 +458,7 @@ func (vs *ValidatorServer) depositBlockSlot(ctx context.Context, currentSlot uin
|
||||
followTime := time.Duration(params.BeaconConfig().Eth1FollowDistance*params.BeaconConfig().GoerliBlockTime) * time.Second
|
||||
eth1UnixTime := time.Unix(int64(blockTimeStamp), 0).Add(followTime)
|
||||
|
||||
votingPeriodSlots := helpers.StartSlot(params.BeaconConfig().SlotsPerEth1VotingPeriod / params.BeaconConfig().SlotsPerEpoch)
|
||||
votingPeriodSlots := helpers.StartSlot(params.BeaconConfig().EpochsPerEth1VotingPeriod)
|
||||
votingPeriodSeconds := time.Duration(votingPeriodSlots*params.BeaconConfig().SecondsPerSlot) * time.Second
|
||||
timeToInclusion := eth1UnixTime.Add(votingPeriodSeconds)
|
||||
|
||||
@@ -488,15 +481,3 @@ func (vs *ValidatorServer) chainStartPubkeys() map[[96]byte]bool {
|
||||
}
|
||||
return pubkeys
|
||||
}
|
||||
|
||||
// DomainData fetches the current domain version information from the beacon state.
|
||||
func (vs *ValidatorServer) DomainData(ctx context.Context, request *pb.DomainRequest) (*pb.DomainResponse, error) {
|
||||
state, err := vs.beaconDB.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not retrieve beacon state: %v", err)
|
||||
}
|
||||
dv := helpers.DomainVersion(state, request.Epoch, params.BeaconConfig().DomainRandao)
|
||||
return &pb.DomainResponse{
|
||||
SignatureDomain: dv,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -163,8 +163,6 @@ func TestNextEpochCommitteeAssignment_CantFindValidatorIdx(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommitteeAssignment_OK(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
Reference in New Issue
Block a user