From 1f206299e32405c0d54766662d77834cbac18fdd Mon Sep 17 00:00:00 2001 From: Nishant Das Date: Fri, 22 May 2020 12:58:21 +0800 Subject: [PATCH] Adhere to ETH1 Follow Distance (#5941) * finally get it working * Update beacon-chain/powchain/service_test.go * Merge refs/heads/v0.12 into eth1Fixes * fix test * Merge branch 'eth1Fixes' of https://github.com/prysmaticlabs/geth-sharding into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes * Merge refs/heads/v0.12 into eth1Fixes --- beacon-chain/powchain/log_processing.go | 22 ++++--- beacon-chain/powchain/log_processing_test.go | 15 +++-- beacon-chain/powchain/service.go | 30 +++++++++- beacon-chain/powchain/service_test.go | 63 ++++++++++++++++++++ beacon-chain/rpc/beacon/validators_stream.go | 2 +- beacon-chain/rpc/validator/status.go | 2 +- shared/params/config.go | 4 -- 7 files changed, 117 insertions(+), 21 deletions(-) diff --git a/beacon-chain/powchain/log_processing.go b/beacon-chain/powchain/log_processing.go index db00ff380dea..e5a52a9e6e7f 100644 --- a/beacon-chain/powchain/log_processing.go +++ b/beacon-chain/powchain/log_processing.go @@ -24,7 +24,6 @@ import ( "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/hashutil" - "github.com/prysmaticlabs/prysm/shared/params" "github.com/sirupsen/logrus" ) @@ -284,15 +283,19 @@ func (s *Service) processPastLogs(ctx context.Context) error { } return nil } - for currentBlockNum < s.LatestBlockHeight().Uint64() { + latestFollowHeight, err := s.followBlockHeight(ctx) + if err != nil { + return err + } + for currentBlockNum < latestFollowHeight { // stop requesting, if we have all the logs if logCount == uint64(s.lastReceivedMerkleIndex+1) { break } start := currentBlockNum end := currentBlockNum + eth1HeaderReqLimit - if end > s.LatestBlockHeight().Uint64() { - end = s.LatestBlockHeight().Uint64() + if end > latestFollowHeight { + end = latestFollowHeight } query := ethereum.FilterQuery{ Addresses: []common.Address{ @@ -303,9 +306,9 @@ func (s *Service) processPastLogs(ctx context.Context) error { } remainingLogs := logCount - uint64(s.lastReceivedMerkleIndex+1) // only change the end block if the remaining logs are below the required log limit. - if remainingLogs < depositlogRequestLimit && end >= s.LatestBlockHeight().Uint64() { - query.ToBlock = s.LatestBlockHeight() - end = s.LatestBlockHeight().Uint64() + if remainingLogs < depositlogRequestLimit && end >= latestFollowHeight { + query.ToBlock = big.NewInt(int64(latestFollowHeight)) + end = latestFollowHeight } logs, err := s.httpLogger.FilterLogs(ctx, query) if err != nil { @@ -355,7 +358,10 @@ func (s *Service) requestBatchedLogs(ctx context.Context) error { // We request for the nth block behind the current head, in order to have // stabilized logs when we retrieve it from the 1.0 chain. - requestedBlock := s.latestEth1Data.BlockHeight - uint64(params.BeaconConfig().LogBlockDelay) + requestedBlock, err := s.followBlockHeight(ctx) + if err != nil { + return err + } for i := s.latestEth1Data.LastRequestedBlock + 1; i <= requestedBlock; i++ { err := s.ProcessETH1Block(ctx, big.NewInt(int64(i))) if err != nil { diff --git a/beacon-chain/powchain/log_processing_test.go b/beacon-chain/powchain/log_processing_test.go index b16043d7981a..555ca681c02b 100644 --- a/beacon-chain/powchain/log_processing_test.go +++ b/beacon-chain/powchain/log_processing_test.go @@ -488,18 +488,18 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) { } web3Service.rpcClient = &mockPOW.RPCClient{Backend: testAcc.Backend} web3Service.httpLogger = testAcc.Backend + web3Service.blockFetcher = &goodFetcher{backend: testAcc.Backend} web3Service.latestEth1Data.LastRequestedBlock = 0 - web3Service.latestEth1Data.BlockHeight = 0 + web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64() + web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time() params.SetupTestConfigCleanup(t) bConfig := params.MinimalSpecConfig() bConfig.MinGenesisTime = 0 + bConfig.SecondsPerETH1Block = 10 params.OverrideBeaconConfig(bConfig) flags.Get().DeploymentBlock = 0 testAcc.Backend.Commit() - if err := testAcc.Backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond()))); err != nil { - t.Fatal(err) - } totalNumOfDeposits := depositsReqForChainStart + 30 @@ -529,7 +529,12 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) { testAcc.Backend.Commit() } } + // Forward the chain to account for the follow distance + for i := uint64(0); i < params.BeaconConfig().Eth1FollowDistance; i++ { + testAcc.Backend.Commit() + } web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64() + web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time() // Set up our subscriber now to listen for the chain started event. stateChannel := make(chan *feed.Event, 1) @@ -726,7 +731,7 @@ func TestConsistentGenesisState(t *testing.T) { testAcc.Backend.Commit() } - for i := 0; i < int(params.BeaconConfig().LogBlockDelay); i++ { + for i := 0; i < int(params.BeaconConfig().Eth1FollowDistance); i++ { testAcc.Backend.Commit() } diff --git a/beacon-chain/powchain/service.go b/beacon-chain/powchain/service.go index 2af2bdd60821..1ef6b859092c 100644 --- a/beacon-chain/powchain/service.go +++ b/beacon-chain/powchain/service.go @@ -334,6 +334,32 @@ func (s *Service) AreAllDepositsProcessed() (bool, error) { return true, nil } +// refers to the latest eth1 block which follows the condition: eth1_timestamp + +// SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= current_unix_time +func (s *Service) followBlockHeight(ctx context.Context) (uint64, error) { + latestValidBlock := uint64(0) + if s.latestEth1Data.BlockHeight > params.BeaconConfig().Eth1FollowDistance { + latestValidBlock = s.latestEth1Data.BlockHeight - params.BeaconConfig().Eth1FollowDistance + } + blockTime, err := s.BlockTimeByHeight(ctx, big.NewInt(int64(latestValidBlock))) + if err != nil { + return 0, err + } + followTime := func(t uint64) uint64 { + return t + params.BeaconConfig().Eth1FollowDistance*params.BeaconConfig().SecondsPerETH1Block + } + for followTime(blockTime) > s.latestEth1Data.BlockTime && latestValidBlock > 0 { + // reduce block height to get eth1 block which + // fulfills stated condition + latestValidBlock-- + blockTime, err = s.BlockTimeByHeight(ctx, big.NewInt(int64(latestValidBlock))) + if err != nil { + return 0, err + } + } + return latestValidBlock, nil +} + func (s *Service) connectToPowChain() error { powClient, httpClient, rpcClient, err := s.dialETH1Nodes() if err != nil { @@ -521,7 +547,7 @@ func safelyHandlePanic() { } } -func (s *Service) handleDelayTicker() { +func (s *Service) handleETH1FollowDistance() { defer safelyHandlePanic() // use a 5 minutes timeout for block time, because the max mining time is 278 sec (block 7208027) @@ -653,7 +679,7 @@ func (s *Service) run(done <-chan struct{}) { s.processSubscribedHeaders(header) } case <-ticker.C: - s.handleDelayTicker() + s.handleETH1FollowDistance() } } } diff --git a/beacon-chain/powchain/service_test.go b/beacon-chain/powchain/service_test.go index b7850f97fae3..aac14f66655a 100644 --- a/beacon-chain/powchain/service_test.go +++ b/beacon-chain/powchain/service_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/prysmaticlabs/prysm/shared/params" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" @@ -259,6 +260,68 @@ func TestStop_OK(t *testing.T) { hook.Reset() } +func TestFollowBlock_OK(t *testing.T) { + depositcontract.Amount32Eth() + testAcc, err := contracts.Setup() + if err != nil { + t.Fatalf("Unable to set up simulated backend %v", err) + } + beaconDB := dbutil.SetupDB(t) + web3Service, err := NewService(context.Background(), &Web3ServiceConfig{ + ETH1Endpoint: endpoint, + DepositContract: testAcc.ContractAddr, + BeaconDB: beaconDB, + }) + if err != nil { + t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err) + } + + // simulated backend sets eth1 block + // time as 10 seconds + conf := params.BeaconConfig() + conf.SecondsPerETH1Block = 10 + params.OverrideBeaconConfig(conf) + defer func() { + params.UseMainnetConfig() + }() + + web3Service = setDefaultMocks(web3Service) + web3Service.blockFetcher = &goodFetcher{backend: testAcc.Backend} + baseHeight := testAcc.Backend.Blockchain().CurrentBlock().NumberU64() + // process follow_distance blocks + for i := 0; i < int(params.BeaconConfig().Eth1FollowDistance); i++ { + testAcc.Backend.Commit() + } + // set current height + web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64() + web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time() + + h, err := web3Service.followBlockHeight(context.Background()) + if err != nil { + t.Fatal(err) + } + if h != baseHeight { + t.Errorf("Unexpected block height of %d received instead of %d", h, baseHeight) + } + numToForward := uint64(2) + expectedHeight := numToForward + baseHeight + // forward 2 blocks + for i := uint64(0); i < numToForward; i++ { + testAcc.Backend.Commit() + } + // set current height + web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64() + web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time() + + h, err = web3Service.followBlockHeight(context.Background()) + if err != nil { + t.Fatal(err) + } + if h != expectedHeight { + t.Errorf("Unexpected block height of %d received instead of %d", h, expectedHeight) + } +} + func TestInitDataFromContract_OK(t *testing.T) { testAcc, err := contracts.Setup() if err != nil { diff --git a/beacon-chain/rpc/beacon/validators_stream.go b/beacon-chain/rpc/beacon/validators_stream.go index 9eefd9568757..6f83edf7515c 100644 --- a/beacon-chain/rpc/beacon/validators_stream.go +++ b/beacon-chain/rpc/beacon/validators_stream.go @@ -515,7 +515,7 @@ func (is *infostream) depositQueueTimestamp(eth1BlockNumber *big.Int) (uint64, e } is.eth1BlocktimesMutex.Unlock() - followTime := time.Duration(params.BeaconConfig().Eth1FollowDistance*params.BeaconConfig().GoerliBlockTime) * time.Second + followTime := time.Duration(params.BeaconConfig().Eth1FollowDistance*params.BeaconConfig().SecondsPerETH1Block) * time.Second eth1UnixTime := time.Unix(int64(blockTimestamp), 0).Add(followTime) period := params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().EpochsPerEth1VotingPeriod diff --git a/beacon-chain/rpc/validator/status.go b/beacon-chain/rpc/validator/status.go index c4c5335130e0..254545b26702 100644 --- a/beacon-chain/rpc/validator/status.go +++ b/beacon-chain/rpc/validator/status.go @@ -235,7 +235,7 @@ func (vs *Server) depositBlockSlot(ctx context.Context, eth1BlockNumBigInt *big. if err != nil { return 0, err } - followTime := time.Duration(params.BeaconConfig().Eth1FollowDistance*params.BeaconConfig().GoerliBlockTime) * time.Second + followTime := time.Duration(params.BeaconConfig().Eth1FollowDistance*params.BeaconConfig().SecondsPerETH1Block) * time.Second eth1UnixTime := time.Unix(int64(blockTimeStamp), 0).Add(followTime) period := params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().EpochsPerEth1VotingPeriod votingPeriod := time.Duration(period*params.BeaconConfig().SecondsPerSlot) * time.Second diff --git a/shared/params/config.go b/shared/params/config.go index 05228e848986..3c5e5ccead98 100644 --- a/shared/params/config.go +++ b/shared/params/config.go @@ -89,7 +89,6 @@ type BeaconChainConfig struct { // Prysm constants. GweiPerEth uint64 // GweiPerEth is the amount of gwei corresponding to 1 eth. - LogBlockDelay int64 // Number of blocks to wait from the current head before processing logs from the deposit contract. BLSSecretKeyLength int // BLSSecretKeyLength defines the expected length of BLS secret keys in bytes. BLSPubkeyLength int // BLSPubkeyLength defines the expected length of BLS public keys in bytes. BLSSignatureLength int // BLSSignatureLength defines the expected length of BLS signatures in bytes. @@ -97,7 +96,6 @@ type BeaconChainConfig struct { ValidatorPrivkeyFileName string // ValidatorPrivKeyFileName specifies the string name of a validator private key file. WithdrawalPrivkeyFileName string // WithdrawalPrivKeyFileName specifies the string name of a withdrawal private key file. RPCSyncCheck time.Duration // Number of seconds to query the sync service, to find out if the node is synced or not. - GoerliBlockTime uint64 // GoerliBlockTime is the number of seconds on avg a Goerli block is created. EmptySignature [96]byte // EmptySignature is used to represent a zeroed out BLS Signature. DefaultPageSize int // DefaultPageSize defines the default page size for RPC server request. MaxPeersToSync int // MaxPeersToSync describes the limit for number of peers in round robin sync. @@ -191,7 +189,6 @@ var defaultBeaconConfig = &BeaconChainConfig{ // Prysm constants. GweiPerEth: 1000000000, - LogBlockDelay: 4, BLSSecretKeyLength: 32, BLSPubkeyLength: 48, BLSSignatureLength: 96, @@ -199,7 +196,6 @@ var defaultBeaconConfig = &BeaconChainConfig{ WithdrawalPrivkeyFileName: "/shardwithdrawalkey", ValidatorPrivkeyFileName: "/validatorprivatekey", RPCSyncCheck: 1, - GoerliBlockTime: 14, // 14 seconds on average for a goerli block to be created. EmptySignature: [96]byte{}, DefaultPageSize: 250, MaxPeersToSync: 15,