From 4265a94bfe0e1851a6e16fe977db3b9807aed824 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Dec 2017 18:09:10 +0100 Subject: [PATCH 01/23] Update EndBlock parameters * Update abci dependencies * Modify references from Diffs to Changes * Fixes issues #924 --- glide.lock | 6 +++--- glide.yaml | 2 +- state/execution.go | 6 +++--- state/state.go | 4 ++-- state/state_test.go | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/glide.lock b/glide.lock index 05e74faa8..c42bd57f6 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: f420f1f858100218dad50997d939eaaf129ff654a0648a47ddc60d626ab0b8e9 -updated: 2017-12-10T05:37:46.41123196Z +hash: ff6e6786ec24ffac91df45d4a1cdcefae5280700667ca76b8b9b96f343d78c95 +updated: 2017-12-13T18:04:10.05914801+01:00 imports: - name: github.com/btcsuite/btcd version: 2e60448ffcc6bf78332d1fe590260095f554dd78 @@ -103,7 +103,7 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: fca2b508c185b855af1446ec4afc19bdfc7b315d + version: 895e14d6bd9cdad98eab4a051decbaad46f7eebd subpackages: - client - example/code diff --git a/glide.yaml b/glide.yaml index e614d0a1e..2b6593a17 100644 --- a/glide.yaml +++ b/glide.yaml @@ -18,7 +18,7 @@ import: - package: github.com/spf13/viper version: v1.0.0 - package: github.com/tendermint/abci - version: ~v0.8.0 + version: feature/enhance-endblock subpackages: - client - example/dummy diff --git a/state/execution.go b/state/execution.go index 7ba4ac3e9..6f6a7ca18 100644 --- a/state/execution.go +++ b/state/execution.go @@ -111,11 +111,11 @@ func execBlockOnProxyApp(txEventPublisher types.TxEventPublisher, proxyAppConn p return nil, err } - valDiff := abciResponses.EndBlock.Diffs + valChanges := abciResponses.EndBlock.Changes logger.Info("Executed block", "height", block.Height, "validTxs", validTxs, "invalidTxs", invalidTxs) - if len(valDiff) > 0 { - logger.Info("Update to validator set", "updates", abci.ValidatorsString(valDiff)) + if len(valChanges) > 0 { + logger.Info("Update to validator set", "updates", abci.ValidatorsString(valChanges)) } return abciResponses, nil diff --git a/state/state.go b/state/state.go index f8a8d1a03..3c9333b75 100644 --- a/state/state.go +++ b/state/state.go @@ -238,8 +238,8 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ nextValSet := prevValSet.Copy() // update the validator set with the latest abciResponses - if len(abciResponses.EndBlock.Diffs) > 0 { - err := updateValidators(nextValSet, abciResponses.EndBlock.Diffs) + if len(abciResponses.EndBlock.Changes) > 0 { + err := updateValidators(nextValSet, abciResponses.EndBlock.Changes) if err != nil { s.logger.Error("Error changing validator set", "err", err) // TODO: err or carry on? diff --git a/state/state_test.go b/state/state_test.go index 9b78b3871..2c403a425 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -80,7 +80,7 @@ func TestABCIResponsesSaveLoad(t *testing.T) { abciResponses := NewABCIResponses(block) abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: []*abci.KVPair{}} abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: []*abci.KVPair{}} - abciResponses.EndBlock = &abci.ResponseEndBlock{Diffs: []*abci.Validator{ + abciResponses.EndBlock = &abci.ResponseEndBlock{Changes: []*abci.Validator{ { PubKey: crypto.GenPrivKeyEd25519().PubKey().Bytes(), Power: 10, @@ -199,13 +199,13 @@ func makeHeaderPartsResponses(state *State, height int64, _, val := state.Validators.GetByIndex(0) abciResponses := &ABCIResponses{ Height: height, - EndBlock: &abci.ResponseEndBlock{Diffs: []*abci.Validator{}}, + EndBlock: &abci.ResponseEndBlock{Changes: []*abci.Validator{}}, } // if the pubkey is new, remove the old and add the new if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) { abciResponses.EndBlock = &abci.ResponseEndBlock{ - Diffs: []*abci.Validator{ + Changes: []*abci.Validator{ {val.PubKey.Bytes(), 0}, {pubkey.Bytes(), 10}, }, From d21f39160f8196efde81a85816a6739a35e51295 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Dec 2017 18:34:17 +0100 Subject: [PATCH 02/23] Apply ConsensusParamChanges to state/State --- state/state.go | 10 ++++++++-- types/params.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/state/state.go b/state/state.go index 3c9333b75..3b04cd69c 100644 --- a/state/state.go +++ b/state/state.go @@ -251,17 +251,22 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ // Update validator accums and set state variables nextValSet.IncrementAccum(1) + nextParams := s.Params.ApplyChanges( + abciResponses.EndBlock.ConsensusParamChanges) + s.setBlockAndValidators(header.Height, header.NumTxs, types.BlockID{header.Hash(), blockPartsHeader}, header.Time, - prevValSet, nextValSet) + prevValSet, nextValSet, + nextParams) } func (s *State) setBlockAndValidators(height int64, newTxs int64, blockID types.BlockID, blockTime time.Time, - prevValSet, nextValSet *types.ValidatorSet) { + prevValSet, nextValSet *types.ValidatorSet, + nextParams types.ConsensusParams) { s.LastBlockHeight = height s.LastBlockTotalTx += newTxs @@ -269,6 +274,7 @@ func (s *State) setBlockAndValidators(height int64, s.LastBlockTime = blockTime s.Validators = nextValSet s.LastValidators = prevValSet + s.Params = nextParams } // GetValidators returns the last and current validator sets. diff --git a/types/params.go b/types/params.go index 322cba612..4047913c3 100644 --- a/types/params.go +++ b/types/params.go @@ -2,6 +2,8 @@ package types import ( "github.com/pkg/errors" + + abci "github.com/tendermint/abci/types" ) const ( @@ -16,6 +18,42 @@ type ConsensusParams struct { BlockGossipParams `json:"block_gossip_params"` } +// ApplyChanges returns a new param set, overriding any +// parameter that is non-zero in argument +func (p ConsensusParams) ApplyChanges(c *abci.ConsensusParams) ConsensusParams { + if c == nil { + return p + } + res := p + // we must defensively consider any structs may be nil + if c.BlockSizeParams != nil { + + if c.BlockSizeParams.MaxBytes != 0 { + res.BlockSizeParams.MaxBytes = int(c.BlockSizeParams.MaxBytes) + } + if c.BlockSizeParams.MaxTxs != 0 { + res.BlockSizeParams.MaxTxs = int(c.BlockSizeParams.MaxTxs) + } + if c.BlockSizeParams.MaxGas != 0 { + res.BlockSizeParams.MaxGas = int(c.BlockSizeParams.MaxGas) + } + } + if c.TxSizeParams != nil { + if c.TxSizeParams.MaxBytes != 0 { + res.TxSizeParams.MaxBytes = int(c.TxSizeParams.MaxBytes) + } + if c.TxSizeParams.MaxGas != 0 { + res.TxSizeParams.MaxGas = int(c.TxSizeParams.MaxGas) + } + } + if c.BlockGossipParams != nil { + if c.BlockGossipParams.BlockPartSizeBytes != 0 { + res.BlockGossipParams.BlockPartSizeBytes = int(c.BlockGossipParams.BlockPartSizeBytes) + } + } + return res +} + // BlockSizeParams contain limits on the block size. type BlockSizeParams struct { MaxBytes int `json:"max_bytes"` // NOTE: must not be 0 nor greater than 100MB From 030fd0023284b50abfcce90534ed21f9d9713df4 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 13 Dec 2017 19:26:44 +0100 Subject: [PATCH 03/23] Added tests for applying consensus param changes --- state/state.go | 40 +++++++++++++++++++++++++++- state/state_test.go | 65 +++++++++++++++++++++++++++++++++++++++++++++ types/params.go | 38 -------------------------- 3 files changed, 104 insertions(+), 39 deletions(-) diff --git a/state/state.go b/state/state.go index 3b04cd69c..34383cb15 100644 --- a/state/state.go +++ b/state/state.go @@ -251,7 +251,7 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ // Update validator accums and set state variables nextValSet.IncrementAccum(1) - nextParams := s.Params.ApplyChanges( + nextParams := applyChanges(s.Params, abciResponses.EndBlock.ConsensusParamChanges) s.setBlockAndValidators(header.Height, @@ -263,6 +263,44 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ } +// applyChanges returns a new param set, overriding any +// parameter that is non-zero in argument +func applyChanges(p types.ConsensusParams, + c *abci.ConsensusParams) types.ConsensusParams { + + if c == nil { + return p + } + res := p + // we must defensively consider any structs may be nil + if c.BlockSizeParams != nil { + + if c.BlockSizeParams.MaxBytes != 0 { + res.BlockSizeParams.MaxBytes = int(c.BlockSizeParams.MaxBytes) + } + if c.BlockSizeParams.MaxTxs != 0 { + res.BlockSizeParams.MaxTxs = int(c.BlockSizeParams.MaxTxs) + } + if c.BlockSizeParams.MaxGas != 0 { + res.BlockSizeParams.MaxGas = int(c.BlockSizeParams.MaxGas) + } + } + if c.TxSizeParams != nil { + if c.TxSizeParams.MaxBytes != 0 { + res.TxSizeParams.MaxBytes = int(c.TxSizeParams.MaxBytes) + } + if c.TxSizeParams.MaxGas != 0 { + res.TxSizeParams.MaxGas = int(c.TxSizeParams.MaxGas) + } + } + if c.BlockGossipParams != nil { + if c.BlockGossipParams.BlockPartSizeBytes != 0 { + res.BlockGossipParams.BlockPartSizeBytes = int(c.BlockGossipParams.BlockPartSizeBytes) + } + } + return res +} + func (s *State) setBlockAndValidators(height int64, newTxs int64, blockID types.BlockID, blockTime time.Time, prevValSet, nextValSet *types.ValidatorSet, diff --git a/state/state_test.go b/state/state_test.go index 2c403a425..d560f9532 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -192,6 +192,71 @@ func TestValidatorChangesSaveLoad(t *testing.T) { } } +func makeParams(blockBytes, blockTx, blockGas, txBytes, + txGas, partSize int) types.ConsensusParams { + + return types.ConsensusParams{ + BlockSizeParams: types.BlockSizeParams{ + MaxBytes: blockBytes, + MaxTxs: blockTx, + MaxGas: blockGas, + }, + TxSizeParams: types.TxSizeParams{ + MaxBytes: txBytes, + MaxGas: txGas, + }, + BlockGossipParams: types.BlockGossipParams{ + BlockPartSizeBytes: partSize, + }, + } +} + +func TestApplyChanges(t *testing.T) { + initParams := makeParams(1, 2, 3, 4, 5, 6) + + cases := [...]struct { + init types.ConsensusParams + changes *abci.ConsensusParams + expected types.ConsensusParams + }{ + 0: {initParams, nil, initParams}, + 1: {initParams, &abci.ConsensusParams{}, initParams}, + 2: {initParams, + &abci.ConsensusParams{ + TxSizeParams: &abci.TxSizeParams{ + MaxBytes: 123, + }, + }, + makeParams(1, 2, 3, 123, 5, 6)}, + 3: {initParams, + &abci.ConsensusParams{ + BlockSizeParams: &abci.BlockSizeParams{ + MaxTxs: 44, + MaxGas: 55, + }, + }, + makeParams(1, 44, 55, 4, 5, 6)}, + 4: {initParams, + &abci.ConsensusParams{ + BlockSizeParams: &abci.BlockSizeParams{ + MaxTxs: 789, + }, + TxSizeParams: &abci.TxSizeParams{ + MaxGas: 888, + }, + BlockGossipParams: &abci.BlockGossipParams{ + BlockPartSizeBytes: 2002, + }, + }, + makeParams(1, 789, 3, 4, 888, 2002)}, + } + + for i, tc := range cases { + res := applyChanges(tc.init, tc.changes) + assert.Equal(t, tc.expected, res, "case %d", i) + } +} + func makeHeaderPartsResponses(state *State, height int64, pubkey crypto.PubKey) (*types.Header, types.PartSetHeader, *ABCIResponses) { diff --git a/types/params.go b/types/params.go index 4047913c3..322cba612 100644 --- a/types/params.go +++ b/types/params.go @@ -2,8 +2,6 @@ package types import ( "github.com/pkg/errors" - - abci "github.com/tendermint/abci/types" ) const ( @@ -18,42 +16,6 @@ type ConsensusParams struct { BlockGossipParams `json:"block_gossip_params"` } -// ApplyChanges returns a new param set, overriding any -// parameter that is non-zero in argument -func (p ConsensusParams) ApplyChanges(c *abci.ConsensusParams) ConsensusParams { - if c == nil { - return p - } - res := p - // we must defensively consider any structs may be nil - if c.BlockSizeParams != nil { - - if c.BlockSizeParams.MaxBytes != 0 { - res.BlockSizeParams.MaxBytes = int(c.BlockSizeParams.MaxBytes) - } - if c.BlockSizeParams.MaxTxs != 0 { - res.BlockSizeParams.MaxTxs = int(c.BlockSizeParams.MaxTxs) - } - if c.BlockSizeParams.MaxGas != 0 { - res.BlockSizeParams.MaxGas = int(c.BlockSizeParams.MaxGas) - } - } - if c.TxSizeParams != nil { - if c.TxSizeParams.MaxBytes != 0 { - res.TxSizeParams.MaxBytes = int(c.TxSizeParams.MaxBytes) - } - if c.TxSizeParams.MaxGas != 0 { - res.TxSizeParams.MaxGas = int(c.TxSizeParams.MaxGas) - } - } - if c.BlockGossipParams != nil { - if c.BlockGossipParams.BlockPartSizeBytes != 0 { - res.BlockGossipParams.BlockPartSizeBytes = int(c.BlockGossipParams.BlockPartSizeBytes) - } - } - return res -} - // BlockSizeParams contain limits on the block size. type BlockSizeParams struct { MaxBytes int `json:"max_bytes"` // NOTE: must not be 0 nor greater than 100MB From a0b2d77bef7d0c4f3e5e4352af36e2f598c1de4d Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 14 Dec 2017 10:13:31 +0100 Subject: [PATCH 04/23] Add hash to ConsensusParams --- types/params.go | 15 ++++++++++++++ types/params_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/types/params.go b/types/params.go index 322cba612..c17196be4 100644 --- a/types/params.go +++ b/types/params.go @@ -2,6 +2,8 @@ package types import ( "github.com/pkg/errors" + + "github.com/tendermint/tmlibs/merkle" ) const ( @@ -85,3 +87,16 @@ func (params *ConsensusParams) Validate() error { } return nil } + +// Hash returns a merkle hash of the parameters to store +// in the block header +func (params *ConsensusParams) Hash() []byte { + return merkle.SimpleHashFromMap(map[string]interface{}{ + "block_gossip_part_size_bytes": params.BlockGossipParams.BlockPartSizeBytes, + "block_size_max_bytes": params.BlockSizeParams.MaxBytes, + "block_size_max_gas": params.BlockSizeParams.MaxGas, + "block_size_max_txs": params.BlockSizeParams.MaxTxs, + "tx_size_max_bytes": params.TxSizeParams.MaxBytes, + "tx_size_max_gas": params.TxSizeParams.MaxGas, + }) +} diff --git a/types/params_test.go b/types/params_test.go index 507c85139..899ca8e19 100644 --- a/types/params_test.go +++ b/types/params_test.go @@ -1,6 +1,8 @@ package types import ( + "bytes" + "sort" "testing" "github.com/stretchr/testify/assert" @@ -38,3 +40,49 @@ func TestConsensusParamsValidation(t *testing.T) { } } } + +func makeParams(blockBytes, blockTx, blockGas, txBytes, + txGas, partSize int) ConsensusParams { + + return ConsensusParams{ + BlockSizeParams: BlockSizeParams{ + MaxBytes: blockBytes, + MaxTxs: blockTx, + MaxGas: blockGas, + }, + TxSizeParams: TxSizeParams{ + MaxBytes: txBytes, + MaxGas: txGas, + }, + BlockGossipParams: BlockGossipParams{ + BlockPartSizeBytes: partSize, + }, + } +} + +func TestConsensusParamsHash(t *testing.T) { + params := []ConsensusParams{ + makeParams(1, 2, 3, 4, 5, 6), + makeParams(7, 2, 3, 4, 5, 6), + makeParams(1, 7, 3, 4, 5, 6), + makeParams(1, 2, 7, 4, 5, 6), + makeParams(1, 2, 3, 7, 5, 6), + makeParams(1, 2, 3, 4, 7, 6), + makeParams(1, 2, 3, 4, 5, 7), + makeParams(6, 5, 4, 3, 2, 1), + } + + hashes := make([][]byte, len(params)) + for i := range params { + hashes[i] = params[i].Hash() + } + + // make sure there are no duplicates... + // sort, then check in order for matches + sort.Slice(hashes, func(i, j int) bool { + return bytes.Compare(hashes[i], hashes[j]) < 0 + }) + for i := 0; i < len(hashes)-1; i++ { + assert.NotEqual(t, hashes[i], hashes[i+1]) + } +} From 56cada6a0ceabebb351b91549f4e783a72ac6277 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 14 Dec 2017 10:14:01 +0100 Subject: [PATCH 05/23] Validate ConsensusParams returned from abci app --- state/state.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/state/state.go b/state/state.go index 34383cb15..94ca05281 100644 --- a/state/state.go +++ b/state/state.go @@ -253,6 +253,12 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ nextParams := applyChanges(s.Params, abciResponses.EndBlock.ConsensusParamChanges) + err := nextParams.Validate() + if err != nil { + s.logger.Error("Error updating consensus params", "err", err) + // TODO: err or carry on? + nextParams = s.Params + } s.setBlockAndValidators(header.Height, header.NumTxs, From d151e36ea80c5a86e8f58bdebb469d7e3e9b417c Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 14 Dec 2017 10:28:04 +0100 Subject: [PATCH 06/23] Add ConsensusHash to header --- blockchain/reactor_test.go | 1 + consensus/state.go | 3 ++- state/execution.go | 2 +- state/execution_test.go | 2 +- state/state.go | 5 +++-- types/block.go | 16 ++++++++++++++-- types/block_test.go | 18 +++++++++++------- 7 files changed, 33 insertions(+), 14 deletions(-) diff --git a/blockchain/reactor_test.go b/blockchain/reactor_test.go index e652df3fd..d3e341644 100644 --- a/blockchain/reactor_test.go +++ b/blockchain/reactor_test.go @@ -112,6 +112,7 @@ func makeBlock(height int64, state *sm.State) *types.Block { block, _ := types.MakeBlock(height, "test_chain", makeTxs(height), state.LastBlockTotalTx, new(types.Commit), prevBlockID, valHash, state.AppHash, + state.Params.Hash(), state.Params.BlockGossipParams.BlockPartSizeBytes) return block } diff --git a/consensus/state.go b/consensus/state.go index 8a2692a22..1018d3704 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -866,7 +866,8 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts return types.MakeBlock(cs.Height, cs.state.ChainID, txs, cs.state.LastBlockTotalTx, commit, cs.state.LastBlockID, cs.state.Validators.Hash(), - cs.state.AppHash, cs.state.Params.BlockPartSizeBytes) + cs.state.AppHash, cs.state.Params.Hash(), + cs.state.Params.BlockPartSizeBytes) } // Enter: `timeoutPropose` after entering Propose. diff --git a/state/execution.go b/state/execution.go index 6f6a7ca18..fbb0954d3 100644 --- a/state/execution.go +++ b/state/execution.go @@ -187,7 +187,7 @@ func (s *State) ValidateBlock(block *types.Block) error { func (s *State) validateBlock(block *types.Block) error { // Basic block validation. err := block.ValidateBasic(s.ChainID, s.LastBlockHeight, - s.LastBlockTotalTx, s.LastBlockID, s.LastBlockTime, s.AppHash) + s.LastBlockTotalTx, s.LastBlockID, s.LastBlockTime, s.AppHash, s.Params.Hash()) if err != nil { return err } diff --git a/state/execution_test.go b/state/execution_test.go index ac5c72f26..081a71e91 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -120,7 +120,7 @@ func makeBlock(height int64, state *State) *types.Block { block, _ := types.MakeBlock(height, chainID, makeTxs(height), state.LastBlockTotalTx, new(types.Commit), prevBlockID, valHash, - state.AppHash, testPartSize) + state.AppHash, state.Params.Hash(), testPartSize) return block } diff --git a/state/state.go b/state/state.go index 94ca05281..d3bca4a81 100644 --- a/state/state.go +++ b/state/state.go @@ -269,8 +269,9 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ } -// applyChanges returns a new param set, overriding any -// parameter that is non-zero in argument +// applyChanges returns new ConsensusParams +// whose fields are set to any non-zero fields of c. +// If c is nil, it returns p unmodified, as it was passed in. func applyChanges(p types.ConsensusParams, c *abci.ConsensusParams) types.ConsensusParams { diff --git a/types/block.go b/types/block.go index ff3d3811b..356776579 100644 --- a/types/block.go +++ b/types/block.go @@ -25,7 +25,7 @@ type Block struct { // TODO: Add version information to the Block struct. func MakeBlock(height int64, chainID string, txs []Tx, totalTxs int64, commit *Commit, - prevBlockID BlockID, valHash, appHash []byte, + prevBlockID BlockID, valHash, appHash, consensusHash []byte, partSize int) (*Block, *PartSet) { newTxs := int64(len(txs)) @@ -39,6 +39,7 @@ func MakeBlock(height int64, chainID string, txs []Tx, LastBlockID: prevBlockID, ValidatorsHash: valHash, AppHash: appHash, // state merkle root of txs from the previous block. + ConsensusHash: consensusHash, }, LastCommit: commit, Data: &Data{ @@ -52,7 +53,7 @@ func MakeBlock(height int64, chainID string, txs []Tx, // ValidateBasic performs basic validation that doesn't involve state data. func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, lastBlockTotalTx int64, lastBlockID BlockID, - lastBlockTime time.Time, appHash []byte) error { + lastBlockTime time.Time, appHash, consensusHash []byte) error { if b.ChainID != chainID { return errors.New(cmn.Fmt("Wrong Block.Header.ChainID. Expected %v, got %v", chainID, b.ChainID)) @@ -91,6 +92,13 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, if !bytes.Equal(b.AppHash, appHash) { return errors.New(cmn.Fmt("Wrong Block.Header.AppHash. Expected %X, got %v", appHash, b.AppHash)) } + // TODO: make testing easier + if len(consensusHash) == 0 { + panic("food") + } + if !bytes.Equal(b.ConsensusHash, consensusHash) { + return errors.New(cmn.Fmt("Wrong Block.Header.ConsensusHash. Expected %X, got %v", consensusHash, b.ConsensusHash)) + } // NOTE: the AppHash and ValidatorsHash are validated later. return nil } @@ -178,6 +186,7 @@ type Header struct { DataHash data.Bytes `json:"data_hash"` // transactions ValidatorsHash data.Bytes `json:"validators_hash"` // validators for the current block AppHash data.Bytes `json:"app_hash"` // state after txs from the previous block + ConsensusHash data.Bytes `json:"consensus_hash"` // consensus params for current block } // Hash returns the hash of the header. @@ -197,6 +206,7 @@ func (h *Header) Hash() data.Bytes { "Data": h.DataHash, "Validators": h.ValidatorsHash, "App": h.AppHash, + "Consensus": h.ConsensusHash, }) } @@ -216,6 +226,7 @@ func (h *Header) StringIndented(indent string) string { %s Data: %v %s Validators: %v %s App: %v +%s Conensus: %v %s}#%v`, indent, h.ChainID, indent, h.Height, @@ -227,6 +238,7 @@ func (h *Header) StringIndented(indent string) string { indent, h.DataHash, indent, h.ValidatorsHash, indent, h.AppHash, + indent, h.ConsensusHash, indent, h.Hash()) } diff --git a/types/block_test.go b/types/block_test.go index 25e5a76e7..a874508a4 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -13,6 +13,7 @@ func TestValidateBlock(t *testing.T) { lastID := makeBlockID() valHash := []byte("val") appHash := []byte("app") + consensusHash := []byte("consensus-params") h := int64(3) voteSet, _, vals := randVoteSet(h-1, 1, VoteTypePrecommit, @@ -21,33 +22,36 @@ func TestValidateBlock(t *testing.T) { require.NoError(t, err) block, _ := MakeBlock(h, "hello", txs, 10, commit, - lastID, valHash, appHash, 2) + lastID, valHash, appHash, consensusHash, 2) require.NotNil(t, block) // proper block must pass - err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash) + err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash, consensusHash) require.NoError(t, err) // wrong chain fails - err = block.ValidateBasic("other", h-1, 10, lastID, block.Time, appHash) + err = block.ValidateBasic("other", h-1, 10, lastID, block.Time, appHash, consensusHash) require.Error(t, err) // wrong height fails - err = block.ValidateBasic("hello", h+4, 10, lastID, block.Time, appHash) + err = block.ValidateBasic("hello", h+4, 10, lastID, block.Time, appHash, consensusHash) require.Error(t, err) // wrong total tx fails - err = block.ValidateBasic("hello", h-1, 15, lastID, block.Time, appHash) + err = block.ValidateBasic("hello", h-1, 15, lastID, block.Time, appHash, consensusHash) require.Error(t, err) // wrong blockid fails - err = block.ValidateBasic("hello", h-1, 10, makeBlockID(), block.Time, appHash) + err = block.ValidateBasic("hello", h-1, 10, makeBlockID(), block.Time, appHash, consensusHash) require.Error(t, err) // wrong app hash fails - err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, []byte("bad-hash")) + err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, []byte("bad-hash"), consensusHash) require.Error(t, err) + // wrong consensus hash fails + err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash, []byte("wrong-params")) + require.Error(t, err) } func makeBlockID() BlockID { From 45bc106de7f9fd9746e0c0a49abf87932e8aa01b Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 14 Dec 2017 10:42:52 +0100 Subject: [PATCH 07/23] Updated lite tests to set ConsensusHash in header --- lite/dynamic_test.go | 6 +++--- lite/files/commit_test.go | 2 +- lite/files/provider_test.go | 2 +- lite/helpers.go | 11 ++++++----- lite/inquirer_test.go | 9 ++++++--- lite/performance_test.go | 4 ++-- lite/provider_test.go | 4 ++-- lite/static_test.go | 2 +- 8 files changed, 22 insertions(+), 18 deletions(-) diff --git a/lite/dynamic_test.go b/lite/dynamic_test.go index 12db19466..acbd1e651 100644 --- a/lite/dynamic_test.go +++ b/lite/dynamic_test.go @@ -46,7 +46,7 @@ func TestDynamicCert(t *testing.T) { for _, tc := range cases { check := tc.keys.GenCommit(chainID, tc.height, nil, tc.vals, - []byte("bar"), tc.first, tc.last) + []byte("bar"), []byte("params"), tc.first, tc.last) err := cert.Certify(check) if tc.proper { assert.Nil(err, "%+v", err) @@ -71,7 +71,7 @@ func TestDynamicUpdate(t *testing.T) { // one valid block to give us a sense of time h := int64(100) - good := keys.GenCommit(chainID, h, nil, vals, []byte("foo"), 0, len(keys)) + good := keys.GenCommit(chainID, h, nil, vals, []byte("foo"), []byte("params"), 0, len(keys)) err := cert.Certify(good) require.Nil(err, "%+v", err) @@ -109,7 +109,7 @@ func TestDynamicUpdate(t *testing.T) { for _, tc := range cases { fc := tc.keys.GenFullCommit(chainID, tc.height, nil, tc.vals, - []byte("bar"), tc.first, tc.last) + []byte("bar"), []byte("params"), tc.first, tc.last) err := cert.Update(fc) if tc.proper { assert.Nil(err, "%d: %+v", tc.height, err) diff --git a/lite/files/commit_test.go b/lite/files/commit_test.go index c2124379a..f6cb2a734 100644 --- a/lite/files/commit_test.go +++ b/lite/files/commit_test.go @@ -29,7 +29,7 @@ func TestSerializeFullCommits(t *testing.T) { // build a fc keys := lite.GenValKeys(5) vals := keys.ToValidators(10, 0) - fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, 5) + fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, 5) require.Equal(h, fc.Height()) require.Equal(vals.Hash(), fc.ValidatorsHash()) diff --git a/lite/files/provider_test.go b/lite/files/provider_test.go index b8d8e88bb..e50d34614 100644 --- a/lite/files/provider_test.go +++ b/lite/files/provider_test.go @@ -46,7 +46,7 @@ func TestFileProvider(t *testing.T) { // (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ... vals := keys.ToValidators(10, int64(count/2)) h := int64(20 + 10*i) - check := keys.GenCommit(chainID, h, nil, vals, appHash, 0, 5) + check := keys.GenCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, 5) seeds[i] = lite.NewFullCommit(check, vals) } diff --git a/lite/helpers.go b/lite/helpers.go index f8d90de5a..394cd666d 100644 --- a/lite/helpers.go +++ b/lite/helpers.go @@ -110,7 +110,7 @@ func makeVote(header *types.Header, vals *types.ValidatorSet, key crypto.PrivKey // Silences warning that vals can also be merkle.Hashable // nolint: interfacer func genHeader(chainID string, height int64, txs types.Txs, - vals *types.ValidatorSet, appHash []byte) *types.Header { + vals *types.ValidatorSet, appHash, consHash []byte) *types.Header { return &types.Header{ ChainID: chainID, @@ -123,14 +123,15 @@ func genHeader(chainID string, height int64, txs types.Txs, ValidatorsHash: vals.Hash(), DataHash: txs.Hash(), AppHash: appHash, + ConsensusHash: consHash, } } // GenCommit calls genHeader and signHeader and combines them into a Commit. func (v ValKeys) GenCommit(chainID string, height int64, txs types.Txs, - vals *types.ValidatorSet, appHash []byte, first, last int) Commit { + vals *types.ValidatorSet, appHash, consHash []byte, first, last int) Commit { - header := genHeader(chainID, height, txs, vals, appHash) + header := genHeader(chainID, height, txs, vals, appHash, consHash) check := Commit{ Header: header, Commit: v.signHeader(header, first, last), @@ -140,9 +141,9 @@ func (v ValKeys) GenCommit(chainID string, height int64, txs types.Txs, // GenFullCommit calls genHeader and signHeader and combines them into a Commit. func (v ValKeys) GenFullCommit(chainID string, height int64, txs types.Txs, - vals *types.ValidatorSet, appHash []byte, first, last int) FullCommit { + vals *types.ValidatorSet, appHash, consHash []byte, first, last int) FullCommit { - header := genHeader(chainID, height, txs, vals, appHash) + header := genHeader(chainID, height, txs, vals, appHash, consHash) commit := Commit{ Header: header, Commit: v.signHeader(header, first, last), diff --git a/lite/inquirer_test.go b/lite/inquirer_test.go index c30d82091..eb45eb3cb 100644 --- a/lite/inquirer_test.go +++ b/lite/inquirer_test.go @@ -22,6 +22,7 @@ func TestInquirerValidPath(t *testing.T) { // construct a bunch of commits, each with one more height than the last chainID := "inquiry-test" + consHash := []byte("params") count := 50 commits := make([]lite.FullCommit, count) for i := 0; i < count; i++ { @@ -30,7 +31,7 @@ func TestInquirerValidPath(t *testing.T) { vals := keys.ToValidators(vote, 0) h := int64(20 + 10*i) appHash := []byte(fmt.Sprintf("h=%d", h)) - commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys)) + commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, 0, len(keys)) } // initialize a certifier with the initial state @@ -69,6 +70,7 @@ func TestInquirerMinimalPath(t *testing.T) { // construct a bunch of commits, each with one more height than the last chainID := "minimal-path" + consHash := []byte("other-params") count := 12 commits := make([]lite.FullCommit, count) for i := 0; i < count; i++ { @@ -77,7 +79,7 @@ func TestInquirerMinimalPath(t *testing.T) { vals := keys.ToValidators(vote, 0) h := int64(5 + 10*i) appHash := []byte(fmt.Sprintf("h=%d", h)) - commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys)) + commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, 0, len(keys)) } // initialize a certifier with the initial state @@ -117,6 +119,7 @@ func TestInquirerVerifyHistorical(t *testing.T) { // construct a bunch of commits, each with one more height than the last chainID := "inquiry-test" count := 10 + consHash := []byte("special-params") commits := make([]lite.FullCommit, count) for i := 0; i < count; i++ { // extend the keys by 1 each time @@ -124,7 +127,7 @@ func TestInquirerVerifyHistorical(t *testing.T) { vals := keys.ToValidators(vote, 0) h := int64(20 + 10*i) appHash := []byte(fmt.Sprintf("h=%d", h)) - commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, len(keys)) + commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, consHash, 0, len(keys)) } // initialize a certifier with the initial state diff --git a/lite/performance_test.go b/lite/performance_test.go index e01b89936..af6eacc33 100644 --- a/lite/performance_test.go +++ b/lite/performance_test.go @@ -33,7 +33,7 @@ func benchmarkGenCommit(b *testing.B, keys lite.ValKeys) { for i := 0; i < b.N; i++ { h := int64(1 + i) appHash := []byte(fmt.Sprintf("h=%d", h)) - keys.GenCommit(chainID, h, nil, vals, appHash, 0, len(keys)) + keys.GenCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, len(keys)) } } @@ -105,7 +105,7 @@ func benchmarkCertifyCommit(b *testing.B, keys lite.ValKeys) { chainID := "bench-certify" vals := keys.ToValidators(20, 10) cert := lite.NewStatic(chainID, vals) - check := keys.GenCommit(chainID, 123, nil, vals, []byte("foo"), 0, len(keys)) + check := keys.GenCommit(chainID, 123, nil, vals, []byte("foo"), []byte("params"), 0, len(keys)) for i := 0; i < b.N; i++ { err := cert.Certify(check) if err != nil { diff --git a/lite/provider_test.go b/lite/provider_test.go index f1165619f..09ad0aa8a 100644 --- a/lite/provider_test.go +++ b/lite/provider_test.go @@ -58,7 +58,7 @@ func checkProvider(t *testing.T, p lite.Provider, chainID, app string) { // (10, 0), (10, 1), (10, 1), (10, 2), (10, 2), ... vals := keys.ToValidators(10, int64(count/2)) h := int64(20 + 10*i) - commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, 5) + commits[i] = keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, 5) } // check provider is empty @@ -129,7 +129,7 @@ func TestCacheGetsBestHeight(t *testing.T) { for i := 0; i < count; i++ { vals := keys.ToValidators(10, int64(count/2)) h := int64(10 * (i + 1)) - fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, 0, 5) + fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), 0, 5) err := p2.StoreCommit(fc) require.NoError(err) } diff --git a/lite/static_test.go b/lite/static_test.go index e4bf435c5..d0a1e6859 100644 --- a/lite/static_test.go +++ b/lite/static_test.go @@ -44,7 +44,7 @@ func TestStaticCert(t *testing.T) { for _, tc := range cases { check := tc.keys.GenCommit(chainID, tc.height, nil, tc.vals, - []byte("foo"), tc.first, tc.last) + []byte("foo"), []byte("params"), tc.first, tc.last) err := cert.Certify(check) if tc.proper { assert.Nil(err, "%+v", err) From 960b25408faffae4013ef810fa0b5b967459e944 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 14 Dec 2017 10:53:36 +0100 Subject: [PATCH 08/23] Store LastConsensusHash in State as well Update all BlockValidation that it matches the last state --- blockchain/reactor_test.go | 2 +- consensus/state.go | 2 +- state/execution.go | 2 +- state/execution_test.go | 2 +- state/state.go | 5 +++++ types/block.go | 4 ---- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/blockchain/reactor_test.go b/blockchain/reactor_test.go index d3e341644..a84051291 100644 --- a/blockchain/reactor_test.go +++ b/blockchain/reactor_test.go @@ -112,7 +112,7 @@ func makeBlock(height int64, state *sm.State) *types.Block { block, _ := types.MakeBlock(height, "test_chain", makeTxs(height), state.LastBlockTotalTx, new(types.Commit), prevBlockID, valHash, state.AppHash, - state.Params.Hash(), + state.LastConsensusHash, state.Params.BlockGossipParams.BlockPartSizeBytes) return block } diff --git a/consensus/state.go b/consensus/state.go index 1018d3704..8187ea72f 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -866,7 +866,7 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts return types.MakeBlock(cs.Height, cs.state.ChainID, txs, cs.state.LastBlockTotalTx, commit, cs.state.LastBlockID, cs.state.Validators.Hash(), - cs.state.AppHash, cs.state.Params.Hash(), + cs.state.AppHash, cs.state.LastConsensusHash, cs.state.Params.BlockPartSizeBytes) } diff --git a/state/execution.go b/state/execution.go index fbb0954d3..6f3266f6b 100644 --- a/state/execution.go +++ b/state/execution.go @@ -187,7 +187,7 @@ func (s *State) ValidateBlock(block *types.Block) error { func (s *State) validateBlock(block *types.Block) error { // Basic block validation. err := block.ValidateBasic(s.ChainID, s.LastBlockHeight, - s.LastBlockTotalTx, s.LastBlockID, s.LastBlockTime, s.AppHash, s.Params.Hash()) + s.LastBlockTotalTx, s.LastBlockID, s.LastBlockTime, s.AppHash, s.LastConsensusHash) if err != nil { return err } diff --git a/state/execution_test.go b/state/execution_test.go index 081a71e91..3080187b3 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -120,7 +120,7 @@ func makeBlock(height int64, state *State) *types.Block { block, _ := types.MakeBlock(height, chainID, makeTxs(height), state.LastBlockTotalTx, new(types.Commit), prevBlockID, valHash, - state.AppHash, state.Params.Hash(), testPartSize) + state.AppHash, state.LastConsensusHash, testPartSize) return block } diff --git a/state/state.go b/state/state.go index d3bca4a81..268e3ae90 100644 --- a/state/state.go +++ b/state/state.go @@ -59,6 +59,8 @@ type State struct { // AppHash is updated after Commit AppHash []byte + // LastConsensusHash is updated after Commit + LastConsensusHash []byte logger log.Logger } @@ -120,6 +122,7 @@ func (s *State) Copy() *State { Validators: s.Validators.Copy(), LastValidators: s.LastValidators.Copy(), AppHash: s.AppHash, + LastConsensusHash: s.LastConsensusHash, LastHeightValidatorsChanged: s.LastHeightValidatorsChanged, logger: s.logger, ChainID: s.ChainID, @@ -319,6 +322,7 @@ func (s *State) setBlockAndValidators(height int64, s.LastBlockTime = blockTime s.Validators = nextValSet s.LastValidators = prevValSet + s.LastConsensusHash = s.Params.Hash() s.Params = nextParams } @@ -428,6 +432,7 @@ func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) (*State, error) { Validators: types.NewValidatorSet(validators), LastValidators: types.NewValidatorSet(nil), AppHash: genDoc.AppHash, + LastConsensusHash: genDoc.ConsensusParams.Hash(), LastHeightValidatorsChanged: 1, }, nil } diff --git a/types/block.go b/types/block.go index 356776579..48b59027c 100644 --- a/types/block.go +++ b/types/block.go @@ -92,10 +92,6 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, if !bytes.Equal(b.AppHash, appHash) { return errors.New(cmn.Fmt("Wrong Block.Header.AppHash. Expected %X, got %v", appHash, b.AppHash)) } - // TODO: make testing easier - if len(consensusHash) == 0 { - panic("food") - } if !bytes.Equal(b.ConsensusHash, consensusHash) { return errors.New(cmn.Fmt("Wrong Block.Header.ConsensusHash. Expected %X, got %v", consensusHash, b.ConsensusHash)) } From 4bca6bf6f502f33cdc593fb08d29f56e4a6d300e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 19 Dec 2017 12:30:34 -0500 Subject: [PATCH 09/23] fix test --- state/execution_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/state/execution_test.go b/state/execution_test.go index 3080187b3..379ac6732 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -81,7 +81,7 @@ func TestBeginBlockAbsentValidators(t *testing.T) { valHash := state.Validators.Hash() block, _ := types.MakeBlock(2, chainID, makeTxs(2), state.LastBlockTotalTx, lastCommit, - prevBlockID, valHash, state.AppHash, testPartSize) + prevBlockID, valHash, state.AppHash, state.LastConsensusHash, testPartSize) _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), lastValidators) require.Nil(t, err, tc.desc) From 843e1ed400549098fa21efd875891f82d60e87c1 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Tue, 19 Dec 2017 12:43:15 -0600 Subject: [PATCH 10/23] Updates -> ValidatoSetUpdates --- blockchain/reactor.go | 2 +- blockchain/reactor_test.go | 4 +- consensus/state.go | 2 +- consensus/wal.go | 2 +- consensus/wal_generator.go | 5 +- docs/architecture/adr-005-consensus-params.md | 19 +++--- glide.lock | 6 +- state/execution.go | 6 +- state/state.go | 42 ++++++------ state/state_test.go | 28 ++++---- types/block.go | 18 ++--- types/genesis_test.go | 2 +- types/params.go | 68 +++++++++---------- types/params_test.go | 10 +-- 14 files changed, 107 insertions(+), 107 deletions(-) diff --git a/blockchain/reactor.go b/blockchain/reactor.go index 60626b3d8..e070830aa 100644 --- a/blockchain/reactor.go +++ b/blockchain/reactor.go @@ -183,7 +183,7 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) // maxMsgSize returns the maximum allowable size of a // message on the blockchain reactor. func (bcR *BlockchainReactor) maxMsgSize() int { - return bcR.state.Params.BlockSizeParams.MaxBytes + 2 + return bcR.state.Params.BlockSize.MaxBytes + 2 } // Handle messages from the poolReactor telling the reactor what to do. diff --git a/blockchain/reactor_test.go b/blockchain/reactor_test.go index a84051291..dd782ea3f 100644 --- a/blockchain/reactor_test.go +++ b/blockchain/reactor_test.go @@ -41,7 +41,7 @@ func newBlockchainReactor(logger log.Logger, maxBlockHeight int64) *BlockchainRe for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ { firstBlock := makeBlock(blockHeight, state) secondBlock := makeBlock(blockHeight+1, state) - firstParts := firstBlock.MakePartSet(state.Params.BlockGossipParams.BlockPartSizeBytes) + firstParts := firstBlock.MakePartSet(state.Params.BlockGossip.BlockPartSizeBytes) blockStore.SaveBlock(firstBlock, firstParts, secondBlock.LastCommit) } @@ -113,7 +113,7 @@ func makeBlock(height int64, state *sm.State) *types.Block { state.LastBlockTotalTx, new(types.Commit), prevBlockID, valHash, state.AppHash, state.LastConsensusHash, - state.Params.BlockGossipParams.BlockPartSizeBytes) + state.Params.BlockGossip.BlockPartSizeBytes) return block } diff --git a/consensus/state.go b/consensus/state.go index 8187ea72f..3a64746ee 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -1307,7 +1307,7 @@ func (cs *ConsensusState) addProposalBlockPart(height int64, part *types.Part, v var n int var err error cs.ProposalBlock = wire.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(), - cs.state.Params.BlockSizeParams.MaxBytes, &n, &err).(*types.Block) + cs.state.Params.BlockSize.MaxBytes, &n, &err).(*types.Block) // NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash()) if cs.Step == cstypes.RoundStepPropose && cs.isProposalComplete() { diff --git a/consensus/wal.go b/consensus/wal.go index 7dc8d2e8b..dfbef8790 100644 --- a/consensus/wal.go +++ b/consensus/wal.go @@ -18,7 +18,7 @@ import ( ) const ( - // must be greater than params.BlockGossipParams.BlockPartSizeBytes + a few bytes + // must be greater than params.BlockGossip.BlockPartSizeBytes + a few bytes maxMsgSizeBytes = 1024 * 1024 // 1MB ) diff --git a/consensus/wal_generator.go b/consensus/wal_generator.go index 36de6bf86..b46ef93d1 100644 --- a/consensus/wal_generator.go +++ b/consensus/wal_generator.go @@ -35,7 +35,6 @@ func WALWithNBlocks(numBlocks int) (data []byte, err error) { logger := log.TestingLogger().With("wal_generator", "wal_generator") logger.Info("generating WAL (last height msg excluded)", "numBlocks", numBlocks) - ///////////////////////////////////////////////////////////////////////////// // COPY PASTE FROM node.go WITH A FEW MODIFICATIONS // NOTE: we can't import node package because of circular dependency @@ -95,7 +94,7 @@ func WALWithNBlocks(numBlocks int) (data []byte, err error) { wr.Flush() return b.Bytes(), nil case <-time.After(1 * time.Minute): - wr.Flush() + wr.Flush() return b.Bytes(), fmt.Errorf("waited too long for tendermint to produce %d blocks (grep logs for `wal_generator`)", numBlocks) } } @@ -147,7 +146,7 @@ type byteBufferWAL struct { heightToStop int64 signalWhenStopsTo chan<- struct{} - logger log.Logger + logger log.Logger } // needed for determinism diff --git a/docs/architecture/adr-005-consensus-params.md b/docs/architecture/adr-005-consensus-params.md index 678de42eb..6656d35b2 100644 --- a/docs/architecture/adr-005-consensus-params.md +++ b/docs/architecture/adr-005-consensus-params.md @@ -22,30 +22,30 @@ The parameters are used to determine the validity of a block (and tx) via the un ``` type ConsensusParams struct { - BlockSizeParams - TxSizeParams - BlockGossipParams + BlockSize + TxSize + BlockGossip } -type BlockSizeParams struct { +type BlockSize struct { MaxBytes int MaxTxs int MaxGas int } -type TxSizeParams struct { +type TxSize struct { MaxBytes int MaxGas int } -type BlockGossipParams struct { +type BlockGossip struct { BlockPartSizeBytes int } ``` The `ConsensusParams` can evolve over time by adding new structs that cover different aspects of the consensus rules. -The `BlockPartSizeBytes` and the `BlockSizeParams.MaxBytes` are enforced to be greater than 0. +The `BlockPartSizeBytes` and the `BlockSize.MaxBytes` are enforced to be greater than 0. The former because we need a part size, the latter so that we always have at least some sanity check over the size of blocks. ### ABCI @@ -58,7 +58,7 @@ like the BlockPartSize, that the app shouldn't really know about. #### EndBlock -The EndBlock response includes a `ConsensusParams`, which includes BlockSizeParams and TxSizeParams, but not BlockGossipParams. +The EndBlock response includes a `ConsensusParams`, which includes BlockSize and TxSize, but not BlockGossip. Other param struct can be added to `ConsensusParams` in the future. The `0` value is used to denote no change. Any other value will update that parameter in the `State.ConsensusParams`, to be applied for the next block. @@ -82,4 +82,5 @@ Proposed. ### Neutral -- The TxSizeParams, which checks validity, may be in conflict with the config's `max_block_size_tx`, which determines proposal sizes +- The TxSize, which checks validity, may be in conflict with the config's `max_block_size_tx`, which determines proposal sizes + diff --git a/glide.lock b/glide.lock index c42bd57f6..37395bb4c 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: ff6e6786ec24ffac91df45d4a1cdcefae5280700667ca76b8b9b96f343d78c95 -updated: 2017-12-13T18:04:10.05914801+01:00 +updated: 2017-12-19T18:45:37.28268356Z imports: - name: github.com/btcsuite/btcd version: 2e60448ffcc6bf78332d1fe590260095f554dd78 @@ -103,7 +103,7 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: 895e14d6bd9cdad98eab4a051decbaad46f7eebd + version: 66296fe11aaa518381c6cd7160bc6318e28c4e02 subpackages: - client - example/code @@ -129,7 +129,7 @@ imports: subpackages: - iavl - name: github.com/tendermint/tmlibs - version: a483e1ff486b577ba94e6a20f08bf52fbb7bff14 + version: e4ef2835f0081c2ece83b9c1f777cf071f956e81 subpackages: - autofile - cli diff --git a/state/execution.go b/state/execution.go index 6f3266f6b..61806a3dc 100644 --- a/state/execution.go +++ b/state/execution.go @@ -111,11 +111,11 @@ func execBlockOnProxyApp(txEventPublisher types.TxEventPublisher, proxyAppConn p return nil, err } - valChanges := abciResponses.EndBlock.Changes + valSetUpdates := abciResponses.EndBlock.ValidatorSetUpdates logger.Info("Executed block", "height", block.Height, "validTxs", validTxs, "invalidTxs", invalidTxs) - if len(valChanges) > 0 { - logger.Info("Update to validator set", "updates", abci.ValidatorsString(valChanges)) + if len(valSetUpdates) > 0 { + logger.Info("Updates to validator set", "updates", abci.ValidatorsString(valSetUpdates)) } return abciResponses, nil diff --git a/state/state.go b/state/state.go index 268e3ae90..381a6301e 100644 --- a/state/state.go +++ b/state/state.go @@ -241,8 +241,8 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ nextValSet := prevValSet.Copy() // update the validator set with the latest abciResponses - if len(abciResponses.EndBlock.Changes) > 0 { - err := updateValidators(nextValSet, abciResponses.EndBlock.Changes) + if len(abciResponses.EndBlock.ValidatorSetUpdates) > 0 { + err := updateValidators(nextValSet, abciResponses.EndBlock.ValidatorSetUpdates) if err != nil { s.logger.Error("Error changing validator set", "err", err) // TODO: err or carry on? @@ -254,8 +254,8 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ // Update validator accums and set state variables nextValSet.IncrementAccum(1) - nextParams := applyChanges(s.Params, - abciResponses.EndBlock.ConsensusParamChanges) + nextParams := applyUpdates(s.Params, + abciResponses.EndBlock.ConsensusParamUpdates) err := nextParams.Validate() if err != nil { s.logger.Error("Error updating consensus params", "err", err) @@ -272,10 +272,10 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ } -// applyChanges returns new ConsensusParams +// applyUpdates returns new ConsensusParams // whose fields are set to any non-zero fields of c. // If c is nil, it returns p unmodified, as it was passed in. -func applyChanges(p types.ConsensusParams, +func applyUpdates(p types.ConsensusParams, c *abci.ConsensusParams) types.ConsensusParams { if c == nil { @@ -283,29 +283,29 @@ func applyChanges(p types.ConsensusParams, } res := p // we must defensively consider any structs may be nil - if c.BlockSizeParams != nil { + if c.BlockSize != nil { - if c.BlockSizeParams.MaxBytes != 0 { - res.BlockSizeParams.MaxBytes = int(c.BlockSizeParams.MaxBytes) + if c.BlockSize.MaxBytes != 0 { + res.BlockSize.MaxBytes = int(c.BlockSize.MaxBytes) } - if c.BlockSizeParams.MaxTxs != 0 { - res.BlockSizeParams.MaxTxs = int(c.BlockSizeParams.MaxTxs) + if c.BlockSize.MaxTxs != 0 { + res.BlockSize.MaxTxs = int(c.BlockSize.MaxTxs) } - if c.BlockSizeParams.MaxGas != 0 { - res.BlockSizeParams.MaxGas = int(c.BlockSizeParams.MaxGas) + if c.BlockSize.MaxGas != 0 { + res.BlockSize.MaxGas = int(c.BlockSize.MaxGas) } } - if c.TxSizeParams != nil { - if c.TxSizeParams.MaxBytes != 0 { - res.TxSizeParams.MaxBytes = int(c.TxSizeParams.MaxBytes) + if c.TxSize != nil { + if c.TxSize.MaxBytes != 0 { + res.TxSize.MaxBytes = int(c.TxSize.MaxBytes) } - if c.TxSizeParams.MaxGas != 0 { - res.TxSizeParams.MaxGas = int(c.TxSizeParams.MaxGas) + if c.TxSize.MaxGas != 0 { + res.TxSize.MaxGas = int(c.TxSize.MaxGas) } } - if c.BlockGossipParams != nil { - if c.BlockGossipParams.BlockPartSizeBytes != 0 { - res.BlockGossipParams.BlockPartSizeBytes = int(c.BlockGossipParams.BlockPartSizeBytes) + if c.BlockGossip != nil { + if c.BlockGossip.BlockPartSizeBytes != 0 { + res.BlockGossip.BlockPartSizeBytes = int(c.BlockGossip.BlockPartSizeBytes) } } return res diff --git a/state/state_test.go b/state/state_test.go index d560f9532..16b1b42f0 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -80,7 +80,7 @@ func TestABCIResponsesSaveLoad(t *testing.T) { abciResponses := NewABCIResponses(block) abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: []*abci.KVPair{}} abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: []*abci.KVPair{}} - abciResponses.EndBlock = &abci.ResponseEndBlock{Changes: []*abci.Validator{ + abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorSetUpdates: []*abci.Validator{ { PubKey: crypto.GenPrivKeyEd25519().PubKey().Bytes(), Power: 10, @@ -196,41 +196,41 @@ func makeParams(blockBytes, blockTx, blockGas, txBytes, txGas, partSize int) types.ConsensusParams { return types.ConsensusParams{ - BlockSizeParams: types.BlockSizeParams{ + BlockSize: types.BlockSize{ MaxBytes: blockBytes, MaxTxs: blockTx, MaxGas: blockGas, }, - TxSizeParams: types.TxSizeParams{ + TxSize: types.TxSize{ MaxBytes: txBytes, MaxGas: txGas, }, - BlockGossipParams: types.BlockGossipParams{ + BlockGossip: types.BlockGossip{ BlockPartSizeBytes: partSize, }, } } -func TestApplyChanges(t *testing.T) { +func TestApplyUpdates(t *testing.T) { initParams := makeParams(1, 2, 3, 4, 5, 6) cases := [...]struct { init types.ConsensusParams - changes *abci.ConsensusParams + updates *abci.ConsensusParams expected types.ConsensusParams }{ 0: {initParams, nil, initParams}, 1: {initParams, &abci.ConsensusParams{}, initParams}, 2: {initParams, &abci.ConsensusParams{ - TxSizeParams: &abci.TxSizeParams{ + TxSize: &abci.TxSize{ MaxBytes: 123, }, }, makeParams(1, 2, 3, 123, 5, 6)}, 3: {initParams, &abci.ConsensusParams{ - BlockSizeParams: &abci.BlockSizeParams{ + BlockSize: &abci.BlockSize{ MaxTxs: 44, MaxGas: 55, }, @@ -238,13 +238,13 @@ func TestApplyChanges(t *testing.T) { makeParams(1, 44, 55, 4, 5, 6)}, 4: {initParams, &abci.ConsensusParams{ - BlockSizeParams: &abci.BlockSizeParams{ + BlockSize: &abci.BlockSize{ MaxTxs: 789, }, - TxSizeParams: &abci.TxSizeParams{ + TxSize: &abci.TxSize{ MaxGas: 888, }, - BlockGossipParams: &abci.BlockGossipParams{ + BlockGossip: &abci.BlockGossip{ BlockPartSizeBytes: 2002, }, }, @@ -252,7 +252,7 @@ func TestApplyChanges(t *testing.T) { } for i, tc := range cases { - res := applyChanges(tc.init, tc.changes) + res := applyUpdates(tc.init, tc.updates) assert.Equal(t, tc.expected, res, "case %d", i) } } @@ -264,13 +264,13 @@ func makeHeaderPartsResponses(state *State, height int64, _, val := state.Validators.GetByIndex(0) abciResponses := &ABCIResponses{ Height: height, - EndBlock: &abci.ResponseEndBlock{Changes: []*abci.Validator{}}, + EndBlock: &abci.ResponseEndBlock{ValidatorSetUpdates: []*abci.Validator{}}, } // if the pubkey is new, remove the old and add the new if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) { abciResponses.EndBlock = &abci.ResponseEndBlock{ - Changes: []*abci.Validator{ + ValidatorSetUpdates: []*abci.Validator{ {val.PubKey.Bytes(), 0}, {pubkey.Bytes(), 10}, }, diff --git a/types/block.go b/types/block.go index 48b59027c..a00e75a62 100644 --- a/types/block.go +++ b/types/block.go @@ -56,10 +56,10 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, lastBlockTime time.Time, appHash, consensusHash []byte) error { if b.ChainID != chainID { - return errors.New(cmn.Fmt("Wrong Block.Header.ChainID. Expected %v, got %v", chainID, b.ChainID)) + return fmt.Errorf("Wrong Block.Header.ChainID. Expected %v, got %v", chainID, b.ChainID) } if b.Height != lastBlockHeight+1 { - return errors.New(cmn.Fmt("Wrong Block.Header.Height. Expected %v, got %v", lastBlockHeight+1, b.Height)) + return fmt.Errorf("Wrong Block.Header.Height. Expected %v, got %v", lastBlockHeight+1, b.Height) } /* TODO: Determine bounds for Time See blockchain/reactor "stopSyncingDurationMinutes" @@ -70,16 +70,16 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, */ newTxs := int64(len(b.Data.Txs)) if b.NumTxs != newTxs { - return errors.New(cmn.Fmt("Wrong Block.Header.NumTxs. Expected %v, got %v", newTxs, b.NumTxs)) + return fmt.Errorf("Wrong Block.Header.NumTxs. Expected %v, got %v", newTxs, b.NumTxs) } if b.TotalTxs != lastBlockTotalTx+newTxs { - return errors.New(cmn.Fmt("Wrong Block.Header.TotalTxs. Expected %v, got %v", lastBlockTotalTx+newTxs, b.TotalTxs)) + return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", lastBlockTotalTx+newTxs, b.TotalTxs) } if !b.LastBlockID.Equals(lastBlockID) { - return errors.New(cmn.Fmt("Wrong Block.Header.LastBlockID. Expected %v, got %v", lastBlockID, b.LastBlockID)) + return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", lastBlockID, b.LastBlockID) } if !bytes.Equal(b.LastCommitHash, b.LastCommit.Hash()) { - return errors.New(cmn.Fmt("Wrong Block.Header.LastCommitHash. Expected %v, got %v", b.LastCommitHash, b.LastCommit.Hash())) + return fmt.Errorf("Wrong Block.Header.LastCommitHash. Expected %v, got %v", b.LastCommitHash, b.LastCommit.Hash()) } if b.Header.Height != 1 { if err := b.LastCommit.ValidateBasic(); err != nil { @@ -87,13 +87,13 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, } } if !bytes.Equal(b.DataHash, b.Data.Hash()) { - return errors.New(cmn.Fmt("Wrong Block.Header.DataHash. Expected %v, got %v", b.DataHash, b.Data.Hash())) + return fmt.Errorf("Wrong Block.Header.DataHash. Expected %v, got %v", b.DataHash, b.Data.Hash()) } if !bytes.Equal(b.AppHash, appHash) { - return errors.New(cmn.Fmt("Wrong Block.Header.AppHash. Expected %X, got %v", appHash, b.AppHash)) + return fmt.Errorf("Wrong Block.Header.AppHash. Expected %X, got %v", appHash, b.AppHash) } if !bytes.Equal(b.ConsensusHash, consensusHash) { - return errors.New(cmn.Fmt("Wrong Block.Header.ConsensusHash. Expected %X, got %v", consensusHash, b.ConsensusHash)) + return fmt.Errorf("Wrong Block.Header.ConsensusHash. Expected %X, got %v", consensusHash, b.ConsensusHash) } // NOTE: the AppHash and ValidatorsHash are validated later. return nil diff --git a/types/genesis_test.go b/types/genesis_test.go index 214bae40e..bdef3b925 100644 --- a/types/genesis_test.go +++ b/types/genesis_test.go @@ -54,7 +54,7 @@ func TestGenesis(t *testing.T) { assert.NoError(t, err, "expected no error for valid genDoc json") // test with invalid consensus params - genDoc.ConsensusParams.BlockSizeParams.MaxBytes = 0 + genDoc.ConsensusParams.BlockSize.MaxBytes = 0 genDocBytes, err = json.Marshal(genDoc) assert.NoError(t, err, "error marshalling genDoc") genDoc, err = GenesisDocFromJSON(genDocBytes) diff --git a/types/params.go b/types/params.go index c17196be4..e7c32f48f 100644 --- a/types/params.go +++ b/types/params.go @@ -13,58 +13,58 @@ const ( // ConsensusParams contains consensus critical parameters // that determine the validity of blocks. type ConsensusParams struct { - BlockSizeParams `json:"block_size_params"` - TxSizeParams `json:"tx_size_params"` - BlockGossipParams `json:"block_gossip_params"` + BlockSize `json:"block_size_params"` + TxSize `json:"tx_size_params"` + BlockGossip `json:"block_gossip_params"` } -// BlockSizeParams contain limits on the block size. -type BlockSizeParams struct { +// BlockSize contain limits on the block size. +type BlockSize struct { MaxBytes int `json:"max_bytes"` // NOTE: must not be 0 nor greater than 100MB MaxTxs int `json:"max_txs"` MaxGas int `json:"max_gas"` } -// TxSizeParams contain limits on the tx size. -type TxSizeParams struct { +// TxSize contain limits on the tx size. +type TxSize struct { MaxBytes int `json:"max_bytes"` MaxGas int `json:"max_gas"` } -// BlockGossipParams determine consensus critical elements of how blocks are gossiped -type BlockGossipParams struct { +// BlockGossip determine consensus critical elements of how blocks are gossiped +type BlockGossip struct { BlockPartSizeBytes int `json:"block_part_size_bytes"` // NOTE: must not be 0 } // DefaultConsensusParams returns a default ConsensusParams. func DefaultConsensusParams() *ConsensusParams { return &ConsensusParams{ - DefaultBlockSizeParams(), - DefaultTxSizeParams(), - DefaultBlockGossipParams(), + DefaultBlockSize(), + DefaultTxSize(), + DefaultBlockGossip(), } } -// DefaultBlockSizeParams returns a default BlockSizeParams. -func DefaultBlockSizeParams() BlockSizeParams { - return BlockSizeParams{ +// DefaultBlockSize returns a default BlockSize. +func DefaultBlockSize() BlockSize { + return BlockSize{ MaxBytes: 22020096, // 21MB MaxTxs: 100000, MaxGas: -1, } } -// DefaultTxSizeParams returns a default TxSizeParams. -func DefaultTxSizeParams() TxSizeParams { - return TxSizeParams{ +// DefaultTxSize returns a default TxSize. +func DefaultTxSize() TxSize { + return TxSize{ MaxBytes: 10240, // 10kB MaxGas: -1, } } -// DefaultBlockGossipParams returns a default BlockGossipParams. -func DefaultBlockGossipParams() BlockGossipParams { - return BlockGossipParams{ +// DefaultBlockGossip returns a default BlockGossip. +func DefaultBlockGossip() BlockGossip { + return BlockGossip{ BlockPartSizeBytes: 65536, // 64kB, } } @@ -73,17 +73,17 @@ func DefaultBlockGossipParams() BlockGossipParams { // are within their allowed limits, and returns an error if they are not. func (params *ConsensusParams) Validate() error { // ensure some values are greater than 0 - if params.BlockSizeParams.MaxBytes <= 0 { - return errors.Errorf("BlockSizeParams.MaxBytes must be greater than 0. Got %d", params.BlockSizeParams.MaxBytes) + if params.BlockSize.MaxBytes <= 0 { + return errors.Errorf("BlockSize.MaxBytes must be greater than 0. Got %d", params.BlockSize.MaxBytes) } - if params.BlockGossipParams.BlockPartSizeBytes <= 0 { - return errors.Errorf("BlockGossipParams.BlockPartSizeBytes must be greater than 0. Got %d", params.BlockGossipParams.BlockPartSizeBytes) + if params.BlockGossip.BlockPartSizeBytes <= 0 { + return errors.Errorf("BlockGossip.BlockPartSizeBytes must be greater than 0. Got %d", params.BlockGossip.BlockPartSizeBytes) } // ensure blocks aren't too big - if params.BlockSizeParams.MaxBytes > maxBlockSizeBytes { - return errors.Errorf("BlockSizeParams.MaxBytes is too big. %d > %d", - params.BlockSizeParams.MaxBytes, maxBlockSizeBytes) + if params.BlockSize.MaxBytes > maxBlockSizeBytes { + return errors.Errorf("BlockSize.MaxBytes is too big. %d > %d", + params.BlockSize.MaxBytes, maxBlockSizeBytes) } return nil } @@ -92,11 +92,11 @@ func (params *ConsensusParams) Validate() error { // in the block header func (params *ConsensusParams) Hash() []byte { return merkle.SimpleHashFromMap(map[string]interface{}{ - "block_gossip_part_size_bytes": params.BlockGossipParams.BlockPartSizeBytes, - "block_size_max_bytes": params.BlockSizeParams.MaxBytes, - "block_size_max_gas": params.BlockSizeParams.MaxGas, - "block_size_max_txs": params.BlockSizeParams.MaxTxs, - "tx_size_max_bytes": params.TxSizeParams.MaxBytes, - "tx_size_max_gas": params.TxSizeParams.MaxGas, + "block_gossip_part_size_bytes": params.BlockGossip.BlockPartSizeBytes, + "block_size_max_bytes": params.BlockSize.MaxBytes, + "block_size_max_gas": params.BlockSize.MaxGas, + "block_size_max_txs": params.BlockSize.MaxTxs, + "tx_size_max_bytes": params.TxSize.MaxBytes, + "tx_size_max_gas": params.TxSize.MaxGas, }) } diff --git a/types/params_test.go b/types/params_test.go index 899ca8e19..a864ce83e 100644 --- a/types/params_test.go +++ b/types/params_test.go @@ -10,8 +10,8 @@ import ( func newConsensusParams(blockSize, partSize int) ConsensusParams { return ConsensusParams{ - BlockSizeParams: BlockSizeParams{MaxBytes: blockSize}, - BlockGossipParams: BlockGossipParams{BlockPartSizeBytes: partSize}, + BlockSize: BlockSize{MaxBytes: blockSize}, + BlockGossip: BlockGossip{BlockPartSizeBytes: partSize}, } } @@ -45,16 +45,16 @@ func makeParams(blockBytes, blockTx, blockGas, txBytes, txGas, partSize int) ConsensusParams { return ConsensusParams{ - BlockSizeParams: BlockSizeParams{ + BlockSize: BlockSize{ MaxBytes: blockBytes, MaxTxs: blockTx, MaxGas: blockGas, }, - TxSizeParams: TxSizeParams{ + TxSize: TxSize{ MaxBytes: txBytes, MaxGas: txGas, }, - BlockGossipParams: BlockGossipParams{ + BlockGossip: BlockGossip{ BlockPartSizeBytes: partSize, }, } From 0ffd60b8cfb758859a3308a20673cb1d7e56525e Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Thu, 21 Dec 2017 11:52:26 -0600 Subject: [PATCH 11/23] ValidatorSetUpdates -> ValidatorUpdates --- glide.lock | 24 ++++++++++++------------ glide.yaml | 2 +- state/execution.go | 6 +++--- state/state.go | 4 ++-- state/state_test.go | 6 +++--- types/protobuf.go | 4 ++-- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/glide.lock b/glide.lock index 37395bb4c..b52090574 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: ff6e6786ec24ffac91df45d4a1cdcefae5280700667ca76b8b9b96f343d78c95 -updated: 2017-12-19T18:45:37.28268356Z +hash: bd982742a0aee39426f3866914a59f7c47e68dc8dedb87219e2099c0d9c19f7e +updated: 2017-12-21T17:45:25.372327218Z imports: - name: github.com/btcsuite/btcd version: 2e60448ffcc6bf78332d1fe590260095f554dd78 @@ -10,7 +10,7 @@ imports: - name: github.com/fsnotify/fsnotify version: 4da3e2cfbabc9f751898f250b49f2439785783a1 - name: github.com/go-kit/kit - version: e3b2152e0063c5f05efea89ecbe297852af2a92d + version: 953e747656a7bbb5e1f998608b460458958b70cc subpackages: - log - log/level @@ -68,7 +68,7 @@ imports: - name: github.com/mitchellh/mapstructure version: 06020f85339e21b2478f756a78e295255ffa4d6a - name: github.com/pelletier/go-toml - version: 4e9e0ee19b60b13eb79915933f44d8ed5f268bdd + version: b8b5e7696574464b2f9bf303a7b37781bb52889f - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/rcrowley/go-metrics @@ -88,7 +88,7 @@ imports: - name: github.com/spf13/viper version: 25b30aa063fc18e48662b86996252eabdcf2f0c7 - name: github.com/syndtr/goleveldb - version: adf24ef3f94bd13ec4163060b21a5678f22b429b + version: 34011bf325bce385408353a30b101fe5e923eb6e subpackages: - leveldb - leveldb/cache @@ -103,7 +103,7 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: 66296fe11aaa518381c6cd7160bc6318e28c4e02 + version: e4b9f1abe794a2117a59738a1294e09b46d0fa00 subpackages: - client - example/code @@ -144,7 +144,7 @@ imports: - pubsub/query - test - name: golang.org/x/crypto - version: 94eea52f7b742c7cbe0b03b22f0c4c8631ece122 + version: d585fd2cc9195196078f516b69daff6744ef5e84 subpackages: - curve25519 - nacl/box @@ -155,7 +155,7 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: a8b9294777976932365dabb6640cf1468d95c70f + version: d866cfc389cec985d6fda2859936a575a55a3ab6 subpackages: - context - http2 @@ -165,18 +165,18 @@ imports: - lex/httplex - trace - name: golang.org/x/sys - version: 8b4580aae2a0dd0c231a45d3ccb8434ff533b840 + version: d818ba11af4465e00c1998bd3f8a55603b422290 subpackages: - unix - name: golang.org/x/text - version: 75cc3cad82b5f47d3fb229ddda8c5167da14f294 + version: eb22672bea55af56d225d4e35405f4d2e9f062a0 subpackages: - secure/bidirule - transform - unicode/bidi - unicode/norm - name: google.golang.org/genproto - version: 7f0da29060c682909f650ad8ed4e515bd74fa12a + version: a8101f21cf983e773d0c1133ebc5424792003214 subpackages: - googleapis/rpc/status - name: google.golang.org/grpc @@ -199,7 +199,7 @@ imports: - tap - transport - name: gopkg.in/go-playground/validator.v9 - version: 61caf9d3038e1af346dbf5c2e16f6678e1548364 + version: b1f51f36f1c98cc97f777d6fc9d4b05eaa0cabb5 - name: gopkg.in/yaml.v2 version: 287cf08546ab5e7e37d55a84f7ed3fd1db036de5 testImports: diff --git a/glide.yaml b/glide.yaml index 2b6593a17..3e699b373 100644 --- a/glide.yaml +++ b/glide.yaml @@ -18,7 +18,7 @@ import: - package: github.com/spf13/viper version: v1.0.0 - package: github.com/tendermint/abci - version: feature/enhance-endblock + version: develop subpackages: - client - example/dummy diff --git a/state/execution.go b/state/execution.go index 61806a3dc..b2b98b835 100644 --- a/state/execution.go +++ b/state/execution.go @@ -111,11 +111,11 @@ func execBlockOnProxyApp(txEventPublisher types.TxEventPublisher, proxyAppConn p return nil, err } - valSetUpdates := abciResponses.EndBlock.ValidatorSetUpdates + valUpdates := abciResponses.EndBlock.ValidatorUpdates logger.Info("Executed block", "height", block.Height, "validTxs", validTxs, "invalidTxs", invalidTxs) - if len(valSetUpdates) > 0 { - logger.Info("Updates to validator set", "updates", abci.ValidatorsString(valSetUpdates)) + if len(valUpdates) > 0 { + logger.Info("Updates to validators", "updates", abci.ValidatorsString(valUpdates)) } return abciResponses, nil diff --git a/state/state.go b/state/state.go index 381a6301e..df6e44370 100644 --- a/state/state.go +++ b/state/state.go @@ -241,8 +241,8 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ nextValSet := prevValSet.Copy() // update the validator set with the latest abciResponses - if len(abciResponses.EndBlock.ValidatorSetUpdates) > 0 { - err := updateValidators(nextValSet, abciResponses.EndBlock.ValidatorSetUpdates) + if len(abciResponses.EndBlock.ValidatorUpdates) > 0 { + err := updateValidators(nextValSet, abciResponses.EndBlock.ValidatorUpdates) if err != nil { s.logger.Error("Error changing validator set", "err", err) // TODO: err or carry on? diff --git a/state/state_test.go b/state/state_test.go index 16b1b42f0..80bb9341d 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -80,7 +80,7 @@ func TestABCIResponsesSaveLoad(t *testing.T) { abciResponses := NewABCIResponses(block) abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: []*abci.KVPair{}} abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: []*abci.KVPair{}} - abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorSetUpdates: []*abci.Validator{ + abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []*abci.Validator{ { PubKey: crypto.GenPrivKeyEd25519().PubKey().Bytes(), Power: 10, @@ -264,13 +264,13 @@ func makeHeaderPartsResponses(state *State, height int64, _, val := state.Validators.GetByIndex(0) abciResponses := &ABCIResponses{ Height: height, - EndBlock: &abci.ResponseEndBlock{ValidatorSetUpdates: []*abci.Validator{}}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []*abci.Validator{}}, } // if the pubkey is new, remove the old and add the new if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) { abciResponses.EndBlock = &abci.ResponseEndBlock{ - ValidatorSetUpdates: []*abci.Validator{ + ValidatorUpdates: []*abci.Validator{ {val.PubKey.Bytes(), 0}, {pubkey.Bytes(), 10}, }, diff --git a/types/protobuf.go b/types/protobuf.go index c97b53872..e97864fb6 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -12,11 +12,11 @@ type tm2pb struct{} func (tm2pb) Header(header *Header) *types.Header { return &types.Header{ - ChainId: header.ChainID, + ChainID: header.ChainID, Height: header.Height, Time: header.Time.Unix(), NumTxs: int32(header.NumTxs), // XXX: overflow - LastBlockId: TM2PB.BlockID(header.LastBlockID), + LastBlockID: TM2PB.BlockID(header.LastBlockID), LastCommitHash: header.LastCommitHash, DataHash: header.DataHash, AppHash: header.AppHash, From c2912d612a0ac57fdd1b8b2fc3940ce00f68115c Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 20 Dec 2017 17:28:24 -0500 Subject: [PATCH 12/23] update glide --- glide.lock | 12 +++++++----- glide.yaml | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/glide.lock b/glide.lock index b52090574..0c9296663 100644 --- a/glide.lock +++ b/glide.lock @@ -64,17 +64,19 @@ imports: - name: github.com/kr/logfmt version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0 - name: github.com/magiconair/properties - version: 49d762b9817ba1c2e9d0c69183c2b4a8b8f1d934 + version: 8d7837e64d3c1ee4e54a880c5a920ab4316fc90a - name: github.com/mitchellh/mapstructure version: 06020f85339e21b2478f756a78e295255ffa4d6a +- name: github.com/pelletier/go-buffruneio + version: c37440a7cf42ac63b919c752ca73a85067e05992 - name: github.com/pelletier/go-toml version: b8b5e7696574464b2f9bf303a7b37781bb52889f - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/rcrowley/go-metrics - version: e181e095bae94582363434144c61a9653aff6e50 + version: 1f30fe9094a513ce4c700b9a54458bbb0c96996c - name: github.com/spf13/afero - version: 8d919cbe7e2627e417f3e45c3c0e489a5b7e2536 + version: 5660eeed305fe5f69c8fc6cf899132a459a97064 subpackages: - mem - name: github.com/spf13/cast @@ -129,7 +131,7 @@ imports: subpackages: - iavl - name: github.com/tendermint/tmlibs - version: e4ef2835f0081c2ece83b9c1f777cf071f956e81 + version: c8ddf156a7ded132708ff6e435e19ac1852822d7 subpackages: - autofile - cli @@ -201,7 +203,7 @@ imports: - name: gopkg.in/go-playground/validator.v9 version: b1f51f36f1c98cc97f777d6fc9d4b05eaa0cabb5 - name: gopkg.in/yaml.v2 - version: 287cf08546ab5e7e37d55a84f7ed3fd1db036de5 + version: eb3733d160e74a9c7e442f435eb3bea458e1d19f testImports: - name: github.com/davecgh/go-spew version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9 diff --git a/glide.yaml b/glide.yaml index 3e699b373..b14a3b8a5 100644 --- a/glide.yaml +++ b/glide.yaml @@ -34,7 +34,7 @@ import: subpackages: - iavl - package: github.com/tendermint/tmlibs - version: e4ef2835f0081c2ece83b9c1f777cf071f956e81 + version: develop subpackages: - autofile - cli From 3d00c477fc982ad626688f7f90be4fc099382be3 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 20 Dec 2017 23:53:15 -0500 Subject: [PATCH 13/23] separate block vs state based validation --- blockchain/reactor.go | 4 +- blockchain/reactor_test.go | 12 +---- consensus/replay_test.go | 8 +-- consensus/state.go | 8 +-- consensus/state_test.go | 14 ++--- state/execution.go | 62 ++++++++++++++++++---- state/execution_test.go | 55 ++++++++++++++----- state/state.go | 105 +++++++++++++++++++++++-------------- state/state_test.go | 4 +- types/block.go | 84 ++++++++++------------------- types/block_test.go | 74 +++++++++----------------- types/vote_set_test.go | 10 ---- 12 files changed, 231 insertions(+), 209 deletions(-) diff --git a/blockchain/reactor.go b/blockchain/reactor.go index e070830aa..e41300d5e 100644 --- a/blockchain/reactor.go +++ b/blockchain/reactor.go @@ -183,7 +183,7 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) // maxMsgSize returns the maximum allowable size of a // message on the blockchain reactor. func (bcR *BlockchainReactor) maxMsgSize() int { - return bcR.state.Params.BlockSize.MaxBytes + 2 + return bcR.state.ConsensusParams.BlockSize.MaxBytes + 2 } // Handle messages from the poolReactor telling the reactor what to do. @@ -251,7 +251,7 @@ FOR_LOOP: // We need both to sync the first block. break SYNC_LOOP } - firstParts := first.MakePartSet(bcR.state.Params.BlockPartSizeBytes) + firstParts := first.MakePartSet(bcR.state.ConsensusParams.BlockPartSizeBytes) firstPartsHeader := firstParts.Header() // Finally, verify the first block using the second's commit // NOTE: we can probably make this more efficient, but note that calling diff --git a/blockchain/reactor_test.go b/blockchain/reactor_test.go index dd782ea3f..36cdc080d 100644 --- a/blockchain/reactor_test.go +++ b/blockchain/reactor_test.go @@ -41,7 +41,7 @@ func newBlockchainReactor(logger log.Logger, maxBlockHeight int64) *BlockchainRe for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ { firstBlock := makeBlock(blockHeight, state) secondBlock := makeBlock(blockHeight+1, state) - firstParts := firstBlock.MakePartSet(state.Params.BlockGossip.BlockPartSizeBytes) + firstParts := firstBlock.MakePartSet(state.ConsensusParams.BlockGossip.BlockPartSizeBytes) blockStore.SaveBlock(firstBlock, firstParts, secondBlock.LastCommit) } @@ -105,15 +105,7 @@ func makeTxs(height int64) (txs []types.Tx) { } func makeBlock(height int64, state *sm.State) *types.Block { - prevHash := state.LastBlockID.Hash - prevParts := types.PartSetHeader{} - valHash := state.Validators.Hash() - prevBlockID := types.BlockID{prevHash, prevParts} - block, _ := types.MakeBlock(height, "test_chain", makeTxs(height), - state.LastBlockTotalTx, new(types.Commit), - prevBlockID, valHash, state.AppHash, - state.LastConsensusHash, - state.Params.BlockGossip.BlockPartSizeBytes) + block, _ := state.MakeBlock(height, makeTxs(height), new(types.Commit)) return block } diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 32f7f4376..fbab03d20 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -107,9 +107,9 @@ func TestWALCrash(t *testing.T) { {"block with a smaller part size", func(cs *ConsensusState, ctx context.Context) { // XXX: is there a better way to change BlockPartSizeBytes? - params := cs.state.Params + params := cs.state.ConsensusParams params.BlockPartSizeBytes = 512 - cs.state.Params = params + cs.state.ConsensusParams = params sendTxs(cs, ctx) }, 1}, @@ -392,7 +392,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) { } func applyBlock(st *sm.State, blk *types.Block, proxyApp proxy.AppConns) { - testPartSize := st.Params.BlockPartSizeBytes + testPartSize := st.ConsensusParams.BlockPartSizeBytes err := st.ApplyBlock(types.NopEventBus{}, proxyApp.Consensus(), blk, blk.MakePartSet(testPartSize).Header(), mempool) if err != nil { panic(err) @@ -590,7 +590,7 @@ func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (*sm.State, *mockBl state, _ := sm.MakeGenesisStateFromFile(stateDB, config.GenesisFile()) state.SetLogger(log.TestingLogger().With("module", "state")) - store := NewMockBlockStore(config, state.Params) + store := NewMockBlockStore(config, state.ConsensusParams) return state, store } diff --git a/consensus/state.go b/consensus/state.go index 3a64746ee..9c89ae4ed 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -863,11 +863,7 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts // Mempool validated transactions txs := cs.mempool.Reap(cs.config.MaxBlockSizeTxs) - return types.MakeBlock(cs.Height, cs.state.ChainID, txs, - cs.state.LastBlockTotalTx, commit, - cs.state.LastBlockID, cs.state.Validators.Hash(), - cs.state.AppHash, cs.state.LastConsensusHash, - cs.state.Params.BlockPartSizeBytes) + return cs.state.MakeBlock(cs.Height, txs, commit) } // Enter: `timeoutPropose` after entering Propose. @@ -1307,7 +1303,7 @@ func (cs *ConsensusState) addProposalBlockPart(height int64, part *types.Part, v var n int var err error cs.ProposalBlock = wire.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(), - cs.state.Params.BlockSize.MaxBytes, &n, &err).(*types.Block) + cs.state.ConsensusParams.BlockSize.MaxBytes, &n, &err).(*types.Block) // NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash()) if cs.Step == cstypes.RoundStepPropose && cs.isProposalComplete() { diff --git a/consensus/state_test.go b/consensus/state_test.go index ecccafed4..6beb7da54 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -184,7 +184,7 @@ func TestBadProposal(t *testing.T) { height, round := cs1.Height, cs1.Round vs2 := vss[1] - partSize := cs1.state.Params.BlockPartSizeBytes + partSize := cs1.state.ConsensusParams.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) voteCh := subscribe(cs1.eventBus, types.EventQueryVote) @@ -339,7 +339,7 @@ func TestLockNoPOL(t *testing.T) { vs2 := vss[1] height := cs1.Height - partSize := cs1.state.Params.BlockPartSizeBytes + partSize := cs1.state.ConsensusParams.BlockPartSizeBytes timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) @@ -507,7 +507,7 @@ func TestLockPOLRelock(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.Params.BlockPartSizeBytes + partSize := cs1.state.ConsensusParams.BlockPartSizeBytes timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) @@ -622,7 +622,7 @@ func TestLockPOLUnlock(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.Params.BlockPartSizeBytes + partSize := cs1.state.ConsensusParams.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) @@ -719,7 +719,7 @@ func TestLockPOLSafety1(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.Params.BlockPartSizeBytes + partSize := cs1.state.ConsensusParams.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) @@ -842,7 +842,7 @@ func TestLockPOLSafety2(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.Params.BlockPartSizeBytes + partSize := cs1.state.ConsensusParams.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) @@ -1021,7 +1021,7 @@ func TestHalt1(t *testing.T) { cs1, vss := randConsensusState(4) vs2, vs3, vs4 := vss[1], vss[2], vss[3] - partSize := cs1.state.Params.BlockPartSizeBytes + partSize := cs1.state.ConsensusParams.BlockPartSizeBytes proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait) diff --git a/state/execution.go b/state/execution.go index b2b98b835..e0c2460f5 100644 --- a/state/execution.go +++ b/state/execution.go @@ -1,6 +1,7 @@ package state import ( + "bytes" "errors" "fmt" @@ -184,26 +185,69 @@ func (s *State) ValidateBlock(block *types.Block) error { return s.validateBlock(block) } -func (s *State) validateBlock(block *types.Block) error { +// MakeBlock builds a block with the given txs and commit from the current state. +func (s *State) MakeBlock(height int64, txs []types.Tx, commit *types.Commit) (*types.Block, *types.PartSet) { + // build base block + block := types.MakeBlock(height, txs, commit) + + // fill header with state data + block.ChainID = s.ChainID + block.TotalTxs = s.LastBlockTotalTx + block.NumTxs + block.LastBlockID = s.LastBlockID + block.ValidatorsHash = s.Validators.Hash() + block.AppHash = s.AppHash + block.ConsensusHash = s.LastConsensusParams.Hash() + + return block, block.MakePartSet(s.ConsensusParams.BlockGossip.BlockPartSizeBytes) +} + +func (s *State) validateBlock(b *types.Block) error { // Basic block validation. - err := block.ValidateBasic(s.ChainID, s.LastBlockHeight, - s.LastBlockTotalTx, s.LastBlockID, s.LastBlockTime, s.AppHash, s.LastConsensusHash) - if err != nil { + if err := b.ValidateBasic(); err != nil { return err } + if b.ChainID != s.ChainID { + return fmt.Errorf("Wrong Block.Header.ChainID. Expected %v, got %v", s.ChainID, b.ChainID) + } + if b.Height != s.LastBlockHeight+1 { + return fmt.Errorf("Wrong Block.Header.Height. Expected %v, got %v", s.LastBlockHeight+1, b.Height) + } + /* TODO: Determine bounds for Time + See blockchain/reactor "stopSyncingDurationMinutes" + + if !b.Time.After(lastBlockTime) { + return errors.New("Invalid Block.Header.Time") + } + */ + + newTxs := int64(len(b.Data.Txs)) + if b.TotalTxs != s.LastBlockTotalTx+newTxs { + return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", s.LastBlockTotalTx+newTxs, b.TotalTxs) + } + if !b.LastBlockID.Equals(s.LastBlockID) { + return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", s.LastBlockID, b.LastBlockID) + } + + if !bytes.Equal(b.AppHash, s.AppHash) { + return fmt.Errorf("Wrong Block.Header.AppHash. Expected %X, got %v", s.AppHash, b.AppHash) + } + if !bytes.Equal(b.ConsensusHash, s.LastConsensusParams.Hash()) { + return fmt.Errorf("Wrong Block.Header.ConsensusHash. Expected %X, got %v", s.LastConsensusParams.Hash(), b.ConsensusHash) + } + // Validate block LastCommit. - if block.Height == 1 { - if len(block.LastCommit.Precommits) != 0 { + if b.Height == 1 { + if len(b.LastCommit.Precommits) != 0 { return errors.New("Block at height 1 (first block) should have no LastCommit precommits") } } else { - if len(block.LastCommit.Precommits) != s.LastValidators.Size() { + if len(b.LastCommit.Precommits) != s.LastValidators.Size() { return errors.New(cmn.Fmt("Invalid block commit size. Expected %v, got %v", - s.LastValidators.Size(), len(block.LastCommit.Precommits))) + s.LastValidators.Size(), len(b.LastCommit.Precommits))) } err := s.LastValidators.VerifyCommit( - s.ChainID, s.LastBlockID, block.Height-1, block.LastCommit) + s.ChainID, s.LastBlockID, b.Height-1, b.LastCommit) if err != nil { return err } diff --git a/state/execution_test.go b/state/execution_test.go index 379ac6732..4dee4b455 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -23,6 +23,43 @@ var ( nTxsPerBlock = 10 ) +/* +func TestValidateBlock(t *testing.T) { + state := state() + state.SetLogger(log.TestingLogger()) + + block := makeBlock(1, state) + + // proper block must pass + err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash, consensusHash) + require.NoError(t, err) + + // wrong chain fails + err = block.ValidateBasic("other", h-1, 10, lastID, block.Time, appHash, consensusHash) + require.Error(t, err) + + // wrong height fails + err = block.ValidateBasic("hello", h+4, 10, lastID, block.Time, appHash, consensusHash) + require.Error(t, err) + + // wrong total tx fails + err = block.ValidateBasic("hello", h-1, 15, lastID, block.Time, appHash, consensusHash) + require.Error(t, err) + + // wrong blockid fails + err = block.ValidateBasic("hello", h-1, 10, makeBlockID(), block.Time, appHash, consensusHash) + require.Error(t, err) + + // wrong app hash fails + err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, []byte("bad-hash"), consensusHash) + require.Error(t, err) + + // wrong consensus hash fails + err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash, []byte("wrong-params")) + require.Error(t, err) +} +*/ + func TestApplyBlock(t *testing.T) { cc := proxy.NewLocalClientCreator(dummy.NewDummyApplication()) proxyApp := proxy.NewAppConns(cc, nil) @@ -33,7 +70,7 @@ func TestApplyBlock(t *testing.T) { state := state() state.SetLogger(log.TestingLogger()) - block := makeBlock(1, state) + block := makeBlock(state, 1) err = state.ApplyBlock(types.NopEventBus{}, proxyApp.Consensus(), block, block.MakePartSet(testPartSize).Header(), types.MockMempool{}) require.Nil(t, err) @@ -79,10 +116,7 @@ func TestBeginBlockAbsentValidators(t *testing.T) { for _, tc := range testCases { lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: tc.lastCommitPrecommits} - valHash := state.Validators.Hash() - block, _ := types.MakeBlock(2, chainID, makeTxs(2), state.LastBlockTotalTx, lastCommit, - prevBlockID, valHash, state.AppHash, state.LastConsensusHash, testPartSize) - + block, _ := state.MakeBlock(2, makeTxs(2), lastCommit) _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), lastValidators) require.Nil(t, err, tc.desc) @@ -112,15 +146,8 @@ func state() *State { return s } -func makeBlock(height int64, state *State) *types.Block { - prevHash := state.LastBlockID.Hash - prevParts := types.PartSetHeader{} - valHash := state.Validators.Hash() - prevBlockID := types.BlockID{prevHash, prevParts} - block, _ := types.MakeBlock(height, chainID, - makeTxs(height), state.LastBlockTotalTx, - new(types.Commit), prevBlockID, valHash, - state.AppHash, state.LastConsensusHash, testPartSize) +func makeBlock(state *State, height int64) *types.Block { + block, _ := state.MakeBlock(height, makeTxs(state.LastBlockHeight), new(types.Commit)) return block } diff --git a/state/state.go b/state/state.go index df6e44370..ca4e8ffd1 100644 --- a/state/state.go +++ b/state/state.go @@ -18,6 +18,7 @@ import ( "github.com/tendermint/tendermint/types" ) +// database keys var ( stateKey = []byte("stateKey") abciResponsesKey = []byte("abciResponsesKey") @@ -27,40 +28,51 @@ func calcValidatorsKey(height int64) []byte { return []byte(cmn.Fmt("validatorsKey:%v", height)) } +/*func calcConsensusParamsKey(height int64) []byte { + return []byte(cmn.Fmt("consensusParamsKey:%v", height)) +}*/ + //----------------------------------------------------------------------------- -// State represents the latest committed state of the Tendermint consensus, -// including the last committed block and validator set. -// Newly committed blocks are validated and executed against the State. +// 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. +// All fields are exposed so the struct can be easily serialized, +// but the fields should only be changed by calling state.SetBlockAndValidators. // NOTE: not goroutine-safe. type State struct { // mtx for writing to db mtx sync.Mutex db dbm.DB + // Immutable ChainID string - // Consensus parameters used for validating blocks - Params types.ConsensusParams - // These fields are updated by SetBlockAndValidators. + // Exposed fields are updated by SetBlockAndValidators. + // LastBlockHeight=0 at genesis (ie. block(H=0) does not exist) - // LastValidators is used to validate block.LastCommit. LastBlockHeight int64 LastBlockTotalTx int64 LastBlockID types.BlockID LastBlockTime time.Time - Validators *types.ValidatorSet - LastValidators *types.ValidatorSet - // When a block returns a validator set change via EndBlock, - // the change only applies to the next block. - // So, if s.LastBlockHeight causes a valset change, + + // LastValidators is used to validate block.LastCommit. + // Validators are persisted to the database separately every time they change, + // so we can query for historical validator sets. + // Note that if s.LastBlockHeight causes a valset change, // we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1 + Validators *types.ValidatorSet + LastValidators *types.ValidatorSet LastHeightValidatorsChanged int64 - // AppHash is updated after Commit + // Consensus parameters used for validating blocks. + // Changes returned by EndBlock and updated after Commit. + ConsensusParams types.ConsensusParams + LastConsensusParams types.ConsensusParams + LastHeightConsensusParamsChanged int64 + + // The latest AppHash we've received from calling abci.Commit() AppHash []byte - // LastConsensusHash is updated after Commit - LastConsensusHash []byte logger log.Logger } @@ -114,19 +126,26 @@ func (s *State) SetLogger(l log.Logger) { // Copy makes a copy of the State for mutating. func (s *State) Copy() *State { return &State{ - db: s.db, - LastBlockHeight: s.LastBlockHeight, - LastBlockTotalTx: s.LastBlockTotalTx, - LastBlockID: s.LastBlockID, - LastBlockTime: s.LastBlockTime, + db: s.db, + + ChainID: s.ChainID, + + LastBlockHeight: s.LastBlockHeight, + LastBlockTotalTx: s.LastBlockTotalTx, + LastBlockID: s.LastBlockID, + LastBlockTime: s.LastBlockTime, + Validators: s.Validators.Copy(), LastValidators: s.LastValidators.Copy(), - AppHash: s.AppHash, - LastConsensusHash: s.LastConsensusHash, LastHeightValidatorsChanged: s.LastHeightValidatorsChanged, - logger: s.logger, - ChainID: s.ChainID, - Params: s.Params, + + ConsensusParams: s.ConsensusParams, + LastConsensusParams: s.LastConsensusParams, + LastHeightConsensusParamsChanged: s.LastHeightConsensusParamsChanged, + + AppHash: s.AppHash, + + logger: s.logger, } } @@ -254,20 +273,20 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ // Update validator accums and set state variables nextValSet.IncrementAccum(1) - nextParams := applyUpdates(s.Params, + nextParams := applyUpdates(s.ConsensusParams, abciResponses.EndBlock.ConsensusParamUpdates) err := nextParams.Validate() if err != nil { s.logger.Error("Error updating consensus params", "err", err) // TODO: err or carry on? - nextParams = s.Params + nextParams = s.ConsensusParams } s.setBlockAndValidators(header.Height, header.NumTxs, types.BlockID{header.Hash(), blockPartsHeader}, header.Time, - prevValSet, nextValSet, + nextValSet, nextParams) } @@ -313,17 +332,19 @@ func applyUpdates(p types.ConsensusParams, func (s *State) setBlockAndValidators(height int64, newTxs int64, blockID types.BlockID, blockTime time.Time, - prevValSet, nextValSet *types.ValidatorSet, - nextParams types.ConsensusParams) { + valSet *types.ValidatorSet, + params types.ConsensusParams) { s.LastBlockHeight = height s.LastBlockTotalTx += newTxs s.LastBlockID = blockID s.LastBlockTime = blockTime - s.Validators = nextValSet - s.LastValidators = prevValSet - s.LastConsensusHash = s.Params.Hash() - s.Params = nextParams + + s.LastValidators = s.Validators.Copy() + s.Validators = valSet + + s.LastConsensusParams = s.ConsensusParams + s.ConsensusParams = params } // GetValidators returns the last and current validator sets. @@ -424,15 +445,19 @@ func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) (*State, error) { db: db, ChainID: genDoc.ChainID, - Params: *genDoc.ConsensusParams, - LastBlockHeight: 0, - LastBlockID: types.BlockID{}, - LastBlockTime: genDoc.GenesisTime, + LastBlockHeight: 0, + LastBlockID: types.BlockID{}, + LastBlockTime: genDoc.GenesisTime, + Validators: types.NewValidatorSet(validators), LastValidators: types.NewValidatorSet(nil), - AppHash: genDoc.AppHash, - LastConsensusHash: genDoc.ConsensusParams.Hash(), LastHeightValidatorsChanged: 1, + + ConsensusParams: *genDoc.ConsensusParams, + LastConsensusParams: types.ConsensusParams{}, + LastHeightConsensusParamsChanged: 1, + + AppHash: genDoc.AppHash, }, nil } diff --git a/state/state_test.go b/state/state_test.go index 80bb9341d..37368d577 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -76,7 +76,7 @@ func TestABCIResponsesSaveLoad(t *testing.T) { state.LastBlockHeight++ // build mock responses - block := makeBlock(2, state) + block := makeBlock(state, 2) abciResponses := NewABCIResponses(block) abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: []*abci.KVPair{}} abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: []*abci.KVPair{}} @@ -260,7 +260,7 @@ func TestApplyUpdates(t *testing.T) { func makeHeaderPartsResponses(state *State, height int64, pubkey crypto.PubKey) (*types.Header, types.PartSetHeader, *ABCIResponses) { - block := makeBlock(height, state) + block := makeBlock(state, height) _, val := state.Validators.GetByIndex(0) abciResponses := &ABCIResponses{ Height: height, diff --git a/types/block.go b/types/block.go index a00e75a62..7a1ed04e9 100644 --- a/types/block.go +++ b/types/block.go @@ -15,31 +15,21 @@ import ( ) // Block defines the atomic unit of a Tendermint blockchain. +// TODO: add Version byte type Block struct { *Header `json:"header"` *Data `json:"data"` LastCommit *Commit `json:"last_commit"` } -// MakeBlock returns a new block and corresponding partset from the given information. -// TODO: Add version information to the Block struct. -func MakeBlock(height int64, chainID string, txs []Tx, - totalTxs int64, commit *Commit, - prevBlockID BlockID, valHash, appHash, consensusHash []byte, - partSize int) (*Block, *PartSet) { - - newTxs := int64(len(txs)) +// MakeBlock returns a new block with an empty header, except what can be computed from itself. +// It populates the same set of fields validated by ValidateBasic +func MakeBlock(height int64, txs []Tx, commit *Commit) *Block { block := &Block{ Header: &Header{ - ChainID: chainID, - Height: height, - Time: time.Now(), - NumTxs: newTxs, - TotalTxs: totalTxs + newTxs, - LastBlockID: prevBlockID, - ValidatorsHash: valHash, - AppHash: appHash, // state merkle root of txs from the previous block. - ConsensusHash: consensusHash, + Height: height, + Time: time.Now(), + NumTxs: int64(len(txs)), }, LastCommit: commit, Data: &Data{ @@ -47,37 +37,16 @@ func MakeBlock(height int64, chainID string, txs []Tx, }, } block.FillHeader() - return block, block.MakePartSet(partSize) + return block } // ValidateBasic performs basic validation that doesn't involve state data. -func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, - lastBlockTotalTx int64, lastBlockID BlockID, - lastBlockTime time.Time, appHash, consensusHash []byte) error { - - if b.ChainID != chainID { - return fmt.Errorf("Wrong Block.Header.ChainID. Expected %v, got %v", chainID, b.ChainID) - } - if b.Height != lastBlockHeight+1 { - return fmt.Errorf("Wrong Block.Header.Height. Expected %v, got %v", lastBlockHeight+1, b.Height) - } - /* TODO: Determine bounds for Time - See blockchain/reactor "stopSyncingDurationMinutes" - - if !b.Time.After(lastBlockTime) { - return errors.New("Invalid Block.Header.Time") - } - */ +// It checks the internal consistency of the block. +func (b *Block) ValidateBasic() error { newTxs := int64(len(b.Data.Txs)) if b.NumTxs != newTxs { return fmt.Errorf("Wrong Block.Header.NumTxs. Expected %v, got %v", newTxs, b.NumTxs) } - if b.TotalTxs != lastBlockTotalTx+newTxs { - return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", lastBlockTotalTx+newTxs, b.TotalTxs) - } - if !b.LastBlockID.Equals(lastBlockID) { - return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", lastBlockID, b.LastBlockID) - } if !bytes.Equal(b.LastCommitHash, b.LastCommit.Hash()) { return fmt.Errorf("Wrong Block.Header.LastCommitHash. Expected %v, got %v", b.LastCommitHash, b.LastCommit.Hash()) } @@ -89,13 +58,6 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight int64, if !bytes.Equal(b.DataHash, b.Data.Hash()) { return fmt.Errorf("Wrong Block.Header.DataHash. Expected %v, got %v", b.DataHash, b.Data.Hash()) } - if !bytes.Equal(b.AppHash, appHash) { - return fmt.Errorf("Wrong Block.Header.AppHash. Expected %X, got %v", appHash, b.AppHash) - } - if !bytes.Equal(b.ConsensusHash, consensusHash) { - return fmt.Errorf("Wrong Block.Header.ConsensusHash. Expected %X, got %v", consensusHash, b.ConsensusHash) - } - // NOTE: the AppHash and ValidatorsHash are validated later. return nil } @@ -171,18 +133,26 @@ func (b *Block) StringShort() string { //----------------------------------------------------------------------------- // Header defines the structure of a Tendermint block header +// TODO: limit header size type Header struct { - ChainID string `json:"chain_id"` - Height int64 `json:"height"` - Time time.Time `json:"time"` - NumTxs int64 `json:"num_txs"` // XXX: Can we get rid of this? - TotalTxs int64 `json:"total_txs"` - LastBlockID BlockID `json:"last_block_id"` + // basic block info + ChainID string `json:"chain_id"` + Height int64 `json:"height"` + Time time.Time `json:"time"` + NumTxs int64 `json:"num_txs"` + + // prev block info + LastBlockID BlockID `json:"last_block_id"` + TotalTxs int64 `json:"total_txs"` + + // hashes of block data LastCommitHash data.Bytes `json:"last_commit_hash"` // commit from validators from the last block DataHash data.Bytes `json:"data_hash"` // transactions - ValidatorsHash data.Bytes `json:"validators_hash"` // validators for the current block - AppHash data.Bytes `json:"app_hash"` // state after txs from the previous block - ConsensusHash data.Bytes `json:"consensus_hash"` // consensus params for current block + + // hashes from the app + ValidatorsHash data.Bytes `json:"validators_hash"` // validators for the current block + ConsensusHash data.Bytes `json:"consensus_hash"` // consensus params for current block + AppHash data.Bytes `json:"app_hash"` // state after txs from the previous block } // Hash returns the hash of the header. diff --git a/types/block_test.go b/types/block_test.go index a874508a4..bde474403 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -2,55 +2,59 @@ package types import ( "testing" - "time" "github.com/stretchr/testify/require" crypto "github.com/tendermint/go-crypto" + cmn "github.com/tendermint/tmlibs/common" ) func TestValidateBlock(t *testing.T) { txs := []Tx{Tx("foo"), Tx("bar")} lastID := makeBlockID() - valHash := []byte("val") - appHash := []byte("app") - consensusHash := []byte("consensus-params") h := int64(3) voteSet, _, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1) - commit, err := makeCommit(lastID, h-1, 1, voteSet, vals) + commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals) require.NoError(t, err) - block, _ := MakeBlock(h, "hello", txs, 10, commit, - lastID, valHash, appHash, consensusHash, 2) + block := MakeBlock(h, txs, commit) require.NotNil(t, block) // proper block must pass - err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash, consensusHash) + err = block.ValidateBasic() require.NoError(t, err) - // wrong chain fails - err = block.ValidateBasic("other", h-1, 10, lastID, block.Time, appHash, consensusHash) + // tamper with NumTxs + block = MakeBlock(h, txs, commit) + block.NumTxs += 1 + err = block.ValidateBasic() require.Error(t, err) - // wrong height fails - err = block.ValidateBasic("hello", h+4, 10, lastID, block.Time, appHash, consensusHash) + // remove 1/2 the commits + block = MakeBlock(h, txs, commit) + block.LastCommit.Precommits = commit.Precommits[:commit.Size()/2] + block.LastCommit.hash = nil // clear hash or change wont be noticed + err = block.ValidateBasic() require.Error(t, err) - // wrong total tx fails - err = block.ValidateBasic("hello", h-1, 15, lastID, block.Time, appHash, consensusHash) + // tamper with LastCommitHash + block = MakeBlock(h, txs, commit) + block.LastCommitHash = []byte("something else") + err = block.ValidateBasic() require.Error(t, err) - // wrong blockid fails - err = block.ValidateBasic("hello", h-1, 10, makeBlockID(), block.Time, appHash, consensusHash) + // tamper with data + block = MakeBlock(h, txs, commit) + block.Data.Txs[0] = Tx("something else") + block.Data.hash = nil // clear hash or change wont be noticed + err = block.ValidateBasic() require.Error(t, err) - // wrong app hash fails - err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, []byte("bad-hash"), consensusHash) - require.Error(t, err) - - // wrong consensus hash fails - err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash, []byte("wrong-params")) + // tamper with DataHash + block = MakeBlock(h, txs, commit) + block.DataHash = cmn.RandBytes(len(block.DataHash)) + err = block.ValidateBasic() require.Error(t, err) } @@ -58,29 +62,3 @@ func makeBlockID() BlockID { blockHash, blockPartsHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)} return BlockID{blockHash, blockPartsHeader} } - -func makeCommit(blockID BlockID, height int64, round int, - voteSet *VoteSet, - validators []*PrivValidatorFS) (*Commit, error) { - - voteProto := &Vote{ - ValidatorAddress: nil, - ValidatorIndex: -1, - Height: height, - Round: round, - Type: VoteTypePrecommit, - BlockID: blockID, - Timestamp: time.Now().UTC(), - } - - // all sign - for i := 0; i < len(validators); i++ { - vote := withValidator(voteProto, validators[i].GetAddress(), i) - _, err := signAddVote(validators[i], vote, voteSet) - if err != nil { - return nil, err - } - } - - return voteSet.MakeCommit(), nil -} diff --git a/types/vote_set_test.go b/types/vote_set_test.go index d125c5502..4a09d04d3 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -59,16 +59,6 @@ func withBlockPartsHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote { return vote } -func signAddVote(privVal *PrivValidatorFS, vote *Vote, voteSet *VoteSet) (bool, error) { - var err error - vote.Signature, err = privVal.Signer.Sign(SignBytes(voteSet.ChainID(), vote)) - if err != nil { - return false, err - } - added, err := voteSet.AddVote(vote) - return added, err -} - func TestAddVote(t *testing.T) { height, round := int64(1), 0 voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1) From 3ad055ef3ac97e304c8623a7c9cee2e251089ffd Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 01:45:01 -0500 Subject: [PATCH 14/23] fix randPort --- rpc/test/helpers.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rpc/test/helpers.go b/rpc/test/helpers.go index 69fe7aa8c..c8671d68e 100644 --- a/rpc/test/helpers.go +++ b/rpc/test/helpers.go @@ -3,7 +3,6 @@ package rpctest import ( "context" "fmt" - "math/rand" "os" "path/filepath" "strings" @@ -11,6 +10,8 @@ import ( "github.com/tendermint/tmlibs/log" abci "github.com/tendermint/abci/types" + cmn "github.com/tendermint/tmlibs/common" + cfg "github.com/tendermint/tendermint/config" nm "github.com/tendermint/tendermint/node" "github.com/tendermint/tendermint/proxy" @@ -57,9 +58,7 @@ func makePathname() string { } func randPort() int { - // returns between base and base + spread - base, spread := 20000, 20000 - return base + rand.Intn(spread) + return int(cmn.RandUint16()/2 + 10000) } func makeAddrs() (string, string, string) { From b5857da87780ccac8cd6c8e7d56bb19ebd8053b7 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 02:20:32 -0500 Subject: [PATCH 15/23] forgot file --- types/test_util.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 types/test_util.go diff --git a/types/test_util.go b/types/test_util.go new file mode 100644 index 000000000..d13de04e2 --- /dev/null +++ b/types/test_util.go @@ -0,0 +1,37 @@ +package types + +import "time" + +func MakeCommit(blockID BlockID, height int64, round int, + voteSet *VoteSet, + validators []*PrivValidatorFS) (*Commit, error) { + + // all sign + for i := 0; i < len(validators); i++ { + + vote := &Vote{ + ValidatorAddress: validators[i].GetAddress(), + ValidatorIndex: i, + Height: height, + Round: round, + Type: VoteTypePrecommit, + BlockID: blockID, + Timestamp: time.Now().UTC(), + } + + _, err := signAddVote(validators[i], vote, voteSet) + if err != nil { + return nil, err + } + } + + return voteSet.MakeCommit(), nil +} + +func signAddVote(privVal *PrivValidatorFS, vote *Vote, voteSet *VoteSet) (signed bool, err error) { + vote.Signature, err = privVal.Signer.Sign(SignBytes(voteSet.ChainID(), vote)) + if err != nil { + return false, err + } + return voteSet.AddVote(vote) +} From be765e4cb9a8a3bb24e0c1cb9b44e97a0eca6324 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 11:16:52 -0500 Subject: [PATCH 16/23] update glide for cmn fixes --- glide.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glide.lock b/glide.lock index 0c9296663..53f69a447 100644 --- a/glide.lock +++ b/glide.lock @@ -131,7 +131,7 @@ imports: subpackages: - iavl - name: github.com/tendermint/tmlibs - version: c8ddf156a7ded132708ff6e435e19ac1852822d7 + version: b0b740210c60b7fc789382ff3a709426eb71903d subpackages: - autofile - cli From 306657a11892f98005effaf89b8e2b497a92022a Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 12:07:52 -0500 Subject: [PATCH 17/23] no patience for metalinter right now --- circle.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/circle.yml b/circle.yml index 3805eb80f..9d03bc46e 100644 --- a/circle.yml +++ b/circle.yml @@ -25,7 +25,6 @@ dependencies: test: override: - - cd "$PROJECT_PATH" && make tools && make get_vendor_deps && make metalinter_test - cd "$PROJECT_PATH" && set -o pipefail && make test_integrations 2>&1 | tee test_integrations.log: timeout: 1800 post: From 4b789ff7e9997b7e1392066544fc8f7fd73cc7d2 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 14:22:14 -0500 Subject: [PATCH 18/23] another cmn fix --- glide.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glide.lock b/glide.lock index 53f69a447..b74ffd78c 100644 --- a/glide.lock +++ b/glide.lock @@ -131,7 +131,7 @@ imports: subpackages: - iavl - name: github.com/tendermint/tmlibs - version: b0b740210c60b7fc789382ff3a709426eb71903d + version: e2d7f1aa41dde5f29057dd08e64371a574b84c86 subpackages: - autofile - cli From 70a744558cf1d14193f55ed81bd96a6f35f93cc1 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 16:47:32 -0500 Subject: [PATCH 19/23] types: params.Update() --- state/state.go | 43 ++---------------------------------------- types/params.go | 50 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/state/state.go b/state/state.go index ca4e8ffd1..74504f0a3 100644 --- a/state/state.go +++ b/state/state.go @@ -273,8 +273,8 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ // Update validator accums and set state variables nextValSet.IncrementAccum(1) - nextParams := applyUpdates(s.ConsensusParams, - abciResponses.EndBlock.ConsensusParamUpdates) + // NOTE: must not mutate s.ConsensusParams + nextParams := s.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates) err := nextParams.Validate() if err != nil { s.logger.Error("Error updating consensus params", "err", err) @@ -291,45 +291,6 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ } -// applyUpdates returns new ConsensusParams -// whose fields are set to any non-zero fields of c. -// If c is nil, it returns p unmodified, as it was passed in. -func applyUpdates(p types.ConsensusParams, - c *abci.ConsensusParams) types.ConsensusParams { - - if c == nil { - return p - } - res := p - // we must defensively consider any structs may be nil - if c.BlockSize != nil { - - if c.BlockSize.MaxBytes != 0 { - res.BlockSize.MaxBytes = int(c.BlockSize.MaxBytes) - } - if c.BlockSize.MaxTxs != 0 { - res.BlockSize.MaxTxs = int(c.BlockSize.MaxTxs) - } - if c.BlockSize.MaxGas != 0 { - res.BlockSize.MaxGas = int(c.BlockSize.MaxGas) - } - } - if c.TxSize != nil { - if c.TxSize.MaxBytes != 0 { - res.TxSize.MaxBytes = int(c.TxSize.MaxBytes) - } - if c.TxSize.MaxGas != 0 { - res.TxSize.MaxGas = int(c.TxSize.MaxGas) - } - } - if c.BlockGossip != nil { - if c.BlockGossip.BlockPartSizeBytes != 0 { - res.BlockGossip.BlockPartSizeBytes = int(c.BlockGossip.BlockPartSizeBytes) - } - } - return res -} - func (s *State) setBlockAndValidators(height int64, newTxs int64, blockID types.BlockID, blockTime time.Time, valSet *types.ValidatorSet, diff --git a/types/params.go b/types/params.go index e7c32f48f..19e86d449 100644 --- a/types/params.go +++ b/types/params.go @@ -3,6 +3,7 @@ package types import ( "github.com/pkg/errors" + abci "github.com/tendermint/abci/types" "github.com/tendermint/tmlibs/merkle" ) @@ -20,15 +21,15 @@ type ConsensusParams struct { // BlockSize contain limits on the block size. type BlockSize struct { - MaxBytes int `json:"max_bytes"` // NOTE: must not be 0 nor greater than 100MB - MaxTxs int `json:"max_txs"` - MaxGas int `json:"max_gas"` + MaxBytes int `json:"max_bytes"` // NOTE: must not be 0 nor greater than 100MB + MaxTxs int `json:"max_txs"` + MaxGas int64 `json:"max_gas"` } // TxSize contain limits on the tx size. type TxSize struct { - MaxBytes int `json:"max_bytes"` - MaxGas int `json:"max_gas"` + MaxBytes int `json:"max_bytes"` + MaxGas int64 `json:"max_gas"` } // BlockGossip determine consensus critical elements of how blocks are gossiped @@ -100,3 +101,42 @@ func (params *ConsensusParams) Hash() []byte { "tx_size_max_gas": params.TxSize.MaxGas, }) } + +// Update returns a copy of the params with updates from the non-zero fields of p2. +// NOTE: note: must not modify the original +func (params ConsensusParams) Update(params2 *abci.ConsensusParams) ConsensusParams { + res := params // explicit copy + + if params2 == nil { + return res + } + + // we must defensively consider any structs may be nil + // XXX: it's cast city over here. It's ok because we only do int32->int + // but still, watch it champ. + if params2.BlockSize != nil { + if params2.BlockSize.MaxBytes > 0 { + res.BlockSize.MaxBytes = int(params2.BlockSize.MaxBytes) + } + if params2.BlockSize.MaxTxs > 0 { + res.BlockSize.MaxTxs = int(params2.BlockSize.MaxTxs) + } + if params2.BlockSize.MaxGas > 0 { + res.BlockSize.MaxGas = params2.BlockSize.MaxGas + } + } + if params2.TxSize != nil { + if params2.TxSize.MaxBytes > 0 { + res.TxSize.MaxBytes = int(params2.TxSize.MaxBytes) + } + if params2.TxSize.MaxGas > 0 { + res.TxSize.MaxGas = params2.TxSize.MaxGas + } + } + if params2.BlockGossip != nil { + if params2.BlockGossip.BlockPartSizeBytes > 0 { + res.BlockGossip.BlockPartSizeBytes = int(params2.BlockGossip.BlockPartSizeBytes) + } + } + return res +} From 35521b553a5325a793cc8edd512d91dab930e538 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 17:46:25 -0500 Subject: [PATCH 20/23] save historical consensus params --- state/errors.go | 8 ++++ state/execution.go | 5 ++- state/state.go | 104 +++++++++++++++++++++++++++++++++++++------- state/state_test.go | 81 ++++++++++++++++++++++++++++++++-- types/protobuf.go | 18 ++++++++ 5 files changed, 196 insertions(+), 20 deletions(-) diff --git a/state/errors.go b/state/errors.go index f7520cf6c..98f44281a 100644 --- a/state/errors.go +++ b/state/errors.go @@ -37,6 +37,10 @@ type ( ErrNoValSetForHeight struct { Height int64 } + + ErrNoConsensusParamsForHeight struct { + Height int64 + } ) func (e ErrUnknownBlock) Error() string { @@ -61,3 +65,7 @@ func (e ErrStateMismatch) Error() string { func (e ErrNoValSetForHeight) Error() string { return cmn.Fmt("Could not find validator set for height #%d", e.Height) } + +func (e ErrNoConsensusParamsForHeight) Error() string { + return cmn.Fmt("Could not find consensus params for height #%d", e.Height) +} diff --git a/state/execution.go b/state/execution.go index e0c2460f5..e90c8e710 100644 --- a/state/execution.go +++ b/state/execution.go @@ -279,7 +279,10 @@ func (s *State) ApplyBlock(txEventPublisher types.TxEventPublisher, proxyAppConn fail.Fail() // XXX // now update the block and validators - s.SetBlockAndValidators(block.Header, partsHeader, abciResponses) + err = s.SetBlockAndValidators(block.Header, partsHeader, abciResponses) + if err != nil { + return fmt.Errorf("Commit failed for application: %v", err) + } // lock mempool, commit state, update mempoool err = s.CommitStateUpdateMempool(proxyAppConn, block, mempool) diff --git a/state/state.go b/state/state.go index 74504f0a3..0bed708a6 100644 --- a/state/state.go +++ b/state/state.go @@ -28,9 +28,9 @@ func calcValidatorsKey(height int64) []byte { return []byte(cmn.Fmt("validatorsKey:%v", height)) } -/*func calcConsensusParamsKey(height int64) []byte { +func calcConsensusParamsKey(height int64) []byte { return []byte(cmn.Fmt("consensusParamsKey:%v", height)) -}*/ +} //----------------------------------------------------------------------------- @@ -155,6 +155,7 @@ func (s *State) Save() { defer s.mtx.Unlock() s.saveValidatorsInfo() + s.saveConsensusParamsInfo() s.db.SetSync(stateKey, s.Bytes()) } @@ -188,13 +189,13 @@ func (s *State) LoadABCIResponses() *ABCIResponses { // LoadValidators loads the ValidatorSet for a given height. func (s *State) LoadValidators(height int64) (*types.ValidatorSet, error) { - valInfo := s.loadValidators(height) + valInfo := s.loadValidatorsInfo(height) if valInfo == nil { return nil, ErrNoValSetForHeight{height} } if valInfo.ValidatorSet == nil { - valInfo = s.loadValidators(valInfo.LastHeightChanged) + valInfo = s.loadValidatorsInfo(valInfo.LastHeightChanged) if valInfo == nil { cmn.PanicSanity(fmt.Sprintf(`Couldn't find validators at height %d as last changed from height %d`, valInfo.LastHeightChanged, height)) @@ -204,7 +205,7 @@ func (s *State) LoadValidators(height int64) (*types.ValidatorSet, error) { return valInfo.ValidatorSet, nil } -func (s *State) loadValidators(height int64) *ValidatorsInfo { +func (s *State) loadValidatorsInfo(height int64) *ValidatorsInfo { buf := s.db.Get(calcValidatorsKey(height)) if len(buf) == 0 { return nil @@ -239,6 +240,61 @@ func (s *State) saveValidatorsInfo() { s.db.SetSync(calcValidatorsKey(nextHeight), valInfo.Bytes()) } +// LoadConsensusParams loads the ConsensusParams for a given height. +func (s *State) LoadConsensusParams(height int64) (types.ConsensusParams, error) { + empty := types.ConsensusParams{} + + paramsInfo := s.loadConsensusParamsInfo(height) + if paramsInfo == nil { + return empty, ErrNoConsensusParamsForHeight{height} + } + + if paramsInfo.ConsensusParams == empty { + paramsInfo = s.loadConsensusParamsInfo(paramsInfo.LastHeightChanged) + if paramsInfo == nil { + cmn.PanicSanity(fmt.Sprintf(`Couldn't find consensus params at height %d as + last changed from height %d`, paramsInfo.LastHeightChanged, height)) + } + } + + return paramsInfo.ConsensusParams, nil +} + +func (s *State) loadConsensusParamsInfo(height int64) *ConsensusParamsInfo { + buf := s.db.Get(calcConsensusParamsKey(height)) + if len(buf) == 0 { + return nil + } + + paramsInfo := new(ConsensusParamsInfo) + r, n, err := bytes.NewReader(buf), new(int), new(error) + wire.ReadBinaryPtr(paramsInfo, r, 0, n, err) + if *err != nil { + // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED + cmn.Exit(cmn.Fmt(`LoadConsensusParams: Data has been corrupted or its spec has changed: + %v\n`, *err)) + } + // TODO: ensure that buf is completely read. + + return paramsInfo +} + +// saveConsensusParamsInfo persists the consensus params for the next block to disk. +// It should be called from s.Save(), right before the state itself is persisted. +// If the consensus params did not change after processing the latest block, +// only the last height for which they changed is persisted. +func (s *State) saveConsensusParamsInfo() { + changeHeight := s.LastHeightConsensusParamsChanged + nextHeight := s.LastBlockHeight + 1 + paramsInfo := &ConsensusParamsInfo{ + LastHeightChanged: changeHeight, + } + if changeHeight == nextHeight { + paramsInfo.ConsensusParams = s.ConsensusParams + } + s.db.SetSync(calcConsensusParamsKey(nextHeight), paramsInfo.Bytes()) +} + // Equals returns true if the States are identical. func (s *State) Equals(s2 *State) bool { return bytes.Equal(s.Bytes(), s2.Bytes()) @@ -252,7 +308,7 @@ func (s *State) Bytes() []byte { // SetBlockAndValidators mutates State variables // to update block and validators after running EndBlock. func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader types.PartSetHeader, - abciResponses *ABCIResponses) { + abciResponses *ABCIResponses) error { // copy the valset so we can apply changes from EndBlock // and update s.LastValidators and s.Validators @@ -263,8 +319,7 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ if len(abciResponses.EndBlock.ValidatorUpdates) > 0 { err := updateValidators(nextValSet, abciResponses.EndBlock.ValidatorUpdates) if err != nil { - s.logger.Error("Error changing validator set", "err", err) - // TODO: err or carry on? + return fmt.Errorf("Error changing validator set: %v", err) } // change results from this height but only applies to the next height s.LastHeightValidatorsChanged = header.Height + 1 @@ -273,13 +328,17 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ // Update validator accums and set state variables nextValSet.IncrementAccum(1) - // NOTE: must not mutate s.ConsensusParams - nextParams := s.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates) - err := nextParams.Validate() - if err != nil { - s.logger.Error("Error updating consensus params", "err", err) - // TODO: err or carry on? - nextParams = s.ConsensusParams + // update the params with the latest abciResponses + nextParams := s.ConsensusParams + if abciResponses.EndBlock.ConsensusParamUpdates != nil { + // NOTE: must not mutate s.ConsensusParams + nextParams = s.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates) + err := nextParams.Validate() + if err != nil { + return fmt.Errorf("Error updating consensus params: %v", err) + } + // change results from this height but only applies to the next height + s.LastHeightConsensusParamsChanged = header.Height + 1 } s.setBlockAndValidators(header.Height, @@ -288,7 +347,7 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ header.Time, nextValSet, nextParams) - + return nil } func (s *State) setBlockAndValidators(height int64, @@ -353,6 +412,19 @@ func (valInfo *ValidatorsInfo) Bytes() []byte { return wire.BinaryBytes(*valInfo) } +//----------------------------------------------------------------------------- + +// ConsensusParamsInfo represents the latest consensus params, or the last height it changed +type ConsensusParamsInfo struct { + ConsensusParams types.ConsensusParams + LastHeightChanged int64 +} + +// Bytes serializes the ConsensusParamsInfo using go-wire +func (params ConsensusParamsInfo) Bytes() []byte { + return wire.BinaryBytes(params) +} + //------------------------------------------------------------------------ // Genesis diff --git a/state/state_test.go b/state/state_test.go index 37368d577..1840d5e15 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -192,6 +192,65 @@ func TestValidatorChangesSaveLoad(t *testing.T) { } } +// TestConsensusParamsChangesSaveLoad tests saving and loading consensus params with changes. +func TestConsensusParamsChangesSaveLoad(t *testing.T) { + tearDown, _, state := setupTestCase(t) + defer tearDown(t) + // nolint: vetshadow + assert := assert.New(t) + + // change vals at these heights + changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20} + N := len(changeHeights) + + // each valset is just one validator. + // create list of them + params := make([]types.ConsensusParams, N+1) + params[0] = state.ConsensusParams + for i := 1; i < N+1; i++ { + params[i] = *types.DefaultConsensusParams() + params[i].BlockSize.MaxBytes += i + } + + // build the params history by running SetBlockAndValidators + // with the right params set for each height + highestHeight := changeHeights[N-1] + 5 + changeIndex := 0 + cp := params[changeIndex] + for i := int64(1); i < highestHeight; i++ { + // when we get to a change height, + // use the next params + if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] { + changeIndex++ + cp = params[changeIndex] + } + header, parts, responses := makeHeaderPartsResponsesParams(state, i, cp) + state.SetBlockAndValidators(header, parts, responses) + state.saveConsensusParamsInfo() + } + + // make all the test cases by using the same params until after the change + testCases := make([]paramsChangeTestCase, highestHeight) + changeIndex = 0 + cp = params[changeIndex] + for i := int64(1); i < highestHeight+1; i++ { + // we we get to the height after a change height + // use the next pubkey (note our counter starts at 0 this time) + if changeIndex < len(changeHeights) && i == changeHeights[changeIndex]+1 { + changeIndex++ + cp = params[changeIndex] + } + testCases[i-1] = paramsChangeTestCase{i, cp} + } + + for _, testCase := range testCases { + p, err := state.LoadConsensusParams(testCase.height) + assert.Nil(err, fmt.Sprintf("expected no err at height %d", testCase.height)) + assert.Equal(testCase.params, p, fmt.Sprintf(`unexpected consensus params at + height %d`, testCase.height)) + } +} + func makeParams(blockBytes, blockTx, blockGas, txBytes, txGas, partSize int) types.ConsensusParams { @@ -199,11 +258,11 @@ func makeParams(blockBytes, blockTx, blockGas, txBytes, BlockSize: types.BlockSize{ MaxBytes: blockBytes, MaxTxs: blockTx, - MaxGas: blockGas, + MaxGas: int64(blockGas), }, TxSize: types.TxSize{ MaxBytes: txBytes, - MaxGas: txGas, + MaxGas: int64(txGas), }, BlockGossip: types.BlockGossip{ BlockPartSizeBytes: partSize, @@ -252,7 +311,7 @@ func TestApplyUpdates(t *testing.T) { } for i, tc := range cases { - res := applyUpdates(tc.init, tc.updates) + res := tc.init.Update(tc.updates) assert.Equal(t, tc.expected, res, "case %d", i) } } @@ -284,3 +343,19 @@ type valChangeTestCase struct { height int64 vals crypto.PubKey } + +func makeHeaderPartsResponsesParams(state *State, height int64, + params types.ConsensusParams) (*types.Header, types.PartSetHeader, *ABCIResponses) { + + block := makeBlock(state, height) + abciResponses := &ABCIResponses{ + Height: height, + EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(¶ms)}, + } + return block.Header, types.PartSetHeader{}, abciResponses +} + +type paramsChangeTestCase struct { + height int64 + params types.ConsensusParams +} diff --git a/types/protobuf.go b/types/protobuf.go index e97864fb6..43c8f4505 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -51,3 +51,21 @@ func (tm2pb) Validators(vals *ValidatorSet) []*types.Validator { } return validators } + +func (tm2pb) ConsensusParams(params *ConsensusParams) *types.ConsensusParams { + return &types.ConsensusParams{ + BlockSize: &types.BlockSize{ + + MaxBytes: int32(params.BlockSize.MaxBytes), + MaxTxs: int32(params.BlockSize.MaxTxs), + MaxGas: params.BlockSize.MaxGas, + }, + TxSize: &types.TxSize{ + MaxBytes: int32(params.TxSize.MaxBytes), + MaxGas: params.TxSize.MaxGas, + }, + BlockGossip: &types.BlockGossip{ + BlockPartSizeBytes: int32(params.BlockGossip.BlockPartSizeBytes), + }, + } +} From dc54ba67e400f1a3390cb92ac719a47969c8c84c Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 17:51:03 -0500 Subject: [PATCH 21/23] state: TestValidateBlock --- state/execution_test.go | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/state/execution_test.go b/state/execution_test.go index 4dee4b455..a639d39a5 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -23,42 +23,51 @@ var ( nTxsPerBlock = 10 ) -/* func TestValidateBlock(t *testing.T) { state := state() state.SetLogger(log.TestingLogger()) - block := makeBlock(1, state) - // proper block must pass - err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash, consensusHash) + block := makeBlock(state, 1) + err := state.ValidateBlock(block) require.NoError(t, err) // wrong chain fails - err = block.ValidateBasic("other", h-1, 10, lastID, block.Time, appHash, consensusHash) + block = makeBlock(state, 1) + block.ChainID = "not-the-real-one" + err = state.ValidateBlock(block) require.Error(t, err) // wrong height fails - err = block.ValidateBasic("hello", h+4, 10, lastID, block.Time, appHash, consensusHash) + block = makeBlock(state, 1) + block.Height += 10 + err = state.ValidateBlock(block) require.Error(t, err) // wrong total tx fails - err = block.ValidateBasic("hello", h-1, 15, lastID, block.Time, appHash, consensusHash) + block = makeBlock(state, 1) + block.TotalTxs += 10 + err = state.ValidateBlock(block) require.Error(t, err) // wrong blockid fails - err = block.ValidateBasic("hello", h-1, 10, makeBlockID(), block.Time, appHash, consensusHash) + block = makeBlock(state, 1) + block.LastBlockID.PartsHeader.Total += 10 + err = state.ValidateBlock(block) require.Error(t, err) // wrong app hash fails - err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, []byte("bad-hash"), consensusHash) + block = makeBlock(state, 1) + block.AppHash = []byte("wrong app hash") + err = state.ValidateBlock(block) require.Error(t, err) // wrong consensus hash fails - err = block.ValidateBasic("hello", h-1, 10, lastID, block.Time, appHash, []byte("wrong-params")) + block = makeBlock(state, 1) + block.ConsensusHash = []byte("wrong consensus hash") + err = state.ValidateBlock(block) require.Error(t, err) } -*/ func TestApplyBlock(t *testing.T) { cc := proxy.NewLocalClientCreator(dummy.NewDummyApplication()) From 91acc51cd11ab8a64dcf91e88b2da8811c567e80 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 17:52:06 -0500 Subject: [PATCH 22/23] fix test --- types/params_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/params_test.go b/types/params_test.go index a864ce83e..f645585eb 100644 --- a/types/params_test.go +++ b/types/params_test.go @@ -48,11 +48,11 @@ func makeParams(blockBytes, blockTx, blockGas, txBytes, BlockSize: BlockSize{ MaxBytes: blockBytes, MaxTxs: blockTx, - MaxGas: blockGas, + MaxGas: int64(blockGas), }, TxSize: TxSize{ MaxBytes: txBytes, - MaxGas: txGas, + MaxGas: int64(txGas), }, BlockGossip: BlockGossip{ BlockPartSizeBytes: partSize, From 38608b1b0fa3b975855f9b7e319214621ce8de37 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 21 Dec 2017 18:22:02 -0500 Subject: [PATCH 23/23] comment and tmlibs fix --- consensus/state.go | 3 ++- glide.lock | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/consensus/state.go b/consensus/state.go index 9c89ae4ed..67a1d8218 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -1338,7 +1338,8 @@ func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerKey string) error { return err } else { - // Probably an invalid signature. Bad peer. + // Probably an invalid signature / Bad peer. + // Seems this can also err sometimes with "Unexpected step" - perhaps not from a bad peer ? cs.Logger.Error("Error attempting to add vote", "err", err) return ErrAddingVote } diff --git a/glide.lock b/glide.lock index b74ffd78c..c29eea4de 100644 --- a/glide.lock +++ b/glide.lock @@ -131,7 +131,7 @@ imports: subpackages: - iavl - name: github.com/tendermint/tmlibs - version: e2d7f1aa41dde5f29057dd08e64371a574b84c86 + version: e236218516289f91bde3273e99fe5c1fc20eb304 subpackages: - autofile - cli