ADR-016: Add versions to Block and State (#2644)

* types: add Version to Header

* abci: add Version to Header

* state: add Version to State

* node: check software and state protocol versions match

* update changelog

* docs/spec: update for versions

* state: more tests

* remove TODOs

* remove empty test
This commit is contained in:
Ethan Buchman
2018-10-17 15:30:53 -04:00
committed by GitHub
parent 6a07f415e9
commit 455d34134c
17 changed files with 999 additions and 504 deletions

View File

@@ -398,9 +398,13 @@ func updateState(
lastHeightParamsChanged = header.Height + 1
}
// TODO: allow app to upgrade version
nextVersion := state.Version
// NOTE: the AppHash has not been populated.
// It will be filled on state.Save.
return State{
Version: nextVersion,
ChainID: state.ChainID,
LastBlockHeight: header.Height,
LastBlockTotalTx: state.LastBlockTotalTx + header.NumTxs,

View File

@@ -8,6 +8,7 @@ import (
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/tendermint/tendermint/version"
)
// database keys
@@ -17,6 +18,25 @@ var (
//-----------------------------------------------------------------------------
// Version is for versioning the State.
// It holds the Block and App version needed for making blocks,
// and the software version to support upgrades to the format of
// the State as stored on disk.
type Version struct {
Consensus version.Consensus
Software string
}
var initStateVersion = Version{
Consensus: version.Consensus{
Block: version.BlockProtocol,
App: 0,
},
Software: version.TMCoreSemVer,
}
//-----------------------------------------------------------------------------
// State is a short description of the latest committed block of the Tendermint consensus.
// It keeps all information necessary to validate new blocks,
// including the last validator set and the consensus params.
@@ -25,6 +45,8 @@ var (
// Instead, use state.Copy() or state.NextState(...).
// NOTE: not goroutine-safe.
type State struct {
Version Version
// immutable
ChainID string
@@ -59,6 +81,7 @@ type State struct {
// Copy makes a copy of the State for mutating.
func (state State) Copy() State {
return State{
Version: state.Version,
ChainID: state.ChainID,
LastBlockHeight: state.LastBlockHeight,
@@ -114,6 +137,7 @@ func (state State) MakeBlock(
block := types.MakeBlock(height, txs, commit, evidence)
// Fill rest of header with state data.
block.Version = state.Version.Consensus
block.ChainID = state.ChainID
// Set time
@@ -217,7 +241,7 @@ func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
}
return State{
Version: initStateVersion,
ChainID: genDoc.ChainID,
LastBlockHeight: 0,

View File

@@ -319,9 +319,11 @@ func TestStateMakeBlock(t *testing.T) {
defer tearDown(t)
proposerAddress := state.Validators.GetProposer().Address
stateVersion := state.Version.Consensus
block := makeBlock(state, 2)
// test we set proposer address
// test we set some fields
assert.Equal(t, stateVersion, block.Version)
assert.Equal(t, proposerAddress, block.ProposerAddress)
}

View File

@@ -20,6 +20,13 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
}
// Validate basic info.
if block.Version != state.Version.Consensus {
return fmt.Errorf(
"Wrong Block.Header.Version. Expected %v, got %v",
state.Version.Consensus,
block.Version,
)
}
if block.ChainID != state.ChainID {
return fmt.Errorf(
"Wrong Block.Header.ChainID. Expected %v, got %v",

View File

@@ -5,6 +5,7 @@ import (
"time"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/libs/log"
@@ -26,13 +27,20 @@ func TestValidateBlockHeader(t *testing.T) {
err := blockExec.ValidateBlock(state, block)
require.NoError(t, err)
// some bad values
wrongHash := tmhash.Sum([]byte("this hash is wrong"))
wrongVersion1 := state.Version.Consensus
wrongVersion1.Block += 1
wrongVersion2 := state.Version.Consensus
wrongVersion2.App += 1
// Manipulation of any header field causes failure.
testCases := []struct {
name string
malleateBlock func(block *types.Block)
}{
{"Version wrong1", func(block *types.Block) { block.Version = wrongVersion1 }},
{"Version wrong2", func(block *types.Block) { block.Version = wrongVersion2 }},
{"ChainID wrong", func(block *types.Block) { block.ChainID = "not-the-real-one" }},
{"Height wrong", func(block *types.Block) { block.Height += 10 }},
{"Time wrong", func(block *types.Block) { block.Time = block.Time.Add(-time.Second * 3600 * 24) }},