[Interop] Improve RPC Codebase + Start Beacon Chain With Mock ETH1 Values (#3407)

* add main.go

* interop readme

* proper visibility

* standardize and abstract into simpler funcs

* formatting

* no os pkg

* add test

* no panics anywhere, properly and nicely handle errors

* proper comments

* fix broken test

* readme

* comment

* recommend ssz

* install

* tool now works

* README

* build

* readme

* 64 validators

* rem print

* register the no powchain flag

* work on mock eth1 start

* common interface

* getting closer with the interface defs

* only two uses of powchain

* remove powchain dependency

* remove powchain dependency

* common powchain interface

* proper comment in case of flag

* proper args into rpc services

* rename fields

* pass in mock flag into RPC

* conforms to iface

* use client instead of block fetcher iface

* broken tests

* block fetcher

* finalized

* resolved broken build

* fix build

* comment

* fix tests

* tests pass

* resolved confs

* took them out

* rename into smaller interfaces

* resolve some confs

* ensure tests pass

* properly utilize mock instead of localized mock

* res lint

* lint

* finish test for mock eth1data

* run gazelle

* include flag again

* fix broken build

* disable powchain

* dont dial eth1 nodes

* reenable pow

* use smaller interfaces, standardize naming

* abstract mock into its own package

* faulty mock lint

* fix stutter in lint

* rpc tests all passing

* use mocks for operations

* no more mocks in the entire rpc package

* no  mock

* viz

* testonly
This commit is contained in:
Raul Jordan 2019-09-09 17:13:50 -04:00 committed by GitHub
parent 8d234014a4
commit af07c13730
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 926 additions and 676 deletions

View File

@ -9,33 +9,32 @@ import (
"github.com/prysmaticlabs/prysm/shared/params"
)
// ChainInfoRetriever defines a common interface for methods in blockchain service which
// ChainInfoFetcher defines a common interface for methods in blockchain service which
// directly retrieves chain info related data.
type ChainInfoRetriever interface {
HeadRetriever
CanonicalRetriever
FinalizationRetriever
GenesisTime() time.Time
type ChainInfoFetcher interface {
HeadFetcher
CanonicalRootFetcher
FinalizationFetcher
}
// HeadRetriever defines a common interface for methods in blockchain service which
// HeadFetcher defines a common interface for methods in blockchain service which
// directly retrieves head related data.
type HeadRetriever interface {
type HeadFetcher interface {
HeadSlot() uint64
HeadRoot() []byte
HeadBlock() *ethpb.BeaconBlock
HeadState() *pb.BeaconState
}
// CanonicalRetriever defines a common interface for methods in blockchain service which
// CanonicalRootFetcher defines a common interface for methods in blockchain service which
// directly retrieves canonical roots related data.
type CanonicalRetriever interface {
type CanonicalRootFetcher interface {
CanonicalRoot(slot uint64) []byte
}
// FinalizationRetriever defines a common interface for methods in blockchain service which
// FinalizationFetcher defines a common interface for methods in blockchain service which
// directly retrieves finalization related data.
type FinalizationRetriever interface {
type FinalizationFetcher interface {
FinalizedCheckpt() *ethpb.Checkpoint
}

View File

@ -5,7 +5,6 @@ import (
"context"
"reflect"
"testing"
"time"
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
@ -14,7 +13,7 @@ import (
)
// Ensure Service implements chain info interface.
var _ = ChainInfoRetriever(&Service{})
var _ = ChainInfoFetcher(&Service{})
func TestFinalizedCheckpt_Nil(t *testing.T) {
c := setupBeaconChain(t, nil)
@ -88,11 +87,3 @@ func TestCanonicalRoot_CanRetrieve(t *testing.T) {
t.Errorf("Wanted head root: %v, got: %d", []byte{'A'}, c.CanonicalRoot(slot))
}
}
func TestGenesisTime_CanRetrieve(t *testing.T) {
c := &Service{}
c.genesisTime = time.Unix(100, 0)
if c.GenesisTime() != time.Unix(100, 0) {
t.Error("incorrect genesis time received")
}
}

View File

@ -43,7 +43,7 @@ type Service struct {
cancel context.CancelFunc
beaconDB db.Database
depositCache *depositcache.DepositCache
web3Service *powchain.Service
chainStartFetcher powchain.ChainStartFetcher
opsPoolService operations.OperationFeeds
forkChoiceStore forkchoice.ForkChoicer
chainStartChan chan time.Time
@ -61,14 +61,14 @@ type Service struct {
// Config options for the service.
type Config struct {
BeaconBlockBuf int
Web3Service *powchain.Service
BeaconDB db.Database
DepositCache *depositcache.DepositCache
OpsPoolService operations.OperationFeeds
P2p p2p.Broadcaster
MaxRoutines int64
PreloadStatePath string
BeaconBlockBuf int
ChainStartFetcher powchain.ChainStartFetcher
BeaconDB db.Database
DepositCache *depositcache.DepositCache
OpsPoolService operations.OperationFeeds
P2p p2p.Broadcaster
MaxRoutines int64
PreloadStatePath string
}
// NewService instantiates a new block service instance that will
@ -81,7 +81,7 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) {
cancel: cancel,
beaconDB: cfg.BeaconDB,
depositCache: cfg.DepositCache,
web3Service: cfg.Web3Service,
chainStartFetcher: cfg.ChainStartFetcher,
opsPoolService: cfg.OpsPoolService,
forkChoiceStore: store,
chainStartChan: make(chan time.Time),
@ -136,11 +136,11 @@ func (s *Service) Start() {
s.stateInitializedFeed.Send(s.genesisTime)
} else {
log.Info("Waiting for ChainStart log from the Validator Deposit Contract to start the beacon chain...")
if s.web3Service == nil {
if s.chainStartFetcher == nil {
log.Fatal("Not configured web3Service for POW chain")
return // return need for TestStartUninitializedChainWithoutConfigPOWChain.
}
subChainStart := s.web3Service.ChainStartFeed().Subscribe(s.chainStartChan)
subChainStart := s.chainStartFetcher.ChainStartFeed().Subscribe(s.chainStartChan)
go func() {
genesisTime := <-s.chainStartChan
s.processChainStartTime(ctx, genesisTime, subChainStart)
@ -152,8 +152,8 @@ func (s *Service) Start() {
// processChainStartTime initializes a series of deposits from the ChainStart deposits in the eth1
// deposit contract, initializes the beacon chain's state, and kicks off the beacon chain.
func (s *Service) processChainStartTime(ctx context.Context, genesisTime time.Time, chainStartSub event.Subscription) {
initialDeposits := s.web3Service.ChainStartDeposits()
if err := s.initializeBeaconChain(ctx, genesisTime, initialDeposits, s.web3Service.ChainStartETH1Data()); err != nil {
initialDeposits := s.chainStartFetcher.ChainStartDeposits()
if err := s.initializeBeaconChain(ctx, genesisTime, initialDeposits, s.chainStartFetcher.ChainStartEth1Data()); err != nil {
log.Fatalf("Could not initialize beacon chain: %v", err)
}
s.stateInitializedFeed.Send(genesisTime)

View File

@ -206,12 +206,12 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
}
cfg := &Config{
BeaconBlockBuf: 0,
BeaconDB: beaconDB,
DepositCache: depositcache.NewDepositCache(),
Web3Service: web3Service,
OpsPoolService: &mockOperationService{},
P2p: &mockBroadcaster{},
BeaconBlockBuf: 0,
BeaconDB: beaconDB,
DepositCache: depositcache.NewDepositCache(),
ChainStartFetcher: web3Service,
OpsPoolService: &mockOperationService{},
P2p: &mockBroadcaster{},
}
if err != nil {
t.Fatalf("could not register blockchain service: %v", err)

View File

@ -2,6 +2,7 @@ package testing
import (
"context"
"time"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
@ -67,7 +68,12 @@ func (ms *ChainService) ReceiveAttestationNoPubsub(context.Context, *ethpb.Attes
return nil
}
// StateInitializedFeed mocks StateInitializedFeed method in chain service.
// GenesisTime mocks the same method in the chain service.
func (ms *ChainService) GenesisTime() time.Time {
return time.Now()
}
// StateInitializedFeed mocks the same method in the chain service.
func (ms *ChainService) StateInitializedFeed() *event.Feed {
return new(event.Feed)
}

View File

@ -53,8 +53,13 @@ var (
Name: "grpc-gateway-port",
Usage: "Enable gRPC gateway for JSON requests",
}
// GenesisState defines a flag for the beacon node to load genesis state via file.
GenesisState = cli.StringFlag{
// InteropMockEth1DataVotesFlag enables mocking the eth1 proof-of-work chain data put into blocks by proposers.
InteropMockEth1DataVotesFlag = cli.BoolFlag{
Name: "interop-eth1data-votes",
Usage: "Enable mocking of eth1 data votes for proposers to package into blocks",
}
// InteropGenesisStateFlag defines a flag for the beacon node to load genesis state via file.
InteropGenesisStateFlag = cli.StringFlag{
Name: "interop-genesis-state",
Usage: "The genesis state file (.SSZ) to load from",
}

View File

@ -30,7 +30,8 @@ var appFlags = []cli.Flag{
flags.KeyFlag,
flags.EnableDBCleanup,
flags.GRPCGatewayPort,
flags.GenesisState,
flags.InteropMockEth1DataVotesFlag,
flags.InteropGenesisStateFlag,
cmd.BootstrapNode,
cmd.NoDiscovery,
cmd.StaticPeers,

View File

@ -201,7 +201,7 @@ func (b *BeaconNode) startDB(ctx *cli.Context) error {
}
func (b *BeaconNode) registerP2P(ctx *cli.Context) error {
// Bootnode ENR may be a filepath to an ENR file.
// Bootnode ENR may be a filepath to an ENR file.
bootnodeENR := ctx.GlobalString(cmd.BootstrapNode.Name)
if filepath.Ext(bootnodeENR) == ".enr" {
b, err := ioutil.ReadFile(bootnodeENR)
@ -249,14 +249,15 @@ func (b *BeaconNode) registerBlockchainService(ctx *cli.Context) error {
}
maxRoutines := ctx.GlobalInt64(cmd.MaxGoroutines.Name)
interopLoadGenesisFlag := ctx.GlobalString(flags.InteropGenesisStateFlag.Name)
blockchainService, err := blockchain.NewService(context.Background(), &blockchain.Config{
BeaconDB: b.db,
DepositCache: b.depositCache,
Web3Service: web3Service,
OpsPoolService: opsService,
P2p: b.fetchP2P(ctx),
MaxRoutines: maxRoutines,
BeaconDB: b.db,
DepositCache: b.depositCache,
ChainStartFetcher: web3Service,
OpsPoolService: opsService,
P2p: b.fetchP2P(ctx),
MaxRoutines: maxRoutines,
PreloadStatePath: interopLoadGenesisFlag,
})
if err != nil {
return errors.Wrap(err, "could not register blockchain service")
@ -277,9 +278,7 @@ func (b *BeaconNode) registerPOWChainService(cliCtx *cli.Context) error {
if cliCtx.GlobalBool(testSkipPowFlag) {
return b.services.RegisterService(&powchain.Service{})
}
depAddress := cliCtx.GlobalString(flags.DepositContractFlag.Name)
if depAddress == "" {
var err error
depAddress, err = fetchDepositContract()
@ -404,17 +403,23 @@ func (b *BeaconNode) registerRPCService(ctx *cli.Context) error {
port := ctx.GlobalString(flags.RPCPort.Name)
cert := ctx.GlobalString(flags.CertFlag.Name)
key := ctx.GlobalString(flags.KeyFlag.Name)
mockEth1DataVotes := ctx.GlobalBool(flags.InteropMockEth1DataVotesFlag.Name)
rpcService := rpc.NewService(context.Background(), &rpc.Config{
Port: port,
CertFlag: cert,
KeyFlag: key,
BeaconDB: b.db,
Broadcaster: b.fetchP2P(ctx),
ChainService: chainService,
OperationService: operationService,
POWChainService: web3Service,
SyncService: syncService,
DepositCache: b.depositCache,
Port: port,
CertFlag: cert,
KeyFlag: key,
BeaconDB: b.db,
Broadcaster: b.fetchP2P(ctx),
HeadFetcher: chainService,
BlockReceiver: chainService,
AttestationReceiver: chainService,
StateFeedListener: chainService,
AttestationsPool: operationService,
OperationsHandler: operationService,
POWChainService: web3Service,
MockEth1Votes: mockEth1DataVotes,
SyncService: syncService,
DepositCache: b.depositCache,
})
return b.services.RegisterService(rpcService)

View File

@ -35,6 +35,11 @@ type Pool interface {
AttestationPool(ctx context.Context, requestedSlot uint64) ([]*ethpb.Attestation, error)
}
// Handler defines an interface for a struct equipped for receiving block operations.
type Handler interface {
HandleAttestation(context.Context, proto.Message) error
}
// OperationFeeds inteface defines the informational feeds from the operations
// service.
type OperationFeeds interface {

View File

@ -0,0 +1,13 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
testonly = True,
srcs = ["mock.go"],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/operations/testing",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//proto/eth/v1alpha1:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
],
)

View File

@ -0,0 +1,23 @@
package testing
import (
"context"
"github.com/gogo/protobuf/proto"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
)
// Operations defines a mock for the operations service.
type Operations struct {
Attestations []*ethpb.Attestation
}
// AttestationPool --
func (op *Operations) AttestationPool(ctx context.Context, requestedSlot uint64) ([]*ethpb.Attestation, error) {
return op.Attestations, nil
}
// HandleAttestation --
func (op *Operations) HandleAttestation(context.Context, proto.Message) error {
return nil
}

View File

@ -25,10 +25,10 @@ func TestLatestMainchainInfo_OK(t *testing.T) {
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
Endpoint: endpoint,
DepositContract: testAcc.ContractAddr,
BlockFetcher: &goodFetcher{},
Reader: &goodReader{},
Logger: &goodLogger{},
HTTPLogger: &goodLogger{},
BlockFetcher: &goodFetcher{},
ContractBackend: testAcc.Backend,
BeaconDB: beaconDB,
})

View File

@ -27,9 +27,9 @@ var (
depositEventSignature = []byte("DepositEvent(bytes,bytes,bytes,bytes,bytes)")
)
// ETH2GenesisTime retrieves the genesis time and eth1 block number of the beacon chain
// Eth2GenesisPowchainInfo retrieves the genesis time and eth1 block number of the beacon chain
// from the deposit contract.
func (s *Service) ETH2GenesisTime() (uint64, *big.Int) {
func (s *Service) Eth2GenesisPowchainInfo() (uint64, *big.Int) {
return s.eth2GenesisTime, s.chainStartBlockNumber
}

View File

@ -50,22 +50,52 @@ type Reader interface {
SubscribeNewHead(ctx context.Context, ch chan<- *gethTypes.Header) (ethereum.Subscription, error)
}
// ChainStartFetcher retrieves information pertaining to the chain start event
// of the beacon chain for usage across various services.
type ChainStartFetcher interface {
ChainStartDeposits() []*ethpb.Deposit
ChainStartEth1Data() *ethpb.Eth1Data
ChainStartFeed() *event.Feed
HasChainStarted() bool
}
// ChainInfoFetcher retrieves information about eth1 metadata at the eth2 genesis time.
type ChainInfoFetcher interface {
Eth2GenesisPowchainInfo() (uint64, *big.Int)
}
// POWBlockFetcher defines a struct that can retrieve mainchain blocks.
type POWBlockFetcher interface {
BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error)
BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error)
HeaderByNumber(ctx context.Context, number *big.Int) (*gethTypes.Header, error)
BlockTimeByHeight(ctx context.Context, height *big.Int) (uint64, error)
BlockNumberByTimestamp(ctx context.Context, time uint64) (*big.Int, error)
BlockHashByHeight(ctx context.Context, height *big.Int) (common.Hash, error)
BlockExists(ctx context.Context, hash common.Hash) (bool, *big.Int, error)
}
// Chain defines a standard interface for the powchain service in Prysm.
type Chain interface {
ChainStartFetcher
ChainInfoFetcher
POWBlockFetcher
}
// Client defines a struct that combines all relevant ETH1.0 mainchain interactions required
// by the beacon chain node.
type Client interface {
Reader
POWBlockFetcher
RPCBlockFetcher
bind.ContractFilterer
bind.ContractCaller
}
// RPCBlockFetcher defines a subset of methods conformed to by ETH1.0 RPC clients for
// fetching block information.
type RPCBlockFetcher interface {
HeaderByNumber(ctx context.Context, number *big.Int) (*gethTypes.Header, error)
BlockByNumber(ctx context.Context, number *big.Int) (*gethTypes.Block, error)
BlockByHash(ctx context.Context, hash common.Hash) (*gethTypes.Block, error)
}
// Service fetches important information about the canonical
// Ethereum ETH1.0 chain via a web3 endpoint using an ethclient. The Random
// Beacon Chain requires synchronization with the ETH1.0 chain's current
@ -83,7 +113,7 @@ type Service struct {
reader Reader
logger bind.ContractFilterer
httpLogger bind.ContractFilterer
blockFetcher POWBlockFetcher
blockFetcher RPCBlockFetcher
blockHeight *big.Int // the latest ETH1.0 chain blockHeight.
blockHash common.Hash // the latest ETH1.0 chain blockHash.
blockTime time.Time // the latest ETH1.0 chain blockTime.
@ -115,7 +145,7 @@ type Web3ServiceConfig struct {
Reader Reader
Logger bind.ContractFilterer
HTTPLogger bind.ContractFilterer
BlockFetcher POWBlockFetcher
BlockFetcher RPCBlockFetcher
ContractBackend bind.ContractBackend
BeaconDB db.Database
DepositCache *depositcache.DepositCache
@ -201,8 +231,8 @@ func (s *Service) ChainStartDeposits() []*ethpb.Deposit {
return s.chainStartDeposits
}
// ChainStartETH1Data returns the eth1 data at chainstart.
func (s *Service) ChainStartETH1Data() *ethpb.Eth1Data {
// ChainStartEth1Data returns the eth1 data at chainstart.
func (s *Service) ChainStartEth1Data() *ethpb.Eth1Data {
return s.chainStartETH1Data
}

View File

@ -21,6 +21,11 @@ import (
logTest "github.com/sirupsen/logrus/hooks/test"
)
var _ = ChainStartFetcher(&Service{})
var _ = ChainInfoFetcher(&Service{})
var _ = POWBlockFetcher(&Service{})
var _ = Chain(&Service{})
type badReader struct{}
func (b *badReader) SubscribeNewHead(ctx context.Context, ch chan<- *gethTypes.Header) (ethereum.Subscription, error) {

View File

@ -0,0 +1,19 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
testonly = True,
srcs = [
"faulty_mock.go",
"mock.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//proto/eth/v1alpha1:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/event:go_default_library",
"//shared/trieutil:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
],
)

View File

@ -0,0 +1,87 @@
package testing
import (
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/event"
"github.com/prysmaticlabs/prysm/shared/trieutil"
)
// FaultyMockPOWChain defines an incorrectly functioning powchain service.
type FaultyMockPOWChain struct {
ChainFeed *event.Feed
HashesByHeight map[int][]byte
}
// HasChainStarted --
func (f *FaultyMockPOWChain) HasChainStarted() bool {
return false
}
// Eth2GenesisPowchainInfo --
func (f *FaultyMockPOWChain) Eth2GenesisPowchainInfo() (uint64, *big.Int) {
return 0, big.NewInt(0)
}
// ChainStartFeed --
func (f *FaultyMockPOWChain) ChainStartFeed() *event.Feed {
return f.ChainFeed
}
// LatestBlockHeight --
func (f *FaultyMockPOWChain) LatestBlockHeight() *big.Int {
return big.NewInt(0)
}
// BlockExists --
func (f *FaultyMockPOWChain) BlockExists(_ context.Context, hash common.Hash) (bool, *big.Int, error) {
if f.HashesByHeight == nil {
return false, big.NewInt(1), errors.New("failed")
}
return true, big.NewInt(1), nil
}
// BlockHashByHeight --
func (f *FaultyMockPOWChain) BlockHashByHeight(_ context.Context, height *big.Int) (common.Hash, error) {
return [32]byte{}, errors.New("failed")
}
// BlockTimeByHeight --
func (f *FaultyMockPOWChain) BlockTimeByHeight(_ context.Context, height *big.Int) (uint64, error) {
return 0, errors.New("failed")
}
// BlockNumberByTimestamp --
func (f *FaultyMockPOWChain) BlockNumberByTimestamp(_ context.Context, _ uint64) (*big.Int, error) {
return big.NewInt(0), nil
}
// DepositRoot --
func (f *FaultyMockPOWChain) DepositRoot() [32]byte {
return [32]byte{}
}
// DepositTrie --
func (f *FaultyMockPOWChain) DepositTrie() *trieutil.MerkleTrie {
return &trieutil.MerkleTrie{}
}
// ChainStartDeposits --
func (f *FaultyMockPOWChain) ChainStartDeposits() []*ethpb.Deposit {
return []*ethpb.Deposit{}
}
// ChainStartDepositHashes --
func (f *FaultyMockPOWChain) ChainStartDepositHashes() ([][]byte, error) {
return [][]byte{}, errors.New("hashing failed")
}
// ChainStartEth1Data --
func (f *FaultyMockPOWChain) ChainStartEth1Data() *ethpb.Eth1Data {
return &ethpb.Eth1Data{}
}

View File

@ -0,0 +1,106 @@
package testing
import (
"context"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/event"
"github.com/prysmaticlabs/prysm/shared/trieutil"
)
// POWChain defines a properly functioning mock for the powchain service.
type POWChain struct {
ChainFeed *event.Feed
LatestBlockNumber *big.Int
HashesByHeight map[int][]byte
TimesByHeight map[int]uint64
BlockNumberByHeight map[uint64]*big.Int
Eth1Data *ethpb.Eth1Data
GenesisEth1Block *big.Int
}
// ChainStartFeed --
func (m *POWChain) ChainStartFeed() *event.Feed {
return m.ChainFeed
}
// HasChainStarted --
func (m *POWChain) HasChainStarted() bool {
return true
}
// Eth2GenesisPowchainInfo --
func (m *POWChain) Eth2GenesisPowchainInfo() (uint64, *big.Int) {
blk := m.GenesisEth1Block
if blk == nil {
blk = big.NewInt(0)
}
return uint64(time.Unix(0, 0).Unix()), blk
}
// DepositTrie --
func (m *POWChain) DepositTrie() *trieutil.MerkleTrie {
return &trieutil.MerkleTrie{}
}
// BlockExists --
func (m *POWChain) BlockExists(_ context.Context, hash common.Hash) (bool, *big.Int, error) {
// Reverse the map of heights by hash.
heightsByHash := make(map[[32]byte]int)
for k, v := range m.HashesByHeight {
h := bytesutil.ToBytes32(v)
heightsByHash[h] = k
}
val, ok := heightsByHash[hash]
if !ok {
return false, nil, fmt.Errorf("could not fetch height for hash: %#x", hash)
}
return true, big.NewInt(int64(val)), nil
}
// BlockHashByHeight --
func (m *POWChain) BlockHashByHeight(_ context.Context, height *big.Int) (common.Hash, error) {
k := int(height.Int64())
val, ok := m.HashesByHeight[k]
if !ok {
return [32]byte{}, fmt.Errorf("could not fetch hash for height: %v", height)
}
return bytesutil.ToBytes32(val), nil
}
// BlockTimeByHeight --
func (m *POWChain) BlockTimeByHeight(_ context.Context, height *big.Int) (uint64, error) {
h := int(height.Int64())
return m.TimesByHeight[h], nil
}
// BlockNumberByTimestamp --
func (m *POWChain) BlockNumberByTimestamp(_ context.Context, time uint64) (*big.Int, error) {
return m.BlockNumberByHeight[time], nil
}
// DepositRoot --
func (m *POWChain) DepositRoot() [32]byte {
root := []byte("depositroot")
return bytesutil.ToBytes32(root)
}
// ChainStartDeposits --
func (m *POWChain) ChainStartDeposits() []*ethpb.Deposit {
return []*ethpb.Deposit{}
}
// ChainStartDepositHashes --
func (m *POWChain) ChainStartDepositHashes() ([][]byte, error) {
return [][]byte{}, nil
}
// ChainStartEth1Data --
func (m *POWChain) ChainStartEth1Data() *ethpb.Eth1Data {
return m.Eth1Data
}

View File

@ -27,18 +27,17 @@ go_library(
"//beacon-chain/db/kv:go_default_library",
"//beacon-chain/operations:go_default_library",
"//beacon-chain/p2p:go_default_library",
"//beacon-chain/powchain:go_default_library",
"//beacon-chain/sync:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//proto/beacon/rpc/v1:go_default_library",
"//proto/eth/v1alpha1:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/event:go_default_library",
"//shared/hashutil:go_default_library",
"//shared/pagination:go_default_library",
"//shared/params:go_default_library",
"//shared/trieutil:go_default_library",
"//shared/version: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_grpc_ecosystem_go_grpc_middleware//:go_default_library",
"@com_github_grpc_ecosystem_go_grpc_middleware//recovery:go_default_library",
@ -78,7 +77,11 @@ go_test(
"//beacon-chain/core/state:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/operations/testing:go_default_library",
"//beacon-chain/p2p/testing:go_default_library",
"//beacon-chain/powchain/testing:go_default_library",
"//beacon-chain/rpc/testing:go_default_library",
"//beacon-chain/sync/testing:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//proto/beacon/rpc/v1:go_default_library",
"//proto/eth/v1alpha1:go_default_library",
@ -86,11 +89,11 @@ go_test(
"//shared/bytesutil:go_default_library",
"//shared/event:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/hashutil:go_default_library",
"//shared/params:go_default_library",
"//shared/testutil:go_default_library",
"//shared/trieutil:go_default_library",
"//shared/version: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",

View File

@ -5,10 +5,12 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"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"
"github.com/prysmaticlabs/prysm/beacon-chain/operations"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
@ -19,11 +21,12 @@ import (
// 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.Database
operationService operationService
chainService chainService
cache *cache.AttestationCache
p2p p2p.Broadcaster
beaconDB db.Database
operationsHandler operations.Handler
attReceiver blockchain.AttestationReceiver
headFetcher blockchain.HeadFetcher
depositCache *cache.AttestationCache
}
// SubmitAttestation is a function called by an attester in a sharding validator to vote
@ -34,12 +37,12 @@ func (as *AttesterServer) SubmitAttestation(ctx context.Context, att *ethpb.Atte
return nil, errors.Wrap(err, "failed to sign root attestation")
}
if err := as.operationService.HandleAttestation(ctx, att); err != nil {
if err := as.operationsHandler.HandleAttestation(ctx, att); err != nil {
return nil, err
}
go func() {
if err := as.chainService.ReceiveAttestation(ctx, att); err != nil {
if err := as.attReceiver.ReceiveAttestation(ctx, att); err != nil {
log.WithError(err).Error("could not receive attestation in chain service")
}
}()
@ -56,7 +59,7 @@ func (as *AttesterServer) RequestAttestation(ctx context.Context, req *pb.Attest
trace.Int64Attribute("slot", int64(req.Slot)),
trace.Int64Attribute("shard", int64(req.Shard)),
)
res, err := as.cache.Get(ctx, req)
res, err := as.depositCache.Get(ctx, req)
if err != nil {
return nil, err
}
@ -65,9 +68,9 @@ func (as *AttesterServer) RequestAttestation(ctx context.Context, req *pb.Attest
return res, nil
}
if err := as.cache.MarkInProgress(req); err != nil {
if err := as.depositCache.MarkInProgress(req); err != nil {
if err == cache.ErrAlreadyInProgress {
res, err := as.cache.Get(ctx, req)
res, err := as.depositCache.Get(ctx, req)
if err != nil {
return nil, err
}
@ -80,13 +83,13 @@ func (as *AttesterServer) RequestAttestation(ctx context.Context, req *pb.Attest
return nil, err
}
defer func() {
if err := as.cache.MarkNotInProgress(req); err != nil {
if err := as.depositCache.MarkNotInProgress(req); err != nil {
log.WithError(err).Error("Failed to mark cache not in progress")
}
}()
headState := as.chainService.HeadState()
headRoot := as.chainService.HeadRoot()
headState := as.headFetcher.HeadState()
headRoot := as.headFetcher.HeadRoot()
headState, err = state.ProcessSlots(ctx, headState, req.Slot)
if err != nil {
@ -130,7 +133,7 @@ func (as *AttesterServer) RequestAttestation(ctx context.Context, req *pb.Attest
},
}
if err := as.cache.Put(ctx, req, res); err != nil {
if err := as.depositCache.Put(ctx, req, res); err != nil {
return nil, err
}

View File

@ -11,6 +11,8 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
mockOps "github.com/prysmaticlabs/prysm/beacon-chain/operations/testing"
mockp2p "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
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"
@ -18,24 +20,18 @@ import (
"github.com/prysmaticlabs/prysm/shared/params"
)
type mockBroadcaster struct{}
func (m *mockBroadcaster) Broadcast(ctx context.Context, msg proto.Message) error {
return nil
}
func TestSubmitAttestation_OK(t *testing.T) {
db := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, db)
ctx := context.Background()
mockOperationService := &mockOperationService{}
attesterServer := &AttesterServer{
chainService: &mock.ChainService{},
operationService: mockOperationService,
p2p: &mockBroadcaster{},
beaconDB: db,
cache: cache.NewAttestationCache(),
headFetcher: &mock.ChainService{},
attReceiver: &mock.ChainService{},
operationsHandler: &mockOps.Operations{},
p2p: &mockp2p.MockBroadcaster{},
beaconDB: db,
depositCache: cache.NewAttestationCache(),
}
head := &ethpb.BeaconBlock{
Slot: 999,
@ -132,9 +128,10 @@ func TestRequestAttestation_OK(t *testing.T) {
beaconState.BlockRoots[1*params.BeaconConfig().SlotsPerEpoch] = targetRoot[:]
beaconState.BlockRoots[2*params.BeaconConfig().SlotsPerEpoch] = justifiedRoot[:]
attesterServer := &AttesterServer{
p2p: &mockBroadcaster{},
cache: cache.NewAttestationCache(),
chainService: &mock.ChainService{State: beaconState, Root: blockRoot[:]},
p2p: &mockp2p.MockBroadcaster{},
depositCache: cache.NewAttestationCache(),
headFetcher: &mock.ChainService{State: beaconState, Root: blockRoot[:]},
attReceiver: &mock.ChainService{State: beaconState, Root: blockRoot[:]},
}
req := &pb.AttestationRequest{
@ -232,9 +229,10 @@ func TestAttestationDataAtSlot_handlesFarAwayJustifiedEpoch(t *testing.T) {
beaconState.BlockRoots[1*params.BeaconConfig().SlotsPerEpoch] = epochBoundaryRoot[:]
beaconState.BlockRoots[2*params.BeaconConfig().SlotsPerEpoch] = justifiedBlockRoot[:]
attesterServer := &AttesterServer{
p2p: &mockBroadcaster{},
cache: cache.NewAttestationCache(),
chainService: &mock.ChainService{State: beaconState, Root: blockRoot[:]},
p2p: &mockp2p.MockBroadcaster{},
depositCache: cache.NewAttestationCache(),
headFetcher: &mock.ChainService{State: beaconState, Root: blockRoot[:]},
attReceiver: &mock.ChainService{State: beaconState, Root: blockRoot[:]},
}
req := &pb.AttestationRequest{
@ -283,7 +281,7 @@ func TestAttestationDataAtSlot_handlesInProgressRequest(t *testing.T) {
ctx := context.Background()
server := &AttesterServer{
cache: cache.NewAttestationCache(),
depositCache: cache.NewAttestationCache(),
}
req := &pb.AttestationRequest{
@ -295,7 +293,7 @@ func TestAttestationDataAtSlot_handlesInProgressRequest(t *testing.T) {
Target: &ethpb.Checkpoint{Epoch: 55},
}
if err := server.cache.MarkInProgress(req); err != nil {
if err := server.depositCache.MarkInProgress(req); err != nil {
t.Fatal(err)
}
@ -317,10 +315,10 @@ func TestAttestationDataAtSlot_handlesInProgressRequest(t *testing.T) {
go func() {
defer wg.Done()
if err := server.cache.Put(ctx, req, res); err != nil {
if err := server.depositCache.Put(ctx, req, res); err != nil {
t.Error(err)
}
if err := server.cache.MarkNotInProgress(req); err != nil {
if err := server.depositCache.MarkNotInProgress(req); err != nil {
t.Error(err)
}
}()

View File

@ -24,9 +24,9 @@ import (
// providing RPC endpoints to access data relevant to the Ethereum 2.0 phase 0
// beacon chain.
type BeaconChainServer struct {
beaconDB db.Database
chainService blockchain.HeadRetriever
pool operations.Pool
beaconDB db.Database
headFetcher blockchain.HeadFetcher
pool operations.Pool
}
// sortableAttestations implements the Sort interface to sort attestations
@ -197,13 +197,13 @@ func (bs *BeaconChainServer) ListBlocks(
// This includes the head block slot and root as well as information about
// the most recent finalized and justified slots.
func (bs *BeaconChainServer) GetChainHead(ctx context.Context, _ *ptypes.Empty) (*ethpb.ChainHead, error) {
finalizedCheckpoint := bs.chainService.HeadState().FinalizedCheckpoint
justifiedCheckpoint := bs.chainService.HeadState().CurrentJustifiedCheckpoint
prevJustifiedCheckpoint := bs.chainService.HeadState().PreviousJustifiedCheckpoint
finalizedCheckpoint := bs.headFetcher.HeadState().FinalizedCheckpoint
justifiedCheckpoint := bs.headFetcher.HeadState().CurrentJustifiedCheckpoint
prevJustifiedCheckpoint := bs.headFetcher.HeadState().PreviousJustifiedCheckpoint
return &ethpb.ChainHead{
BlockRoot: bs.chainService.HeadRoot(),
BlockSlot: bs.chainService.HeadSlot(),
BlockRoot: bs.headFetcher.HeadRoot(),
BlockSlot: bs.headFetcher.HeadSlot(),
FinalizedBlockRoot: finalizedCheckpoint.Root,
FinalizedSlot: finalizedCheckpoint.Epoch * params.BeaconConfig().SlotsPerEpoch,
JustifiedBlockRoot: justifiedCheckpoint.Root,
@ -460,7 +460,7 @@ func (bs *BeaconChainServer) GetValidatorParticipation(
ctx context.Context, req *ethpb.GetValidatorParticipationRequest,
) (*ethpb.ValidatorParticipation, error) {
headState := bs.chainService.HeadState()
headState := bs.headFetcher.HeadState()
currentEpoch := helpers.SlotToEpoch(headState.Slot)
finalized := currentEpoch == headState.FinalizedCheckpoint.Epoch

View File

@ -17,28 +17,12 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
testutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
mockOps "github.com/prysmaticlabs/prysm/beacon-chain/operations/testing"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params"
)
type mockPool struct{}
func (m *mockPool) AttestationPool(ctx context.Context, expectedSlot uint64) ([]*ethpb.Attestation, error) {
return []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
BeaconBlockRoot: []byte("1"),
},
},
{
Data: &ethpb.AttestationData{
BeaconBlockRoot: []byte("2"),
},
},
}, nil
}
func TestBeaconChainServer_ListAttestationsNoPagination(t *testing.T) {
db := testutil.SetupDB(t)
defer testutil.TeardownDB(t, db)
@ -259,7 +243,20 @@ func TestBeaconChainServer_AttestationPool(t *testing.T) {
db := testutil.SetupDB(t)
defer testutil.TeardownDB(t, db)
bs := &BeaconChainServer{
pool: &mockPool{},
pool: &mockOps.Operations{
Attestations: []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
BeaconBlockRoot: []byte("1"),
},
},
{
Data: &ethpb.AttestationData{
BeaconBlockRoot: []byte("2"),
},
},
},
},
beaconDB: db,
}
block := &ethpb.BeaconBlock{
@ -806,8 +803,8 @@ func TestBeaconChainServer_GetValidatorsParticipation(t *testing.T) {
}
bs := &BeaconChainServer{
beaconDB: db,
chainService: &mock.ChainService{State: s},
beaconDB: db,
headFetcher: &mock.ChainService{State: s},
}
res, err := bs.GetValidatorParticipation(ctx, &ethpb.GetValidatorParticipationRequest{Epoch: epoch})
@ -1000,7 +997,7 @@ func TestBeaconChainServer_GetChainHead(t *testing.T) {
FinalizedCheckpoint: &ethpb.Checkpoint{Epoch: 1, Root: []byte{'C'}},
}
bs := &BeaconChainServer{chainService: &mock.ChainService{State: s}}
bs := &BeaconChainServer{headFetcher: &mock.ChainService{State: s}}
head, err := bs.GetChainHead(context.Background(), nil)
if err != nil {

View File

@ -8,6 +8,7 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
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"
@ -22,9 +23,10 @@ import (
type BeaconServer struct {
beaconDB db.Database
ctx context.Context
powChainService powChainService
chainService chainService
operationService operationService
chainStartFetcher powchain.ChainStartFetcher
eth1InfoFetcher powchain.ChainInfoFetcher
headFetcher blockchain.HeadFetcher
stateFeedListener blockchain.ChainFeeds
incomingAttestation chan *ethpb.Attestation
canonicalStateChan chan *pbp2p.BeaconState
chainStartChan chan time.Time
@ -35,11 +37,9 @@ type BeaconServer struct {
// 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()
ok := bs.chainStartFetcher.HasChainStarted()
if ok {
genesisTime, _ := bs.powChainService.ETH2GenesisTime()
genesisTime, _ := bs.eth1InfoFetcher.Eth2GenesisPowchainInfo()
res := &pb.ChainStartResponse{
Started: true,
GenesisTime: genesisTime,
@ -47,7 +47,7 @@ func (bs *BeaconServer) WaitForChainStart(req *ptypes.Empty, stream pb.BeaconSer
return stream.Send(res)
}
sub := bs.chainService.StateInitializedFeed().Subscribe(bs.chainStartChan)
sub := bs.stateFeedListener.StateInitializedFeed().Subscribe(bs.chainStartChan)
defer sub.Unsubscribe()
for {
select {
@ -69,8 +69,7 @@ func (bs *BeaconServer) WaitForChainStart(req *ptypes.Empty, stream pb.BeaconSer
// 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) {
headBlock := bs.chainService.(blockchain.HeadRetriever).HeadBlock()
return headBlock, nil
return bs.headFetcher.HeadBlock(), nil
}
// BlockTree returns the current tree of saved blocks and their votes starting from the justified state.

View File

@ -2,186 +2,37 @@ package rpc
import (
"context"
"errors"
"fmt"
"math/big"
"strings"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
ptypes "github.com/gogo/protobuf/types"
"github.com/golang/mock/gomock"
mockClient "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
mockRPC "github.com/prysmaticlabs/prysm/beacon-chain/rpc/testing"
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/event"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/shared/trieutil"
logTest "github.com/sirupsen/logrus/hooks/test"
)
var closedContext = "context closed"
var mockSig [96]byte
var mockCreds [32]byte
type faultyPOWChainService struct {
chainStartFeed *event.Feed
hashesByHeight map[int][]byte
}
func (f *faultyPOWChainService) HasChainStarted() bool {
return false
}
func (f *faultyPOWChainService) ETH2GenesisTime() (uint64, *big.Int) {
return 0, big.NewInt(0)
}
func (f *faultyPOWChainService) ChainStartFeed() *event.Feed {
return f.chainStartFeed
}
func (f *faultyPOWChainService) LatestBlockHeight() *big.Int {
return big.NewInt(0)
}
func (f *faultyPOWChainService) BlockExists(_ context.Context, hash common.Hash) (bool, *big.Int, error) {
if f.hashesByHeight == nil {
return false, big.NewInt(1), errors.New("failed")
}
return true, big.NewInt(1), nil
}
func (f *faultyPOWChainService) BlockHashByHeight(_ context.Context, height *big.Int) (common.Hash, error) {
return [32]byte{}, errors.New("failed")
}
func (f *faultyPOWChainService) BlockTimeByHeight(_ context.Context, height *big.Int) (uint64, error) {
return 0, errors.New("failed")
}
func (f *faultyPOWChainService) BlockNumberByTimestamp(_ context.Context, _ uint64) (*big.Int, error) {
return big.NewInt(0), nil
}
func (f *faultyPOWChainService) DepositRoot() [32]byte {
return [32]byte{}
}
func (f *faultyPOWChainService) DepositTrie() *trieutil.MerkleTrie {
return &trieutil.MerkleTrie{}
}
func (f *faultyPOWChainService) ChainStartDeposits() []*ethpb.Deposit {
return []*ethpb.Deposit{}
}
func (f *faultyPOWChainService) ChainStartDepositHashes() ([][]byte, error) {
return [][]byte{}, errors.New("hashing failed")
}
func (f *faultyPOWChainService) ChainStartETH1Data() *ethpb.Eth1Data {
return &ethpb.Eth1Data{}
}
type mockPOWChainService struct {
chainStartFeed *event.Feed
latestBlockNumber *big.Int
hashesByHeight map[int][]byte
blockTimeByHeight map[int]uint64
blockNumberByHeight map[uint64]*big.Int
eth1Data *ethpb.Eth1Data
genesisEth1Block *big.Int
}
func (m *mockPOWChainService) HasChainStarted() bool {
return true
}
func (m *mockPOWChainService) ETH2GenesisTime() (uint64, *big.Int) {
blk := m.genesisEth1Block
if blk == nil {
blk = big.NewInt(0)
}
return uint64(time.Unix(0, 0).Unix()), blk
}
func (m *mockPOWChainService) ChainStartFeed() *event.Feed {
return m.chainStartFeed
}
func (m *mockPOWChainService) LatestBlockHeight() *big.Int {
return m.latestBlockNumber
}
func (m *mockPOWChainService) DepositTrie() *trieutil.MerkleTrie {
return &trieutil.MerkleTrie{}
}
func (m *mockPOWChainService) BlockExists(_ context.Context, hash common.Hash) (bool, *big.Int, error) {
// Reverse the map of heights by hash.
heightsByHash := make(map[[32]byte]int)
for k, v := range m.hashesByHeight {
h := bytesutil.ToBytes32(v)
heightsByHash[h] = k
}
val, ok := heightsByHash[hash]
if !ok {
return false, nil, fmt.Errorf("could not fetch height for hash: %#x", hash)
}
return true, big.NewInt(int64(val)), nil
}
func (m *mockPOWChainService) BlockHashByHeight(_ context.Context, height *big.Int) (common.Hash, error) {
k := int(height.Int64())
val, ok := m.hashesByHeight[k]
if !ok {
return [32]byte{}, fmt.Errorf("could not fetch hash for height: %v", height)
}
return bytesutil.ToBytes32(val), nil
}
func (m *mockPOWChainService) BlockTimeByHeight(_ context.Context, height *big.Int) (uint64, error) {
h := int(height.Int64())
return m.blockTimeByHeight[h], nil
}
func (m *mockPOWChainService) BlockNumberByTimestamp(_ context.Context, time uint64) (*big.Int, error) {
return m.blockNumberByHeight[time], nil
}
func (m *mockPOWChainService) DepositRoot() [32]byte {
root := []byte("depositroot")
return bytesutil.ToBytes32(root)
}
func (m *mockPOWChainService) ChainStartDeposits() []*ethpb.Deposit {
return []*ethpb.Deposit{}
}
func (m *mockPOWChainService) ChainStartDepositHashes() ([][]byte, error) {
return [][]byte{}, nil
}
func (m *mockPOWChainService) ChainStartETH1Data() *ethpb.Eth1Data {
return m.eth1Data
}
func TestWaitForChainStart_ContextClosed(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
beaconServer := &BeaconServer{
ctx: ctx,
powChainService: &faultyPOWChainService{
chainStartFeed: new(event.Feed),
chainStartFetcher: &mockPOW.FaultyMockPOWChain{
ChainFeed: new(event.Feed),
},
chainService: &mockClient.ChainService{},
eth1InfoFetcher: &mockPOW.POWChain{},
stateFeedListener: &mockChain.ChainService{},
}
exitRoutine := make(chan bool)
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockStream := mockRPC.NewMockBeaconService_WaitForChainStartServer(ctrl)
go func(tt *testing.T) {
if err := beaconServer.WaitForChainStart(&ptypes.Empty{}, mockStream); !strings.Contains(err.Error(), closedContext) {
if err := beaconServer.WaitForChainStart(&ptypes.Empty{}, mockStream); !strings.Contains(err.Error(), "context closed") {
tt.Errorf("Could not call RPC method: %v", err)
}
<-exitRoutine
@ -193,10 +44,11 @@ func TestWaitForChainStart_ContextClosed(t *testing.T) {
func TestWaitForChainStart_AlreadyStarted(t *testing.T) {
beaconServer := &BeaconServer{
ctx: context.Background(),
powChainService: &mockPOWChainService{
chainStartFeed: new(event.Feed),
chainStartFetcher: &mockPOW.POWChain{
ChainFeed: new(event.Feed),
},
chainService: &mockClient.ChainService{},
eth1InfoFetcher: &mockPOW.POWChain{},
stateFeedListener: &mockChain.ChainService{},
}
ctrl := gomock.NewController(t)
defer ctrl.Finish()
@ -217,10 +69,11 @@ func TestWaitForChainStart_NotStartedThenLogFired(t *testing.T) {
beaconServer := &BeaconServer{
ctx: context.Background(),
chainStartChan: make(chan time.Time, 1),
powChainService: &faultyPOWChainService{
chainStartFeed: new(event.Feed),
chainStartFetcher: &mockPOW.FaultyMockPOWChain{
ChainFeed: new(event.Feed),
},
chainService: &mockClient.ChainService{},
eth1InfoFetcher: &mockPOW.POWChain{},
stateFeedListener: &mockChain.ChainService{},
}
exitRoutine := make(chan bool)
ctrl := gomock.NewController(t)

View File

@ -7,15 +7,19 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
"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/db"
"github.com/prysmaticlabs/prysm/beacon-chain/operations"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
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/params"
"github.com/prysmaticlabs/prysm/shared/trieutil"
"github.com/sirupsen/logrus"
@ -27,9 +31,13 @@ import (
// beacon blocks to a beacon node, and more.
type ProposerServer struct {
beaconDB db.Database
chainService chainService
powChainService powChainService
operationService operationService
headFetcher blockchain.HeadFetcher
blockReceiver blockchain.BlockReceiver
mockEth1Votes bool
chainStartFetcher powchain.ChainStartFetcher
eth1InfoFetcher powchain.ChainInfoFetcher
eth1BlockFetcher powchain.POWBlockFetcher
pool operations.Pool
canonicalStateChan chan *pbp2p.BeaconState
depositCache *depositcache.DepositCache
}
@ -42,15 +50,13 @@ func (ps *ProposerServer) RequestBlock(ctx context.Context, req *pb.BlockRequest
span.AddAttributes(trace.Int64Attribute("slot", int64(req.Slot)))
// Retrieve the parent block as the current head of the canonical chain
parent := ps.chainService.HeadBlock()
parent := ps.headFetcher.HeadBlock()
parentRoot, err := ssz.SigningRoot(parent)
if err != nil {
return nil, errors.Wrap(err, "could not get parent block signing root")
}
// Construct block body
// Pack ETH1 deposits which have not been included in the beacon chain
eth1Data, err := ps.eth1Data(ctx, req.Slot)
if err != nil {
return nil, errors.Wrap(err, "could not get ETH1 data")
@ -114,8 +120,7 @@ func (ps *ProposerServer) ProposeBlock(ctx context.Context, blk *ethpb.BeaconBlo
}
log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(root[:]))).Debugf(
"Block proposal received via RPC")
if err := ps.chainService.ReceiveBlock(ctx, blk); err != nil {
if err := ps.blockReceiver.ReceiveBlock(ctx, blk); err != nil {
return nil, errors.Wrap(err, "could not process beacon block")
}
@ -128,15 +133,15 @@ func (ps *ProposerServer) ProposeBlock(ctx context.Context, blk *ethpb.BeaconBlo
// 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, expectedSlot uint64) ([]*ethpb.Attestation, error) {
headState := ps.chainService.HeadState()
atts, err := ps.operationService.AttestationPool(ctx, expectedSlot)
beaconState := ps.headFetcher.HeadState()
atts, err := ps.pool.AttestationPool(ctx, expectedSlot)
if err != nil {
return nil, errors.Wrap(err, "could not retrieve pending attestations from operations service")
}
// advance slot, if it is behind
if headState.Slot < expectedSlot {
headState, err = state.ProcessSlots(ctx, headState, expectedSlot)
if beaconState.Slot < expectedSlot {
beaconState, err = state.ProcessSlots(ctx, beaconState, expectedSlot)
if err != nil {
return nil, err
}
@ -144,24 +149,24 @@ func (ps *ProposerServer) attestations(ctx context.Context, expectedSlot uint64)
var attsReadyForInclusion []*ethpb.Attestation
for _, att := range atts {
slot, err := helpers.AttestationDataSlot(headState, att.Data)
slot, err := helpers.AttestationDataSlot(beaconState, att.Data)
if err != nil {
return nil, errors.Wrap(err, "could not get attestation slot")
}
if slot+params.BeaconConfig().MinAttestationInclusionDelay <= headState.Slot &&
headState.Slot <= slot+params.BeaconConfig().SlotsPerEpoch {
if slot+params.BeaconConfig().MinAttestationInclusionDelay <= beaconState.Slot &&
beaconState.Slot <= slot+params.BeaconConfig().SlotsPerEpoch {
attsReadyForInclusion = append(attsReadyForInclusion, att)
}
}
validAtts := make([]*ethpb.Attestation, 0, len(attsReadyForInclusion))
for _, att := range attsReadyForInclusion {
slot, err := helpers.AttestationDataSlot(headState, att.Data)
slot, err := helpers.AttestationDataSlot(beaconState, att.Data)
if err != nil {
return nil, errors.Wrap(err, "could not get attestation slot")
}
if _, err := blocks.ProcessAttestationNoVerify(headState, att); err != nil {
if _, err := blocks.ProcessAttestationNoVerify(beaconState, att); err != nil {
if ctx.Err() != nil {
return nil, ctx.Err()
}
@ -175,7 +180,6 @@ func (ps *ProposerServer) attestations(ctx context.Context, expectedSlot uint64)
if err != nil {
return nil, err
}
if err := ps.beaconDB.DeleteAttestation(ctx, root); err != nil {
return nil, errors.Wrap(err, "could not delete failed attestation")
}
@ -194,11 +198,39 @@ func (ps *ProposerServer) attestations(ctx context.Context, expectedSlot uint64)
// - Subtract that eth1block.number by ETH1_FOLLOW_DISTANCE.
// - This is the eth1block to use for the block proposal.
func (ps *ProposerServer) eth1Data(ctx context.Context, slot uint64) (*ethpb.Eth1Data, error) {
eth1VotingPeriodStartTime, _ := ps.powChainService.ETH2GenesisTime()
if ps.mockEth1Votes {
// If a mock eth1 data votes is specified, we use the following for the
// eth1data we provide to every proposer based on https://github.com/ethereum/eth2.0-pm/issues/62:
//
// slot_in_voting_period = current_slot % SLOTS_PER_ETH1_VOTING_PERIOD
// Eth1Data(
// DepositRoot = hash(current_epoch + slot_in_voting_period),
// DepositCount = state.eth1_deposit_index,
// BlockHash = hash(hash(current_epoch + slot_in_voting_period)),
// )
slotInVotingPeriod := slot % params.BeaconConfig().SlotsPerEth1VotingPeriod
headState, err := ps.beaconDB.HeadState(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not get head state")
}
enc, err := ssz.Marshal(helpers.SlotToEpoch(slot) + slotInVotingPeriod)
if err != nil {
return nil, err
}
depRoot := hashutil.Hash(enc)
blockHash := hashutil.Hash(depRoot[:])
return &ethpb.Eth1Data{
DepositRoot: depRoot[:],
DepositCount: headState.Eth1DepositIndex,
BlockHash: blockHash[:],
}, nil
}
eth1VotingPeriodStartTime, _ := ps.eth1InfoFetcher.Eth2GenesisPowchainInfo()
eth1VotingPeriodStartTime += (slot - (slot % params.BeaconConfig().SlotsPerEth1VotingPeriod)) * params.BeaconConfig().SecondsPerSlot
// Look up most recent block up to timestamp
blockNumber, err := ps.powChainService.BlockNumberByTimestamp(ctx, eth1VotingPeriodStartTime)
blockNumber, err := ps.eth1BlockFetcher.BlockNumberByTimestamp(ctx, eth1VotingPeriodStartTime)
if err != nil {
return nil, err
}
@ -239,14 +271,13 @@ func (ps *ProposerServer) computeStateRoot(ctx context.Context, block *ethpb.Bea
func (ps *ProposerServer) deposits(ctx context.Context, currentVote *ethpb.Eth1Data) ([]*ethpb.Deposit, error) {
// 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.
headState := ps.chainService.HeadState()
canonicalEth1Data, latestEth1DataHeight, err := ps.canonicalEth1Data(ctx, headState, currentVote)
beaconState := ps.headFetcher.HeadState()
canonicalEth1Data, latestEth1DataHeight, err := ps.canonicalEth1Data(ctx, beaconState, currentVote)
if err != nil {
return nil, err
}
_, genesisEth1Block := ps.powChainService.ETH2GenesisTime()
_, genesisEth1Block := ps.eth1InfoFetcher.Eth2GenesisPowchainInfo()
if genesisEth1Block.Cmp(latestEth1DataHeight) == 0 {
return []*ethpb.Deposit{}, nil
}
@ -272,7 +303,7 @@ func (ps *ProposerServer) deposits(ctx context.Context, currentVote *ethpb.Eth1D
// deposits are sorted from lowest to highest.
var pendingDeps []*depositcache.DepositContainer
for _, dep := range allPendingContainers {
if uint64(dep.Index) >= headState.Eth1DepositIndex && uint64(dep.Index) < canonicalEth1Data.DepositCount {
if uint64(dep.Index) >= beaconState.Eth1DepositIndex && uint64(dep.Index) < canonicalEth1Data.DepositCount {
pendingDeps = append(pendingDeps, dep)
}
}
@ -313,7 +344,7 @@ func (ps *ProposerServer) canonicalEth1Data(ctx context.Context, beaconState *pb
canonicalEth1Data = beaconState.Eth1Data
eth1BlockHash = bytesutil.ToBytes32(beaconState.Eth1Data.BlockHash)
}
_, latestEth1DataHeight, err := ps.powChainService.BlockExists(ctx, eth1BlockHash)
_, latestEth1DataHeight, err := ps.eth1BlockFetcher.BlockExists(ctx, eth1BlockHash)
if err != nil {
return nil, nil, errors.Wrap(err, "could not fetch eth1data height")
}
@ -327,14 +358,14 @@ func (ps *ProposerServer) canonicalEth1Data(ctx context.Context, beaconState *pb
func (ps *ProposerServer) defaultEth1DataResponse(ctx context.Context, currentHeight *big.Int) (*ethpb.Eth1Data, error) {
eth1FollowDistance := int64(params.BeaconConfig().Eth1FollowDistance)
ancestorHeight := big.NewInt(0).Sub(currentHeight, big.NewInt(eth1FollowDistance))
blockHash, err := ps.powChainService.BlockHashByHeight(ctx, ancestorHeight)
blockHash, err := ps.eth1BlockFetcher.BlockHashByHeight(ctx, ancestorHeight)
if err != nil {
return nil, errors.Wrap(err, "could not fetch ETH1_FOLLOW_DISTANCE ancestor")
}
// Fetch all historical deposits up to an ancestor height.
depositsTillHeight, depositRoot := ps.depositCache.DepositsNumberAndRootAtHeight(ctx, ancestorHeight)
if depositsTillHeight == 0 {
return ps.powChainService.ChainStartETH1Data(), nil
return ps.chainStartFetcher.ChainStartEth1Data(), nil
}
return &ethpb.Eth1Data{
DepositRoot: depositRoot[:],

View File

@ -17,9 +17,12 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
mockOps "github.com/prysmaticlabs/prysm/beacon-chain/operations/testing"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/shared/trieutil"
@ -60,9 +63,12 @@ func TestProposeBlock_OK(t *testing.T) {
}
proposerServer := &ProposerServer{
beaconDB: db,
powChainService: &mockPOWChainService{},
chainService: &mock.ChainService{},
beaconDB: db,
chainStartFetcher: &mockPOW.POWChain{},
eth1InfoFetcher: &mockPOW.POWChain{},
eth1BlockFetcher: &mockPOW.POWChain{},
blockReceiver: &mock.ChainService{},
headFetcher: &mock.ChainService{},
}
req := &ethpb.BeaconBlock{
Slot: 5,
@ -113,8 +119,10 @@ func TestComputeStateRoot_OK(t *testing.T) {
}
proposerServer := &ProposerServer{
beaconDB: db,
powChainService: &mockPOWChainService{},
beaconDB: db,
chainStartFetcher: &mockPOW.POWChain{},
eth1InfoFetcher: &mockPOW.POWChain{},
eth1BlockFetcher: &mockPOW.POWChain{},
}
req := &ethpb.BeaconBlock{
@ -256,10 +264,11 @@ func TestPendingAttestations_FiltersWithinInclusionDelay(t *testing.T) {
}
proposerServer := &ProposerServer{
operationService: &mockOperationService{
pendingAttestations: []*ethpb.Attestation{att},
pool: &mockOps.Operations{
Attestations: []*ethpb.Attestation{att},
},
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
atts, err := proposerServer.attestations(context.Background(), stateSlot)
@ -375,8 +384,8 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
att2 := proto.Clone(att).(*ethpb.Attestation)
att3 := proto.Clone(att).(*ethpb.Attestation)
opService := &mockOperationService{
pendingAttestations: []*ethpb.Attestation{
opService := &mockOps.Operations{
Attestations: []*ethpb.Attestation{
//Expired attestations
{
Data: &ethpb.AttestationData{
@ -448,9 +457,10 @@ func TestPendingAttestations_FiltersExpiredAttestations(t *testing.T) {
expectedNumberOfAttestations := 3
proposerServer := &ProposerServer{
beaconDB: db,
operationService: opService,
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
beaconDB: db,
pool: opService,
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
atts, err := proposerServer.attestations(context.Background(), currentSlot+params.BeaconConfig().MinAttestationInclusionDelay+1)
@ -507,9 +517,9 @@ func TestPendingDeposits_Eth1DataVoteOK(t *testing.T) {
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
newHeight := big.NewInt(height.Int64() + 11000)
p := &mockPOWChainService{
latestBlockNumber: height,
hashesByHeight: map[int][]byte{
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
int(newHeight.Int64()): []byte("0x1"),
},
@ -544,12 +554,15 @@ func TestPendingDeposits_Eth1DataVoteOK(t *testing.T) {
}
bs := &ProposerServer{
powChainService: p,
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
// It should also return the recent deposits after their follow window.
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
_, eth1Height, err := bs.canonicalEth1Data(ctx, beaconState, &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)
@ -596,9 +609,9 @@ func TestPendingDeposits_OutsideEth1FollowWindow(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOWChainService{
latestBlockNumber: height,
hashesByHeight: map[int][]byte{
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
@ -690,9 +703,12 @@ func TestPendingDeposits_OutsideEth1FollowWindow(t *testing.T) {
}
bs := &ProposerServer{
powChainService: p,
depositCache: depositCache,
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
depositCache: depositCache,
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
deposits, err := bs.deposits(ctx, &ethpb.Eth1Data{})
@ -705,7 +721,7 @@ func TestPendingDeposits_OutsideEth1FollowWindow(t *testing.T) {
// It should not return the recent deposits after their follow window.
// as latest block number makes no difference in retrieval of deposits
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err = bs.deposits(ctx, &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)
@ -724,9 +740,9 @@ func TestPendingDeposits_FollowsCorrectEth1Block(t *testing.T) {
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
newHeight := big.NewInt(height.Int64() + 11000)
p := &mockPOWChainService{
latestBlockNumber: height,
hashesByHeight: map[int][]byte{
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
int(newHeight.Int64()): []byte("0x1"),
},
@ -830,9 +846,12 @@ func TestPendingDeposits_FollowsCorrectEth1Block(t *testing.T) {
}
bs := &ProposerServer{
powChainService: p,
depositCache: depositCache,
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
depositCache: depositCache,
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
deposits, err := bs.deposits(ctx, &ethpb.Eth1Data{})
@ -844,7 +863,7 @@ func TestPendingDeposits_FollowsCorrectEth1Block(t *testing.T) {
}
// It should also return the recent deposits after their follow window.
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
// we should get our pending deposits once this vote pushes the vote tally to include
// the updated eth1 data.
deposits, err = bs.deposits(ctx, vote)
@ -863,9 +882,9 @@ func TestPendingDeposits_FollowsCorrectEth1Block(t *testing.T) {
func TestPendingDeposits_CantReturnBelowStateEth1DepositIndex(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOWChainService{
latestBlockNumber: height,
hashesByHeight: map[int][]byte{
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
@ -943,13 +962,16 @@ func TestPendingDeposits_CantReturnBelowStateEth1DepositIndex(t *testing.T) {
}
bs := &ProposerServer{
powChainService: p,
depositCache: depositCache,
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
depositCache: depositCache,
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
// It should also return the recent deposits after their follow window.
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err := bs.deposits(ctx, &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)
@ -969,9 +991,9 @@ func TestPendingDeposits_CantReturnMoreThanMax(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOWChainService{
latestBlockNumber: height,
hashesByHeight: map[int][]byte{
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
@ -1048,13 +1070,16 @@ func TestPendingDeposits_CantReturnMoreThanMax(t *testing.T) {
}
bs := &ProposerServer{
powChainService: p,
depositCache: depositCache,
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
depositCache: depositCache,
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
// It should also return the recent deposits after their follow window.
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err := bs.deposits(ctx, &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)
@ -1072,9 +1097,9 @@ func TestPendingDeposits_CantReturnMoreDepositCount(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOWChainService{
latestBlockNumber: height,
hashesByHeight: map[int][]byte{
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
@ -1151,13 +1176,16 @@ func TestPendingDeposits_CantReturnMoreDepositCount(t *testing.T) {
}
bs := &ProposerServer{
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
powChainService: p,
depositCache: depositCache,
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
depositCache: depositCache,
}
// It should also return the recent deposits after their follow window.
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err := bs.deposits(ctx, &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)
@ -1178,11 +1206,15 @@ func TestEth1Data_EmptyVotesFetchBlockHashFailure(t *testing.T) {
},
Eth1DataVotes: []*ethpb.Eth1Data{},
}
p := &mockPOW.FaultyMockPOWChain{
HashesByHeight: make(map[int][]byte),
}
proposerServer := &ProposerServer{
powChainService: &faultyPOWChainService{
hashesByHeight: make(map[int][]byte),
},
chainService: &mock.ChainService{State: beaconState},
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
blockReceiver: &mock.ChainService{State: beaconState},
headFetcher: &mock.ChainService{State: beaconState},
}
want := "could not fetch ETH1_FOLLOW_DISTANCE ancestor"
if _, err := proposerServer.eth1Data(context.Background(), beaconState.Slot+1); !strings.Contains(err.Error(), want) {
@ -1201,8 +1233,8 @@ func TestDefaultEth1Data_NoBlockExists(t *testing.T) {
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: []byte("a"),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
},
{
@ -1211,8 +1243,8 @@ func TestDefaultEth1Data_NoBlockExists(t *testing.T) {
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: []byte("b"),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
},
}
@ -1225,16 +1257,18 @@ func TestDefaultEth1Data_NoBlockExists(t *testing.T) {
depositCache.InsertDeposit(context.Background(), dp.Deposit, dp.Block, dp.Index, depositTrie.Root())
}
powChainService := &mockPOWChainService{
latestBlockNumber: height,
hashesByHeight: map[int][]byte{
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
0: []byte("hash0"),
476: []byte("hash1024"),
},
}
proposerServer := &ProposerServer{
powChainService: powChainService,
depositCache: depositCache,
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
depositCache: depositCache,
}
defEth1Data := &ethpb.Eth1Data{
@ -1243,7 +1277,7 @@ func TestDefaultEth1Data_NoBlockExists(t *testing.T) {
DepositRoot: []byte{'r', 'o', 'o', 't'},
}
powChainService.eth1Data = defEth1Data
p.Eth1Data = defEth1Data
result, err := proposerServer.defaultEth1DataResponse(ctx, big.NewInt(1500))
if err != nil {
@ -1260,19 +1294,22 @@ func TestEth1Data(t *testing.T) {
slot := uint64(10000)
ps := &ProposerServer{
powChainService: &mockPOWChainService{
blockNumberByHeight: map[uint64]*big.Int{
60000: big.NewInt(4096),
},
hashesByHeight: map[int][]byte{
3072: []byte("3072"),
},
eth1Data: &ethpb.Eth1Data{
DepositCount: 55,
},
p := &mockPOW.POWChain{
BlockNumberByHeight: map[uint64]*big.Int{
60000: big.NewInt(4096),
},
depositCache: depositcache.NewDepositCache(),
HashesByHeight: map[int][]byte{
3072: []byte("3072"),
},
Eth1Data: &ethpb.Eth1Data{
DepositCount: 55,
},
}
ps := &ProposerServer{
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
depositCache: depositcache.NewDepositCache(),
}
ctx := context.Background()
@ -1286,6 +1323,57 @@ func TestEth1Data(t *testing.T) {
}
}
func TestEth1Data_MockEnabled(t *testing.T) {
db := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, db)
// If a mock eth1 data votes is specified, we use the following for the
// eth1data we provide to every proposer based on https://github.com/ethereum/eth2.0-pm/issues/62:
//
// slot_in_voting_period = current_slot % SLOTS_PER_ETH1_VOTING_PERIOD
// Eth1Data(
// DepositRoot = hash(current_epoch + slot_in_voting_period),
// DepositCount = state.eth1_deposit_index,
// BlockHash = hash(hash(current_epoch + slot_in_voting_period)),
// )
ctx := context.Background()
ps := &ProposerServer{
headFetcher: &mock.ChainService{},
beaconDB: db,
mockEth1Votes: true,
}
headBlockRoot := [32]byte{1, 2, 3}
headState := &pbp2p.BeaconState{
Eth1DepositIndex: 64,
}
if err := db.SaveHeadBlockRoot(ctx, headBlockRoot); err != nil {
t.Fatal(err)
}
if err := db.SaveState(ctx, headState, headBlockRoot); err != nil {
t.Fatal(err)
}
eth1Data, err := ps.eth1Data(ctx, 100)
if err != nil {
t.Fatal(err)
}
wantedSlot := 100 % params.BeaconConfig().SlotsPerEth1VotingPeriod
currentEpoch := helpers.SlotToEpoch(100)
enc, err := ssz.Marshal(currentEpoch + wantedSlot)
if err != nil {
t.Fatal(err)
}
depRoot := hashutil.Hash(enc)
blockHash := hashutil.Hash(depRoot[:])
want := &ethpb.Eth1Data{
DepositRoot: depRoot[:],
DepositCount: 64,
BlockHash: blockHash[:],
}
if !proto.Equal(eth1Data, want) {
t.Errorf("Wanted %v, received %v", want, eth1Data)
}
}
func Benchmark_Eth1Data(b *testing.B) {
ctx := context.Background()
@ -1347,13 +1435,17 @@ func Benchmark_Eth1Data(b *testing.B) {
}
currentHeight := params.BeaconConfig().Eth1FollowDistance + 5
p := &mockPOW.POWChain{
LatestBlockNumber: big.NewInt(int64(currentHeight)),
HashesByHeight: hashesByHeight,
}
proposerServer := &ProposerServer{
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
powChainService: &mockPOWChainService{
latestBlockNumber: big.NewInt(int64(currentHeight)),
hashesByHeight: hashesByHeight,
},
depositCache: depositCache,
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
depositCache: depositCache,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
@ -1368,12 +1460,12 @@ func TestDeposits_ReturnsEmptyList_IfLatestEth1DataEqGenesisEth1Block(t *testing
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOWChainService{
latestBlockNumber: height,
hashesByHeight: map[int][]byte{
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
genesisEth1Block: height,
GenesisEth1Block: height,
}
beaconState := &pbp2p.BeaconState{
@ -1448,13 +1540,16 @@ func TestDeposits_ReturnsEmptyList_IfLatestEth1DataEqGenesisEth1Block(t *testing
}
bs := &ProposerServer{
chainService: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
powChainService: p,
depositCache: depositCache,
blockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
headFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
chainStartFetcher: p,
eth1InfoFetcher: p,
eth1BlockFetcher: p,
depositCache: depositCache,
}
// It should also return the recent deposits after their follow window.
p.latestBlockNumber = big.NewInt(0).Add(p.latestBlockNumber, big.NewInt(10000))
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err := bs.deposits(ctx, &ethpb.Eth1Data{})
if err != nil {
t.Fatal(err)

View File

@ -4,12 +4,9 @@ package rpc
import (
"context"
"fmt"
"math/big"
"net"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/gogo/protobuf/proto"
middleware "github.com/grpc-ecosystem/go-grpc-middleware"
recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
@ -19,13 +16,12 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/db"
"github.com/prysmaticlabs/prysm/beacon-chain/operations"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
"github.com/prysmaticlabs/prysm/beacon-chain/sync"
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/event"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/trieutil"
"github.com/sirupsen/logrus"
"go.opencensus.io/plugin/ocgrpc"
"google.golang.org/grpc"
@ -39,43 +35,19 @@ func init() {
log = logrus.WithField("prefix", "rpc")
}
type chainService interface {
blockchain.HeadRetriever
blockchain.AttestationReceiver
blockchain.BlockReceiver
StateInitializedFeed() *event.Feed
}
type operationService interface {
operations.Pool
HandleAttestation(context.Context, proto.Message) error
IncomingAttFeed() *event.Feed
}
type powChainService interface {
HasChainStarted() bool
ETH2GenesisTime() (uint64, *big.Int)
ChainStartFeed() *event.Feed
LatestBlockHeight() *big.Int
BlockExists(ctx context.Context, hash common.Hash) (bool, *big.Int, error)
BlockHashByHeight(ctx context.Context, height *big.Int) (common.Hash, error)
BlockTimeByHeight(ctx context.Context, height *big.Int) (uint64, error)
BlockNumberByTimestamp(ctx context.Context, time uint64) (*big.Int, error)
DepositRoot() [32]byte
DepositTrie() *trieutil.MerkleTrie
ChainStartDepositHashes() ([][]byte, error)
ChainStartDeposits() []*ethpb.Deposit
ChainStartETH1Data() *ethpb.Eth1Data
}
// Service defining an RPC server for a beacon node.
type Service struct {
ctx context.Context
cancel context.CancelFunc
beaconDB db.Database
chainService chainService
powChainService powChainService
operationService operationService
stateFeedListener blockchain.ChainFeeds
headFetcher blockchain.HeadFetcher
attestationReceiver blockchain.AttestationReceiver
blockReceiver blockchain.BlockReceiver
powChainService powchain.Chain
mockEth1Votes bool
attestationsPool operations.Pool
operationsHandler operations.Handler
syncService sync.Checker
port string
listener net.Listener
@ -91,16 +63,21 @@ type Service struct {
// Config options for the beacon node RPC server.
type Config struct {
Port string
CertFlag string
KeyFlag string
BeaconDB db.Database
ChainService chainService
POWChainService powChainService
OperationService operationService
SyncService sync.Checker
Broadcaster p2p.Broadcaster
DepositCache *depositcache.DepositCache
Port string
CertFlag string
KeyFlag string
BeaconDB db.Database
StateFeedListener blockchain.ChainFeeds
HeadFetcher blockchain.HeadFetcher
AttestationReceiver blockchain.AttestationReceiver
BlockReceiver blockchain.BlockReceiver
POWChainService powchain.Chain
MockEth1Votes bool
OperationsHandler operations.Handler
AttestationsPool operations.Pool
SyncService sync.Checker
Broadcaster p2p.Broadcaster
DepositCache *depositcache.DepositCache
}
// NewService instantiates a new RPC service instance that will
@ -111,10 +88,15 @@ func NewService(ctx context.Context, cfg *Config) *Service {
ctx: ctx,
cancel: cancel,
beaconDB: cfg.BeaconDB,
stateFeedListener: cfg.StateFeedListener,
headFetcher: cfg.HeadFetcher,
attestationReceiver: cfg.AttestationReceiver,
blockReceiver: cfg.BlockReceiver,
p2p: cfg.Broadcaster,
chainService: cfg.ChainService,
powChainService: cfg.POWChainService,
operationService: cfg.OperationService,
mockEth1Votes: cfg.MockEth1Votes,
attestationsPool: cfg.AttestationsPool,
operationsHandler: cfg.OperationsHandler,
syncService: cfg.SyncService,
port: cfg.Port,
withCert: cfg.CertFlag,
@ -163,34 +145,41 @@ func (s *Service) Start() {
beaconServer := &BeaconServer{
beaconDB: s.beaconDB,
ctx: s.ctx,
powChainService: s.powChainService,
chainService: s.chainService,
operationService: s.operationService,
chainStartFetcher: s.powChainService,
eth1InfoFetcher: s.powChainService,
headFetcher: s.headFetcher,
stateFeedListener: s.stateFeedListener,
incomingAttestation: s.incomingAttestation,
canonicalStateChan: s.canonicalStateChan,
chainStartChan: make(chan time.Time, 1),
}
proposerServer := &ProposerServer{
beaconDB: s.beaconDB,
chainService: s.chainService,
powChainService: s.powChainService,
operationService: s.operationService,
headFetcher: s.headFetcher,
blockReceiver: s.blockReceiver,
chainStartFetcher: s.powChainService,
eth1InfoFetcher: s.powChainService,
eth1BlockFetcher: s.powChainService,
mockEth1Votes: s.mockEth1Votes,
pool: s.attestationsPool,
canonicalStateChan: s.canonicalStateChan,
depositCache: s.depositCache,
}
attesterServer := &AttesterServer{
beaconDB: s.beaconDB,
operationService: s.operationService,
p2p: s.p2p,
chainService: s.chainService,
cache: cache.NewAttestationCache(),
p2p: s.p2p,
beaconDB: s.beaconDB,
operationsHandler: s.operationsHandler,
attReceiver: s.attestationReceiver,
headFetcher: s.headFetcher,
depositCache: cache.NewAttestationCache(),
}
validatorServer := &ValidatorServer{
ctx: s.ctx,
beaconDB: s.beaconDB,
chainService: s.chainService,
headFetcher: s.headFetcher,
canonicalStateChan: s.canonicalStateChan,
powChainService: s.powChainService,
blockFetcher: s.powChainService,
chainStartFetcher: s.powChainService,
depositCache: s.depositCache,
}
nodeServer := &NodeServer{
@ -199,9 +188,9 @@ func (s *Service) Start() {
syncChecker: s.syncService,
}
beaconChainServer := &BeaconChainServer{
beaconDB: s.beaconDB,
pool: s.operationService,
chainService: s.chainService,
beaconDB: s.beaconDB,
pool: s.attestationsPool,
headFetcher: s.headFetcher,
}
pb.RegisterBeaconServiceServer(s.grpcServer, beaconServer)
pb.RegisterProposerServiceServer(s.grpcServer, proposerServer)

View File

@ -7,11 +7,8 @@ import (
"io/ioutil"
"testing"
"github.com/gogo/protobuf/proto"
mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/event"
"github.com/prysmaticlabs/prysm/shared/params"
mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/testing"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/sirupsen/logrus"
logTest "github.com/sirupsen/logrus/hooks/test"
@ -22,80 +19,17 @@ func init() {
logrus.SetOutput(ioutil.Discard)
}
type mockOperationService struct {
pendingAttestations []*ethpb.Attestation
}
func (ms *mockOperationService) IncomingAttFeed() *event.Feed {
return new(event.Feed)
}
func (ms *mockOperationService) IncomingExitFeed() *event.Feed {
return new(event.Feed)
}
func (ms *mockOperationService) HandleAttestation(_ context.Context, _ proto.Message) error {
return nil
}
func (ms *mockOperationService) IsAttCanonical(_ context.Context, att *ethpb.Attestation) (bool, error) {
return true, nil
}
func (ms *mockOperationService) AttestationPool(_ context.Context, expectedSlot uint64) ([]*ethpb.Attestation, error) {
if ms.pendingAttestations != nil {
return ms.pendingAttestations, nil
}
return []*ethpb.Attestation{
{
AggregationBits: []byte{0xC0},
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
Shard: params.BeaconConfig().SlotsPerEpoch,
DataRoot: params.BeaconConfig().ZeroHash[:],
},
},
},
{
AggregationBits: []byte{0xC1},
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
Shard: params.BeaconConfig().SlotsPerEpoch,
DataRoot: params.BeaconConfig().ZeroHash[:],
},
},
},
{
AggregationBits: []byte{0xC2},
Data: &ethpb.AttestationData{
Crosslink: &ethpb.Crosslink{
Shard: params.BeaconConfig().SlotsPerEpoch,
DataRoot: params.BeaconConfig().ZeroHash[:],
},
},
},
}, nil
}
type mockSyncService struct {
}
func (ms *mockSyncService) Status() error {
return nil
}
func (ms *mockSyncService) Syncing() bool {
return false
}
func TestLifecycle_OK(t *testing.T) {
hook := logTest.NewGlobal()
rpcService := NewService(context.Background(), &Config{
Port: "7348",
CertFlag: "alice.crt",
KeyFlag: "alice.key",
SyncService: &mockSyncService{},
ChainService: &mock.ChainService{},
Port: "7348",
CertFlag: "alice.crt",
KeyFlag: "alice.key",
SyncService: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
AttestationReceiver: &mock.ChainService{},
HeadFetcher: &mock.ChainService{},
StateFeedListener: &mock.ChainService{},
})
rpcService.Start()
@ -112,9 +46,12 @@ func TestRPC_BadEndpoint(t *testing.T) {
hook := logTest.NewGlobal()
rpcService := NewService(context.Background(), &Config{
Port: "ralph merkle!!!",
SyncService: &mockSyncService{},
ChainService: &mock.ChainService{},
Port: "ralph merkle!!!",
SyncService: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
AttestationReceiver: &mock.ChainService{},
HeadFetcher: &mock.ChainService{},
StateFeedListener: &mock.ChainService{},
})
testutil.AssertLogsDoNotContain(t, hook, "Could not listen to port in Start()")
@ -141,9 +78,12 @@ func TestStatus_CredentialError(t *testing.T) {
func TestRPC_InsecureEndpoint(t *testing.T) {
hook := logTest.NewGlobal()
rpcService := NewService(context.Background(), &Config{
Port: "7777",
SyncService: &mockSyncService{},
ChainService: &mock.ChainService{},
Port: "7777",
SyncService: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
AttestationReceiver: &mock.ChainService{},
HeadFetcher: &mock.ChainService{},
StateFeedListener: &mock.ChainService{},
})
rpcService.Start()

View File

@ -8,11 +8,13 @@ import (
"time"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state/stateutils"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
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"
@ -29,9 +31,10 @@ import (
type ValidatorServer struct {
ctx context.Context
beaconDB db.Database
chainService chainService
headFetcher blockchain.HeadFetcher
canonicalStateChan chan *pbp2p.BeaconState
powChainService powChainService
blockFetcher powchain.POWBlockFetcher
chainStartFetcher powchain.ChainStartFetcher
depositCache *depositcache.DepositCache
}
@ -103,7 +106,7 @@ func (vs *ValidatorServer) ValidatorPerformance(
if !ok {
return nil, status.Errorf(codes.Internal, "could not find validator index for public key %#x not found", req.PublicKey)
}
headState := vs.chainService.HeadState()
headState := vs.headFetcher.HeadState()
activeCount, err := helpers.ActiveValidatorCount(headState, helpers.SlotToEpoch(req.Slot))
if err != nil {
@ -133,7 +136,7 @@ func (vs *ValidatorServer) ValidatorPerformance(
// 4.) The bool signaling if the validator is expected to propose a block at the assigned slot.
func (vs *ValidatorServer) CommitteeAssignment(ctx context.Context, req *pb.AssignmentRequest) (*pb.AssignmentResponse, error) {
var err error
s := vs.chainService.HeadState()
s := vs.headFetcher.HeadState()
// Advance state with empty transitions up to the requested epoch start slot.
if epochStartSlot := helpers.StartSlot(req.EpochStart); s.Slot < epochStartSlot {
@ -226,9 +229,9 @@ func (vs *ValidatorServer) assignment(
func (vs *ValidatorServer) ValidatorStatus(
ctx context.Context,
req *pb.ValidatorIndexRequest) (*pb.ValidatorStatusResponse, error) {
headState := vs.chainService.HeadState()
headState := vs.headFetcher.HeadState()
chainStarted := vs.powChainService.HasChainStarted()
chainStarted := vs.chainStartFetcher.HasChainStarted()
chainStartKeys := vs.chainStartPubkeys()
validatorIndexMap := stateutils.ValidatorIndexMap(headState)
return vs.validatorStatus(ctx, req.PublicKey, chainStarted, chainStartKeys, validatorIndexMap, headState), nil
@ -239,13 +242,13 @@ func (vs *ValidatorServer) ValidatorStatus(
func (vs *ValidatorServer) MultipleValidatorStatus(
ctx context.Context,
pubkeys [][]byte) (bool, []*pb.ValidatorActivationResponse_Status, error) {
chainStarted := vs.powChainService.HasChainStarted()
chainStarted := vs.chainStartFetcher.HasChainStarted()
if !chainStarted {
return false, nil, nil
}
activeValidatorExists := false
statusResponses := make([]*pb.ValidatorActivationResponse_Status, len(pubkeys))
headState := vs.chainService.HeadState()
headState := vs.headFetcher.HeadState()
chainStartKeys := vs.chainStartPubkeys()
validatorIndexMap := stateutils.ValidatorIndexMap(headState)
@ -425,7 +428,7 @@ func (vs *ValidatorServer) lookupValidatorStatus(validatorIdx uint64, beaconStat
func (vs *ValidatorServer) depositBlockSlot(ctx context.Context, currentSlot uint64,
eth1BlockNumBigInt *big.Int, beaconState *pbp2p.BeaconState) (uint64, error) {
blockTimeStamp, err := vs.powChainService.BlockTimeByHeight(ctx, eth1BlockNumBigInt)
blockTimeStamp, err := vs.blockFetcher.BlockTimeByHeight(ctx, eth1BlockNumBigInt)
if err != nil {
return 0, err
}
@ -449,7 +452,7 @@ func (vs *ValidatorServer) depositBlockSlot(ctx context.Context, currentSlot uin
func (vs *ValidatorServer) chainStartPubkeys() map[[96]byte]bool {
pubkeys := make(map[[96]byte]bool)
deposits := vs.powChainService.ChainStartDeposits()
deposits := vs.chainStartFetcher.ChainStartDeposits()
for _, dep := range deposits {
pubkeys[bytesutil.ToBytes96(dep.Data.PublicKey)] = true
}
@ -458,7 +461,7 @@ func (vs *ValidatorServer) chainStartPubkeys() map[[96]byte]bool {
// DomainData fetches the current domain version information from the beacon state.
func (vs *ValidatorServer) DomainData(ctx context.Context, request *pb.DomainRequest) (*pb.DomainResponse, error) {
headState := vs.chainService.HeadState()
headState := vs.headFetcher.HeadState()
dv := helpers.Domain(headState, request.Epoch, request.Domain)
return &pb.DomainResponse{
SignatureDomain: dv,

View File

@ -20,7 +20,8 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/rpc/testing"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
internal "github.com/prysmaticlabs/prysm/beacon-chain/rpc/testing"
mockRPC "github.com/prysmaticlabs/prysm/beacon-chain/rpc/testing"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
@ -78,8 +79,8 @@ func TestNextEpochCommitteeAssignment_WrongPubkeyLength(t *testing.T) {
}
validatorServer := &ValidatorServer{
beaconDB: db,
chainService: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
beaconDB: db,
headFetcher: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
}
req := &pb.AssignmentRequest{
PublicKeys: [][]byte{{1}},
@ -107,7 +108,7 @@ func TestNextEpochCommitteeAssignment_CantFindValidatorIdx(t *testing.T) {
}
vs := &ValidatorServer{
chainService: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
headFetcher: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
}
pubKey := make([]byte, 96)
@ -159,8 +160,8 @@ func TestCommitteeAssignment_OK(t *testing.T) {
}
vs := &ValidatorServer{
beaconDB: db,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
beaconDB: db,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
// Test the first validator in registry.
@ -241,8 +242,8 @@ func TestCommitteeAssignment_CurrentEpoch_ShouldNotFail(t *testing.T) {
}
vs := &ValidatorServer{
beaconDB: db,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
beaconDB: db,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
// Test the first validator in registry.
@ -295,8 +296,8 @@ func TestCommitteeAssignment_MultipleKeys_OK(t *testing.T) {
}
vs := &ValidatorServer{
beaconDB: db,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
beaconDB: db,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
pubkey0 := deposits[0].Data.PublicKey
@ -367,15 +368,17 @@ func TestValidatorStatus_PendingActive(t *testing.T) {
depositCache.InsertDeposit(ctx, deposit, big.NewInt(0) /*blockNum*/, 0, depositTrie.Root())
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
vs := &ValidatorServer{
beaconDB: db,
powChainService: &mockPOWChainService{
blockTimeByHeight: map[int]uint64{
0: uint64(height),
},
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
0: uint64(height),
},
depositCache: depositCache,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
vs := &ValidatorServer{
beaconDB: db,
chainStartFetcher: p,
blockFetcher: p,
depositCache: depositCache,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
req := &pb.ValidatorIndexRequest{
PublicKey: pubKey,
@ -440,15 +443,17 @@ func TestValidatorStatus_Active(t *testing.T) {
}}
timestamp := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
vs := &ValidatorServer{
beaconDB: db,
powChainService: &mockPOWChainService{
blockTimeByHeight: map[int]uint64{
int(params.BeaconConfig().Eth1FollowDistance): uint64(timestamp),
},
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
int(params.BeaconConfig().Eth1FollowDistance): uint64(timestamp),
},
depositCache: depositCache,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
vs := &ValidatorServer{
beaconDB: db,
chainStartFetcher: p,
blockFetcher: p,
depositCache: depositCache,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
req := &pb.ValidatorIndexRequest{
PublicKey: pubKey,
@ -517,15 +522,17 @@ func TestValidatorStatus_InitiatedExit(t *testing.T) {
depositCache := depositcache.NewDepositCache()
depositCache.InsertDeposit(ctx, deposit, big.NewInt(0) /*blockNum*/, 0, depositTrie.Root())
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
vs := &ValidatorServer{
beaconDB: db,
powChainService: &mockPOWChainService{
blockTimeByHeight: map[int]uint64{
0: uint64(height),
},
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
0: uint64(height),
},
depositCache: depositCache,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
vs := &ValidatorServer{
beaconDB: db,
chainStartFetcher: p,
blockFetcher: p,
depositCache: depositCache,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
req := &pb.ValidatorIndexRequest{
PublicKey: pubKey,
@ -584,15 +591,17 @@ func TestValidatorStatus_Withdrawable(t *testing.T) {
depositCache := depositcache.NewDepositCache()
depositCache.InsertDeposit(ctx, deposit, big.NewInt(0) /*blockNum*/, 0, depositTrie.Root())
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
vs := &ValidatorServer{
beaconDB: db,
powChainService: &mockPOWChainService{
blockTimeByHeight: map[int]uint64{
0: uint64(height),
},
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
0: uint64(height),
},
depositCache: depositCache,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
vs := &ValidatorServer{
beaconDB: db,
chainStartFetcher: p,
blockFetcher: p,
depositCache: depositCache,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
req := &pb.ValidatorIndexRequest{
PublicKey: pubKey,
@ -651,15 +660,17 @@ func TestValidatorStatus_ExitedSlashed(t *testing.T) {
depositCache := depositcache.NewDepositCache()
depositCache.InsertDeposit(ctx, deposit, big.NewInt(0) /*blockNum*/, 0, depositTrie.Root())
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
vs := &ValidatorServer{
beaconDB: db,
powChainService: &mockPOWChainService{
blockTimeByHeight: map[int]uint64{
0: uint64(height),
},
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
0: uint64(height),
},
depositCache: depositCache,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
vs := &ValidatorServer{
beaconDB: db,
chainStartFetcher: p,
depositCache: depositCache,
blockFetcher: p,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
req := &pb.ValidatorIndexRequest{
PublicKey: pubKey,
@ -719,15 +730,17 @@ func TestValidatorStatus_Exited(t *testing.T) {
depositCache := depositcache.NewDepositCache()
depositCache.InsertDeposit(ctx, deposit, big.NewInt(0) /*blockNum*/, 0, depositTrie.Root())
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
vs := &ValidatorServer{
beaconDB: db,
powChainService: &mockPOWChainService{
blockTimeByHeight: map[int]uint64{
0: uint64(height),
},
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
0: uint64(height),
},
depositCache: depositCache,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
vs := &ValidatorServer{
beaconDB: db,
chainStartFetcher: p,
blockFetcher: p,
depositCache: depositCache,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
req := &pb.ValidatorIndexRequest{
PublicKey: pubKey,
@ -782,15 +795,17 @@ func TestValidatorStatus_UnknownStatus(t *testing.T) {
depositCache := depositcache.NewDepositCache()
depositCache.InsertDeposit(ctx, deposit, big.NewInt(0) /*blockNum*/, 0, depositTrie.Root())
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
vs := &ValidatorServer{
beaconDB: db,
powChainService: &mockPOWChainService{
blockTimeByHeight: map[int]uint64{
0: uint64(height),
},
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
0: uint64(height),
},
depositCache: depositCache,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
vs := &ValidatorServer{
beaconDB: db,
chainStartFetcher: p,
blockFetcher: p,
depositCache: depositCache,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
req := &pb.ValidatorIndexRequest{
PublicKey: pubKey,
@ -826,10 +841,11 @@ func TestWaitForActivation_ContextClosed(t *testing.T) {
vs := &ValidatorServer{
beaconDB: db,
ctx: ctx,
powChainService: &mockPOWChainService{},
chainStartFetcher: &mockPOW.POWChain{},
blockFetcher: &mockPOW.POWChain{},
canonicalStateChan: make(chan *pbp2p.BeaconState, 1),
depositCache: depositcache.NewDepositCache(),
chainService: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
headFetcher: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
}
req := &pb.ValidatorActivationRequest{
PublicKeys: [][]byte{[]byte("A")},
@ -929,9 +945,10 @@ func TestWaitForActivation_ValidatorOriginallyExists(t *testing.T) {
beaconDB: db,
ctx: context.Background(),
canonicalStateChan: make(chan *pbp2p.BeaconState, 1),
powChainService: &mockPOWChainService{},
chainStartFetcher: &mockPOW.POWChain{},
blockFetcher: &mockPOW.POWChain{},
depositCache: depositCache,
chainService: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
headFetcher: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
}
req := &pb.ValidatorActivationRequest{
PublicKeys: [][]byte{pubKey1, pubKey2},
@ -1042,9 +1059,10 @@ func TestMultipleValidatorStatus_OK(t *testing.T) {
beaconDB: db,
ctx: context.Background(),
canonicalStateChan: make(chan *pbp2p.BeaconState, 1),
powChainService: &mockPOWChainService{},
chainStartFetcher: &mockPOW.POWChain{},
blockFetcher: &mockPOW.POWChain{},
depositCache: depositCache,
chainService: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
headFetcher: &mockChain.ChainService{State: beaconState, Root: genesisRoot[:]},
}
activeExists, response, err := vs.MultipleValidatorStatus(context.Background(), pubKeys)
if err != nil {
@ -1108,8 +1126,8 @@ func BenchmarkAssignment(b *testing.B) {
}
vs := &ValidatorServer{
beaconDB: db,
chainService: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
beaconDB: db,
headFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
}
// Set up request for 100 public keys at a time

View File

@ -23,7 +23,7 @@ var _ = shared.Service(&InitialSync{})
type blockchainService interface {
blockchain.BlockReceiver
blockchain.HeadRetriever
blockchain.HeadFetcher
blockchain.ChainFeeds
}

View File

@ -26,8 +26,8 @@ type Config struct {
// This defines the interface for interacting with block chain service
type blockchainService interface {
blockchain.BlockReceiver
blockchain.HeadRetriever
blockchain.FinalizationRetriever
blockchain.HeadFetcher
blockchain.FinalizationFetcher
blockchain.AttestationReceiver
}

View File

@ -0,0 +1,9 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
testonly = True,
srcs = ["mock.go"],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/sync/testing",
visibility = ["//beacon-chain:__subpackages__"],
)

View File

@ -0,0 +1,16 @@
package testing
// Sync defines a mock for the sync service.
type Sync struct {
IsSyncing bool
}
// Syncing --
func (s *Sync) Syncing() bool {
return s.IsSyncing
}
// Status --
func (s *Sync) Status() error {
return nil
}

View File

@ -75,6 +75,8 @@ var appHelpFlagGroups = []flagGroup{
Name: "beacon-chain",
Flags: []cli.Flag{
flags.NoCustomConfigFlag,
flags.InteropMockEth1DataVotesFlag,
flags.InteropGenesisStateFlag,
flags.DepositContractFlag,
flags.Web3ProviderFlag,
flags.RPCPort,
@ -83,7 +85,6 @@ var appHelpFlagGroups = []flagGroup{
flags.EnableDBCleanup,
flags.GRPCGatewayPort,
flags.HTTPWeb3ProviderFlag,
flags.GenesisState,
},
},
{