Refactor updateState #2865 (#2929)

* Refactor updateState #2865

* Apply suggestions from code review

Co-Authored-By: danil-lashin <danil-lashin@yandex.ru>

* Apply suggestions from code review
This commit is contained in:
Daniil Lashin
2018-11-28 16:32:16 +03:00
committed by Ethan Buchman
parent ef9902e602
commit 7213869fc6
3 changed files with 41 additions and 32 deletions

View File

@ -107,8 +107,18 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
fail.Fail() // XXX fail.Fail() // XXX
// these are tendermint types now
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates)
if err != nil {
return state, err
}
if len(validatorUpdates) > 0 {
blockExec.logger.Info("Updates to validators", "updates", makeValidatorUpdatesLogString(validatorUpdates))
}
// Update the state with the block and responses. // Update the state with the block and responses.
state, err = updateState(blockExec.logger, state, blockID, &block.Header, abciResponses) state, err = updateState(state, blockID, &block.Header, abciResponses, validatorUpdates)
if err != nil { if err != nil {
return state, fmt.Errorf("Commit failed for application: %v", err) return state, fmt.Errorf("Commit failed for application: %v", err)
} }
@ -132,7 +142,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
// Events are fired after everything else. // Events are fired after everything else.
// NOTE: if we crash between Commit and Save, events wont be fired during replay // NOTE: if we crash between Commit and Save, events wont be fired during replay
fireEvents(blockExec.logger, blockExec.eventBus, block, abciResponses) fireEvents(blockExec.logger, blockExec.eventBus, block, abciResponses, validatorUpdates)
return state, nil return state, nil
} }
@ -311,16 +321,10 @@ func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorS
// If more or equal than 1/3 of total voting power changed in one block, then // If more or equal than 1/3 of total voting power changed in one block, then
// a light client could never prove the transition externally. See // a light client could never prove the transition externally. See
// ./lite/doc.go for details on how a light client tracks validators. // ./lite/doc.go for details on how a light client tracks validators.
func updateValidators(currentSet *types.ValidatorSet, abciUpdates []abci.ValidatorUpdate) ([]*types.Validator, error) { func updateValidators(currentSet *types.ValidatorSet, updates []*types.Validator) error {
updates, err := types.PB2TM.ValidatorUpdates(abciUpdates)
if err != nil {
return nil, err
}
// these are tendermint types now
for _, valUpdate := range updates { for _, valUpdate := range updates {
if valUpdate.VotingPower < 0 { if valUpdate.VotingPower < 0 {
return nil, fmt.Errorf("Voting power can't be negative %v", valUpdate) return fmt.Errorf("Voting power can't be negative %v", valUpdate)
} }
address := valUpdate.Address address := valUpdate.Address
@ -329,32 +333,32 @@ func updateValidators(currentSet *types.ValidatorSet, abciUpdates []abci.Validat
// remove val // remove val
_, removed := currentSet.Remove(address) _, removed := currentSet.Remove(address)
if !removed { if !removed {
return nil, fmt.Errorf("Failed to remove validator %X", address) return fmt.Errorf("Failed to remove validator %X", address)
} }
} else if val == nil { } else if val == nil {
// add val // add val
added := currentSet.Add(valUpdate) added := currentSet.Add(valUpdate)
if !added { if !added {
return nil, fmt.Errorf("Failed to add new validator %v", valUpdate) return fmt.Errorf("Failed to add new validator %v", valUpdate)
} }
} else { } else {
// update val // update val
updated := currentSet.Update(valUpdate) updated := currentSet.Update(valUpdate)
if !updated { if !updated {
return nil, fmt.Errorf("Failed to update validator %X to %v", address, valUpdate) return fmt.Errorf("Failed to update validator %X to %v", address, valUpdate)
} }
} }
} }
return updates, nil return nil
} }
// updateState returns a new State updated according to the header and responses. // updateState returns a new State updated according to the header and responses.
func updateState( func updateState(
logger log.Logger,
state State, state State,
blockID types.BlockID, blockID types.BlockID,
header *types.Header, header *types.Header,
abciResponses *ABCIResponses, abciResponses *ABCIResponses,
validatorUpdates []*types.Validator,
) (State, error) { ) (State, error) {
// Copy the valset so we can apply changes from EndBlock // Copy the valset so we can apply changes from EndBlock
@ -364,14 +368,12 @@ func updateState(
// Update the validator set with the latest abciResponses. // Update the validator set with the latest abciResponses.
lastHeightValsChanged := state.LastHeightValidatorsChanged lastHeightValsChanged := state.LastHeightValidatorsChanged
if len(abciResponses.EndBlock.ValidatorUpdates) > 0 { if len(abciResponses.EndBlock.ValidatorUpdates) > 0 {
validatorUpdates, err := updateValidators(nValSet, abciResponses.EndBlock.ValidatorUpdates) err := updateValidators(nValSet, validatorUpdates)
if err != nil { if err != nil {
return state, fmt.Errorf("Error changing validator set: %v", err) return state, fmt.Errorf("Error changing validator set: %v", err)
} }
// Change results from this height but only applies to the next next height. // Change results from this height but only applies to the next next height.
lastHeightValsChanged = header.Height + 1 + 1 lastHeightValsChanged = header.Height + 1 + 1
logger.Info("Updates to validators", "updates", makeValidatorUpdatesLogString(validatorUpdates))
} }
// Update validator accums and set state variables. // Update validator accums and set state variables.
@ -417,7 +419,7 @@ func updateState(
// Fire NewBlock, NewBlockHeader. // Fire NewBlock, NewBlockHeader.
// Fire TxEvent for every tx. // Fire TxEvent for every tx.
// NOTE: if Tendermint crashes before commit, some or all of these events may be published again. // NOTE: if Tendermint crashes before commit, some or all of these events may be published again.
func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *types.Block, abciResponses *ABCIResponses) { func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *types.Block, abciResponses *ABCIResponses, validatorUpdates []*types.Validator) {
eventBus.PublishEventNewBlock(types.EventDataNewBlock{ eventBus.PublishEventNewBlock(types.EventDataNewBlock{
Block: block, Block: block,
ResultBeginBlock: *abciResponses.BeginBlock, ResultBeginBlock: *abciResponses.BeginBlock,
@ -438,12 +440,9 @@ func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *ty
}}) }})
} }
abciValUpdates := abciResponses.EndBlock.ValidatorUpdates if len(validatorUpdates) > 0 {
if len(abciValUpdates) > 0 {
// if there were an error, we would've stopped in updateValidators
updates, _ := types.PB2TM.ValidatorUpdates(abciValUpdates)
eventBus.PublishEventValidatorSetUpdates( eventBus.PublishEventValidatorSetUpdates(
types.EventDataValidatorSetUpdates{ValidatorUpdates: updates}) types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates})
} }
} }

