Skip to content

Commit

Permalink
Fix Stuck Beacon Node (#4454)
Browse files Browse the repository at this point in the history
* Revert "Revert #4392 (#4449)"

This reverts commit 67c380b.
* bound start req
* Merge refs/heads/master into revert-4449-revert-4392
* fix test
* Merge branch 'revert-4449-revert-4392' of https://github.com/prysmaticlabs/geth-sharding into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* add flag for deployment block
* Merge branch 'revert-4449-revert-4392' of https://github.com/prysmaticlabs/geth-sharding into revert-4449-revert-4392
* use constant and comments
* lint
* skip test for now
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Update shared/params/config.go

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>
* Update beacon-chain/powchain/testing/mock.go

Co-Authored-By: terence tsao <terence@prysmaticlabs.com>
* preston's review
* Merge branch 'revert-4449-revert-4392' of https://github.com/prysmaticlabs/geth-sharding into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* add flag
* Merge branch 'revert-4449-revert-4392' of https://github.com/prysmaticlabs/geth-sharding into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* use stateutils
* Merge branch 'revert-4449-revert-4392' of https://github.com/prysmaticlabs/geth-sharding into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
* Merge refs/heads/master into revert-4449-revert-4392
  • Loading branch information
nisdas authored and prylabs-bulldozer[bot] committed Jan 16, 2020
1 parent 0a63206 commit 2e5429c
Show file tree
Hide file tree
Showing 15 changed files with 223 additions and 48 deletions.
1 change: 1 addition & 0 deletions beacon-chain/blockchain/BUILD.bazel
Expand Up @@ -31,6 +31,7 @@ go_library(
"//shared/featureconfig:go_default_library",
"//shared/params:go_default_library",
"//shared/slotutil:go_default_library",
"//shared/stateutil:go_default_library",
"//shared/traceutil:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_pkg_errors//:go_default_library",
Expand Down
3 changes: 2 additions & 1 deletion beacon-chain/blockchain/service.go
Expand Up @@ -29,6 +29,7 @@ import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/stateutil"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
Expand Down Expand Up @@ -306,7 +307,7 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState *pb.BeaconSt
s.headLock.Lock()
defer s.headLock.Unlock()

stateRoot, err := ssz.HashTreeRoot(genesisState)
stateRoot, err := stateutil.HashTreeRootState(genesisState)
if err != nil {
return errors.Wrap(err, "could not tree hash genesis state")
}
Expand Down
7 changes: 6 additions & 1 deletion beacon-chain/flags/base.go
Expand Up @@ -48,14 +48,19 @@ var (
Name: "grpc-gateway-port",
Usage: "Enable gRPC gateway for JSON requests",
}

// MinSyncPeers specifies the required number of successful peer handshakes in order
// to start syncing with external peers.
MinSyncPeers = cli.IntFlag{
Name: "min-sync-peers",
Usage: "The required number of valid peers to connect with before syncing.",
Value: 3,
}
// ContractDeploymentBlock is the block in which the eth1 deposit contract was deployed.
ContractDeploymentBlock = cli.IntFlag{
Name: "contract-deployment-block",
Usage: "The eth1 block in which the deposit contract was deployed.",
Value: 1960177,
}
// SlasherCertFlag defines a flag for the slasher TLS certificate.
SlasherCertFlag = cli.StringFlag{
Name: "slasher-tls-cert",
Expand Down
2 changes: 2 additions & 0 deletions beacon-chain/flags/config.go
Expand Up @@ -14,6 +14,7 @@ type GlobalFlags struct {
EnableArchivedBlocks bool
EnableArchivedAttestations bool
MinimumSyncPeers int
DeploymentBlock int
}

var globalConfig *GlobalFlags
Expand Down Expand Up @@ -47,6 +48,7 @@ func ConfigureGlobalFlags(ctx *cli.Context) {
if ctx.GlobalBool(ArchiveAttestationsFlag.Name) {
cfg.EnableArchivedAttestations = true
}
cfg.DeploymentBlock = ctx.GlobalInt(ContractDeploymentBlock.Name)
configureMinimumPeers(ctx, cfg)

Init(cfg)
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/main.go
Expand Up @@ -33,6 +33,7 @@ var appFlags = []cli.Flag{
flags.KeyFlag,
flags.GRPCGatewayPort,
flags.MinSyncPeers,
flags.ContractDeploymentBlock,
flags.InteropMockEth1DataVotesFlag,
flags.InteropGenesisStateFlag,
flags.InteropNumValidatorsFlag,
Expand Down
3 changes: 3 additions & 0 deletions beacon-chain/powchain/BUILD.bazel
Expand Up @@ -23,6 +23,7 @@ go_library(
"//beacon-chain/core/state:go_default_library",
"//beacon-chain/core/state/stateutils:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/flags:go_default_library",
"//contracts/deposit-contract:go_default_library",
"//proto/beacon/db:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
Expand Down Expand Up @@ -68,6 +69,8 @@ go_test(
"//beacon-chain/core/state:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/db/testing:go_default_library",
"//beacon-chain/flags:go_default_library",
"//beacon-chain/powchain/testing:go_default_library",
"//contracts/deposit-contract:go_default_library",
"//proto/beacon/db:go_default_library",
"//shared/bls:go_default_library",
Expand Down
3 changes: 3 additions & 0 deletions beacon-chain/powchain/block_reader_test.go
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
gethTypes "github.com/ethereum/go-ethereum/core/types"
dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
)
Expand Down Expand Up @@ -42,6 +43,8 @@ func TestLatestMainchainInfo_OK(t *testing.T) {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
web3Service = setDefaultMocks(web3Service)
web3Service.rpcClient = &mockPOW.RPCClient{Backend: testAcc.Backend}

web3Service.depositContractCaller, err = contracts.NewDepositContractCaller(testAcc.ContractAddr, testAcc.Backend)
if err != nil {
t.Fatal(err)
Expand Down
148 changes: 110 additions & 38 deletions beacon-chain/powchain/log_processing.go
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
gethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/pkg/errors"
Expand All @@ -17,6 +18,7 @@ import (
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/beacon-chain/flags"
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
protodb "github.com/prysmaticlabs/prysm/proto/beacon/db"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
Expand All @@ -32,6 +34,8 @@ var (

const eth1LookBackPeriod = 100
const eth1DataSavingInterval = 100
const eth1HeaderReqLimit = 2000
const depositlogRequestLimit = 10000

// Eth2GenesisPowchainInfo retrieves the genesis time and eth1 block number of the beacon chain
// from the deposit contract.
Expand Down Expand Up @@ -62,7 +66,7 @@ func (s *Service) ProcessETH1Block(ctx context.Context, blkNum *big.Int) error {
}
}
if !s.chainStartData.Chainstarted {
if err := s.checkForChainStart(ctx, blkNum); err != nil {
if err := s.checkBlockNumberForChainStart(ctx, blkNum); err != nil {
return err
}
}
Expand Down Expand Up @@ -248,46 +252,85 @@ func (s *Service) createGenesisTime(timeStamp uint64) uint64 {
// updates the deposit trie with the data from each individual log.
func (s *Service) processPastLogs(ctx context.Context) error {
currentBlockNum := s.latestEth1Data.LastRequestedBlock
query := ethereum.FilterQuery{
Addresses: []common.Address{
s.depositContractAddress,
},
deploymentBlock := int64(flags.Get().DeploymentBlock)
if uint64(deploymentBlock) > currentBlockNum {
currentBlockNum = uint64(deploymentBlock)
}
// To store all blocks.
headersMap := make(map[uint64]*gethTypes.Header)
rawLogCount, err := s.depositContractCaller.GetDepositCount(&bind.CallOpts{})
if err != nil {
return err
}
logCount := binary.LittleEndian.Uint64(rawLogCount)

// Batch request the desired headers and store them in a
// map for quick access.
requestHeaders := func(startBlk uint64, endBlk uint64) error {
headers, err := s.batchRequestHeaders(startBlk, endBlk)
if err != nil {
return err
}
for _, h := range headers {
if h != nil && h.Number != nil {
headersMap[h.Number.Uint64()] = h
}
}
return nil
}

// if we are not starting from the first deposit log, we use
// the current saved last requested block number.
if s.lastReceivedMerkleIndex != -1 {
query = ethereum.FilterQuery{
for currentBlockNum < s.LatestBlockHeight().Uint64() {
// 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()
}
query := ethereum.FilterQuery{
Addresses: []common.Address{
s.depositContractAddress,
},
FromBlock: big.NewInt(int64(currentBlockNum)),
FromBlock: big.NewInt(int64(start)),
ToBlock: big.NewInt(int64(end)),
}
remainingLogs := logCount - uint64(s.lastReceivedMerkleIndex+1)
if remainingLogs < depositlogRequestLimit {
query.ToBlock = s.LatestBlockHeight()
end = s.LatestBlockHeight().Uint64()
}
logs, err := s.httpLogger.FilterLogs(ctx, query)
if err != nil {
return err
}
if !s.chainStartData.Chainstarted {
if err := requestHeaders(start, end); err != nil {
return err
}
}
}

logs, err := s.httpLogger.FilterLogs(ctx, query)
if err != nil {
return err
}

for _, log := range logs {
if log.BlockNumber > currentBlockNum {
if !s.chainStartData.Chainstarted {
if err := s.checkForChainStart(ctx, big.NewInt(int64(currentBlockNum))); err != nil {
for _, log := range logs {
if log.BlockNumber > currentBlockNum {
if err := s.checkHeaderRange(currentBlockNum, log.BlockNumber-1, headersMap, requestHeaders); err != nil {
return err
}
// set new block number after checking for chainstart for previous block.
s.latestEth1Data.LastRequestedBlock = currentBlockNum
currentBlockNum = log.BlockNumber
}
if err := s.ProcessLog(ctx, log); err != nil {
return err
}
// set new block number after checking for chainstart for previous block.
s.latestEth1Data.LastRequestedBlock = currentBlockNum
currentBlockNum = log.BlockNumber
}
if err := s.ProcessLog(ctx, log); err != nil {
if err := s.checkHeaderRange(currentBlockNum, end, headersMap, requestHeaders); err != nil {
return err
}
currentBlockNum = end
}

s.latestEth1Data.LastRequestedBlock = currentBlockNum

currentState, err := s.beaconDB.HeadState(ctx)
if err != nil {
return errors.Wrap(err, "could not get head state")
Expand Down Expand Up @@ -362,24 +405,53 @@ func (s *Service) processBlksInRange(ctx context.Context, startBlk uint64, endBl
return nil
}

// checkForChainStart checks the given block number for if chainstart has occurred.
func (s *Service) checkForChainStart(ctx context.Context, blkNum *big.Int) error {
blk, err := s.blockFetcher.BlockByNumber(ctx, blkNum)
// checkBlockNumberForChainStart checks the given block number for if chainstart has occurred.
func (s *Service) checkBlockNumberForChainStart(ctx context.Context, blkNum *big.Int) error {
hash, err := s.BlockHashByHeight(ctx, blkNum)
if err != nil {
return errors.Wrap(err, "could not get eth1 block")
return errors.Wrap(err, "could not get eth1 block hash")
}
if hash == [32]byte{} {
return errors.Wrap(err, "got empty block hash")
}
if blk == nil {
return errors.Wrap(err, "got empty block from powchain service")

timeStamp, err := s.BlockTimeByHeight(ctx, blkNum)
if err != nil {
return errors.Wrap(err, "could not get block timestamp")
}
if blk.Hash() == [32]byte{} {
return errors.New("got empty blockhash from powchain service")
s.checkForChainstart(hash, blkNum, timeStamp)
return nil
}

func (s *Service) checkHeaderForChainstart(header *gethTypes.Header) {
s.checkForChainstart(header.Hash(), header.Number, header.Time)
}

func (s *Service) checkHeaderRange(start uint64, end uint64,
headersMap map[uint64]*gethTypes.Header,
requestHeaders func(uint64, uint64) error) error {
for i := start; i <= end; i++ {
if !s.chainStartData.Chainstarted {
h, ok := headersMap[i]
if !ok {
if err := requestHeaders(i, i+eth1HeaderReqLimit); err != nil {
return err
}
// Retry this block.
i--
continue
}
s.checkHeaderForChainstart(h)
}
}
timeStamp := blk.Time()
return nil
}

func (s *Service) checkForChainstart(blockHash [32]byte, blockNumber *big.Int, blockTime uint64) {
valCount, _ := helpers.ActiveValidatorCount(s.preGenesisState, 0)
triggered := state.IsValidGenesisState(valCount, s.createGenesisTime(timeStamp))
triggered := state.IsValidGenesisState(valCount, s.createGenesisTime(blockTime))
if triggered {
s.chainStartData.GenesisTime = s.createGenesisTime(timeStamp)
s.ProcessChainStart(s.chainStartData.GenesisTime, blk.Hash(), blk.Number())
s.chainStartData.GenesisTime = s.createGenesisTime(blockTime)
s.ProcessChainStart(s.chainStartData.GenesisTime, blockHash, blockNumber)
}
return nil
}
8 changes: 8 additions & 0 deletions beacon-chain/powchain/log_processing_test.go
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/flags"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
Expand Down Expand Up @@ -451,12 +453,14 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
if err != nil {
t.Fatal(err)
}
web3Service.rpcClient = &mockPOW.RPCClient{Backend: testAcc.Backend}
web3Service.httpLogger = testAcc.Backend
web3Service.latestEth1Data.LastRequestedBlock = 0
web3Service.latestEth1Data.BlockHeight = 0
bConfig := params.MinimalSpecConfig()
bConfig.MinGenesisTime = 0
params.OverrideBeaconConfig(bConfig)
flags.Get().DeploymentBlock = 0

testAcc.Backend.Commit()
testAcc.Backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond())))
Expand Down Expand Up @@ -486,6 +490,7 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
testAcc.Backend.Commit()
}
}
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()

// Set up our subscriber now to listen for the chain started event.
stateChannel := make(chan *feed.Event, 1)
Expand Down Expand Up @@ -631,6 +636,7 @@ func TestWeb3ServiceProcessDepositLog_RequestMissedDeposits(t *testing.T) {
}

func TestConsistentGenesisState(t *testing.T) {
t.Skip("Incorrect test setup")
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
Expand Down Expand Up @@ -715,6 +721,8 @@ func newPowchainService(t *testing.T, eth1Backend *contracts.TestAccount, beacon
if err != nil {
t.Fatal(err)
}

web3Service.rpcClient = &mockPOW.RPCClient{Backend: eth1Backend.Backend}
web3Service.reader = &goodReader{backend: eth1Backend.Backend}
web3Service.blockFetcher = &goodFetcher{backend: eth1Backend.Backend}
web3Service.httpLogger = &goodLogger{backend: eth1Backend.Backend}
Expand Down

0 comments on commit 2e5429c

Please sign in to comment.