mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-24 22:32:15 +00:00
Delay validator set changes by 1 block.
This commit is contained in:
parent
ce0d0b312f
commit
a5b7ea93c4
4
Makefile
4
Makefile
@ -132,11 +132,11 @@ vagrant_test:
|
|||||||
### go tests
|
### go tests
|
||||||
test:
|
test:
|
||||||
@echo "--> Running go test"
|
@echo "--> Running go test"
|
||||||
@go test $(PACKAGES)
|
@GOCACHE=off go test -p 1 $(PACKAGES)
|
||||||
|
|
||||||
test_race:
|
test_race:
|
||||||
@echo "--> Running go test --race"
|
@echo "--> Running go test --race"
|
||||||
@go test -v -race $(PACKAGES)
|
@GOCACHE=off go test -p 1 -v -race $(PACKAGES)
|
||||||
|
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
@ -174,14 +174,14 @@ func TestReactorRecordsBlockParts(t *testing.T) {
|
|||||||
require.Equal(t, 1, ps.BlockPartsSent(), "number of block parts sent should stay the same")
|
require.Equal(t, 1, ps.BlockPartsSent(), "number of block parts sent should stay the same")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test we record votes from other peers
|
// Test we record votes from other peers.
|
||||||
func TestReactorRecordsVotes(t *testing.T) {
|
func TestReactorRecordsVotes(t *testing.T) {
|
||||||
// create dummy peer
|
// Create dummy peer.
|
||||||
peer := p2pdummy.NewPeer()
|
peer := p2pdummy.NewPeer()
|
||||||
ps := NewPeerState(peer).SetLogger(log.TestingLogger())
|
ps := NewPeerState(peer).SetLogger(log.TestingLogger())
|
||||||
peer.Set(types.PeerStateKey, ps)
|
peer.Set(types.PeerStateKey, ps)
|
||||||
|
|
||||||
// create reactor
|
// Create reactor.
|
||||||
css := randConsensusNet(1, "consensus_reactor_records_votes_test", newMockTickerFunc(true), newPersistentKVStore)
|
css := randConsensusNet(1, "consensus_reactor_records_votes_test", newMockTickerFunc(true), newPersistentKVStore)
|
||||||
reactor := NewConsensusReactor(css[0], false) // so we dont start the consensus states
|
reactor := NewConsensusReactor(css[0], false) // so we dont start the consensus states
|
||||||
reactor.SetEventBus(css[0].eventBus)
|
reactor.SetEventBus(css[0].eventBus)
|
||||||
|
@ -264,15 +264,15 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
|
|||||||
stateBlockHeight := state.LastBlockHeight
|
stateBlockHeight := state.LastBlockHeight
|
||||||
h.logger.Info("ABCI Replay Blocks", "appHeight", appBlockHeight, "storeHeight", storeBlockHeight, "stateHeight", stateBlockHeight)
|
h.logger.Info("ABCI Replay Blocks", "appHeight", appBlockHeight, "storeHeight", storeBlockHeight, "stateHeight", stateBlockHeight)
|
||||||
|
|
||||||
// If appBlockHeight == 0 it means that we are at genesis and hence should send InitChain
|
// If appBlockHeight == 0 it means that we are at genesis and hence should send InitChain.
|
||||||
if appBlockHeight == 0 {
|
if appBlockHeight == 0 {
|
||||||
validators := types.TM2PB.Validators(state.Validators)
|
nvals := types.TM2PB.Validators(state.Validators) // state.Validators would work too.
|
||||||
csParams := types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams)
|
csParams := types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams)
|
||||||
req := abci.RequestInitChain{
|
req := abci.RequestInitChain{
|
||||||
Time: h.genDoc.GenesisTime.Unix(), // TODO
|
Time: h.genDoc.GenesisTime.Unix(), // TODO
|
||||||
ChainId: h.genDoc.ChainID,
|
ChainId: h.genDoc.ChainID,
|
||||||
ConsensusParams: csParams,
|
ConsensusParams: csParams,
|
||||||
Validators: validators,
|
Validators: nvals,
|
||||||
AppStateBytes: h.genDoc.AppStateJSON,
|
AppStateBytes: h.genDoc.AppStateJSON,
|
||||||
}
|
}
|
||||||
res, err := proxyApp.Consensus().InitChainSync(req)
|
res, err := proxyApp.Consensus().InitChainSync(req)
|
||||||
@ -280,9 +280,7 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the app returned validators
|
// If the app returned validators or consensus params, update the state.
|
||||||
// or consensus params, update the state
|
|
||||||
// with the them
|
|
||||||
if len(res.Validators) > 0 {
|
if len(res.Validators) > 0 {
|
||||||
vals, err := types.PB2TM.Validators(res.Validators)
|
vals, err := types.PB2TM.Validators(res.Validators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -296,7 +294,7 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
|
|||||||
sm.SaveState(h.stateDB, state)
|
sm.SaveState(h.stateDB, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// First handle edge cases and constraints on the storeBlockHeight
|
// First handle edge cases and constraints on the storeBlockHeight.
|
||||||
if storeBlockHeight == 0 {
|
if storeBlockHeight == 0 {
|
||||||
return appHash, checkAppHash(state, appHash)
|
return appHash, checkAppHash(state, appHash)
|
||||||
|
|
||||||
|
@ -74,7 +74,6 @@ type ConsensusState struct {
|
|||||||
privValidator types.PrivValidator // for signing votes
|
privValidator types.PrivValidator // for signing votes
|
||||||
|
|
||||||
// services for creating and executing blocks
|
// services for creating and executing blocks
|
||||||
// TODO: encapsulate all of this in one "BlockManager"
|
|
||||||
blockExec *sm.BlockExecutor
|
blockExec *sm.BlockExecutor
|
||||||
blockStore sm.BlockStore
|
blockStore sm.BlockStore
|
||||||
mempool sm.Mempool
|
mempool sm.Mempool
|
||||||
|
@ -64,22 +64,22 @@ func TestStateProposerSelection0(t *testing.T) {
|
|||||||
|
|
||||||
startTestRound(cs1, height, round)
|
startTestRound(cs1, height, round)
|
||||||
|
|
||||||
// wait for new round so proposer is set
|
// Wait for new round so proposer is set.
|
||||||
<-newRoundCh
|
<-newRoundCh
|
||||||
|
|
||||||
// lets commit a block and ensure proposer for the next height is correct
|
// Commit a block and ensure proposer for the next height is correct.
|
||||||
prop := cs1.GetRoundState().Validators.GetProposer()
|
prop := cs1.GetRoundState().Validators.GetProposer()
|
||||||
if !bytes.Equal(prop.Address, cs1.privValidator.GetAddress()) {
|
if !bytes.Equal(prop.Address, cs1.privValidator.GetAddress()) {
|
||||||
t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address)
|
t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for complete proposal
|
// Wait for complete proposal.
|
||||||
<-proposalCh
|
<-proposalCh
|
||||||
|
|
||||||
rs := cs1.GetRoundState()
|
rs := cs1.GetRoundState()
|
||||||
signAddVotes(cs1, types.VoteTypePrecommit, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vss[1:]...)
|
signAddVotes(cs1, types.VoteTypePrecommit, rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(), vss[1:]...)
|
||||||
|
|
||||||
// wait for new round so next validator is set
|
// Wait for new round so next validator is set.
|
||||||
<-newRoundCh
|
<-newRoundCh
|
||||||
|
|
||||||
prop = cs1.GetRoundState().Validators.GetProposer()
|
prop = cs1.GetRoundState().Validators.GetProposer()
|
||||||
|
@ -27,6 +27,7 @@ func initializeValidatorState(valAddr []byte, height int64) dbm.DB {
|
|||||||
LastBlockHeight: 0,
|
LastBlockHeight: 0,
|
||||||
LastBlockTime: time.Now(),
|
LastBlockTime: time.Now(),
|
||||||
Validators: valSet,
|
Validators: valSet,
|
||||||
|
NextValidators: valSet.CopyIncrementAccum(1),
|
||||||
LastHeightValidatorsChanged: 1,
|
LastHeightValidatorsChanged: 1,
|
||||||
ConsensusParams: types.ConsensusParams{
|
ConsensusParams: types.ConsensusParams{
|
||||||
EvidenceParams: types.EvidenceParams{
|
EvidenceParams: types.EvidenceParams{
|
||||||
|
@ -109,7 +109,7 @@ func validatorAtHeight(h int64) *types.Validator {
|
|||||||
|
|
||||||
privValAddress := pubKey.Address()
|
privValAddress := pubKey.Address()
|
||||||
|
|
||||||
// if we're still at height h, search in the current validator set
|
// If we're still at height h, search in the current validator set.
|
||||||
if lastBlockHeight == h {
|
if lastBlockHeight == h {
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
if bytes.Equal(val.Address, privValAddress) {
|
if bytes.Equal(val.Address, privValAddress) {
|
||||||
@ -118,12 +118,11 @@ func validatorAtHeight(h int64) *types.Validator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we've moved to the next height, retrieve the validator set from DB
|
// If we've moved to the next height, retrieve the validator set from DB.
|
||||||
if lastBlockHeight > h {
|
if lastBlockHeight > h {
|
||||||
vals, err := sm.LoadValidators(stateDB, h)
|
vals, err := sm.LoadValidators(stateDB, h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// should not happen
|
return nil // should not happen
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
_, val := vals.GetByAddress(privValAddress)
|
_, val := vals.GetByAddress(privValAddress)
|
||||||
return val
|
return val
|
||||||
|
@ -80,18 +80,18 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
|
|||||||
|
|
||||||
fail.Fail() // XXX
|
fail.Fail() // XXX
|
||||||
|
|
||||||
// save the results before we commit
|
// Save the results before we commit.
|
||||||
saveABCIResponses(blockExec.db, block.Height, abciResponses)
|
saveABCIResponses(blockExec.db, block.Height, abciResponses)
|
||||||
|
|
||||||
fail.Fail() // XXX
|
fail.Fail() // XXX
|
||||||
|
|
||||||
// update the state with the block and responses
|
// Update the state with the block and responses.
|
||||||
state, err = updateState(state, blockID, block.Header, abciResponses)
|
state, err = updateState(state, blockID, block.Header, abciResponses)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// lock mempool, commit app state, update mempoool
|
// Lock mempool, commit app state, update mempoool.
|
||||||
appHash, err := blockExec.Commit(block)
|
appHash, err := blockExec.Commit(block)
|
||||||
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)
|
||||||
@ -102,13 +102,13 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
|
|||||||
|
|
||||||
fail.Fail() // XXX
|
fail.Fail() // XXX
|
||||||
|
|
||||||
// update the app hash and save the state
|
// Update the app hash and save the state.
|
||||||
state.AppHash = appHash
|
state.AppHash = appHash
|
||||||
SaveState(blockExec.db, state)
|
SaveState(blockExec.db, state)
|
||||||
|
|
||||||
fail.Fail() // XXX
|
fail.Fail() // XXX
|
||||||
|
|
||||||
// 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)
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||||||
txIndex := 0
|
txIndex := 0
|
||||||
abciResponses := NewABCIResponses(block)
|
abciResponses := NewABCIResponses(block)
|
||||||
|
|
||||||
// Execute transactions and get hash
|
// Execute transactions and get hash.
|
||||||
proxyCb := func(req *abci.Request, res *abci.Response) {
|
proxyCb := func(req *abci.Request, res *abci.Response) {
|
||||||
switch r := res.Value.(type) {
|
switch r := res.Value.(type) {
|
||||||
case *abci.Response_DeliverTx:
|
case *abci.Response_DeliverTx:
|
||||||
@ -186,7 +186,7 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||||||
|
|
||||||
signVals, byzVals := getBeginBlockValidatorInfo(block, lastValSet, stateDB)
|
signVals, byzVals := getBeginBlockValidatorInfo(block, lastValSet, stateDB)
|
||||||
|
|
||||||
// Begin block
|
// Begin block.
|
||||||
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
|
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
|
||||||
Hash: block.Hash(),
|
Hash: block.Hash(),
|
||||||
Header: types.TM2PB.Header(block.Header),
|
Header: types.TM2PB.Header(block.Header),
|
||||||
@ -198,7 +198,7 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run txs of block
|
// Run txs of block.
|
||||||
for _, tx := range block.Txs {
|
for _, tx := range block.Txs {
|
||||||
proxyAppConn.DeliverTxAsync(tx)
|
proxyAppConn.DeliverTxAsync(tx)
|
||||||
if err := proxyAppConn.Error(); err != nil {
|
if err := proxyAppConn.Error(); err != nil {
|
||||||
@ -206,7 +206,7 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// End block
|
// End block.
|
||||||
abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{block.Height})
|
abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{block.Height})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error in proxyAppConn.EndBlock", "err", err)
|
logger.Error("Error in proxyAppConn.EndBlock", "err", err)
|
||||||
@ -307,26 +307,25 @@ func updateValidators(currentSet *types.ValidatorSet, abciUpdates []abci.Validat
|
|||||||
func updateState(state State, blockID types.BlockID, header *types.Header,
|
func updateState(state State, blockID types.BlockID, header *types.Header,
|
||||||
abciResponses *ABCIResponses) (State, error) {
|
abciResponses *ABCIResponses) (State, error) {
|
||||||
|
|
||||||
// copy the valset so we can apply changes from EndBlock
|
// Copy the valset so we can apply changes from EndBlock
|
||||||
// and update s.LastValidators and s.Validators
|
// and update s.LastValidators and s.Validators.
|
||||||
prevValSet := state.Validators.Copy()
|
nValSet := state.NextValidators.Copy()
|
||||||
nextValSet := prevValSet.Copy()
|
|
||||||
|
|
||||||
// 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 {
|
||||||
err := updateValidators(nextValSet, abciResponses.EndBlock.ValidatorUpdates)
|
err := updateValidators(nValSet, abciResponses.EndBlock.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 height
|
// Change results from this height but only applies to the next next height.
|
||||||
lastHeightValsChanged = header.Height + 1
|
lastHeightValsChanged = header.Height + 1 + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update validator accums and set state variables
|
// Update validator accums and set state variables.
|
||||||
nextValSet.IncrementAccum(1)
|
nValSet.IncrementAccum(1)
|
||||||
|
|
||||||
// update the params with the latest abciResponses
|
// Update the params with the latest abciResponses.
|
||||||
nextParams := state.ConsensusParams
|
nextParams := state.ConsensusParams
|
||||||
lastHeightParamsChanged := state.LastHeightConsensusParamsChanged
|
lastHeightParamsChanged := state.LastHeightConsensusParamsChanged
|
||||||
if abciResponses.EndBlock.ConsensusParamUpdates != nil {
|
if abciResponses.EndBlock.ConsensusParamUpdates != nil {
|
||||||
@ -336,7 +335,7 @@ func updateState(state State, blockID types.BlockID, header *types.Header,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return state, fmt.Errorf("Error updating consensus params: %v", err)
|
return state, fmt.Errorf("Error updating consensus params: %v", err)
|
||||||
}
|
}
|
||||||
// change results from this height but only applies to the next height
|
// Change results from this height but only applies to the next height.
|
||||||
lastHeightParamsChanged = header.Height + 1
|
lastHeightParamsChanged = header.Height + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +347,8 @@ func updateState(state State, blockID types.BlockID, header *types.Header,
|
|||||||
LastBlockTotalTx: state.LastBlockTotalTx + header.NumTxs,
|
LastBlockTotalTx: state.LastBlockTotalTx + header.NumTxs,
|
||||||
LastBlockID: blockID,
|
LastBlockID: blockID,
|
||||||
LastBlockTime: header.Time,
|
LastBlockTime: header.Time,
|
||||||
Validators: nextValSet,
|
NextValidators: nValSet,
|
||||||
|
Validators: state.NextValidators.Copy(),
|
||||||
LastValidators: state.Validators.Copy(),
|
LastValidators: state.Validators.Copy(),
|
||||||
LastHeightValidatorsChanged: lastHeightValsChanged,
|
LastHeightValidatorsChanged: lastHeightValsChanged,
|
||||||
ConsensusParams: nextParams,
|
ConsensusParams: nextParams,
|
||||||
|
@ -24,7 +24,7 @@ var (
|
|||||||
// Instead, use state.Copy() or state.NextState(...).
|
// Instead, use state.Copy() or state.NextState(...).
|
||||||
// NOTE: not goroutine-safe.
|
// NOTE: not goroutine-safe.
|
||||||
type State struct {
|
type State struct {
|
||||||
// Immutable
|
// immutable
|
||||||
ChainID string
|
ChainID string
|
||||||
|
|
||||||
// LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
|
// LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
|
||||||
@ -38,6 +38,7 @@ type State struct {
|
|||||||
// so we can query for historical validator sets.
|
// so we can query for historical validator sets.
|
||||||
// Note that if s.LastBlockHeight causes a valset change,
|
// Note that if s.LastBlockHeight causes a valset change,
|
||||||
// we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1
|
// we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1
|
||||||
|
NextValidators *types.ValidatorSet
|
||||||
Validators *types.ValidatorSet
|
Validators *types.ValidatorSet
|
||||||
LastValidators *types.ValidatorSet
|
LastValidators *types.ValidatorSet
|
||||||
LastHeightValidatorsChanged int64
|
LastHeightValidatorsChanged int64
|
||||||
@ -50,7 +51,7 @@ type State struct {
|
|||||||
// Merkle root of the results from executing prev block
|
// Merkle root of the results from executing prev block
|
||||||
LastResultsHash []byte
|
LastResultsHash []byte
|
||||||
|
|
||||||
// The latest AppHash we've received from calling abci.Commit()
|
// the latest AppHash we've received from calling abci.Commit()
|
||||||
AppHash []byte
|
AppHash []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ func (state State) Copy() State {
|
|||||||
LastBlockID: state.LastBlockID,
|
LastBlockID: state.LastBlockID,
|
||||||
LastBlockTime: state.LastBlockTime,
|
LastBlockTime: state.LastBlockTime,
|
||||||
|
|
||||||
|
NextValidators: state.NextValidators.Copy(),
|
||||||
Validators: state.Validators.Copy(),
|
Validators: state.Validators.Copy(),
|
||||||
LastValidators: state.LastValidators.Copy(),
|
LastValidators: state.LastValidators.Copy(),
|
||||||
LastHeightValidatorsChanged: state.LastHeightValidatorsChanged,
|
LastHeightValidatorsChanged: state.LastHeightValidatorsChanged,
|
||||||
@ -93,24 +95,20 @@ func (state State) IsEmpty() bool {
|
|||||||
return state.Validators == nil // XXX can't compare to Empty
|
return state.Validators == nil // XXX can't compare to Empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetValidators returns the last and current validator sets.
|
|
||||||
func (state State) GetValidators() (last *types.ValidatorSet, current *types.ValidatorSet) {
|
|
||||||
return state.LastValidators, state.Validators
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
// Create a block from the latest state
|
// Create a block from the latest state
|
||||||
|
|
||||||
// MakeBlock builds a block with the given txs and commit from the current state.
|
// MakeBlock builds a block with the given txs and commit from the current state.
|
||||||
func (state State) MakeBlock(height int64, txs []types.Tx, commit *types.Commit) (*types.Block, *types.PartSet) {
|
func (state State) MakeBlock(height int64, txs []types.Tx, commit *types.Commit) (*types.Block, *types.PartSet) {
|
||||||
// build base block
|
// Build base block.
|
||||||
block := types.MakeBlock(height, txs, commit)
|
block := types.MakeBlock(height, txs, commit)
|
||||||
|
|
||||||
// fill header with state data
|
// Fill header with state data.
|
||||||
block.ChainID = state.ChainID
|
block.ChainID = state.ChainID
|
||||||
block.TotalTxs = state.LastBlockTotalTx + block.NumTxs
|
block.TotalTxs = state.LastBlockTotalTx + block.NumTxs
|
||||||
block.LastBlockID = state.LastBlockID
|
block.LastBlockID = state.LastBlockID
|
||||||
block.ValidatorsHash = state.Validators.Hash()
|
block.ValidatorsHash = state.Validators.Hash()
|
||||||
|
block.NextValidatorsHash = state.NextValidators.Hash()
|
||||||
block.AppHash = state.AppHash
|
block.AppHash = state.AppHash
|
||||||
block.ConsensusHash = state.ConsensusParams.Hash()
|
block.ConsensusHash = state.ConsensusParams.Hash()
|
||||||
block.LastResultsHash = state.LastResultsHash
|
block.LastResultsHash = state.LastResultsHash
|
||||||
@ -175,6 +173,7 @@ func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
|
|||||||
LastBlockID: types.BlockID{},
|
LastBlockID: types.BlockID{},
|
||||||
LastBlockTime: genDoc.GenesisTime,
|
LastBlockTime: genDoc.GenesisTime,
|
||||||
|
|
||||||
|
NextValidators: types.NewValidatorSet(validators).CopyIncrementAccum(1),
|
||||||
Validators: types.NewValidatorSet(validators),
|
Validators: types.NewValidatorSet(validators),
|
||||||
LastValidators: types.NewValidatorSet(nil),
|
LastValidators: types.NewValidatorSet(nil),
|
||||||
LastHeightValidatorsChanged: 1,
|
LastHeightValidatorsChanged: 1,
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// setupTestCase does setup common to all test cases
|
// setupTestCase does setup common to all test cases.
|
||||||
func setupTestCase(t *testing.T) (func(t *testing.T), dbm.DB, State) {
|
func setupTestCase(t *testing.T) (func(t *testing.T), dbm.DB, State) {
|
||||||
config := cfg.ResetTestRoot("state_")
|
config := cfg.ResetTestRoot("state_")
|
||||||
dbType := dbm.DBBackendType(config.DBBackend)
|
dbType := dbm.DBBackendType(config.DBBackend)
|
||||||
@ -72,7 +72,7 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
|
|||||||
|
|
||||||
state.LastBlockHeight++
|
state.LastBlockHeight++
|
||||||
|
|
||||||
// build mock responses
|
// Build mock responses.
|
||||||
block := makeBlock(state, 2)
|
block := makeBlock(state, 2)
|
||||||
abciResponses := NewABCIResponses(block)
|
abciResponses := NewABCIResponses(block)
|
||||||
abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: nil}
|
abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: nil}
|
||||||
@ -89,7 +89,7 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
|
|||||||
loadedABCIResponses, abciResponses))
|
loadedABCIResponses, abciResponses))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestResultsSaveLoad tests saving and loading abci results.
|
// TestResultsSaveLoad tests saving and loading ABCI results.
|
||||||
func TestABCIResponsesSaveLoad2(t *testing.T) {
|
func TestABCIResponsesSaveLoad2(t *testing.T) {
|
||||||
tearDown, stateDB, _ := setupTestCase(t)
|
tearDown, stateDB, _ := setupTestCase(t)
|
||||||
defer tearDown(t)
|
defer tearDown(t)
|
||||||
@ -97,8 +97,8 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
cases := [...]struct {
|
cases := [...]struct {
|
||||||
// height is implied index+2
|
// Height is implied to equal index+2,
|
||||||
// as block 1 is created from genesis
|
// as block 1 is created from genesis.
|
||||||
added []*abci.ResponseDeliverTx
|
added []*abci.ResponseDeliverTx
|
||||||
expected types.ABCIResults
|
expected types.ABCIResults
|
||||||
}{
|
}{
|
||||||
@ -132,14 +132,14 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// query all before, should return error
|
// Query all before, this should return error.
|
||||||
for i := range cases {
|
for i := range cases {
|
||||||
h := int64(i + 1)
|
h := int64(i + 1)
|
||||||
res, err := LoadABCIResponses(stateDB, h)
|
res, err := LoadABCIResponses(stateDB, h)
|
||||||
assert.Error(err, "%d: %#v", i, res)
|
assert.Error(err, "%d: %#v", i, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all cases
|
// Add all cases.
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
h := int64(i + 1) // last block height, one below what we save
|
h := int64(i + 1) // last block height, one below what we save
|
||||||
responses := &ABCIResponses{
|
responses := &ABCIResponses{
|
||||||
@ -149,7 +149,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
|
|||||||
saveABCIResponses(stateDB, h, responses)
|
saveABCIResponses(stateDB, h, responses)
|
||||||
}
|
}
|
||||||
|
|
||||||
// query all before, should return expected value
|
// Query all before, should return expected value.
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
h := int64(i + 1)
|
h := int64(i + 1)
|
||||||
res, err := LoadABCIResponses(stateDB, h)
|
res, err := LoadABCIResponses(stateDB, h)
|
||||||
@ -165,34 +165,30 @@ func TestValidatorSimpleSaveLoad(t *testing.T) {
|
|||||||
// nolint: vetshadow
|
// nolint: vetshadow
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
// can't load anything for height 0
|
// Can't load anything for height 0.
|
||||||
v, err := LoadValidators(stateDB, 0)
|
v, err := LoadValidators(stateDB, 0)
|
||||||
assert.IsType(ErrNoValSetForHeight{}, err, "expected err at height 0")
|
assert.IsType(ErrNoValSetForHeight{}, err, "expected err at height 0")
|
||||||
|
|
||||||
// should be able to load for height 1
|
// Should be able to load for height 1.
|
||||||
v, err = LoadValidators(stateDB, 1)
|
v, err = LoadValidators(stateDB, 1)
|
||||||
assert.Nil(err, "expected no err at height 1")
|
assert.Nil(err, "expected no err at height 1")
|
||||||
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
||||||
|
|
||||||
// increment height, save; should be able to load for next height
|
// Should be able to load for height 2.
|
||||||
|
v, err = LoadValidators(stateDB, 2)
|
||||||
|
assert.Nil(err, "expected no err at height 2")
|
||||||
|
assert.Equal(v.Hash(), state.NextValidators.Hash(), "expected validator hashes to match")
|
||||||
|
|
||||||
|
// Increment height, save; should be able to load for next & next next height.
|
||||||
state.LastBlockHeight++
|
state.LastBlockHeight++
|
||||||
nextHeight := state.LastBlockHeight + 1
|
nextHeight := state.LastBlockHeight + 1
|
||||||
saveValidatorsInfo(stateDB, nextHeight, state.LastHeightValidatorsChanged, state.Validators)
|
saveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators)
|
||||||
v, err = LoadValidators(stateDB, nextHeight)
|
vp0, err := LoadValidators(stateDB, nextHeight+0)
|
||||||
assert.Nil(err, "expected no err")
|
assert.Nil(err, "expected no err")
|
||||||
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
vp1, err := LoadValidators(stateDB, nextHeight+1)
|
||||||
|
|
||||||
// increment height, save; should be able to load for next height
|
|
||||||
state.LastBlockHeight += 10
|
|
||||||
nextHeight = state.LastBlockHeight + 1
|
|
||||||
saveValidatorsInfo(stateDB, nextHeight, state.LastHeightValidatorsChanged, state.Validators)
|
|
||||||
v, err = LoadValidators(stateDB, nextHeight)
|
|
||||||
assert.Nil(err, "expected no err")
|
assert.Nil(err, "expected no err")
|
||||||
assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
assert.Equal(vp0.Hash(), state.Validators.Hash(), "expected validator hashes to match")
|
||||||
|
assert.Equal(vp1.Hash(), state.NextValidators.Hash(), "expected next validator hashes to match")
|
||||||
// should be able to load for next next height
|
|
||||||
_, err = LoadValidators(stateDB, state.LastBlockHeight+2)
|
|
||||||
assert.IsType(ErrNoValSetForHeight{}, err, "expected err at unknown height")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestValidatorChangesSaveLoad tests saving and loading a validator set with changes.
|
// TestValidatorChangesSaveLoad tests saving and loading a validator set with changes.
|
||||||
@ -200,38 +196,37 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) {
|
|||||||
tearDown, stateDB, state := setupTestCase(t)
|
tearDown, stateDB, state := setupTestCase(t)
|
||||||
defer tearDown(t)
|
defer tearDown(t)
|
||||||
|
|
||||||
// change vals at these heights
|
// Change vals at these heights.
|
||||||
changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20}
|
changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20}
|
||||||
N := len(changeHeights)
|
N := len(changeHeights)
|
||||||
|
|
||||||
// build the validator history by running updateState
|
// Build the validator history by running updateState
|
||||||
// with the right validator set for each height
|
// with the right validator set for each height.
|
||||||
highestHeight := changeHeights[N-1] + 5
|
highestHeight := changeHeights[N-1] + 5
|
||||||
changeIndex := 0
|
changeIndex := 0
|
||||||
_, val := state.Validators.GetByIndex(0)
|
_, val := state.Validators.GetByIndex(0)
|
||||||
power := val.VotingPower
|
power := val.VotingPower
|
||||||
var err error
|
var err error
|
||||||
for i := int64(1); i < highestHeight; i++ {
|
for i := int64(1); i < highestHeight; i++ {
|
||||||
// when we get to a change height,
|
// When we get to a change height, use the next pubkey.
|
||||||
// use the next pubkey
|
|
||||||
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] {
|
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] {
|
||||||
changeIndex++
|
changeIndex++
|
||||||
power++
|
power++
|
||||||
}
|
}
|
||||||
header, blockID, responses := makeHeaderPartsResponsesValPowerChange(state, i, power)
|
header, blockID, responses := makeHeaderPartsResponsesValPowerChange(state, power)
|
||||||
state, err = updateState(state, blockID, header, responses)
|
state, err = updateState(state, blockID, header, responses)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
nextHeight := state.LastBlockHeight + 1
|
nextHeight := state.LastBlockHeight + 1
|
||||||
saveValidatorsInfo(stateDB, nextHeight, state.LastHeightValidatorsChanged, state.Validators)
|
saveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators)
|
||||||
}
|
}
|
||||||
|
|
||||||
// on each change height, increment the power by one.
|
// On each height change, increment the power by one.
|
||||||
testCases := make([]int64, highestHeight)
|
testCases := make([]int64, highestHeight)
|
||||||
changeIndex = 0
|
changeIndex = 0
|
||||||
power = val.VotingPower
|
power = val.VotingPower
|
||||||
for i := int64(1); i < highestHeight+1; i++ {
|
for i := int64(1); i < highestHeight+1; i++ {
|
||||||
// we we get to the height after a change height
|
// We get to the height after a change height use the next pubkey (note
|
||||||
// use the next pubkey (note our counter starts at 0 this time)
|
// our counter starts at 0 this time).
|
||||||
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex]+1 {
|
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex]+1 {
|
||||||
changeIndex++
|
changeIndex++
|
||||||
power++
|
power++
|
||||||
@ -240,7 +235,7 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, power := range testCases {
|
for i, power := range testCases {
|
||||||
v, err := LoadValidators(stateDB, int64(i+1))
|
v, err := LoadValidators(stateDB, int64(i+1+1)) // +1 because vset changes delayed by 1 block.
|
||||||
assert.Nil(t, err, fmt.Sprintf("expected no err at height %d", i))
|
assert.Nil(t, err, fmt.Sprintf("expected no err at height %d", i))
|
||||||
assert.Equal(t, v.Size(), 1, "validator set size is greater than 1: %d", v.Size())
|
assert.Equal(t, v.Size(), 1, "validator set size is greater than 1: %d", v.Size())
|
||||||
_, val := v.GetByIndex(0)
|
_, val := v.GetByIndex(0)
|
||||||
@ -255,25 +250,41 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) {
|
|||||||
func TestManyValidatorChangesSaveLoad(t *testing.T) {
|
func TestManyValidatorChangesSaveLoad(t *testing.T) {
|
||||||
const valSetSize = 7
|
const valSetSize = 7
|
||||||
tearDown, stateDB, state := setupTestCase(t)
|
tearDown, stateDB, state := setupTestCase(t)
|
||||||
|
require.Equal(t, int64(0), state.LastBlockHeight)
|
||||||
state.Validators = genValSet(valSetSize)
|
state.Validators = genValSet(valSetSize)
|
||||||
|
state.NextValidators = state.Validators.CopyIncrementAccum(1)
|
||||||
SaveState(stateDB, state)
|
SaveState(stateDB, state)
|
||||||
defer tearDown(t)
|
defer tearDown(t)
|
||||||
|
|
||||||
const height = 1
|
_, valOld := state.Validators.GetByIndex(0)
|
||||||
pubkey := crypto.GenPrivKeyEd25519().PubKey()
|
var pubkeyOld = valOld.PubKey
|
||||||
// swap the first validator with a new one ^^^ (validator set size stays the same)
|
var pubkey = crypto.GenPrivKeyEd25519().PubKey()
|
||||||
header, blockID, responses := makeHeaderPartsResponsesValPubKeyChange(state, height, pubkey)
|
|
||||||
|
// Swap the first validator with a new one (validator set size stays the same).
|
||||||
|
header, blockID, responses := makeHeaderPartsResponsesValPubKeyChange(state, pubkey)
|
||||||
|
|
||||||
|
// Save state etc.
|
||||||
var err error
|
var err error
|
||||||
state, err = updateState(state, blockID, header, responses)
|
state, err = updateState(state, blockID, header, responses)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
nextHeight := state.LastBlockHeight + 1
|
nextHeight := state.LastBlockHeight + 1
|
||||||
saveValidatorsInfo(stateDB, nextHeight, state.LastHeightValidatorsChanged, state.Validators)
|
saveValidatorsInfo(stateDB, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators)
|
||||||
|
|
||||||
v, err := LoadValidators(stateDB, height+1)
|
// Load nextheight, it should be the oldpubkey.
|
||||||
|
v0, err := LoadValidators(stateDB, nextHeight)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, valSetSize, v.Size())
|
assert.Equal(t, valSetSize, v0.Size())
|
||||||
|
index, val := v0.GetByAddress(pubkeyOld.Address())
|
||||||
|
assert.NotNil(t, val)
|
||||||
|
if index < 0 {
|
||||||
|
t.Fatal("expected to find old validator")
|
||||||
|
}
|
||||||
|
|
||||||
index, val := v.GetByAddress(pubkey.Address())
|
// Load nextheight+1, it should be the new pubkey.
|
||||||
|
v1, err := LoadValidators(stateDB, nextHeight+1)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, valSetSize, v1.Size())
|
||||||
|
index, val = v1.GetByAddress(pubkey.Address())
|
||||||
assert.NotNil(t, val)
|
assert.NotNil(t, val)
|
||||||
if index < 0 {
|
if index < 0 {
|
||||||
t.Fatal("expected to find newly added validator")
|
t.Fatal("expected to find newly added validator")
|
||||||
@ -294,12 +305,12 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
|
|||||||
tearDown, stateDB, state := setupTestCase(t)
|
tearDown, stateDB, state := setupTestCase(t)
|
||||||
defer tearDown(t)
|
defer tearDown(t)
|
||||||
|
|
||||||
// change vals at these heights
|
// Change vals at these heights.
|
||||||
changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20}
|
changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20}
|
||||||
N := len(changeHeights)
|
N := len(changeHeights)
|
||||||
|
|
||||||
// each valset is just one validator
|
// Each valset is just one validator.
|
||||||
// create list of them
|
// create list of them.
|
||||||
params := make([]types.ConsensusParams, N+1)
|
params := make([]types.ConsensusParams, N+1)
|
||||||
params[0] = state.ConsensusParams
|
params[0] = state.ConsensusParams
|
||||||
for i := 1; i < N+1; i++ {
|
for i := 1; i < N+1; i++ {
|
||||||
@ -307,20 +318,19 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
|
|||||||
params[i].BlockSize.MaxBytes += i
|
params[i].BlockSize.MaxBytes += i
|
||||||
}
|
}
|
||||||
|
|
||||||
// build the params history by running updateState
|
// Build the params history by running updateState
|
||||||
// with the right params set for each height
|
// with the right params set for each height.
|
||||||
highestHeight := changeHeights[N-1] + 5
|
highestHeight := changeHeights[N-1] + 5
|
||||||
changeIndex := 0
|
changeIndex := 0
|
||||||
cp := params[changeIndex]
|
cp := params[changeIndex]
|
||||||
var err error
|
var err error
|
||||||
for i := int64(1); i < highestHeight; i++ {
|
for i := int64(1); i < highestHeight; i++ {
|
||||||
// when we get to a change height,
|
// When we get to a change height, use the next params.
|
||||||
// use the next params
|
|
||||||
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] {
|
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] {
|
||||||
changeIndex++
|
changeIndex++
|
||||||
cp = params[changeIndex]
|
cp = params[changeIndex]
|
||||||
}
|
}
|
||||||
header, blockID, responses := makeHeaderPartsResponsesParams(state, i, cp)
|
header, blockID, responses := makeHeaderPartsResponsesParams(state, cp)
|
||||||
state, err = updateState(state, blockID, header, responses)
|
state, err = updateState(state, blockID, header, responses)
|
||||||
|
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
@ -328,13 +338,13 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
|
|||||||
saveConsensusParamsInfo(stateDB, nextHeight, state.LastHeightConsensusParamsChanged, state.ConsensusParams)
|
saveConsensusParamsInfo(stateDB, nextHeight, state.LastHeightConsensusParamsChanged, state.ConsensusParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
// make all the test cases by using the same params until after the change
|
// Make all the test cases by using the same params until after the change.
|
||||||
testCases := make([]paramsChangeTestCase, highestHeight)
|
testCases := make([]paramsChangeTestCase, highestHeight)
|
||||||
changeIndex = 0
|
changeIndex = 0
|
||||||
cp = params[changeIndex]
|
cp = params[changeIndex]
|
||||||
for i := int64(1); i < highestHeight+1; i++ {
|
for i := int64(1); i < highestHeight+1; i++ {
|
||||||
// we we get to the height after a change height
|
// We get to the height after a change height use the next pubkey (note
|
||||||
// use the next pubkey (note our counter starts at 0 this time)
|
// our counter starts at 0 this time).
|
||||||
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex]+1 {
|
if changeIndex < len(changeHeights) && i == changeHeights[changeIndex]+1 {
|
||||||
changeIndex++
|
changeIndex++
|
||||||
cp = params[changeIndex]
|
cp = params[changeIndex]
|
||||||
@ -419,16 +429,16 @@ func TestApplyUpdates(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHeaderPartsResponsesValPubKeyChange(state State, height int64,
|
func makeHeaderPartsResponsesValPubKeyChange(state State, pubkey crypto.PubKey) (
|
||||||
pubkey crypto.PubKey) (*types.Header, types.BlockID, *ABCIResponses) {
|
*types.Header, types.BlockID, *ABCIResponses) {
|
||||||
|
|
||||||
block := makeBlock(state, height)
|
block := makeBlock(state, state.LastBlockHeight+1)
|
||||||
abciResponses := &ABCIResponses{
|
abciResponses := &ABCIResponses{
|
||||||
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
|
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the pubkey is new, remove the old and add the new
|
// If the pubkey is new, remove the old and add the new.
|
||||||
_, val := state.Validators.GetByIndex(0)
|
_, val := state.NextValidators.GetByIndex(0)
|
||||||
if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) {
|
if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) {
|
||||||
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
||||||
ValidatorUpdates: []abci.Validator{
|
ValidatorUpdates: []abci.Validator{
|
||||||
@ -441,16 +451,16 @@ func makeHeaderPartsResponsesValPubKeyChange(state State, height int64,
|
|||||||
return block.Header, types.BlockID{block.Hash(), types.PartSetHeader{}}, abciResponses
|
return block.Header, types.BlockID{block.Hash(), types.PartSetHeader{}}, abciResponses
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHeaderPartsResponsesValPowerChange(state State, height int64,
|
func makeHeaderPartsResponsesValPowerChange(state State, power int64) (
|
||||||
power int64) (*types.Header, types.BlockID, *ABCIResponses) {
|
*types.Header, types.BlockID, *ABCIResponses) {
|
||||||
|
|
||||||
block := makeBlock(state, height)
|
block := makeBlock(state, state.LastBlockHeight+1)
|
||||||
abciResponses := &ABCIResponses{
|
abciResponses := &ABCIResponses{
|
||||||
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
|
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the pubkey is new, remove the old and add the new
|
// If the pubkey is new, remove the old and add the new.
|
||||||
_, val := state.Validators.GetByIndex(0)
|
_, val := state.NextValidators.GetByIndex(0)
|
||||||
if val.VotingPower != power {
|
if val.VotingPower != power {
|
||||||
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
||||||
ValidatorUpdates: []abci.Validator{
|
ValidatorUpdates: []abci.Validator{
|
||||||
@ -462,10 +472,10 @@ func makeHeaderPartsResponsesValPowerChange(state State, height int64,
|
|||||||
return block.Header, types.BlockID{block.Hash(), types.PartSetHeader{}}, abciResponses
|
return block.Header, types.BlockID{block.Hash(), types.PartSetHeader{}}, abciResponses
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHeaderPartsResponsesParams(state State, height int64,
|
func makeHeaderPartsResponsesParams(state State, params types.ConsensusParams) (
|
||||||
params types.ConsensusParams) (*types.Header, types.BlockID, *ABCIResponses) {
|
*types.Header, types.BlockID, *ABCIResponses) {
|
||||||
|
|
||||||
block := makeBlock(state, height)
|
block := makeBlock(state, state.LastBlockHeight+1)
|
||||||
abciResponses := &ABCIResponses{
|
abciResponses := &ABCIResponses{
|
||||||
EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(¶ms)},
|
EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(¶ms)},
|
||||||
}
|
}
|
||||||
@ -476,14 +486,3 @@ type paramsChangeTestCase struct {
|
|||||||
height int64
|
height int64
|
||||||
params types.ConsensusParams
|
params types.ConsensusParams
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHeaderPartsResults(state State, height int64,
|
|
||||||
results []*abci.ResponseDeliverTx) (*types.Header, types.BlockID, *ABCIResponses) {
|
|
||||||
|
|
||||||
block := makeBlock(state, height)
|
|
||||||
abciResponses := &ABCIResponses{
|
|
||||||
DeliverTx: results,
|
|
||||||
EndBlock: &abci.ResponseEndBlock{},
|
|
||||||
}
|
|
||||||
return block.Header, types.BlockID{block.Hash(), types.PartSetHeader{}}, abciResponses
|
|
||||||
}
|
|
||||||
|
@ -86,7 +86,14 @@ func SaveState(db dbm.DB, state State) {
|
|||||||
|
|
||||||
func saveState(db dbm.DB, state State, key []byte) {
|
func saveState(db dbm.DB, state State, key []byte) {
|
||||||
nextHeight := state.LastBlockHeight + 1
|
nextHeight := state.LastBlockHeight + 1
|
||||||
saveValidatorsInfo(db, nextHeight, state.LastHeightValidatorsChanged, state.Validators)
|
// If first block, save validators for block 1.
|
||||||
|
if nextHeight == 1 {
|
||||||
|
lastHeightVoteChanged := int64(1) // Due to Tendermint validator set changes being delayed 1 block.
|
||||||
|
saveValidatorsInfo(db, nextHeight, lastHeightVoteChanged, state.Validators)
|
||||||
|
}
|
||||||
|
// Save next validators.
|
||||||
|
saveValidatorsInfo(db, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators)
|
||||||
|
// Save next consensus params.
|
||||||
saveConsensusParamsInfo(db, nextHeight, state.LastHeightConsensusParamsChanged, state.ConsensusParams)
|
saveConsensusParamsInfo(db, nextHeight, state.LastHeightConsensusParamsChanged, state.ConsensusParams)
|
||||||
db.SetSync(stateKey, state.Bytes())
|
db.SetSync(stateKey, state.Bytes())
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,12 @@ import (
|
|||||||
// Validate block
|
// Validate block
|
||||||
|
|
||||||
func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||||
// validate internal consistency
|
// Validate internal consistency.
|
||||||
if err := block.ValidateBasic(); err != nil {
|
if err := block.ValidateBasic(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate basic info
|
// Validate basic info.
|
||||||
if block.ChainID != state.ChainID {
|
if block.ChainID != state.ChainID {
|
||||||
return fmt.Errorf("Wrong Block.Header.ChainID. Expected %v, got %v", state.ChainID, block.ChainID)
|
return fmt.Errorf("Wrong Block.Header.ChainID. Expected %v, got %v", state.ChainID, block.ChainID)
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// validate prev block info
|
// Validate prev block info.
|
||||||
if !block.LastBlockID.Equals(state.LastBlockID) {
|
if !block.LastBlockID.Equals(state.LastBlockID) {
|
||||||
return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", state.LastBlockID, block.LastBlockID)
|
return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", state.LastBlockID, block.LastBlockID)
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
|||||||
return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", state.LastBlockTotalTx+newTxs, block.TotalTxs)
|
return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", state.LastBlockTotalTx+newTxs, block.TotalTxs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate app info
|
// Validate app info
|
||||||
if !bytes.Equal(block.AppHash, state.AppHash) {
|
if !bytes.Equal(block.AppHash, state.AppHash) {
|
||||||
return fmt.Errorf("Wrong Block.Header.AppHash. Expected %X, got %v", state.AppHash, block.AppHash)
|
return fmt.Errorf("Wrong Block.Header.AppHash. Expected %X, got %v", state.AppHash, block.AppHash)
|
||||||
}
|
}
|
||||||
@ -55,6 +55,9 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
|||||||
if !bytes.Equal(block.ValidatorsHash, state.Validators.Hash()) {
|
if !bytes.Equal(block.ValidatorsHash, state.Validators.Hash()) {
|
||||||
return fmt.Errorf("Wrong Block.Header.ValidatorsHash. Expected %X, got %v", state.Validators.Hash(), block.ValidatorsHash)
|
return fmt.Errorf("Wrong Block.Header.ValidatorsHash. Expected %X, got %v", state.Validators.Hash(), block.ValidatorsHash)
|
||||||
}
|
}
|
||||||
|
if !bytes.Equal(block.NextValidatorsHash, state.NextValidators.Hash()) {
|
||||||
|
return fmt.Errorf("Wrong Block.Header.NextValidatorsHash. Expected %X, got %v", state.NextValidators.Hash(), block.NextValidatorsHash)
|
||||||
|
}
|
||||||
|
|
||||||
// Validate block LastCommit.
|
// Validate block LastCommit.
|
||||||
if block.Height == 1 {
|
if block.Height == 1 {
|
||||||
@ -73,6 +76,7 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate all evidence.
|
||||||
// TODO: Each check requires loading an old validator set.
|
// TODO: Each check requires loading an old validator set.
|
||||||
// We should cap the amount of evidence per block
|
// We should cap the amount of evidence per block
|
||||||
// to prevent potential proposer DoS.
|
// to prevent potential proposer DoS.
|
||||||
|
@ -196,10 +196,11 @@ type Header struct {
|
|||||||
DataHash cmn.HexBytes `json:"data_hash"` // transactions
|
DataHash cmn.HexBytes `json:"data_hash"` // transactions
|
||||||
|
|
||||||
// hashes from the app output from the prev block
|
// hashes from the app output from the prev block
|
||||||
ValidatorsHash cmn.HexBytes `json:"validators_hash"` // validators for the current block
|
ValidatorsHash cmn.HexBytes `json:"validators_hash"` // validators for the current block
|
||||||
ConsensusHash cmn.HexBytes `json:"consensus_hash"` // consensus params for current block
|
NextValidatorsHash cmn.HexBytes `json:"next_validators_hash"` // validators for the next block
|
||||||
AppHash cmn.HexBytes `json:"app_hash"` // state after txs from the previous block
|
ConsensusHash cmn.HexBytes `json:"consensus_hash"` // consensus params for current block
|
||||||
LastResultsHash cmn.HexBytes `json:"last_results_hash"` // root hash of all results from the txs from the previous block
|
AppHash cmn.HexBytes `json:"app_hash"` // state after txs from the previous block
|
||||||
|
LastResultsHash cmn.HexBytes `json:"last_results_hash"` // root hash of all results from the txs from the previous block
|
||||||
|
|
||||||
// consensus info
|
// consensus info
|
||||||
EvidenceHash cmn.HexBytes `json:"evidence_hash"` // evidence included in the block
|
EvidenceHash cmn.HexBytes `json:"evidence_hash"` // evidence included in the block
|
||||||
@ -214,19 +215,20 @@ func (h *Header) Hash() cmn.HexBytes {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return merkle.SimpleHashFromMap(map[string]merkle.Hasher{
|
return merkle.SimpleHashFromMap(map[string]merkle.Hasher{
|
||||||
"ChainID": aminoHasher(h.ChainID),
|
"ChainID": aminoHasher(h.ChainID),
|
||||||
"Height": aminoHasher(h.Height),
|
"Height": aminoHasher(h.Height),
|
||||||
"Time": aminoHasher(h.Time),
|
"Time": aminoHasher(h.Time),
|
||||||
"NumTxs": aminoHasher(h.NumTxs),
|
"NumTxs": aminoHasher(h.NumTxs),
|
||||||
"TotalTxs": aminoHasher(h.TotalTxs),
|
"TotalTxs": aminoHasher(h.TotalTxs),
|
||||||
"LastBlockID": aminoHasher(h.LastBlockID),
|
"LastBlockID": aminoHasher(h.LastBlockID),
|
||||||
"LastCommit": aminoHasher(h.LastCommitHash),
|
"LastCommit": aminoHasher(h.LastCommitHash),
|
||||||
"Data": aminoHasher(h.DataHash),
|
"Data": aminoHasher(h.DataHash),
|
||||||
"Validators": aminoHasher(h.ValidatorsHash),
|
"Validators": aminoHasher(h.ValidatorsHash),
|
||||||
"App": aminoHasher(h.AppHash),
|
"NextValidators": aminoHasher(h.NextValidatorsHash),
|
||||||
"Consensus": aminoHasher(h.ConsensusHash),
|
"App": aminoHasher(h.AppHash),
|
||||||
"Results": aminoHasher(h.LastResultsHash),
|
"Consensus": aminoHasher(h.ConsensusHash),
|
||||||
"Evidence": aminoHasher(h.EvidenceHash),
|
"Results": aminoHasher(h.LastResultsHash),
|
||||||
|
"Evidence": aminoHasher(h.EvidenceHash),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,6 +247,7 @@ func (h *Header) StringIndented(indent string) string {
|
|||||||
%s LastCommit: %v
|
%s LastCommit: %v
|
||||||
%s Data: %v
|
%s Data: %v
|
||||||
%s Validators: %v
|
%s Validators: %v
|
||||||
|
%s NextValidators: %v
|
||||||
%s App: %v
|
%s App: %v
|
||||||
%s Consensus: %v
|
%s Consensus: %v
|
||||||
%s Results: %v
|
%s Results: %v
|
||||||
@ -259,6 +262,7 @@ func (h *Header) StringIndented(indent string) string {
|
|||||||
indent, h.LastCommitHash,
|
indent, h.LastCommitHash,
|
||||||
indent, h.DataHash,
|
indent, h.DataHash,
|
||||||
indent, h.ValidatorsHash,
|
indent, h.ValidatorsHash,
|
||||||
|
indent, h.NextValidatorsHash,
|
||||||
indent, h.AppHash,
|
indent, h.AppHash,
|
||||||
indent, h.ConsensusHash,
|
indent, h.ConsensusHash,
|
||||||
indent, h.LastResultsHash,
|
indent, h.LastResultsHash,
|
||||||
|
@ -46,7 +46,14 @@ func NewValidatorSet(vals []*Validator) *ValidatorSet {
|
|||||||
return vs
|
return vs
|
||||||
}
|
}
|
||||||
|
|
||||||
// incrementAccum and update the proposer
|
// Increment Accum and update the proposer on a copy, and return it.
|
||||||
|
func (valSet *ValidatorSet) CopyIncrementAccum(times int) *ValidatorSet {
|
||||||
|
copy := valSet.Copy()
|
||||||
|
copy.IncrementAccum(times)
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment Accum and update the proposer.
|
||||||
func (valSet *ValidatorSet) IncrementAccum(times int) {
|
func (valSet *ValidatorSet) IncrementAccum(times int) {
|
||||||
// Add VotingPower * times to each validator and order into heap.
|
// Add VotingPower * times to each validator and order into heap.
|
||||||
validatorsHeap := cmn.NewHeap()
|
validatorsHeap := cmn.NewHeap()
|
||||||
@ -387,7 +394,7 @@ func (valSet *ValidatorSet) StringIndented(indent string) string {
|
|||||||
%s}`,
|
%s}`,
|
||||||
indent, valSet.GetProposer().String(),
|
indent, valSet.GetProposer().String(),
|
||||||
indent,
|
indent,
|
||||||
indent, strings.Join(valStrings, "\n"+indent+" "),
|
indent, strings.Join(valStrings, "\n"+indent+" "),
|
||||||
indent)
|
indent)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user