View File

@ -218,7 +218,9 @@ func TestUpdateValidators(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
_, err := updateValidators(tc.currentSet, tc.abciUpdates) updates, err := types.PB2TM.ValidatorUpdates(tc.abciUpdates)
assert.NoError(t, err)
err = updateValidators(tc.currentSet, updates)
if tc.shouldErr { if tc.shouldErr {
assert.Error(t, err) assert.Error(t, err)
} else { } else {

View File

@ -5,12 +5,11 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/tendermint/tendermint/libs/log"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
crypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/ed25519"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db" dbm "github.com/tendermint/tendermint/libs/db"
@ -223,6 +222,7 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) {
_, val := state.Validators.GetByIndex(0) _, val := state.Validators.GetByIndex(0)
power := val.VotingPower power := val.VotingPower
var err error var err error
var validatorUpdates []*types.Validator
for i := int64(1); i < highestHeight; i++ { for i := int64(1); i < highestHeight; i++ {
// When we get to a change height, use the next pubkey. // When we get to a change height, use the next pubkey.
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] { if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] {
@ -230,8 +230,10 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) {
power++ power++
} }
header, blockID, responses := makeHeaderPartsResponsesValPowerChange(state, i, power) header, blockID, responses := makeHeaderPartsResponsesValPowerChange(state, i, power)
state, err = updateState(log.TestingLogger(), state, blockID, &header, responses) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates)
assert.Nil(t, err) require.NoError(t, err)
state, err = updateState(state, blockID, &header, responses, validatorUpdates)
require.NoError(t, err)
nextHeight := state.LastBlockHeight + 1 nextHeight := state.LastBlockHeight + 1
saveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators) saveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators)
} }
@ -303,7 +305,10 @@ func TestManyValidatorChangesSaveLoad(t *testing.T) {
// Save state etc. // Save state etc.
var err error var err error
state, err = updateState(log.TestingLogger(), state, blockID, &header, responses) var validatorUpdates []*types.Validator
validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates)
require.NoError(t, err)
state, err = updateState(state, blockID, &header, responses, validatorUpdates)
require.Nil(t, err) require.Nil(t, err)
nextHeight := state.LastBlockHeight + 1 nextHeight := state.LastBlockHeight + 1
saveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators) saveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators)
@ -375,6 +380,7 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
changeIndex := 0 changeIndex := 0
cp := params[changeIndex] cp := params[changeIndex]
var err error var err error
var validatorUpdates []*types.Validator
for i := int64(1); i < highestHeight; i++ { for i := int64(1); i < highestHeight; i++ {
// When we get to a change height, use the next params. // When we get to a change height, use the next params.
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] { if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] {
@ -382,7 +388,9 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
cp = params[changeIndex] cp = params[changeIndex]
} }
header, blockID, responses := makeHeaderPartsResponsesParams(state, i, cp) header, blockID, responses := makeHeaderPartsResponsesParams(state, i, cp)
state, err = updateState(log.TestingLogger(), state, blockID, &header, responses) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates)
require.NoError(t, err)
state, err = updateState(state, blockID, &header, responses, validatorUpdates)
require.Nil(t, err) require.Nil(t, err)
nextHeight := state.LastBlockHeight + 1 nextHeight := state.LastBlockHeight + 1