diff --git a/beacon-chain/blockchain/chain_info.go b/beacon-chain/blockchain/chain_info.go index e83f440d1..d659e1e58 100644 --- a/beacon-chain/blockchain/chain_info.go +++ b/beacon-chain/blockchain/chain_info.go @@ -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 } diff --git a/beacon-chain/blockchain/chain_info_test.go b/beacon-chain/blockchain/chain_info_test.go index 25b1d41cc..03c99537b 100644 --- a/beacon-chain/blockchain/chain_info_test.go +++ b/beacon-chain/blockchain/chain_info_test.go @@ -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") - } -} diff --git a/beacon-chain/blockchain/service.go b/beacon-chain/blockchain/service.go index 462d9bba1..33ab3c068 100644 --- a/beacon-chain/blockchain/service.go +++ b/beacon-chain/blockchain/service.go @@ -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) diff --git a/beacon-chain/blockchain/service_test.go b/beacon-chain/blockchain/service_test.go index 59e9de3b5..0970b0290 100644 --- a/beacon-chain/blockchain/service_test.go +++ b/beacon-chain/blockchain/service_test.go @@ -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) diff --git a/beacon-chain/blockchain/testing/mock.go b/beacon-chain/blockchain/testing/mock.go index 19e24c9a6..9230be42d 100644 --- a/beacon-chain/blockchain/testing/mock.go +++ b/beacon-chain/blockchain/testing/mock.go @@ -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) } diff --git a/beacon-chain/flags/flags.go b/beacon-chain/flags/flags.go index 082b5ba8d..aff96750d 100644 --- a/beacon-chain/flags/flags.go +++ b/beacon-chain/flags/flags.go @@ -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", } diff --git a/beacon-chain/main.go b/beacon-chain/main.go index 9cfeba633..5c8ab1a42 100644 --- a/beacon-chain/main.go +++ b/beacon-chain/main.go @@ -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, diff --git a/beacon-chain/node/node.go b/beacon-chain/node/node.go index af29a44bb..da8e1f607 100644 --- a/beacon-chain/node/node.go +++ b/beacon-chain/node/node.go @@ -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) diff --git a/beacon-chain/operations/service.go b/beacon-chain/operations/service.go index 63117f115..e3761bbf8 100644 --- a/beacon-chain/operations/service.go +++ b/beacon-chain/operations/service.go @@ -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 { diff --git a/beacon-chain/operations/testing/BUILD.bazel b/beacon-chain/operations/testing/BUILD.bazel new file mode 100644 index 000000000..04ca3d222 --- /dev/null +++ b/beacon-chain/operations/testing/BUILD.bazel @@ -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", + ], +) diff --git a/beacon-chain/operations/testing/mock.go b/beacon-chain/operations/testing/mock.go new file mode 100644 index 000000000..91fc04728 --- /dev/null +++ b/beacon-chain/operations/testing/mock.go @@ -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 +} diff --git a/beacon-chain/powchain/block_reader_test.go b/beacon-chain/powchain/block_reader_test.go index 8be94f3f7..a17d67acb 100644 --- a/beacon-chain/powchain/block_reader_test.go +++ b/beacon-chain/powchain/block_reader_test.go @@ -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, }) diff --git a/beacon-chain/powchain/log_processing.go b/beacon-chain/powchain/log_processing.go index b7bd42933..b224ace62 100644 --- a/beacon-chain/powchain/log_processing.go +++ b/beacon-chain/powchain/log_processing.go @@ -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 } diff --git a/beacon-chain/powchain/service.go b/beacon-chain/powchain/service.go index c1d975d2c..d56794ae4 100644 --- a/beacon-chain/powchain/service.go +++ b/beacon-chain/powchain/service.go @@ -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 } diff --git a/beacon-chain/powchain/service_test.go b/beacon-chain/powchain/service_test.go index dc5d0f1f0..5a849858b 100644 --- a/beacon-chain/powchain/service_test.go +++ b/beacon-chain/powchain/service_test.go @@ -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) { diff --git a/beacon-chain/powchain/testing/BUILD.bazel b/beacon-chain/powchain/testing/BUILD.bazel new file mode 100644 index 000000000..ac904bd13 --- /dev/null +++ b/beacon-chain/powchain/testing/BUILD.bazel @@ -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", + ], +) diff --git a/beacon-chain/powchain/testing/faulty_mock.go b/beacon-chain/powchain/testing/faulty_mock.go new file mode 100644 index 000000000..2606d1c8d --- /dev/null +++ b/beacon-chain/powchain/testing/faulty_mock.go @@ -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 ðpb.Eth1Data{} +} diff --git a/beacon-chain/powchain/testing/mock.go b/beacon-chain/powchain/testing/mock.go new file mode 100644 index 000000000..8afb8c1e7 --- /dev/null +++ b/beacon-chain/powchain/testing/mock.go @@ -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 +} diff --git a/beacon-chain/rpc/BUILD.bazel b/beacon-chain/rpc/BUILD.bazel index 17b29dfc8..b9ac6ea3a 100644 --- a/beacon-chain/rpc/BUILD.bazel +++ b/beacon-chain/rpc/BUILD.bazel @@ -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", diff --git a/beacon-chain/rpc/attester_server.go b/beacon-chain/rpc/attester_server.go index 65cf27e7e..d57445a52 100644 --- a/beacon-chain/rpc/attester_server.go +++ b/beacon-chain/rpc/attester_server.go @@ -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 } diff --git a/beacon-chain/rpc/attester_server_test.go b/beacon-chain/rpc/attester_server_test.go index f0d7d150e..bc6c9c827 100644 --- a/beacon-chain/rpc/attester_server_test.go +++ b/beacon-chain/rpc/attester_server_test.go @@ -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 := ðpb.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: ðpb.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) } }() diff --git a/beacon-chain/rpc/beacon_chain_server.go b/beacon-chain/rpc/beacon_chain_server.go index 17c6b2ed3..12e8fb691 100644 --- a/beacon-chain/rpc/beacon_chain_server.go +++ b/beacon-chain/rpc/beacon_chain_server.go @@ -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 ðpb.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 diff --git a/beacon-chain/rpc/beacon_chain_server_test.go b/beacon-chain/rpc/beacon_chain_server_test.go index fb9d8ab98..771d14dfd 100644 --- a/beacon-chain/rpc/beacon_chain_server_test.go +++ b/beacon-chain/rpc/beacon_chain_server_test.go @@ -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: ðpb.AttestationData{ - BeaconBlockRoot: []byte("1"), - }, - }, - { - Data: ðpb.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: ðpb.AttestationData{ + BeaconBlockRoot: []byte("1"), + }, + }, + { + Data: ðpb.AttestationData{ + BeaconBlockRoot: []byte("2"), + }, + }, + }, + }, beaconDB: db, } block := ðpb.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, ðpb.GetValidatorParticipationRequest{Epoch: epoch}) @@ -1000,7 +997,7 @@ func TestBeaconChainServer_GetChainHead(t *testing.T) { FinalizedCheckpoint: ðpb.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 { diff --git a/beacon-chain/rpc/beacon_server.go b/beacon-chain/rpc/beacon_server.go index 52df36844..53736d51e 100644 --- a/beacon-chain/rpc/beacon_server.go +++ b/beacon-chain/rpc/beacon_server.go @@ -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. diff --git a/beacon-chain/rpc/beacon_server_test.go b/beacon-chain/rpc/beacon_server_test.go index 5c04d1c12..1b522f4a2 100644 --- a/beacon-chain/rpc/beacon_server_test.go +++ b/beacon-chain/rpc/beacon_server_test.go @@ -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 ðpb.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) diff --git a/beacon-chain/rpc/proposer_server.go b/beacon-chain/rpc/proposer_server.go index 42d427d9a..2187548d6 100644 --- a/beacon-chain/rpc/proposer_server.go +++ b/beacon-chain/rpc/proposer_server.go @@ -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 ðpb.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 ðpb.Eth1Data{ DepositRoot: depositRoot[:], diff --git a/beacon-chain/rpc/proposer_server_test.go b/beacon-chain/rpc/proposer_server_test.go index 0eba82bcd..3d7c7ea46 100644 --- a/beacon-chain/rpc/proposer_server_test.go +++ b/beacon-chain/rpc/proposer_server_test.go @@ -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 := ðpb.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 := ðpb.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: ðpb.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, ðpb.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, ðpb.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, ðpb.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, ðpb.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, ðpb.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, ðpb.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, ðpb.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: ðpb.Deposit{ Data: ðpb.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: ðpb.Deposit{ Data: ðpb.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 := ðpb.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: ðpb.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: ðpb.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 := ðpb.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, ðpb.Eth1Data{}) if err != nil { t.Fatal(err) diff --git a/beacon-chain/rpc/service.go b/beacon-chain/rpc/service.go index 6f8641427..04cc8b6fe 100644 --- a/beacon-chain/rpc/service.go +++ b/beacon-chain/rpc/service.go @@ -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) diff --git a/beacon-chain/rpc/service_test.go b/beacon-chain/rpc/service_test.go index 449772677..1407542ad 100644 --- a/beacon-chain/rpc/service_test.go +++ b/beacon-chain/rpc/service_test.go @@ -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: ðpb.AttestationData{ - Crosslink: ðpb.Crosslink{ - Shard: params.BeaconConfig().SlotsPerEpoch, - DataRoot: params.BeaconConfig().ZeroHash[:], - }, - }, - }, - { - AggregationBits: []byte{0xC1}, - Data: ðpb.AttestationData{ - Crosslink: ðpb.Crosslink{ - Shard: params.BeaconConfig().SlotsPerEpoch, - DataRoot: params.BeaconConfig().ZeroHash[:], - }, - }, - }, - { - AggregationBits: []byte{0xC2}, - Data: ðpb.AttestationData{ - Crosslink: ðpb.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() diff --git a/beacon-chain/rpc/validator_server.go b/beacon-chain/rpc/validator_server.go index d8a75b40a..031a1da1d 100644 --- a/beacon-chain/rpc/validator_server.go +++ b/beacon-chain/rpc/validator_server.go @@ -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, diff --git a/beacon-chain/rpc/validator_server_test.go b/beacon-chain/rpc/validator_server_test.go index 941c37b05..d3f322207 100644 --- a/beacon-chain/rpc/validator_server_test.go +++ b/beacon-chain/rpc/validator_server_test.go @@ -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 diff --git a/beacon-chain/sync/initial-sync/service.go b/beacon-chain/sync/initial-sync/service.go index b78fb6667..32e1f81c2 100644 --- a/beacon-chain/sync/initial-sync/service.go +++ b/beacon-chain/sync/initial-sync/service.go @@ -23,7 +23,7 @@ var _ = shared.Service(&InitialSync{}) type blockchainService interface { blockchain.BlockReceiver - blockchain.HeadRetriever + blockchain.HeadFetcher blockchain.ChainFeeds } diff --git a/beacon-chain/sync/service.go b/beacon-chain/sync/service.go index a36ec9b1f..41c205c94 100644 --- a/beacon-chain/sync/service.go +++ b/beacon-chain/sync/service.go @@ -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 } diff --git a/beacon-chain/sync/testing/BUILD.bazel b/beacon-chain/sync/testing/BUILD.bazel new file mode 100644 index 000000000..db678f589 --- /dev/null +++ b/beacon-chain/sync/testing/BUILD.bazel @@ -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__"], +) diff --git a/beacon-chain/sync/testing/mock.go b/beacon-chain/sync/testing/mock.go new file mode 100644 index 000000000..32ba84c79 --- /dev/null +++ b/beacon-chain/sync/testing/mock.go @@ -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 +} diff --git a/beacon-chain/usage.go b/beacon-chain/usage.go index d8d6f48e2..16cc42dff 100644 --- a/beacon-chain/usage.go +++ b/beacon-chain/usage.go @@ -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, }, }, {