From 39d2ac4dbc4e55e95d78d5833b06440923baad50 Mon Sep 17 00:00:00 2001 From: Erik Grinaker Date: Thu, 3 Sep 2020 17:05:04 +0200 Subject: [PATCH] statesync: fix the validator set heights (again) (#5330) This reverts the "fix" in #5311, after the real fix in #5328. --- CHANGELOG_PENDING.md | 2 -- statesync/stateprovider.go | 31 +++++++++++++++++++------------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 918f59eb6..a74cac809 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -42,8 +42,6 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi - [statesync] \#5302 Fix genesis state propagation to state sync routine (@erikgrinaker) -- [statesync] \#5311 Fix validator set off-by-one causing consensus failures (@erikgrinaker) - - [statesync] \#5320 Broadcast snapshot request to all pre-connected peers on start (@erikgrinaker) - [consensus] \#5329 Fix wrong proposer schedule for validators returned by `InitChain` (@erikgrinaker) diff --git a/statesync/stateprovider.go b/statesync/stateprovider.go index f805e0f2c..1abe5b92a 100644 --- a/statesync/stateprovider.go +++ b/statesync/stateprovider.go @@ -120,29 +120,36 @@ func (s *lightClientStateProvider) State(height uint64) (sm.State, error) { state.InitialHeight = 1 } - // We need to verify the previous block to get the validator set. - prevLightBlock, err := s.lc.VerifyLightBlockAtHeight(int64(height-1), time.Now()) + // The snapshot height maps onto the state heights as follows: + // + // height: last block, i.e. the snapshotted height + // height+1: current block, i.e. the first block we'll process after the snapshot + // height+2: next block, i.e. the second block after the snapshot + // + // We need to fetch the NextValidators from height+2 because if the application changed + // the validator set at the snapshot height then this only takes effect at height+2. + lastLightBlock, err := s.lc.VerifyLightBlockAtHeight(int64(height), time.Now()) if err != nil { return sm.State{}, err } - lightBlock, err := s.lc.VerifyLightBlockAtHeight(int64(height), time.Now()) + curLightBlock, err := s.lc.VerifyLightBlockAtHeight(int64(height+1), time.Now()) if err != nil { return sm.State{}, err } - nextLightBlock, err := s.lc.VerifyLightBlockAtHeight(int64(height+1), time.Now()) + nextLightBlock, err := s.lc.VerifyLightBlockAtHeight(int64(height+2), time.Now()) if err != nil { return sm.State{}, err } - state.LastBlockHeight = lightBlock.Height - state.LastBlockTime = lightBlock.Time - state.LastBlockID = lightBlock.Commit.BlockID - state.AppHash = nextLightBlock.AppHash - state.LastResultsHash = nextLightBlock.LastResultsHash - state.LastValidators = prevLightBlock.ValidatorSet - state.Validators = lightBlock.ValidatorSet + state.LastBlockHeight = lastLightBlock.Height + state.LastBlockTime = lastLightBlock.Time + state.LastBlockID = lastLightBlock.Commit.BlockID + state.AppHash = curLightBlock.AppHash + state.LastResultsHash = curLightBlock.LastResultsHash + state.LastValidators = lastLightBlock.ValidatorSet + state.Validators = curLightBlock.ValidatorSet state.NextValidators = nextLightBlock.ValidatorSet - state.LastHeightValidatorsChanged = int64(height) + state.LastHeightValidatorsChanged = nextLightBlock.Height // We'll also need to fetch consensus params via RPC, using light client verification. primaryURL, ok := s.providers[s.lc.Primary()]