From 0e0461d9bc1c3db2f73c05e0f6b0cfc802a3ae13 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 5 Jun 2018 18:54:30 -0700 Subject: [PATCH 01/30] dev version bump --- CHANGELOG.md | 4 ++++ version/version.go | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb532e013..c3de2157e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.19.10 + +*TBD* + ## 0.19.9 *June 5th, 2018* diff --git a/version/version.go b/version/version.go index a26ad913e..1296657da 100644 --- a/version/version.go +++ b/version/version.go @@ -4,13 +4,13 @@ package version const ( Maj = "0" Min = "19" - Fix = "9" + Fix = "10" ) var ( // Version is the current version of Tendermint // Must be a string because scripts like dist.sh read this file. - Version = "0.19.9" + Version = "0.19.10-dev" // GitCommit is the current HEAD set using ldflags. GitCommit string From e13c1ab7358c8c1fede53ee757d26466dab9ce2a Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 11:09:37 -0400 Subject: [PATCH 02/30] update for new abci --- Gopkg.lock | 11 +++++------ Gopkg.toml | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index fff269b66..104c99a01 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -57,11 +57,8 @@ name = "github.com/gogo/protobuf" packages = [ "gogoproto", - "jsonpb", "proto", - "protoc-gen-gogo/descriptor", - "sortkeys", - "types" + "protoc-gen-gogo/descriptor" ] revision = "1adfc126b41513cc696b209667c8656ea7aac67c" version = "v1.0.0" @@ -69,10 +66,12 @@ [[projects]] name = "github.com/golang/protobuf" packages = [ + "jsonpb", "proto", "ptypes", "ptypes/any", "ptypes/duration", + "ptypes/struct", "ptypes/timestamp" ] revision = "925541529c1fa6821df4e44ce2723319eb2be768" @@ -238,8 +237,8 @@ "server", "types" ] - revision = "78a8905690ef54f9d57e3b2b0ee7ad3a04ef3f1f" - version = "v0.10.3" + revision = "b1b784cfa837cfbcd14f3bb38d97c2a899ff882a" + version = "v0.11.0-rc2" [[projects]] branch = "master" diff --git a/Gopkg.toml b/Gopkg.toml index 0c34ea034..43b273f96 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -71,7 +71,7 @@ [[constraint]] name = "github.com/tendermint/abci" - version = "~0.10.3" + version = "~0.11.0-rc2" [[constraint]] name = "github.com/tendermint/go-crypto" From f28eae7816df5a65f906a7ec904cc9d77c67e45e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 11:09:42 -0400 Subject: [PATCH 03/30] update types --- types/protobuf.go | 51 ++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/types/protobuf.go b/types/protobuf.go index e7ae20e39..828294d82 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -1,7 +1,11 @@ package types import ( + "fmt" + "reflect" + "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" ) // TM2PB is used for converting Tendermint types to protobuf types. @@ -12,38 +16,39 @@ type tm2pb struct{} func (tm2pb) Header(header *Header) types.Header { return types.Header{ - ChainID: header.ChainID, - Height: header.Height, - Time: header.Time.Unix(), - NumTxs: int32(header.NumTxs), // XXX: overflow - LastBlockID: TM2PB.BlockID(header.LastBlockID), - LastCommitHash: header.LastCommitHash, - DataHash: header.DataHash, - AppHash: header.AppHash, - } -} - -func (tm2pb) BlockID(blockID BlockID) types.BlockID { - return types.BlockID{ - Hash: blockID.Hash, - Parts: TM2PB.PartSetHeader(blockID.PartsHeader), - } -} - -func (tm2pb) PartSetHeader(partSetHeader PartSetHeader) types.PartSetHeader { - return types.PartSetHeader{ - Total: int32(partSetHeader.Total), // XXX: overflow - Hash: partSetHeader.Hash, + ChainId: header.ChainID, + Height: header.Height, + Time: header.Time.Unix(), + NumTxs: int32(header.NumTxs), // XXX: overflow + LastBlockHash: header.LastBlockID.Hash, + AppHash: header.AppHash, } } func (tm2pb) Validator(val *Validator) types.Validator { return types.Validator{ - PubKey: val.PubKey.Bytes(), + PubKey: TM2PB.PubKey(val.PubKey), Power: val.VotingPower, } } +func (tm2pb) PubKey(pubKey crypto.PubKey) *types.PubKey { + switch pk := pubKey.(type) { + case crypto.PubKeyEd25519: + return &types.PubKey{ + Type: "ed25519", + Data: pk[:], + } + case crypto.PubKeySecp256k1: + return &types.PubKey{ + Type: "secp256k1", + Data: pk[:], + } + default: + panic(fmt.Sprintf("unknown pubkey type: %v %v", pubKey, reflect.TypeOf(pubKey))) + } +} + func (tm2pb) Validators(vals *ValidatorSet) []types.Validator { validators := make([]types.Validator, len(vals.Validators)) for i, val := range vals.Validators { From ebd2fe7a688a3540d1d8235e09e89dc8d82ccfaf Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 11:54:22 -0400 Subject: [PATCH 04/30] more types --- types/protobuf.go | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/types/protobuf.go b/types/protobuf.go index 828294d82..bb7b71072 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -14,8 +14,8 @@ var TM2PB = tm2pb{} type tm2pb struct{} -func (tm2pb) Header(header *Header) types.Header { - return types.Header{ +func (tm2pb) Header(header *Header) *types.Header { + return &types.Header{ ChainId: header.ChainID, Height: header.Height, Time: header.Time.Unix(), @@ -25,8 +25,8 @@ func (tm2pb) Header(header *Header) types.Header { } } -func (tm2pb) Validator(val *Validator) types.Validator { - return types.Validator{ +func (tm2pb) Validator(val *Validator) *types.Validator { + return &types.Validator{ PubKey: TM2PB.PubKey(val.PubKey), Power: val.VotingPower, } @@ -49,8 +49,8 @@ func (tm2pb) PubKey(pubKey crypto.PubKey) *types.PubKey { } } -func (tm2pb) Validators(vals *ValidatorSet) []types.Validator { - validators := make([]types.Validator, len(vals.Validators)) +func (tm2pb) Validators(vals *ValidatorSet) []*types.Validator { + validators := make([]*types.Validator, len(vals.Validators)) for i, val := range vals.Validators { validators[i] = TM2PB.Validator(val) } @@ -74,3 +74,27 @@ func (tm2pb) ConsensusParams(params *ConsensusParams) *types.ConsensusParams { }, } } + +//---------------------------------------------------------------------------- + +// PB2TM is used for converting protobuf types to Tendermint types. +// UNSTABLE +var PB2TM = pb2tm{} + +type pb2tm struct{} + +// TODO: validate key lengths ... +func (pb2tm) PubKey(pubKey *types.PubKey) (crypto.PubKey, error) { + switch pubKey.Type { + case "ed25519": + var pk crypto.PubKeyEd25519 + copy(pk[:], pubKey.Data) + return pk, nil + case "secp256k1": + var pk crypto.PubKeySecp256k1 + copy(pk[:], pubKey.Data) + return pk, nil + default: + return nil, fmt.Errorf("Unknown pubkey type %v", pubKey.Type) + } +} From 575d94dbb96ef5f05a6cc12877434ef443609dd1 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 11:57:14 -0400 Subject: [PATCH 05/30] state compiles --- state/execution.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/state/execution.go b/state/execution.go index 770911597..45f3daab0 100644 --- a/state/execution.go +++ b/state/execution.go @@ -5,7 +5,6 @@ import ( fail "github.com/ebuchman/fail-test" abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" "github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tmlibs/db" @@ -192,20 +191,19 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, } } - // TODO: determine which validators were byzantine - byzantineVals := make([]abci.Evidence, len(block.Evidence.Evidence)) + byzantineVals := make([]*abci.Evidence, len(block.Evidence.Evidence)) for i, ev := range block.Evidence.Evidence { - byzantineVals[i] = abci.Evidence{ - PubKey: ev.Address(), // XXX + byzantineVals[i] = &abci.Evidence{ + // TODO: fill this in Height: ev.Height(), } } // Begin block _, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{ - Hash: block.Hash(), - Header: types.TM2PB.Header(block.Header), - AbsentValidators: absentVals, + Hash: block.Hash(), + Header: types.TM2PB.Header(block.Header), + // TODO: fill this in ByzantineValidators: byzantineVals, }) if err != nil { @@ -241,9 +239,9 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, // If more or equal than 1/3 of total voting power changed in one block, then // a light client could never prove the transition externally. See // ./lite/doc.go for details on how a light client tracks validators. -func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator) error { +func updateValidators(currentSet *types.ValidatorSet, updates []*abci.Validator) error { for _, v := range updates { - pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-amino encoded pubkey + pubkey, err := types.PB2TM.PubKey(v.PubKey) if err != nil { return err } From 485b4a0c6fb42b91f5c1f8695801723893693761 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 22:05:15 -0400 Subject: [PATCH 06/30] revert gogo --- state/execution.go | 6 +++--- types/protobuf.go | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/state/execution.go b/state/execution.go index 45f3daab0..86da99c5a 100644 --- a/state/execution.go +++ b/state/execution.go @@ -191,9 +191,9 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, } } - byzantineVals := make([]*abci.Evidence, len(block.Evidence.Evidence)) + byzantineVals := make([]abci.Evidence, len(block.Evidence.Evidence)) for i, ev := range block.Evidence.Evidence { - byzantineVals[i] = &abci.Evidence{ + byzantineVals[i] = abci.Evidence{ // TODO: fill this in Height: ev.Height(), } @@ -239,7 +239,7 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, // If more or equal than 1/3 of total voting power changed in one block, then // a light client could never prove the transition externally. See // ./lite/doc.go for details on how a light client tracks validators. -func updateValidators(currentSet *types.ValidatorSet, updates []*abci.Validator) error { +func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator) error { for _, v := range updates { pubkey, err := types.PB2TM.PubKey(v.PubKey) if err != nil { diff --git a/types/protobuf.go b/types/protobuf.go index bb7b71072..48cc02024 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -14,9 +14,9 @@ var TM2PB = tm2pb{} type tm2pb struct{} -func (tm2pb) Header(header *Header) *types.Header { - return &types.Header{ - ChainId: header.ChainID, +func (tm2pb) Header(header *Header) types.Header { + return types.Header{ + ChainID: header.ChainID, Height: header.Height, Time: header.Time.Unix(), NumTxs: int32(header.NumTxs), // XXX: overflow @@ -25,22 +25,22 @@ func (tm2pb) Header(header *Header) *types.Header { } } -func (tm2pb) Validator(val *Validator) *types.Validator { - return &types.Validator{ +func (tm2pb) Validator(val *Validator) types.Validator { + return types.Validator{ PubKey: TM2PB.PubKey(val.PubKey), Power: val.VotingPower, } } -func (tm2pb) PubKey(pubKey crypto.PubKey) *types.PubKey { +func (tm2pb) PubKey(pubKey crypto.PubKey) types.PubKey { switch pk := pubKey.(type) { case crypto.PubKeyEd25519: - return &types.PubKey{ + return types.PubKey{ Type: "ed25519", Data: pk[:], } case crypto.PubKeySecp256k1: - return &types.PubKey{ + return types.PubKey{ Type: "secp256k1", Data: pk[:], } @@ -49,16 +49,16 @@ func (tm2pb) PubKey(pubKey crypto.PubKey) *types.PubKey { } } -func (tm2pb) Validators(vals *ValidatorSet) []*types.Validator { - validators := make([]*types.Validator, len(vals.Validators)) +func (tm2pb) Validators(vals *ValidatorSet) []types.Validator { + validators := make([]types.Validator, len(vals.Validators)) for i, val := range vals.Validators { validators[i] = TM2PB.Validator(val) } return validators } -func (tm2pb) ConsensusParams(params *ConsensusParams) *types.ConsensusParams { - return &types.ConsensusParams{ +func (tm2pb) ConsensusParams(params *ConsensusParams) types.ConsensusParams { + return types.ConsensusParams{ BlockSize: &types.BlockSize{ MaxBytes: int32(params.BlockSize.MaxBytes), @@ -84,7 +84,7 @@ var PB2TM = pb2tm{} type pb2tm struct{} // TODO: validate key lengths ... -func (pb2tm) PubKey(pubKey *types.PubKey) (crypto.PubKey, error) { +func (pb2tm) PubKey(pubKey types.PubKey) (crypto.PubKey, error) { switch pubKey.Type { case "ed25519": var pk crypto.PubKeyEd25519 From 7606b7595fa11cf07b16ca7aabdff3e224f337db Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 22:18:17 -0400 Subject: [PATCH 07/30] compiles --- consensus/replay.go | 14 ++++++++------ consensus/replay_file.go | 2 +- consensus/wal_generator.go | 2 +- node/node.go | 2 +- types/protobuf.go | 4 ++-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/consensus/replay.go b/consensus/replay.go index 13d665f7a..a51c07bb3 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -2,7 +2,6 @@ package consensus import ( "bytes" - "encoding/json" "fmt" "hash/crc32" "io" @@ -197,20 +196,20 @@ type Handshaker struct { stateDB dbm.DB initialState sm.State store sm.BlockStore - appState json.RawMessage + genDoc *types.GenesisDoc logger log.Logger nBlocks int // number of blocks applied to the state } func NewHandshaker(stateDB dbm.DB, state sm.State, - store sm.BlockStore, appState json.RawMessage) *Handshaker { + store sm.BlockStore, genDoc *types.GenesisDoc) *Handshaker { return &Handshaker{ stateDB: stateDB, initialState: state, store: store, - appState: appState, + genDoc: genDoc, logger: log.NewNopLogger(), nBlocks: 0, } @@ -269,8 +268,11 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight if appBlockHeight == 0 { validators := types.TM2PB.Validators(state.Validators) req := abci.RequestInitChain{ - Validators: validators, - AppStateBytes: h.appState, + Time: h.genDoc.GenesisTime.Unix(), // TODO + ChainId: h.genDoc.ChainID, + ConsensusParams: types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams), + Validators: validators, + AppStateBytes: h.genDoc.AppStateJSON, } _, err := proxyApp.Consensus().InitChainSync(req) if err != nil { diff --git a/consensus/replay_file.go b/consensus/replay_file.go index 4f8343469..57204b01a 100644 --- a/consensus/replay_file.go +++ b/consensus/replay_file.go @@ -299,7 +299,7 @@ func newConsensusStateForReplay(config cfg.BaseConfig, csConfig *cfg.ConsensusCo // Create proxyAppConn connection (consensus, mempool, query) clientCreator := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()) proxyApp := proxy.NewAppConns(clientCreator, - NewHandshaker(stateDB, state, blockStore, gdoc.AppState())) + NewHandshaker(stateDB, state, blockStore, gdoc)) err = proxyApp.Start() if err != nil { cmn.Exit(cmn.Fmt("Error starting proxy app conns: %v", err)) diff --git a/consensus/wal_generator.go b/consensus/wal_generator.go index 38bed4ac1..f61af15f5 100644 --- a/consensus/wal_generator.go +++ b/consensus/wal_generator.go @@ -52,7 +52,7 @@ func WALWithNBlocks(numBlocks int) (data []byte, err error) { return nil, errors.Wrap(err, "failed to make genesis state") } blockStore := bc.NewBlockStore(blockStoreDB) - handshaker := NewHandshaker(stateDB, state, blockStore, genDoc.AppState()) + handshaker := NewHandshaker(stateDB, state, blockStore, genDoc) proxyApp := proxy.NewAppConns(proxy.NewLocalClientCreator(app), handshaker) proxyApp.SetLogger(logger.With("module", "proxy")) if err := proxyApp.Start(); err != nil { diff --git a/node/node.go b/node/node.go index 5da57665b..a8b5c9b2f 100644 --- a/node/node.go +++ b/node/node.go @@ -159,7 +159,7 @@ func NewNode(config *cfg.Config, // and sync tendermint and the app by performing a handshake // and replaying any necessary blocks consensusLogger := logger.With("module", "consensus") - handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc.AppState()) + handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc) handshaker.SetLogger(consensusLogger) proxyApp := proxy.NewAppConns(clientCreator, handshaker) proxyApp.SetLogger(logger.With("module", "proxy")) diff --git a/types/protobuf.go b/types/protobuf.go index 48cc02024..2e772faf3 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -57,8 +57,8 @@ func (tm2pb) Validators(vals *ValidatorSet) []types.Validator { return validators } -func (tm2pb) ConsensusParams(params *ConsensusParams) types.ConsensusParams { - return types.ConsensusParams{ +func (tm2pb) ConsensusParams(params *ConsensusParams) *types.ConsensusParams { + return &types.ConsensusParams{ BlockSize: &types.BlockSize{ MaxBytes: int32(params.BlockSize.MaxBytes), From e4147b6f1a35d2c06b88298997bbe17a53c0842b Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 22:46:19 -0400 Subject: [PATCH 08/30] state test runs --- state/execution_test.go | 12 ++++---- state/state_test.go | 11 +++---- types/protobuf.go | 64 +++++++++++++++++++++++++++++------------ 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/state/execution_test.go b/state/execution_test.go index b6c7f9a6c..2d14f35f4 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -80,7 +80,7 @@ func TestBeginBlockAbsentValidators(t *testing.T) { require.Nil(t, err, tc.desc) // -> app must receive an index of the absent validator - assert.Equal(t, tc.expectedAbsentValidators, app.AbsentValidators, tc.desc) + assert.Equal(t, tc.expectedAbsentValidators, app.Validators, tc.desc) } } @@ -110,10 +110,10 @@ func TestBeginBlockByzantineValidators(t *testing.T) { expectedByzantineValidators []abci.Evidence }{ {"none byzantine", []types.Evidence{}, []abci.Evidence{}}, - {"one byzantine", []types.Evidence{ev1}, []abci.Evidence{{ev1.Address(), ev1.Height()}}}, + {"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1)}}, {"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{ - {ev1.Address(), ev1.Height()}, - {ev2.Address(), ev2.Height()}}}, + types.TM2PB.Evidence(ev1), + types.TM2PB.Evidence(ev1)}}, } for _, tc := range testCases { @@ -162,7 +162,7 @@ var _ abci.Application = (*testApp)(nil) type testApp struct { abci.BaseApplication - AbsentValidators []int32 + Validators []abci.SigningValidator ByzantineValidators []abci.Evidence } @@ -175,7 +175,7 @@ func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) { } func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock { - app.AbsentValidators = req.AbsentValidators + app.Validators = req.Validators app.ByzantineValidators = req.ByzantineValidators return abci.ResponseBeginBlock{} } diff --git a/state/state_test.go b/state/state_test.go index 497695373..464456ca5 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -78,10 +78,7 @@ func TestABCIResponsesSaveLoad1(t *testing.T) { abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: nil} abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: nil} abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.Validator{ - { - PubKey: crypto.GenPrivKeyEd25519().PubKey().Bytes(), - Power: 10, - }, + types.TM2PB.ValidatorFromPubKeyAndPower(crypto.GenPrivKeyEd25519().PubKey(), 10), }} saveABCIResponses(stateDB, block.Height, abciResponses) @@ -435,8 +432,8 @@ func makeHeaderPartsResponsesValPubKeyChange(state State, height int64, if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) { abciResponses.EndBlock = &abci.ResponseEndBlock{ ValidatorUpdates: []abci.Validator{ - {val.PubKey.Bytes(), 0}, - {pubkey.Bytes(), 10}, + types.TM2PB.ValidatorFromPubKeyAndPower(val.PubKey, 0), + types.TM2PB.ValidatorFromPubKeyAndPower(pubkey, 10), }, } } @@ -457,7 +454,7 @@ func makeHeaderPartsResponsesValPowerChange(state State, height int64, if val.VotingPower != power { abciResponses.EndBlock = &abci.ResponseEndBlock{ ValidatorUpdates: []abci.Validator{ - {val.PubKey.Bytes(), power}, + types.TM2PB.ValidatorFromPubKeyAndPower(val.PubKey, power), }, } } diff --git a/types/protobuf.go b/types/protobuf.go index 2e772faf3..a0347450e 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -4,18 +4,18 @@ import ( "fmt" "reflect" - "github.com/tendermint/abci/types" + abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" ) -// TM2PB is used for converting Tendermint types to protobuf types. +// TM2PB is used for converting Tendermint abci to protobuf abci. // UNSTABLE var TM2PB = tm2pb{} type tm2pb struct{} -func (tm2pb) Header(header *Header) types.Header { - return types.Header{ +func (tm2pb) Header(header *Header) abci.Header { + return abci.Header{ ChainID: header.ChainID, Height: header.Height, Time: header.Time.Unix(), @@ -25,22 +25,22 @@ func (tm2pb) Header(header *Header) types.Header { } } -func (tm2pb) Validator(val *Validator) types.Validator { - return types.Validator{ +func (tm2pb) Validator(val *Validator) abci.Validator { + return abci.Validator{ PubKey: TM2PB.PubKey(val.PubKey), Power: val.VotingPower, } } -func (tm2pb) PubKey(pubKey crypto.PubKey) types.PubKey { +func (tm2pb) PubKey(pubKey crypto.PubKey) abci.PubKey { switch pk := pubKey.(type) { case crypto.PubKeyEd25519: - return types.PubKey{ + return abci.PubKey{ Type: "ed25519", Data: pk[:], } case crypto.PubKeySecp256k1: - return types.PubKey{ + return abci.PubKey{ Type: "secp256k1", Data: pk[:], } @@ -49,42 +49,70 @@ func (tm2pb) PubKey(pubKey crypto.PubKey) types.PubKey { } } -func (tm2pb) Validators(vals *ValidatorSet) []types.Validator { - validators := make([]types.Validator, len(vals.Validators)) +func (tm2pb) Validators(vals *ValidatorSet) []abci.Validator { + validators := make([]abci.Validator, len(vals.Validators)) for i, val := range vals.Validators { validators[i] = TM2PB.Validator(val) } return validators } -func (tm2pb) ConsensusParams(params *ConsensusParams) *types.ConsensusParams { - return &types.ConsensusParams{ - BlockSize: &types.BlockSize{ +func (tm2pb) ConsensusParams(params *ConsensusParams) *abci.ConsensusParams { + return &abci.ConsensusParams{ + BlockSize: &abci.BlockSize{ MaxBytes: int32(params.BlockSize.MaxBytes), MaxTxs: int32(params.BlockSize.MaxTxs), MaxGas: params.BlockSize.MaxGas, }, - TxSize: &types.TxSize{ + TxSize: &abci.TxSize{ MaxBytes: int32(params.TxSize.MaxBytes), MaxGas: params.TxSize.MaxGas, }, - BlockGossip: &types.BlockGossip{ + BlockGossip: &abci.BlockGossip{ BlockPartSizeBytes: int32(params.BlockGossip.BlockPartSizeBytes), }, } } +func (tm2pb) Evidence(ev_ Evidence) abci.Evidence { + switch ev := ev_.(type) { + case *DuplicateVoteEvidence: + return abci.Evidence{ + Type: "duplicate/vote", + Validator: abci.Validator{ + Address: ev.Address(), + // TODO + }, + Height: ev.Height(), + // Time: ev.Time(), + // TotalVotingPower: 10, + } + default: + panic(fmt.Sprintf("Unknown evidence type: %v %v", ev_, reflect.TypeOf(ev_))) + } + +} + +func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci.Validator { + pubkeyABCI := TM2PB.PubKey(pubkey) + return abci.Validator{ + Address: pubkey.Address(), + PubKey: pubkeyABCI, + Power: power, + } +} + //---------------------------------------------------------------------------- -// PB2TM is used for converting protobuf types to Tendermint types. +// PB2TM is used for converting protobuf abci to Tendermint abci. // UNSTABLE var PB2TM = pb2tm{} type pb2tm struct{} // TODO: validate key lengths ... -func (pb2tm) PubKey(pubKey types.PubKey) (crypto.PubKey, error) { +func (pb2tm) PubKey(pubKey abci.PubKey) (crypto.PubKey, error) { switch pubKey.Type { case "ed25519": var pk crypto.PubKeyEd25519 From e1e6878a4d84e26edd5f05529159b9b911862e34 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 23:29:46 -0400 Subject: [PATCH 09/30] fix state tests --- state/execution.go | 32 ++++++++++--------- state/execution_test.go | 67 +++++++++++++++++++++++++++------------- state/validation_test.go | 2 +- types/protobuf.go | 11 +++++++ 4 files changed, 74 insertions(+), 38 deletions(-) diff --git a/state/execution.go b/state/execution.go index 86da99c5a..052510e87 100644 --- a/state/execution.go +++ b/state/execution.go @@ -73,7 +73,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b return state, ErrInvalidBlock(err) } - abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block) + abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, s.LastValidators) if err != nil { return state, ErrProxyAppConn(err) } @@ -157,7 +157,8 @@ func (blockExec *BlockExecutor) Commit(block *types.Block) ([]byte, error) { // Executes block's transactions on proxyAppConn. // Returns a list of transaction results and updates to the validator set -func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, block *types.Block) (*ABCIResponses, error) { +func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, + block *types.Block, valSet *types.ValidatorSet) (*ABCIResponses, error) { var validTxs, invalidTxs = 0, 0 txIndex := 0 @@ -184,26 +185,26 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, proxyAppConn.SetResponseCallback(proxyCb) // determine which validators did not sign last block - absentVals := make([]int32, 0) - for valI, vote := range block.LastCommit.Precommits { - if vote == nil { - absentVals = append(absentVals, int32(valI)) + signVals := make([]abci.SigningValidator, len(block.LastCommit.Precommits)) + for i, val := range valSet.Validators { + vote := block.LastCommit.Precommits[i] + val := abci.SigningValidator{ + Validator: types.TM2PB.Validator(val), + SignedLastBlock: vote != nil, } + signVals[i] = val } byzantineVals := make([]abci.Evidence, len(block.Evidence.Evidence)) for i, ev := range block.Evidence.Evidence { - byzantineVals[i] = abci.Evidence{ - // TODO: fill this in - Height: ev.Height(), - } + byzantineVals[i] = types.TM2PB.Evidence(ev) } // Begin block _, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{ - Hash: block.Hash(), - Header: types.TM2PB.Header(block.Header), - // TODO: fill this in + Hash: block.Hash(), + Header: types.TM2PB.Header(block.Header), + Validators: signVals, ByzantineValidators: byzantineVals, }) if err != nil { @@ -355,8 +356,9 @@ func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *ty // ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state. // It returns the application root hash (result of abci.Commit). -func ExecCommitBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block, logger log.Logger) ([]byte, error) { - _, err := execBlockOnProxyApp(logger, appConnConsensus, block) +func ExecCommitBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block, + logger log.Logger, valSet *types.ValidatorSet) ([]byte, error) { + _, err := execBlockOnProxyApp(logger, appConnConsensus, block, valSet) if err != nil { logger.Error("Error executing block on proxy app", "height", block.Height, "err", err) return nil, err diff --git a/state/execution_test.go b/state/execution_test.go index 2d14f35f4..e31a0fd13 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -1,6 +1,7 @@ package state import ( + "fmt" "testing" "time" @@ -19,7 +20,6 @@ import ( ) var ( - privKey = crypto.GenPrivKeyEd25519FromSecret([]byte("execution_test")) chainID = "execution_chain" testPartSize = 65536 nTxsPerBlock = 10 @@ -32,7 +32,7 @@ func TestApplyBlock(t *testing.T) { require.Nil(t, err) defer proxyApp.Stop() - state, stateDB := state(), dbm.NewMemDB() + state, stateDB := state(1), dbm.NewMemDB() blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), MockMempool{}, MockEvidencePool{}) @@ -46,8 +46,8 @@ func TestApplyBlock(t *testing.T) { // TODO check state and mempool } -// TestBeginBlockAbsentValidators ensures we send absent validators list. -func TestBeginBlockAbsentValidators(t *testing.T) { +// TestBeginBlockValidators ensures we send absent validators list. +func TestBeginBlockValidators(t *testing.T) { app := &testApp{} cc := proxy.NewLocalClientCreator(app) proxyApp := proxy.NewAppConns(cc, nil) @@ -55,32 +55,45 @@ func TestBeginBlockAbsentValidators(t *testing.T) { require.Nil(t, err) defer proxyApp.Stop() - state := state() + state := state(2) prevHash := state.LastBlockID.Hash prevParts := types.PartSetHeader{} prevBlockID := types.BlockID{prevHash, prevParts} now := time.Now().UTC() + vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit} + vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now} + testCases := []struct { desc string lastCommitPrecommits []*types.Vote - expectedAbsentValidators []int32 + expectedAbsentValidators []int }{ - {"none absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}, {ValidatorIndex: 1, Timestamp: now}}, []int32{}}, - {"one absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}, nil}, []int32{1}}, - {"multiple absent", []*types.Vote{nil, nil}, []int32{0, 1}}, + {"none absent", []*types.Vote{vote0, vote1}, []int{}}, + {"one absent", []*types.Vote{vote0, nil}, []int{1}}, + {"multiple absent", []*types.Vote{nil, nil}, []int{0, 1}}, } for _, tc := range testCases { lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: tc.lastCommitPrecommits} block, _ := state.MakeBlock(2, makeTxs(2), lastCommit) - _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger()) + _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators) require.Nil(t, err, tc.desc) - // -> app must receive an index of the absent validator - assert.Equal(t, tc.expectedAbsentValidators, app.Validators, tc.desc) + // -> app receives a list of validators with a bool indicating if they signed + ctr := 0 + for i, v := range app.Validators { + if ctr < len(tc.expectedAbsentValidators) && + tc.expectedAbsentValidators[ctr] == i { + + assert.False(t, v.SignedLastBlock) + ctr++ + } else { + assert.True(t, v.SignedLastBlock) + } + } } } @@ -93,7 +106,7 @@ func TestBeginBlockByzantineValidators(t *testing.T) { require.Nil(t, err) defer proxyApp.Stop() - state := state() + state := state(2) prevHash := state.LastBlockID.Hash prevParts := types.PartSetHeader{} @@ -113,15 +126,19 @@ func TestBeginBlockByzantineValidators(t *testing.T) { {"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1)}}, {"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{ types.TM2PB.Evidence(ev1), - types.TM2PB.Evidence(ev1)}}, + types.TM2PB.Evidence(ev2)}}, } + now := time.Now().UTC() + vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit} + vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now} + votes := []*types.Vote{vote0, vote1} + lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: votes} for _, tc := range testCases { - lastCommit := &types.Commit{BlockID: prevBlockID} block, _ := state.MakeBlock(10, makeTxs(2), lastCommit) block.Evidence.Evidence = tc.evidence - _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger()) + _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators) require.Nil(t, err, tc.desc) // -> app must receive an index of the byzantine validator @@ -139,13 +156,19 @@ func makeTxs(height int64) (txs []types.Tx) { return txs } -func state() State { +func state(nVals int) State { + vals := make([]types.GenesisValidator, nVals) + for i := 0; i < nVals; i++ { + secret := []byte(fmt.Sprintf("test%d", i)) + pk := crypto.GenPrivKeyEd25519FromSecret(secret) + vals[i] = types.GenesisValidator{ + pk.PubKey(), 1000, fmt.Sprintf("test%d", i), + } + } s, _ := MakeGenesisState(&types.GenesisDoc{ - ChainID: chainID, - Validators: []types.GenesisValidator{ - {privKey.PubKey(), 10000, "test"}, - }, - AppHash: nil, + ChainID: chainID, + Validators: vals, + AppHash: nil, }) return s } diff --git a/state/validation_test.go b/state/validation_test.go index e0b7fe9ee..f72021975 100644 --- a/state/validation_test.go +++ b/state/validation_test.go @@ -9,7 +9,7 @@ import ( ) func TestValidateBlock(t *testing.T) { - state := state() + state := state(1) blockExec := NewBlockExecutor(dbm.NewMemDB(), log.TestingLogger(), nil, nil, nil) diff --git a/types/protobuf.go b/types/protobuf.go index a0347450e..20cf8a561 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -88,6 +88,17 @@ func (tm2pb) Evidence(ev_ Evidence) abci.Evidence { // Time: ev.Time(), // TotalVotingPower: 10, } + case *MockGoodEvidence, MockGoodEvidence: + return abci.Evidence{ + Type: "mock/good", + Validator: abci.Validator{ + Address: ev.Address(), + // TODO + }, + Height: ev.Height(), + // Time: ev.Time(), + // TotalVotingPower: 10, + } default: panic(fmt.Sprintf("Unknown evidence type: %v %v", ev_, reflect.TypeOf(ev_))) } From 866bcceb35df564022dbc851479c77999da21324 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 23:56:44 -0400 Subject: [PATCH 10/30] fix consensus tests --- consensus/reactor_test.go | 23 ++++++++++++++--------- consensus/replay.go | 2 +- consensus/replay_test.go | 15 ++++++++------- state/execution.go | 20 +++++++++++++++++--- 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/consensus/reactor_test.go b/consensus/reactor_test.go index 058bf1e71..0d9971192 100644 --- a/consensus/reactor_test.go +++ b/consensus/reactor_test.go @@ -254,7 +254,8 @@ func TestReactorVotingPowerChange(t *testing.T) { logger.Debug("---------------------------- Testing changing the voting power of one validator a few times") val1PubKey := css[0].privValidator.GetPubKey() - updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKey.Bytes(), 25) + val1PubKeyABCI := types.TM2PB.PubKey(val1PubKey) + updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKeyABCI, 25) previousTotalVotingPower := css[0].GetRoundState().LastValidators.TotalVotingPower() waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx) @@ -266,7 +267,7 @@ func TestReactorVotingPowerChange(t *testing.T) { t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower()) } - updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKey.Bytes(), 2) + updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 2) previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower() waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx) @@ -278,7 +279,7 @@ func TestReactorVotingPowerChange(t *testing.T) { t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower()) } - updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKey.Bytes(), 26) + updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 26) previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower() waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx) @@ -316,7 +317,8 @@ func TestReactorValidatorSetChanges(t *testing.T) { logger.Info("---------------------------- Testing adding one validator") newValidatorPubKey1 := css[nVals].privValidator.GetPubKey() - newValidatorTx1 := kvstore.MakeValSetChangeTx(newValidatorPubKey1.Bytes(), testMinPower) + valPubKey1ABCI := types.TM2PB.PubKey(newValidatorPubKey1) + newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower) // wait till everyone makes block 2 // ensure the commit includes all validators @@ -342,7 +344,8 @@ func TestReactorValidatorSetChanges(t *testing.T) { logger.Info("---------------------------- Testing changing the voting power of one validator") updateValidatorPubKey1 := css[nVals].privValidator.GetPubKey() - updateValidatorTx1 := kvstore.MakeValSetChangeTx(updateValidatorPubKey1.Bytes(), 25) + updatePubKey1ABCI := types.TM2PB.PubKey(updateValidatorPubKey1) + updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25) previousTotalVotingPower := css[nVals].GetRoundState().LastValidators.TotalVotingPower() waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, updateValidatorTx1) @@ -358,10 +361,12 @@ func TestReactorValidatorSetChanges(t *testing.T) { logger.Info("---------------------------- Testing adding two validators at once") newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey() - newValidatorTx2 := kvstore.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), testMinPower) + newVal2ABCI := types.TM2PB.PubKey(newValidatorPubKey2) + newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower) newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey() - newValidatorTx3 := kvstore.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), testMinPower) + newVal3ABCI := types.TM2PB.PubKey(newValidatorPubKey3) + newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower) waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3) waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3) @@ -373,8 +378,8 @@ func TestReactorValidatorSetChanges(t *testing.T) { //--------------------------------------------------------------------------- logger.Info("---------------------------- Testing removing two validators at once") - removeValidatorTx2 := kvstore.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), 0) - removeValidatorTx3 := kvstore.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), 0) + removeValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, 0) + removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0) waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, removeValidatorTx2, removeValidatorTx3) waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, removeValidatorTx2, removeValidatorTx3) diff --git a/consensus/replay.go b/consensus/replay.go index a51c07bb3..c4ee2d32d 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -367,7 +367,7 @@ func (h *Handshaker) replayBlocks(state sm.State, proxyApp proxy.AppConns, appBl for i := appBlockHeight + 1; i <= finalBlock; i++ { h.logger.Info("Applying block", "height", i) block := h.store.LoadBlock(i) - appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger) + appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger, state.LastValidators) if err != nil { return nil, err } diff --git a/consensus/replay_test.go b/consensus/replay_test.go index e0f8a4b9a..2836110c1 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -366,7 +366,8 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) { } // now start the app using the handshake - it should sync - handshaker := NewHandshaker(stateDB, state, store, nil) + genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile()) + handshaker := NewHandshaker(stateDB, state, store, genDoc) proxyApp := proxy.NewAppConns(clientCreator2, handshaker) if err := proxyApp.Start(); err != nil { t.Fatalf("Error starting proxy app connections: %v", err) @@ -416,10 +417,10 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateDB dbm.DB, } defer proxyApp.Stop() - // TODO: get the genesis bytes (https://github.com/tendermint/tendermint/issues/1224) - var genesisBytes []byte validators := types.TM2PB.Validators(state.Validators) - if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators, genesisBytes}); err != nil { + if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{ + Validators: validators, + }); err != nil { panic(err) } @@ -453,10 +454,10 @@ func buildTMStateFromChain(config *cfg.Config, stateDB dbm.DB, state sm.State, c } defer proxyApp.Stop() - // TODO: get the genesis bytes (https://github.com/tendermint/tendermint/issues/1224) - var genesisBytes []byte validators := types.TM2PB.Validators(state.Validators) - if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators, genesisBytes}); err != nil { + if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{ + Validators: validators, + }); err != nil { panic(err) } diff --git a/state/execution.go b/state/execution.go index 052510e87..b65c2ebd7 100644 --- a/state/execution.go +++ b/state/execution.go @@ -184,10 +184,24 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, } proxyAppConn.SetResponseCallback(proxyCb) - // determine which validators did not sign last block - signVals := make([]abci.SigningValidator, len(block.LastCommit.Precommits)) + // determine which validators did not sign last block. + // only applies after first block + if block.Height > 1 { + precommitLen := len(block.LastCommit.Precommits) + valSetLen := len(valSet.Validators) + if precommitLen != valSetLen { + // sanity check + panic(fmt.Sprintf("precommit length (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v", + precommitLen, valSetLen, block.Height, block.LastCommit.Precommits, valSet.Validators)) + } + } + + signVals := make([]abci.SigningValidator, len(valSet.Validators)) for i, val := range valSet.Validators { - vote := block.LastCommit.Precommits[i] + var vote *types.Vote + if i < len(block.LastCommit.Precommits) { + vote = block.LastCommit.Precommits[i] + } val := abci.SigningValidator{ Validator: types.TM2PB.Validator(val), SignedLastBlock: vote != nil, From e5bca1df6ffb5889037e765d8f80fd0a00448899 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 1 Jun 2018 00:00:28 -0400 Subject: [PATCH 11/30] update godep for abci --- Gopkg.lock | 11 ++++++----- Gopkg.toml | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 104c99a01..199a5298e 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -57,8 +57,11 @@ name = "github.com/gogo/protobuf" packages = [ "gogoproto", + "jsonpb", "proto", - "protoc-gen-gogo/descriptor" + "protoc-gen-gogo/descriptor", + "sortkeys", + "types" ] revision = "1adfc126b41513cc696b209667c8656ea7aac67c" version = "v1.0.0" @@ -66,12 +69,10 @@ [[projects]] name = "github.com/golang/protobuf" packages = [ - "jsonpb", "proto", "ptypes", "ptypes/any", "ptypes/duration", - "ptypes/struct", "ptypes/timestamp" ] revision = "925541529c1fa6821df4e44ce2723319eb2be768" @@ -237,8 +238,8 @@ "server", "types" ] - revision = "b1b784cfa837cfbcd14f3bb38d97c2a899ff882a" - version = "v0.11.0-rc2" + revision = "c681347ee3c4906b169d39ffc4def87714494cbd" + version = "v0.11.0-rc3" [[projects]] branch = "master" diff --git a/Gopkg.toml b/Gopkg.toml index 43b273f96..94bc945c7 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -71,7 +71,7 @@ [[constraint]] name = "github.com/tendermint/abci" - version = "~0.11.0-rc2" + version = "~0.11.0-rc3" [[constraint]] name = "github.com/tendermint/go-crypto" From 3d2c4fd309e54d3cee9e49e4bb8e3284bda85ec9 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 1 Jun 2018 15:27:59 -0400 Subject: [PATCH 12/30] update Evidence type - requires pubkey and valset to verify and convert to abci.Evidence --- consensus/replay.go | 2 +- state/execution.go | 84 ++++++++++++++++++++++++---------------- state/execution_test.go | 38 +++++++++++------- state/store.go | 5 ++- state/validation.go | 31 ++++++++------- state/validation_test.go | 2 +- types/evidence.go | 56 +++++++++++++-------------- types/evidence_test.go | 11 +++--- types/protobuf.go | 50 +++++++++++++----------- 9 files changed, 157 insertions(+), 122 deletions(-) diff --git a/consensus/replay.go b/consensus/replay.go index c4ee2d32d..b30a1f151 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -367,7 +367,7 @@ func (h *Handshaker) replayBlocks(state sm.State, proxyApp proxy.AppConns, appBl for i := appBlockHeight + 1; i <= finalBlock; i++ { h.logger.Info("Applying block", "height", i) block := h.store.LoadBlock(i) - appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger, state.LastValidators) + appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger, state.LastValidators, h.stateDB) if err != nil { return nil, err } diff --git a/state/execution.go b/state/execution.go index b65c2ebd7..370fa0954 100644 --- a/state/execution.go +++ b/state/execution.go @@ -73,7 +73,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b return state, ErrInvalidBlock(err) } - abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, s.LastValidators) + abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, s.LastValidators, blockExec.db) if err != nil { return state, ErrProxyAppConn(err) } @@ -158,7 +158,7 @@ func (blockExec *BlockExecutor) Commit(block *types.Block) ([]byte, error) { // Executes block's transactions on proxyAppConn. // Returns a list of transaction results and updates to the validator set func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, - block *types.Block, valSet *types.ValidatorSet) (*ABCIResponses, error) { + block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) (*ABCIResponses, error) { var validTxs, invalidTxs = 0, 0 txIndex := 0 @@ -184,42 +184,14 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, } proxyAppConn.SetResponseCallback(proxyCb) - // determine which validators did not sign last block. - // only applies after first block - if block.Height > 1 { - precommitLen := len(block.LastCommit.Precommits) - valSetLen := len(valSet.Validators) - if precommitLen != valSetLen { - // sanity check - panic(fmt.Sprintf("precommit length (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v", - precommitLen, valSetLen, block.Height, block.LastCommit.Precommits, valSet.Validators)) - } - } - - signVals := make([]abci.SigningValidator, len(valSet.Validators)) - for i, val := range valSet.Validators { - var vote *types.Vote - if i < len(block.LastCommit.Precommits) { - vote = block.LastCommit.Precommits[i] - } - val := abci.SigningValidator{ - Validator: types.TM2PB.Validator(val), - SignedLastBlock: vote != nil, - } - signVals[i] = val - } - - byzantineVals := make([]abci.Evidence, len(block.Evidence.Evidence)) - for i, ev := range block.Evidence.Evidence { - byzantineVals[i] = types.TM2PB.Evidence(ev) - } + signVals, byzVals := getBeginBlockValidatorInfo(block, lastValSet, stateDB) // Begin block _, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{ Hash: block.Hash(), Header: types.TM2PB.Header(block.Header), Validators: signVals, - ByzantineValidators: byzantineVals, + ByzantineValidators: byzVals, }) if err != nil { logger.Error("Error in proxyAppConn.BeginBlock", "err", err) @@ -251,6 +223,50 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, return abciResponses, nil } +func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) ([]abci.SigningValidator, []abci.Evidence) { + + // Sanity check that commit length matches validator set size - + // only applies after first block + if block.Height > 1 { + precommitLen := len(block.LastCommit.Precommits) + valSetLen := len(lastValSet.Validators) + if precommitLen != valSetLen { + // sanity check + panic(fmt.Sprintf("precommit length (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v", + precommitLen, valSetLen, block.Height, block.LastCommit.Precommits, lastValSet.Validators)) + } + } + + // determine which validators did not sign last block. + signVals := make([]abci.SigningValidator, len(lastValSet.Validators)) + for i, val := range lastValSet.Validators { + var vote *types.Vote + if i < len(block.LastCommit.Precommits) { + vote = block.LastCommit.Precommits[i] + } + val := abci.SigningValidator{ + Validator: types.TM2PB.Validator(val), + SignedLastBlock: vote != nil, + } + signVals[i] = val + } + + byzVals := make([]abci.Evidence, len(block.Evidence.Evidence)) + for i, ev := range block.Evidence.Evidence { + // We need the validator set. We already did this in validateBlock. + // TODO: Should we instead cache the valset in the evidence itself and add + // `SetValidatorSet()` and `ToABCI` methods ? + valset, err := LoadValidators(stateDB, ev.Height()) + if err != nil { + panic(err) // shoudn't happen + } + byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time) + } + + return signVals, byzVals + +} + // If more or equal than 1/3 of total voting power changed in one block, then // a light client could never prove the transition externally. See // ./lite/doc.go for details on how a light client tracks validators. @@ -371,8 +387,8 @@ func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *ty // ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state. // It returns the application root hash (result of abci.Commit). func ExecCommitBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block, - logger log.Logger, valSet *types.ValidatorSet) ([]byte, error) { - _, err := execBlockOnProxyApp(logger, appConnConsensus, block, valSet) + logger log.Logger, lastValSet *types.ValidatorSet, stateDB dbm.DB) ([]byte, error) { + _, err := execBlockOnProxyApp(logger, appConnConsensus, block, lastValSet, stateDB) if err != nil { logger.Error("Error executing block on proxy app", "height", block.Height, "err", err) return nil, err diff --git a/state/execution_test.go b/state/execution_test.go index e31a0fd13..b520b0c12 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -32,7 +32,7 @@ func TestApplyBlock(t *testing.T) { require.Nil(t, err) defer proxyApp.Stop() - state, stateDB := state(1), dbm.NewMemDB() + state, stateDB := state(1, 1) blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(), MockMempool{}, MockEvidencePool{}) @@ -55,7 +55,7 @@ func TestBeginBlockValidators(t *testing.T) { require.Nil(t, err) defer proxyApp.Stop() - state := state(2) + state, stateDB := state(2, 2) prevHash := state.LastBlockID.Hash prevParts := types.PartSetHeader{} @@ -78,8 +78,9 @@ func TestBeginBlockValidators(t *testing.T) { for _, tc := range testCases { lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: tc.lastCommitPrecommits} + // block for height 2 block, _ := state.MakeBlock(2, makeTxs(2), lastCommit) - _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators) + _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB) require.Nil(t, err, tc.desc) // -> app receives a list of validators with a bool indicating if they signed @@ -106,30 +107,31 @@ func TestBeginBlockByzantineValidators(t *testing.T) { require.Nil(t, err) defer proxyApp.Stop() - state := state(2) + state, stateDB := state(2, 12) prevHash := state.LastBlockID.Hash prevParts := types.PartSetHeader{} prevBlockID := types.BlockID{prevHash, prevParts} - height1, idx1, val1 := int64(8), 0, []byte("val1") - height2, idx2, val2 := int64(3), 1, []byte("val2") + height1, idx1, val1 := int64(8), 0, state.Validators.Validators[0].Address + height2, idx2, val2 := int64(3), 1, state.Validators.Validators[1].Address ev1 := types.NewMockGoodEvidence(height1, idx1, val1) ev2 := types.NewMockGoodEvidence(height2, idx2, val2) + now := time.Now() + valSet := state.Validators testCases := []struct { desc string evidence []types.Evidence expectedByzantineValidators []abci.Evidence }{ {"none byzantine", []types.Evidence{}, []abci.Evidence{}}, - {"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1)}}, + {"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1, valSet, now)}}, {"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{ - types.TM2PB.Evidence(ev1), - types.TM2PB.Evidence(ev2)}}, + types.TM2PB.Evidence(ev1, valSet, now), + types.TM2PB.Evidence(ev2, valSet, now)}}, } - now := time.Now().UTC() vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit} vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now} votes := []*types.Vote{vote0, vote1} @@ -137,8 +139,9 @@ func TestBeginBlockByzantineValidators(t *testing.T) { for _, tc := range testCases { block, _ := state.MakeBlock(10, makeTxs(2), lastCommit) + block.Time = now block.Evidence.Evidence = tc.evidence - _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators) + _, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB) require.Nil(t, err, tc.desc) // -> app must receive an index of the byzantine validator @@ -156,7 +159,7 @@ func makeTxs(height int64) (txs []types.Tx) { return txs } -func state(nVals int) State { +func state(nVals, height int) (State, dbm.DB) { vals := make([]types.GenesisValidator, nVals) for i := 0; i < nVals; i++ { secret := []byte(fmt.Sprintf("test%d", i)) @@ -170,7 +173,16 @@ func state(nVals int) State { Validators: vals, AppHash: nil, }) - return s + + // save validators to db for 2 heights + stateDB := dbm.NewMemDB() + SaveState(stateDB, s) + + for i := 1; i < height; i++ { + s.LastBlockHeight += 1 + SaveState(stateDB, s) + } + return s, stateDB } func makeBlock(state State, height int64) *types.Block { diff --git a/state/store.go b/state/store.go index 60acf9e1e..2164d699d 100644 --- a/state/store.go +++ b/state/store.go @@ -173,11 +173,12 @@ func LoadValidators(db dbm.DB, height int64) (*types.ValidatorSet, error) { } if valInfo.ValidatorSet == nil { - valInfo = loadValidatorsInfo(db, valInfo.LastHeightChanged) - if valInfo == nil { + valInfo2 := loadValidatorsInfo(db, valInfo.LastHeightChanged) + if valInfo2 == nil { cmn.PanicSanity(fmt.Sprintf(`Couldn't find validators at height %d as last changed from height %d`, valInfo.LastHeightChanged, height)) } + valInfo = valInfo2 } return valInfo.ValidatorSet, nil diff --git a/state/validation.go b/state/validation.go index 0726b61ea..ac133aff2 100644 --- a/state/validation.go +++ b/state/validation.go @@ -73,6 +73,9 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error { } } + // TODO: Each check requires loading an old validator set. + // We should cap the amount of evidence per block + // to prevent potential proposer DoS. for _, ev := range block.Evidence.Evidence { if err := VerifyEvidence(stateDB, state, ev); err != nil { return types.NewEvidenceInvalidErr(ev, err) @@ -82,11 +85,11 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error { return nil } -// XXX: What's cheaper (ie. what should be checked first): -// evidence internal validity (ie. sig checks) or validator existed (fetch historical val set from db) - -// VerifyEvidence verifies the evidence fully by checking it is internally -// consistent and sufficiently recent. +// VerifyEvidence verifies the evidence fully by checking: +// - it is sufficiently recent (MaxAge) +// - it is from a key who was a validator at the given height +// - it is internally consistent +// - it was properly signed by the alleged equivocator func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error { height := state.LastBlockHeight @@ -97,10 +100,6 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error evidence.Height(), height-maxAge) } - if err := evidence.Verify(state.ChainID); err != nil { - return err - } - valset, err := LoadValidators(stateDB, evidence.Height()) if err != nil { // TODO: if err is just that we cant find it cuz we pruned, ignore. @@ -108,14 +107,18 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error return err } - // The address must have been an active validator at the height + // The address must have been an active validator at the height. + // NOTE: we will ignore evidence from H if the key was not a validator + // at H, even if it is a validator at some nearby H' ev := evidence - height, addr, idx := ev.Height(), ev.Address(), ev.Index() - valIdx, val := valset.GetByAddress(addr) + height, addr := ev.Height(), ev.Address() + _, val := valset.GetByAddress(addr) if val == nil { return fmt.Errorf("Address %X was not a validator at height %d", addr, height) - } else if idx != valIdx { - return fmt.Errorf("Address %X was validator %d at height %d, not %d", addr, valIdx, height, idx) + } + + if err := evidence.Verify(s.ChainID, val.PubKey); err != nil { + return err } return nil diff --git a/state/validation_test.go b/state/validation_test.go index f72021975..b4695b077 100644 --- a/state/validation_test.go +++ b/state/validation_test.go @@ -9,7 +9,7 @@ import ( ) func TestValidateBlock(t *testing.T) { - state := state(1) + state, _ := state(1, 1) blockExec := NewBlockExecutor(dbm.NewMemDB(), log.TestingLogger(), nil, nil, nil) diff --git a/types/evidence.go b/types/evidence.go index ee7f44a58..1a823df07 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -28,12 +28,11 @@ func (err *ErrEvidenceInvalid) Error() string { // Evidence represents any provable malicious activity by a validator type Evidence interface { - Height() int64 // height of the equivocation - Address() []byte // address of the equivocating validator - Index() int // index of the validator in the validator set - Hash() []byte // hash of the evidence - Verify(chainID string) error // verify the evidence - Equal(Evidence) bool // check equality of evidence + Height() int64 // height of the equivocation + Address() []byte // address of the equivocating validator + Hash() []byte // hash of the evidence + Verify(chainID string, pubKey crypto.PubKey) error // verify the evidence + Equal(Evidence) bool // check equality of evidence String() string } @@ -68,11 +67,6 @@ func (dve *DuplicateVoteEvidence) Address() []byte { return dve.PubKey.Address() } -// Index returns the index of the validator. -func (dve *DuplicateVoteEvidence) Index() int { - return dve.VoteA.ValidatorIndex -} - // Hash returns the hash of the evidence. func (dve *DuplicateVoteEvidence) Hash() []byte { return aminoHasher(dve).Hash() @@ -80,7 +74,7 @@ func (dve *DuplicateVoteEvidence) Hash() []byte { // Verify returns an error if the two votes aren't conflicting. // To be conflicting, they must be from the same validator, for the same H/R/S, but for different blocks. -func (dve *DuplicateVoteEvidence) Verify(chainID string) error { +func (dve *DuplicateVoteEvidence) Verify(chainID string, pubKey crypto.PubKey) error { // H/R/S must be the same if dve.VoteA.Height != dve.VoteB.Height || dve.VoteA.Round != dve.VoteB.Round || @@ -92,7 +86,8 @@ func (dve *DuplicateVoteEvidence) Verify(chainID string) error { if !bytes.Equal(dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress) { return fmt.Errorf("DuplicateVoteEvidence Error: Validator addresses do not match. Got %X and %X", dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress) } - // XXX: Should we enforce index is the same ? + + // Index must be the same if dve.VoteA.ValidatorIndex != dve.VoteB.ValidatorIndex { return fmt.Errorf("DuplicateVoteEvidence Error: Validator indices do not match. Got %d and %d", dve.VoteA.ValidatorIndex, dve.VoteB.ValidatorIndex) } @@ -102,11 +97,18 @@ func (dve *DuplicateVoteEvidence) Verify(chainID string) error { return fmt.Errorf("DuplicateVoteEvidence Error: BlockIDs are the same (%v) - not a real duplicate vote", dve.VoteA.BlockID) } + // pubkey must match address (this should already be true, sanity check) + addr := dve.VoteA.ValidatorAddress + if !bytes.Equal(pubKey.Address(), addr) { + return fmt.Errorf("DuplicateVoteEvidence FAILED SANITY CHECK - address (%X) doesn't match pubkey (%v - %X)", + addr, pubKey, pubKey.Address()) + } + // Signatures must be valid - if !dve.PubKey.VerifyBytes(dve.VoteA.SignBytes(chainID), dve.VoteA.Signature) { + if !pubKey.VerifyBytes(dve.VoteA.SignBytes(chainID), dve.VoteA.Signature) { return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteA: %v", ErrVoteInvalidSignature) } - if !dve.PubKey.VerifyBytes(dve.VoteB.SignBytes(chainID), dve.VoteB.Signature) { + if !pubKey.VerifyBytes(dve.VoteB.SignBytes(chainID), dve.VoteB.Signature) { return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteB: %v", ErrVoteInvalidSignature) } @@ -131,29 +133,26 @@ func (dve *DuplicateVoteEvidence) Equal(ev Evidence) bool { type MockGoodEvidence struct { Height_ int64 Address_ []byte - Index_ int } // UNSTABLE -func NewMockGoodEvidence(height int64, index int, address []byte) MockGoodEvidence { - return MockGoodEvidence{height, address, index} +func NewMockGoodEvidence(height int64, idx int, address []byte) MockGoodEvidence { + return MockGoodEvidence{height, address} } func (e MockGoodEvidence) Height() int64 { return e.Height_ } func (e MockGoodEvidence) Address() []byte { return e.Address_ } -func (e MockGoodEvidence) Index() int { return e.Index_ } func (e MockGoodEvidence) Hash() []byte { - return []byte(fmt.Sprintf("%d-%d", e.Height_, e.Index_)) + return []byte(fmt.Sprintf("%d-%x", e.Height_, e.Address_)) } -func (e MockGoodEvidence) Verify(chainID string) error { return nil } +func (e MockGoodEvidence) Verify(chainID string, pubKey crypto.PubKey) error { return nil } func (e MockGoodEvidence) Equal(ev Evidence) bool { e2 := ev.(MockGoodEvidence) return e.Height_ == e2.Height_ && - bytes.Equal(e.Address_, e2.Address_) && - e.Index_ == e2.Index_ + bytes.Equal(e.Address_, e2.Address_) } func (e MockGoodEvidence) String() string { - return fmt.Sprintf("GoodEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_) + return fmt.Sprintf("GoodEvidence: %d/%s/%d", e.Height_, e.Address_) } // UNSTABLE @@ -161,15 +160,16 @@ type MockBadEvidence struct { MockGoodEvidence } -func (e MockBadEvidence) Verify(chainID string) error { return fmt.Errorf("MockBadEvidence") } +func (e MockBadEvidence) Verify(chainID string, pubKey crypto.PubKey) error { + return fmt.Errorf("MockBadEvidence") +} func (e MockBadEvidence) Equal(ev Evidence) bool { e2 := ev.(MockBadEvidence) return e.Height_ == e2.Height_ && - bytes.Equal(e.Address_, e2.Address_) && - e.Index_ == e2.Index_ + bytes.Equal(e.Address_, e2.Address_) } func (e MockBadEvidence) String() string { - return fmt.Sprintf("BadEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_) + return fmt.Sprintf("BadEvidence: %d/%s/%d", e.Height_, e.Address_) } //------------------------------------------- diff --git a/types/evidence_test.go b/types/evidence_test.go index f2b1f91bb..5bbb2a37d 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -59,17 +59,16 @@ func TestEvidence(t *testing.T) { {vote1, badVote, false}, // signed by wrong key } + pubKey := val.GetPubKey() for _, c := range cases { ev := &DuplicateVoteEvidence{ - PubKey: val.GetPubKey(), - VoteA: c.vote1, - VoteB: c.vote2, + VoteA: c.vote1, + VoteB: c.vote2, } if c.valid { - assert.Nil(t, ev.Verify(chainID), "evidence should be valid") + assert.Nil(t, ev.Verify(chainID, pubKey), "evidence should be valid") } else { - assert.NotNil(t, ev.Verify(chainID), "evidence should be invalid") + assert.NotNil(t, ev.Verify(chainID, pubKey), "evidence should be invalid") } } - } diff --git a/types/protobuf.go b/types/protobuf.go index 20cf8a561..608ebb653 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -3,6 +3,7 @@ package types import ( "fmt" "reflect" + "time" abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" @@ -75,34 +76,37 @@ func (tm2pb) ConsensusParams(params *ConsensusParams) *abci.ConsensusParams { } } -func (tm2pb) Evidence(ev_ Evidence) abci.Evidence { - switch ev := ev_.(type) { +// ABCI Evidence includes information from the past that's not included in the evidence itself +// so Evidence types stays compact. +func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.Evidence { + _, val := valSet.GetByAddress(ev.Address()) + if val == nil { + // should already have checked this + panic(val) + } + + abciEvidence := abci.Evidence{ + Validator: abci.Validator{ + Address: ev.Address(), + PubKey: TM2PB.PubKey(val.PubKey), + Power: val.VotingPower, + }, + Height: ev.Height(), + Time: evTime.Unix(), + TotalVotingPower: valSet.TotalVotingPower(), + } + + // set type + switch ev.(type) { case *DuplicateVoteEvidence: - return abci.Evidence{ - Type: "duplicate/vote", - Validator: abci.Validator{ - Address: ev.Address(), - // TODO - }, - Height: ev.Height(), - // Time: ev.Time(), - // TotalVotingPower: 10, - } + abciEvidence.Type = "duplicate/vote" case *MockGoodEvidence, MockGoodEvidence: - return abci.Evidence{ - Type: "mock/good", - Validator: abci.Validator{ - Address: ev.Address(), - // TODO - }, - Height: ev.Height(), - // Time: ev.Time(), - // TotalVotingPower: 10, - } + abciEvidence.Type = "mock/good" default: - panic(fmt.Sprintf("Unknown evidence type: %v %v", ev_, reflect.TypeOf(ev_))) + panic(fmt.Sprintf("Unknown evidence type: %v %v", ev, reflect.TypeOf(ev))) } + return abciEvidence } func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci.Validator { From 909f66e84183e18160e6b1f9914ef7b6543f40ca Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 1 Jun 2018 20:22:46 -0400 Subject: [PATCH 13/30] remove extra eventBus --- consensus/byzantine_test.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/consensus/byzantine_test.go b/consensus/byzantine_test.go index a8f559f60..d3be8c358 100644 --- a/consensus/byzantine_test.go +++ b/consensus/byzantine_test.go @@ -58,14 +58,11 @@ func TestByzantine(t *testing.T) { css[i].doPrevote = func(height int64, round int) {} } - eventBus := types.NewEventBus() + eventBus := css[i].eventBus eventBus.SetLogger(logger.With("module", "events", "validator", i)) - err := eventBus.Start() - require.NoError(t, err) - defer eventBus.Stop() eventChans[i] = make(chan interface{}, 1) - err = eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock, eventChans[i]) + err := eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock, eventChans[i]) require.NoError(t, err) conR := NewConsensusReactor(css[i], true) // so we dont start the consensus states From aa8be33da15b5d19bd9a762912b6323394bb0a24 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 1 Jun 2018 21:56:09 -0400 Subject: [PATCH 14/30] fix fmt --- types/evidence.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/evidence.go b/types/evidence.go index 1a823df07..10907869e 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -152,7 +152,7 @@ func (e MockGoodEvidence) Equal(ev Evidence) bool { bytes.Equal(e.Address_, e2.Address_) } func (e MockGoodEvidence) String() string { - return fmt.Sprintf("GoodEvidence: %d/%s/%d", e.Height_, e.Address_) + return fmt.Sprintf("GoodEvidence: %d/%s", e.Height_, e.Address_) } // UNSTABLE @@ -169,7 +169,7 @@ func (e MockBadEvidence) Equal(ev Evidence) bool { bytes.Equal(e.Address_, e2.Address_) } func (e MockBadEvidence) String() string { - return fmt.Sprintf("BadEvidence: %d/%s/%d", e.Height_, e.Address_) + return fmt.Sprintf("BadEvidence: %d/%s", e.Height_, e.Address_) } //------------------------------------------- From e2f5a6fbe45574743ba9e6a0409c8ce438a89431 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 1 Jun 2018 22:07:36 -0400 Subject: [PATCH 15/30] update abci --- Gopkg.lock | 10 ++-------- Gopkg.toml | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 199a5298e..6bfcbc9ec 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -238,8 +238,8 @@ "server", "types" ] - revision = "c681347ee3c4906b169d39ffc4def87714494cbd" - version = "v0.11.0-rc3" + revision = "9af8b7a7c87478869f8c280ed9539470b8f470b4" + version = "v0.11.0-rc4" [[projects]] branch = "master" @@ -263,12 +263,6 @@ revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19" version = "v0.6.2" -[[projects]] - name = "github.com/tendermint/go-wire" - packages = ["."] - revision = "3c22a7a539411f89a96738fcfa14c1027e24e5ec" - version = "0.9.10" - [[projects]] name = "github.com/tendermint/tmlibs" packages = [ diff --git a/Gopkg.toml b/Gopkg.toml index 94bc945c7..f0e8ab5b9 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -71,7 +71,7 @@ [[constraint]] name = "github.com/tendermint/abci" - version = "~0.11.0-rc3" + version = "~0.11.0-rc4" [[constraint]] name = "github.com/tendermint/go-crypto" From 5c7ccbd4a71f8da8c3f8c76109f20aef9b5c8335 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 2 Jun 2018 19:03:03 -0400 Subject: [PATCH 16/30] use const for abci type strings --- types/protobuf.go | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/types/protobuf.go b/types/protobuf.go index 608ebb653..dd9d8bb66 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -9,7 +9,22 @@ import ( crypto "github.com/tendermint/go-crypto" ) -// TM2PB is used for converting Tendermint abci to protobuf abci. +//------------------------------------------------------- +// Use strings to distinguish types in ABCI messages + +const ( + ABCIEvidenceTypeDuplicateVote = "duplicate/vote" + ABCIEvidenceTypeMockGood = "mock/good" +) + +const ( + ABCIPubKeyTypeEd25519 = "ed25519" + ABCIPubKeyTypeSecp256k1 = "secp256k1" +) + +//------------------------------------------------------- + +// TM2PB is used for converting Tendermint ABCI to protobuf ABCI. // UNSTABLE var TM2PB = tm2pb{} @@ -99,9 +114,9 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci. // set type switch ev.(type) { case *DuplicateVoteEvidence: - abciEvidence.Type = "duplicate/vote" + abciEvidence.Type = ABCIEvidenceTypeDuplicateVote case *MockGoodEvidence, MockGoodEvidence: - abciEvidence.Type = "mock/good" + abciEvidence.Type = ABCIEvidenceTypeMockGood default: panic(fmt.Sprintf("Unknown evidence type: %v %v", ev, reflect.TypeOf(ev))) } @@ -120,20 +135,28 @@ func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci //---------------------------------------------------------------------------- -// PB2TM is used for converting protobuf abci to Tendermint abci. +// PB2TM is used for converting protobuf ABCI to Tendermint ABCI. // UNSTABLE var PB2TM = pb2tm{} type pb2tm struct{} -// TODO: validate key lengths ... func (pb2tm) PubKey(pubKey abci.PubKey) (crypto.PubKey, error) { + // TODO: define these in go-crypto and use them + sizeEd := 32 + sizeSecp := 33 switch pubKey.Type { - case "ed25519": + case ABCIPubKeyTypeEd25519: + if len(pubKey.Data) != sizeEd { + return nil, fmt.Errorf("Invalid size for PubKeyEd25519. Got %d, expected %d", len(pubKey.Data), sizeEd) + } var pk crypto.PubKeyEd25519 copy(pk[:], pubKey.Data) return pk, nil - case "secp256k1": + case ABCIPubKeyTypeSecp256k1: + if len(pubKey.Data) != sizeSecp { + return nil, fmt.Errorf("Invalid size for PubKeyEd25519. Got %d, expected %d", len(pubKey.Data), sizeSecp) + } var pk crypto.PubKeySecp256k1 copy(pk[:], pubKey.Data) return pk, nil From 54e61468d44bc180e9efef4ce7a2b1fe5cb38a6c Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 5 Jun 2018 21:54:59 -0700 Subject: [PATCH 17/30] fixes from review --- state/execution.go | 2 +- types/protobuf.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/state/execution.go b/state/execution.go index 370fa0954..9ffd2be71 100644 --- a/state/execution.go +++ b/state/execution.go @@ -258,7 +258,7 @@ func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorS // `SetValidatorSet()` and `ToABCI` methods ? valset, err := LoadValidators(stateDB, ev.Height()) if err != nil { - panic(err) // shoudn't happen + panic(err) // shouldn't happen } byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time) } diff --git a/types/protobuf.go b/types/protobuf.go index dd9d8bb66..00e36215b 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -52,12 +52,12 @@ func (tm2pb) PubKey(pubKey crypto.PubKey) abci.PubKey { switch pk := pubKey.(type) { case crypto.PubKeyEd25519: return abci.PubKey{ - Type: "ed25519", + Type: ABCIPubKeyTypeEd25519, Data: pk[:], } case crypto.PubKeySecp256k1: return abci.PubKey{ - Type: "secp256k1", + Type: ABCIPubKeyTypeSecp256k1, Data: pk[:], } default: From 71556c62eb35683d0b213d67db157a35cada41aa Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 5 Jun 2018 22:14:37 -0700 Subject: [PATCH 18/30] fixes from rebase --- Gopkg.lock | 2 +- state/execution.go | 2 +- state/validation.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 6bfcbc9ec..5413c3a0a 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -374,6 +374,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "bdcf814c0cd3b8d6cc11ad03da556abe169f872a45e6dcbd8b08588b4587ddde" + inputs-digest = "6d7d755329cebd1f640324a38507c41b638ca0898737db9d633c75eff58c46f0" solver-name = "gps-cdcl" solver-version = 1 diff --git a/state/execution.go b/state/execution.go index 9ffd2be71..435b29ee6 100644 --- a/state/execution.go +++ b/state/execution.go @@ -73,7 +73,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b return state, ErrInvalidBlock(err) } - abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, s.LastValidators, blockExec.db) + abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, state.LastValidators, blockExec.db) if err != nil { return state, ErrProxyAppConn(err) } diff --git a/state/validation.go b/state/validation.go index ac133aff2..84a4cc824 100644 --- a/state/validation.go +++ b/state/validation.go @@ -117,7 +117,7 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error return fmt.Errorf("Address %X was not a validator at height %d", addr, height) } - if err := evidence.Verify(s.ChainID, val.PubKey); err != nil { + if err := evidence.Verify(state.ChainID, val.PubKey); err != nil { return err } From 2897685c57e3a8b7f13fa1a7b87fed76db1bc58e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jun 2018 00:28:12 -0700 Subject: [PATCH 19/30] abci header takes ValidatorsHash --- Gopkg.lock | 8 ++++---- Gopkg.toml | 2 +- types/protobuf.go | 13 +++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 5413c3a0a..20ae605a1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -238,8 +238,8 @@ "server", "types" ] - revision = "9af8b7a7c87478869f8c280ed9539470b8f470b4" - version = "v0.11.0-rc4" + revision = "7cf66f570e2f47b286985e2d688b0a400c028e4c" + version = "v0.11.0-rc6" [[projects]] branch = "master" @@ -293,7 +293,7 @@ "ripemd160", "salsa20/salsa" ] - revision = "df8d4716b3472e4a531c33cedbe537dae921a1a9" + revision = "b47b1587369238182299fe4dad77d05b8b461e06" [[projects]] branch = "master" @@ -374,6 +374,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "6d7d755329cebd1f640324a38507c41b638ca0898737db9d633c75eff58c46f0" + inputs-digest = "132980da98fc92b6c0dd988df07316a340f5fc91ee77593cf984ade4e3e5fd62" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index f0e8ab5b9..f95fb2961 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -71,7 +71,7 @@ [[constraint]] name = "github.com/tendermint/abci" - version = "~0.11.0-rc4" + version = "~0.11.0-rc6" [[constraint]] name = "github.com/tendermint/go-crypto" diff --git a/types/protobuf.go b/types/protobuf.go index 00e36215b..bfe3df343 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -32,12 +32,13 @@ type tm2pb struct{} func (tm2pb) Header(header *Header) abci.Header { return abci.Header{ - ChainID: header.ChainID, - Height: header.Height, - Time: header.Time.Unix(), - NumTxs: int32(header.NumTxs), // XXX: overflow - LastBlockHash: header.LastBlockID.Hash, - AppHash: header.AppHash, + ChainID: header.ChainID, + Height: header.Height, + Time: header.Time.Unix(), + NumTxs: int32(header.NumTxs), // XXX: overflow + LastBlockHash: header.LastBlockID.Hash, + ValidatorsHash: header.ValidatorsHash, + AppHash: header.AppHash, } } From fe4123684d4a02cbc53eacf93458724ccc8c6d91 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Wed, 6 Jun 2018 11:07:10 -0700 Subject: [PATCH 20/30] Change reset messages (#1699) --- cmd/tendermint/commands/reset_priv_validator.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/tendermint/commands/reset_priv_validator.go b/cmd/tendermint/commands/reset_priv_validator.go index cf4b7c575..78744db71 100644 --- a/cmd/tendermint/commands/reset_priv_validator.go +++ b/cmd/tendermint/commands/reset_priv_validator.go @@ -13,14 +13,14 @@ import ( // instance. var ResetAllCmd = &cobra.Command{ Use: "unsafe_reset_all", - Short: "(unsafe) Remove all the data and WAL, reset this node's validator", + Short: "(unsafe) Remove all the data and WAL, reset this node's validator to genesis state", Run: resetAll, } // ResetPrivValidatorCmd resets the private validator files. var ResetPrivValidatorCmd = &cobra.Command{ Use: "unsafe_reset_priv_validator", - Short: "(unsafe) Reset this node's validator", + Short: "(unsafe) Reset this node's validator to genesis state", Run: resetPrivValidator, } @@ -32,7 +32,7 @@ func ResetAll(dbDir, privValFile string, logger log.Logger) { logger.Error("Error removing directory", "err", err) return } - logger.Info("Removed all data", "dir", dbDir) + logger.Info("Removed all blockchain history", "dir", dbDir) } // XXX: this is totally unsafe. @@ -52,7 +52,7 @@ func resetFilePV(privValFile string, logger log.Logger) { if _, err := os.Stat(privValFile); err == nil { pv := privval.LoadFilePV(privValFile) pv.Reset() - logger.Info("Reset PrivValidator", "file", privValFile) + logger.Info("Reset PrivValidator to genesis state", "file", privValFile) } else { pv := privval.GenFilePV(privValFile) pv.Save() From 2edc68c59bea3e242011b5bb308df2f399d5548b Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jun 2018 13:07:17 -0700 Subject: [PATCH 21/30] use all fields in abci types --- types/protobuf.go | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/types/protobuf.go b/types/protobuf.go index bfe3df343..d1b0ae7fb 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -32,20 +32,26 @@ type tm2pb struct{} func (tm2pb) Header(header *Header) abci.Header { return abci.Header{ - ChainID: header.ChainID, - Height: header.Height, - Time: header.Time.Unix(), - NumTxs: int32(header.NumTxs), // XXX: overflow + ChainID: header.ChainID, + Height: header.Height, + + Time: header.Time.Unix(), + NumTxs: int32(header.NumTxs), // XXX: overflow + TotalTxs: header.NumTxs, + LastBlockHash: header.LastBlockID.Hash, ValidatorsHash: header.ValidatorsHash, AppHash: header.AppHash, + + // Proposer: TODO } } func (tm2pb) Validator(val *Validator) abci.Validator { return abci.Validator{ - PubKey: TM2PB.PubKey(val.PubKey), - Power: val.VotingPower, + Address: val.PubKey.Address(), + PubKey: TM2PB.PubKey(val.PubKey), + Power: val.VotingPower, } } @@ -101,28 +107,24 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci. panic(val) } - abciEvidence := abci.Evidence{ - Validator: abci.Validator{ - Address: ev.Address(), - PubKey: TM2PB.PubKey(val.PubKey), - Power: val.VotingPower, - }, - Height: ev.Height(), - Time: evTime.Unix(), - TotalVotingPower: valSet.TotalVotingPower(), - } - // set type + var evType string switch ev.(type) { case *DuplicateVoteEvidence: - abciEvidence.Type = ABCIEvidenceTypeDuplicateVote + evType = ABCIEvidenceTypeDuplicateVote case *MockGoodEvidence, MockGoodEvidence: - abciEvidence.Type = ABCIEvidenceTypeMockGood + evType = ABCIEvidenceTypeMockGood default: panic(fmt.Sprintf("Unknown evidence type: %v %v", ev, reflect.TypeOf(ev))) } - return abciEvidence + return abci.Evidence{ + Type: evType, + Validator: TM2PB.Validator(val), + Height: ev.Height(), + Time: evTime.Unix(), + TotalVotingPower: valSet.TotalVotingPower(), + } } func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci.Validator { From 8e45348737d3c5b412a470385d2654f245ea2efa Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jun 2018 15:47:04 -0700 Subject: [PATCH 22/30] update for abci v0.11.0 release. let InitChain update validators --- CHANGELOG.md | 16 +++++++++++-- Gopkg.lock | 8 +++---- Gopkg.toml | 2 +- consensus/replay.go | 18 ++++++++++++-- consensus/replay_test.go | 51 ++++++++++++++++++++++++++++++++++++++++ types/protobuf.go | 16 +++++++++++++ version/version.go | 6 ++--- 7 files changed, 105 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3de2157e..97c3dfb44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,20 @@ # Changelog -## 0.19.10 +## 0.20.0 + +*June 6th, 2018* + +BREAKING CHANGES + +- [abci] Upgrade to + [v0.11.0](https://github.com/tendermint/abci/blob/master/CHANGELOG.md#0110) + +NOTE: this release does not break any blockchain data structures or +protocols other than the ABCI messages between Tendermint and the application. + +Applications that upgrade for ABCI v0.11.0 should be able to continue running Tendermint +v0.20.0 on blockchains created with v0.19.X -*TBD* ## 0.19.9 diff --git a/Gopkg.lock b/Gopkg.lock index 20ae605a1..f21e38427 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -238,8 +238,8 @@ "server", "types" ] - revision = "7cf66f570e2f47b286985e2d688b0a400c028e4c" - version = "v0.11.0-rc6" + revision = "ebee2fe114020aa49c70bbbae50b7079fc7e7b90" + version = "v0.11.0" [[projects]] branch = "master" @@ -313,7 +313,7 @@ branch = "master" name = "golang.org/x/sys" packages = ["unix"] - revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f" + revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb" [[projects]] name = "golang.org/x/text" @@ -374,6 +374,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "132980da98fc92b6c0dd988df07316a340f5fc91ee77593cf984ade4e3e5fd62" + inputs-digest = "ae6792578b0664708339f4c05e020687d6b799ad6f8282394b919de69e403d1f" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index f95fb2961..77a6af9b5 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -71,7 +71,7 @@ [[constraint]] name = "github.com/tendermint/abci" - version = "~0.11.0-rc6" + version = "~0.11.0" [[constraint]] name = "github.com/tendermint/go-crypto" diff --git a/consensus/replay.go b/consensus/replay.go index b30a1f151..c0c300b37 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -267,17 +267,31 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight // If appBlockHeight == 0 it means that we are at genesis and hence should send InitChain if appBlockHeight == 0 { validators := types.TM2PB.Validators(state.Validators) + csParams := types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams) req := abci.RequestInitChain{ Time: h.genDoc.GenesisTime.Unix(), // TODO ChainId: h.genDoc.ChainID, - ConsensusParams: types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams), + ConsensusParams: csParams, Validators: validators, AppStateBytes: h.genDoc.AppStateJSON, } - _, err := proxyApp.Consensus().InitChainSync(req) + res, err := proxyApp.Consensus().InitChainSync(req) if err != nil { return nil, err } + + // update the state + if len(res.Validators) > 0 { + vals, err := types.PB2TM.Validators(res.Validators) + if err != nil { + return nil, err + } + state.Validators = types.NewValidatorSet(vals) + } + if res.ConsensusParams != nil { + // TODO + } + sm.SaveState(h.stateDB, state) } // First handle edge cases and constraints on the storeBlockHeight diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 2836110c1..725568ed5 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -13,6 +13,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/abci/example/kvstore" @@ -634,3 +635,53 @@ func (bs *mockBlockStore) LoadBlockCommit(height int64) *types.Commit { func (bs *mockBlockStore) LoadSeenCommit(height int64) *types.Commit { return bs.commits[height-1] } + +//---------------------------------------- + +func TestInitChainUpdateValidators(t *testing.T) { + val, _ := types.RandValidator(true, 10) + vals := types.NewValidatorSet([]*types.Validator{val}) + app := &initChainApp{vals: types.TM2PB.Validators(vals)} + clientCreator := proxy.NewLocalClientCreator(app) + + config := ResetConfig("proxy_test_") + privVal := privval.LoadFilePV(config.PrivValidatorFile()) + stateDB, state, store := stateAndStore(config, privVal.GetPubKey()) + + oldValAddr := state.Validators.Validators[0].Address + + // now start the app using the handshake - it should sync + genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile()) + handshaker := NewHandshaker(stateDB, state, store, genDoc) + proxyApp := proxy.NewAppConns(clientCreator, handshaker) + if err := proxyApp.Start(); err != nil { + t.Fatalf("Error starting proxy app connections: %v", err) + } + defer proxyApp.Stop() + + // reload the state, check the validator set was updated + state = sm.LoadState(stateDB) + + newValAddr := state.Validators.Validators[0].Address + expectValAddr := val.Address + assert.NotEqual(t, oldValAddr, newValAddr) + assert.Equal(t, newValAddr, expectValAddr) +} + +func newInitChainApp(vals []abci.Validator) *initChainApp { + return &initChainApp{ + vals: vals, + } +} + +// returns the vals on InitChain +type initChainApp struct { + abci.BaseApplication + vals []abci.Validator +} + +func (ica *initChainApp) InitChain(req abci.RequestInitChain) abci.ResponseInitChain { + return abci.ResponseInitChain{ + Validators: ica.vals, + } +} diff --git a/types/protobuf.go b/types/protobuf.go index d1b0ae7fb..730c60052 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -167,3 +167,19 @@ func (pb2tm) PubKey(pubKey abci.PubKey) (crypto.PubKey, error) { return nil, fmt.Errorf("Unknown pubkey type %v", pubKey.Type) } } + +func (pb2tm) Validators(vals []abci.Validator) ([]*Validator, error) { + tmVals := make([]*Validator, len(vals)) + for i, v := range vals { + pub, err := PB2TM.PubKey(v.PubKey) + if err != nil { + return nil, err + } + tmVals[i] = &Validator{ + Address: v.Address, + PubKey: pub, + VotingPower: v.Power, + } + } + return tmVals, nil +} diff --git a/version/version.go b/version/version.go index 1296657da..2c9c88c09 100644 --- a/version/version.go +++ b/version/version.go @@ -3,14 +3,14 @@ package version // Version components const ( Maj = "0" - Min = "19" - Fix = "10" + Min = "20" + Fix = "0" ) var ( // Version is the current version of Tendermint // Must be a string because scripts like dist.sh read this file. - Version = "0.19.10-dev" + Version = "0.20.0-dev" // GitCommit is the current HEAD set using ldflags. GitCommit string From c661a3ec214671fe322c1bb8510e240bb8ba7a13 Mon Sep 17 00:00:00 2001 From: Alexander Simmerl Date: Thu, 7 Jun 2018 01:09:13 +0200 Subject: [PATCH 23/30] Fix race when mutating MConnConfig Instead of mutating the passed in MConnConfig part of P2PConfig we just use the default and override the values, the same as before as it was always the default version. This is yet another good reason to not embed information and access to config structs in our components and will go away with the ongoing refactoring in #1325. --- config/config.go | 8 ++------ p2p/peer.go | 3 ++- p2p/peer_test.go | 12 ++++++++---- p2p/switch.go | 15 ++++++++++----- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/config/config.go b/config/config.go index a5a212f59..a508d6b4a 100644 --- a/config/config.go +++ b/config/config.go @@ -5,8 +5,6 @@ import ( "os" "path/filepath" "time" - - tmconn "github.com/tendermint/tendermint/p2p/conn" ) const ( @@ -304,9 +302,8 @@ type P2PConfig struct { AllowDuplicateIP bool `mapstructure:"allow_duplicate_ip"` // Peer connection configuration. - HandshakeTimeout time.Duration `mapstructure:"handshake_timeout"` - DialTimeout time.Duration `mapstructure:"dial_timeout"` - MConfig tmconn.MConnConfig `mapstructure:"connection"` + HandshakeTimeout time.Duration `mapstructure:"handshake_timeout"` + DialTimeout time.Duration `mapstructure:"dial_timeout"` // Testing params. // Force dial to fail @@ -332,7 +329,6 @@ func DefaultP2PConfig() *P2PConfig { AllowDuplicateIP: true, // so non-breaking yet HandshakeTimeout: 20 * time.Second, DialTimeout: 3 * time.Second, - MConfig: tmconn.DefaultMConnConfig(), TestDialFail: false, TestFuzz: false, TestFuzzConfig: DefaultFuzzConnConfig(), diff --git a/p2p/peer.go b/p2p/peer.go index 73e2eac20..da69fe74f 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -102,6 +102,7 @@ type peer struct { func newPeer( pc peerConn, + mConfig tmconn.MConnConfig, nodeInfo NodeInfo, reactorsByCh map[byte]Reactor, chDescs []*tmconn.ChannelDescriptor, @@ -120,7 +121,7 @@ func newPeer( reactorsByCh, chDescs, onPeerError, - pc.config.MConfig, + mConfig, ) p.BaseService = *cmn.NewBaseService(nil, "Peer", p) diff --git a/p2p/peer_test.go b/p2p/peer_test.go index d4781c658..3a477199d 100644 --- a/p2p/peer_test.go +++ b/p2p/peer_test.go @@ -27,7 +27,7 @@ func TestPeerBasic(t *testing.T) { rp.Start() defer rp.Stop() - p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), cfg) + p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), cfg, tmconn.DefaultMConnConfig()) require.Nil(err) err = p.Start() @@ -53,7 +53,7 @@ func TestPeerSend(t *testing.T) { rp.Start() defer rp.Stop() - p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), config) + p, err := createOutboundPeerAndPerformHandshake(rp.Addr(), config, tmconn.DefaultMConnConfig()) require.Nil(err) err = p.Start() @@ -65,7 +65,11 @@ func TestPeerSend(t *testing.T) { assert.True(p.Send(testCh, []byte("Asylum"))) } -func createOutboundPeerAndPerformHandshake(addr *NetAddress, config *config.P2PConfig) (*peer, error) { +func createOutboundPeerAndPerformHandshake( + addr *NetAddress, + config *config.P2PConfig, + mConfig tmconn.MConnConfig, +) (*peer, error) { chDescs := []*tmconn.ChannelDescriptor{ {ID: testCh, Priority: 1}, } @@ -86,7 +90,7 @@ func createOutboundPeerAndPerformHandshake(addr *NetAddress, config *config.P2PC return nil, err } - p := newPeer(pc, nodeInfo, reactorsByCh, chDescs, func(p Peer, r interface{}) {}) + p := newPeer(pc, mConfig, nodeInfo, reactorsByCh, chDescs, func(p Peer, r interface{}) {}) p.SetLogger(log.TestingLogger().With("peer", addr)) return p, nil } diff --git a/p2p/switch.go b/p2p/switch.go index 9068aa113..f1ceee5c6 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -70,6 +70,8 @@ type Switch struct { filterConnByAddr func(net.Addr) error filterConnByID func(ID) error + mConfig conn.MConnConfig + rng *cmn.Rand // seed for randomizing dial times and orders } @@ -88,10 +90,13 @@ func NewSwitch(cfg *config.P2PConfig) *Switch { // Ensure we have a completely undeterministic PRNG. sw.rng = cmn.NewRand() - sw.config.MConfig.FlushThrottle = time.Duration(cfg.FlushThrottleTimeout) * time.Millisecond - sw.config.MConfig.SendRate = cfg.SendRate - sw.config.MConfig.RecvRate = cfg.RecvRate - sw.config.MConfig.MaxPacketMsgPayloadSize = cfg.MaxPacketMsgPayloadSize + mConfig := conn.DefaultMConnConfig() + mConfig.FlushThrottle = time.Duration(cfg.FlushThrottleTimeout) * time.Millisecond + mConfig.SendRate = cfg.SendRate + mConfig.RecvRate = cfg.RecvRate + mConfig.MaxPacketMsgPayloadSize = cfg.MaxPacketMsgPayloadSize + + sw.mConfig = mConfig sw.BaseService = *cmn.NewBaseService(nil, "P2P Switch", sw) return sw @@ -600,7 +605,7 @@ func (sw *Switch) addPeer(pc peerConn) error { return err } - peer := newPeer(pc, peerNodeInfo, sw.reactorsByCh, sw.chDescs, sw.StopPeerForError) + peer := newPeer(pc, sw.mConfig, peerNodeInfo, sw.reactorsByCh, sw.chDescs, sw.StopPeerForError) peer.SetLogger(sw.Logger.With("peer", addr)) peer.Logger.Info("Successful handshake with peer", "peerNodeInfo", peerNodeInfo) From 8be27494bb7e8a0f492ee8db99bf190790ccd45d Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jun 2018 16:11:58 -0700 Subject: [PATCH 24/30] update abci spec. add address spec --- docs/spec/blockchain/encoding.md | 37 ++++++++++++++++++++++++++------ docs/spec/consensus/abci.md | 25 +++++++++++++++------ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/docs/spec/blockchain/encoding.md b/docs/spec/blockchain/encoding.md index c60f7035f..aa1842107 100644 --- a/docs/spec/blockchain/encoding.md +++ b/docs/spec/blockchain/encoding.md @@ -49,14 +49,14 @@ spec](https://github.com/tendermint/go-amino#computing-the-prefix-and-disambigua In what follows, we provide the type names and prefix bytes directly. Notice that when encoding byte-arrays, the length of the byte-array is appended to the PrefixBytes. Thus the encoding of a byte array becomes ` - `. In other words, to encode any type listed below you do not need to be -familiar with amino encoding. -You can simply use below table and concatenate Prefix || Length (of raw bytes) || raw bytes + `. In other words, to encode any type listed below you do not need to be +familiar with amino encoding. +You can simply use below table and concatenate Prefix || Length (of raw bytes) || raw bytes ( while || stands for byte concatenation here). | Type | Name | Prefix | Length | -| ---- | ---- | ------ | ----- | -| PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE62 | 0x20 | +| ---- | ---- | ------ | ----- | +| PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE62 | 0x20 | | PubKeyLedgerEd25519 | tendermint/PubKeyLedgerEd25519 | 0x5C3453B2 | 0x20 | | PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE982 | 0x21 | | PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288912 | 0x40 | @@ -69,7 +69,7 @@ You can simply use below table and concatenate Prefix || Length (of raw bytes) | ### Examples 1. For example, the 33-byte (or 0x21-byte in hex) Secp256k1 pubkey -`020BD40F225A57ED383B440CF073BC5539D0341F5767D2BF2D78406D00475A2EE9` +`020BD40F225A57ED383B440CF073BC5539D0341F5767D2BF2D78406D00475A2EE9` would be encoded as `EB5AE98221020BD40F225A57ED383B440CF073BC5539D0341F5767D2BF2D78406D00475A2EE9` @@ -78,6 +78,31 @@ would be encoded as would be encoded as `16E1FEEA46304402201CD4B8C764D2FD8AF23ECFE6666CA8A53886D47754D951295D2D311E1FEA33BF02201E0F906BB1CF2C30EAACFFB032A7129358AFF96B9F79B06ACFFB18AC90C2ADD7` +### Addresses + +Addresses for each public key types are computed as follows: + +#### Ed25519 + +RIPEMD160 hash of the Amino encoded public key: + +``` +address = RIPEMD160(AMINO(pubkey)) +``` + +NOTE: this will soon change to the truncated 20-bytes of the SHA256 of the raw +public key + +#### Secp256k1 + +RIPEMD160 hash of the SHA256 hash of the OpenSSL compressed public key: + +``` +address = RIPEMD160(SHA256(pubkey)) +``` + +This is the same as Bitcoin. + ## Other Common Types ### BitArray diff --git a/docs/spec/consensus/abci.md b/docs/spec/consensus/abci.md index aa09cf3ad..e6d865400 100644 --- a/docs/spec/consensus/abci.md +++ b/docs/spec/consensus/abci.md @@ -52,20 +52,33 @@ objects in the `ResponseBeginBlock`: ``` message Validator { - bytes pub_key = 1; - int64 power = 2; + bytes address = 1; + PubKey pub_key = 2; + int64 power = 3; } + +message PubKey { + string type = 1; + bytes data = 2; +} + ``` -The `pub_key` is the Amino encoded public key for the validator. For details on -Amino encoded public keys, see the [section of the encoding spec](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography). +The `pub_key` currently supports two types: + - `type = "ed25519" and `data = ` + - `type = "secp256k1" and `data = <33-byte OpenSSL compressed public key>` + +If the address is provided, it must match the address of the pubkey, as +specified [here](/docs/spec/blockchain/encoding.md#Addresses) +(Note: In the v0.19 series, the `pub_key` is the [Amino encoded public +key](/docs/spec/blockchain/encoding.md#public-key-cryptography). For Ed25519 pubkeys, the Amino prefix is always "1624DE6220". For example, the 32-byte Ed25519 pubkey `76852933A4686A721442E931A8415F62F5F1AEDF4910F1F252FB393F74C40C85` would be Amino encoded as -`1624DE622076852933A4686A721442E931A8415F62F5F1AEDF4910F1F252FB393F74C40C85` +`1624DE622076852933A4686A721442E931A8415F62F5F1AEDF4910F1F252FB393F74C40C85`) -(Note: in old versions of Tendermint (pre-v0.19.0), the pubkey is just prefixed with a +(Note: In old versions of Tendermint (pre-v0.19.0), the pubkey is just prefixed with a single type byte, so for ED25519 we'd have `pub_key = 0x1 | pub`) The `power` is the new voting power for the validator, with the From 6b8613b3e77de0711a4f646a55ef795e571e7d69 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jun 2018 16:12:14 -0700 Subject: [PATCH 25/30] ResponseEndBlock: ensure Address matches PubKey if provided --- state/execution.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/state/execution.go b/state/execution.go index 435b29ee6..ec37e0d13 100644 --- a/state/execution.go +++ b/state/execution.go @@ -1,6 +1,7 @@ package state import ( + "bytes" "fmt" fail "github.com/ebuchman/fail-test" @@ -278,6 +279,16 @@ func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator) } address := pubkey.Address() + + // If the app provided an address too, it must match. + // This is just a sanity check. + if len(v.Address) > 0 { + if !bytes.Equal(address, v.Address) { + return fmt.Errorf("Validator.Address (%X) does not match PubKey.Address (%X)", + v.Address, address) + } + } + power := int64(v.Power) // mind the overflow from int64 if power < 0 { From 89925501f353d7ebd9742909ed40820cc72c05da Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jun 2018 16:13:51 -0700 Subject: [PATCH 26/30] p2p/filter/pubkey -> p2p/filter/id --- CHANGELOG.md | 2 ++ docs/spec/consensus/abci.md | 2 +- node/node.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97c3dfb44..019b8e04d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ BREAKING CHANGES - [abci] Upgrade to [v0.11.0](https://github.com/tendermint/abci/blob/master/CHANGELOG.md#0110) +- [abci] Query path for filtering peers by node ID changed from + `p2p/filter/pubkey/` to `p2p/filter/id/` NOTE: this release does not break any blockchain data structures or protocols other than the ABCI messages between Tendermint and the application. diff --git a/docs/spec/consensus/abci.md b/docs/spec/consensus/abci.md index e6d865400..2669a78e1 100644 --- a/docs/spec/consensus/abci.md +++ b/docs/spec/consensus/abci.md @@ -107,7 +107,7 @@ using the following paths, with no additional data: - `/p2p/filter/addr/`, where `` denote the IP address and the port of the connection - - `p2p/filter/pubkey/`, where `` is the peer node ID (ie. the + - `p2p/filter/id/`, where `` is the peer node ID (ie. the pubkey.Address() for the peer's PubKey) If either of these queries return a non-zero ABCI code, Tendermint will refuse diff --git a/node/node.go b/node/node.go index a8b5c9b2f..efeb17ee0 100644 --- a/node/node.go +++ b/node/node.go @@ -302,7 +302,7 @@ func NewNode(config *cfg.Config, return nil }) sw.SetIDFilter(func(id p2p.ID) error { - resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: cmn.Fmt("/p2p/filter/pubkey/%s", id)}) + resQuery, err := proxyApp.Query().QuerySync(abci.RequestQuery{Path: cmn.Fmt("/p2p/filter/id/%s", id)}) if err != nil { return err } From fcf61b80881a671a2eca69672bc47fee2e1c8034 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jun 2018 16:32:31 -0700 Subject: [PATCH 27/30] check addrs match pubkeys in abci Validator. version bump --- CHANGELOG.md | 16 ++++++++------ docs/spec/consensus/abci.md | 13 +++++++++++ state/execution.go | 43 +++++++++++-------------------------- types/protobuf.go | 11 +++++++++- version/version.go | 2 +- 5 files changed, 46 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 019b8e04d..e7f9baf2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,19 +4,21 @@ *June 6th, 2018* -BREAKING CHANGES - -- [abci] Upgrade to - [v0.11.0](https://github.com/tendermint/abci/blob/master/CHANGELOG.md#0110) -- [abci] Query path for filtering peers by node ID changed from - `p2p/filter/pubkey/` to `p2p/filter/id/` +This is the first in a series of breaking releases coming to Tendermint after +soliciting developer feedback and conducting security audits. -NOTE: this release does not break any blockchain data structures or +This release does not break any blockchain data structures or protocols other than the ABCI messages between Tendermint and the application. Applications that upgrade for ABCI v0.11.0 should be able to continue running Tendermint v0.20.0 on blockchains created with v0.19.X +BREAKING CHANGES + +- [abci] Upgrade to + [v0.11.0](https://github.com/tendermint/abci/blob/master/CHANGELOG.md#0110) +- [abci] Change Query path for filtering peers by node ID from + `p2p/filter/pubkey/` to `p2p/filter/id/` ## 0.19.9 diff --git a/docs/spec/consensus/abci.md b/docs/spec/consensus/abci.md index 2669a78e1..9c9e6a58b 100644 --- a/docs/spec/consensus/abci.md +++ b/docs/spec/consensus/abci.md @@ -92,6 +92,19 @@ following rules: set with the given power - if the validator does already exist, its power will be adjusted to the given power +## InitChain Validator Updates + +ResponseInitChain has the option to return a list of validators. +If the list is not empty, Tendermint will adopt it for the validator set. +This way the application can determine the initial validator set for the +blockchain. + +Note that if addressses are included in the returned validators, they must match +the address of the public key. + +ResponseInitChain also includes ConsensusParams, but these are presently +ignored. + ## Query Query is a generic message type with lots of flexibility to enable diverse sets diff --git a/state/execution.go b/state/execution.go index ec37e0d13..e6b94429e 100644 --- a/state/execution.go +++ b/state/execution.go @@ -1,7 +1,6 @@ package state import ( - "bytes" "fmt" fail "github.com/ebuchman/fail-test" @@ -271,38 +270,23 @@ func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorS // If more or equal than 1/3 of total voting power changed in one block, then // a light client could never prove the transition externally. See // ./lite/doc.go for details on how a light client tracks validators. -func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator) error { - for _, v := range updates { - pubkey, err := types.PB2TM.PubKey(v.PubKey) - if err != nil { - return err - } - - address := pubkey.Address() - - // If the app provided an address too, it must match. - // This is just a sanity check. - if len(v.Address) > 0 { - if !bytes.Equal(address, v.Address) { - return fmt.Errorf("Validator.Address (%X) does not match PubKey.Address (%X)", - v.Address, address) - } - } - - power := int64(v.Power) - // mind the overflow from int64 - if power < 0 { - return fmt.Errorf("Power (%d) overflows int64", v.Power) - } +func updateValidators(currentSet *types.ValidatorSet, abciUpdates []abci.Validator) error { + updates, err := types.PB2TM.Validators(abciUpdates) + if err != nil { + return err + } + // these are tendermint types now + for _, valUpdate := range updates { + address := valUpdate.Address _, val := currentSet.GetByAddress(address) if val == nil { // add val - added := currentSet.Add(types.NewValidator(pubkey, power)) + added := currentSet.Add(valUpdate) if !added { - return fmt.Errorf("Failed to add new validator %X with voting power %d", address, power) + return fmt.Errorf("Failed to add new validator %v", valUpdate) } - } else if v.Power == 0 { + } else if valUpdate.VotingPower == 0 { // remove val _, removed := currentSet.Remove(address) if !removed { @@ -310,10 +294,9 @@ func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator) } } else { // update val - val.VotingPower = power - updated := currentSet.Update(val) + updated := currentSet.Update(valUpdate) if !updated { - return fmt.Errorf("Failed to update validator %X with voting power %d", address, power) + return fmt.Errorf("Failed to update validator %X to %v", address, valUpdate) } } } diff --git a/types/protobuf.go b/types/protobuf.go index 730c60052..90ec8dab3 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "fmt" "reflect" "time" @@ -175,8 +176,16 @@ func (pb2tm) Validators(vals []abci.Validator) ([]*Validator, error) { if err != nil { return nil, err } + // If the app provided an address too, it must match. + // This is just a sanity check. + if len(v.Address) > 0 { + if !bytes.Equal(pub.Address(), v.Address) { + return nil, fmt.Errorf("Validator.Address (%X) does not match PubKey.Address (%X)", + v.Address, pub.Address()) + } + } tmVals[i] = &Validator{ - Address: v.Address, + Address: pub.Address(), PubKey: pub, VotingPower: v.Power, } diff --git a/version/version.go b/version/version.go index 2c9c88c09..e6c1815b5 100644 --- a/version/version.go +++ b/version/version.go @@ -10,7 +10,7 @@ const ( var ( // Version is the current version of Tendermint // Must be a string because scripts like dist.sh read this file. - Version = "0.20.0-dev" + Version = "0.20.0" // GitCommit is the current HEAD set using ldflags. GitCommit string From a6a4fc7784f876bc6f58ca533ddaa72e77cba366 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Tue, 5 Jun 2018 20:28:57 -0700 Subject: [PATCH 28/30] docs: Add BSD install script --- docs/install.rst | 6 ++- scripts/install/install_tendermint_bsd.sh | 54 +++++++++++++++++++ .../install_tendermint_ubuntu.sh} | 0 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 scripts/install/install_tendermint_bsd.sh rename scripts/{install_tendermint.sh => install/install_tendermint_ubuntu.sh} (100%) diff --git a/docs/install.rst b/docs/install.rst index 63a4bb654..7ae87eae7 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -2,7 +2,11 @@ Install Tendermint ================== The fastest and easiest way to install the ``tendermint`` binary -is to run `this script `__ on a fresh Ubuntu instance. Read the comments / instructions carefully (i.e., reset your terminal after running the script). +is to run `this script `__ on +a fresh Ubuntu instance, +or `this script `__ +on a fresh FreeBSD instance. Read the comments / instructions carefully (i.e., reset your terminal after running the script, +make sure your okay with the network connections being made). From Binary ----------- diff --git a/scripts/install/install_tendermint_bsd.sh b/scripts/install/install_tendermint_bsd.sh new file mode 100644 index 000000000..aba584f2e --- /dev/null +++ b/scripts/install/install_tendermint_bsd.sh @@ -0,0 +1,54 @@ +#!/usr/bin/tcsh + +# XXX: this script is intended to be run from +# a fresh Digital Ocean droplet with FreeBSD +# Just run tcsh install_tendermint_bsd.sh + +# upon its completion, you must either reset +# your terminal or run `source ~/.tcshrc` + +# This assumes your installing it through tcsh as root. +# Change the relevant lines from tcsh to csh if your +# installing as a different user, along with changing the +# gopath. + +# change this to a specific release or branch +set BRANCH=master + +sudo pkg update + +sudo pkg upgrade -y +sudo pkg install -y gmake +sudo pkg install -y git + +# get and unpack golang +curl -O https://storage.googleapis.com/golang/go1.10.freebsd-amd64.tar.gz +tar -xvf go1.10.freebsd-amd64.tar.gz + +# move go binary and add to path +mv go /usr/local +set path=($path /usr/local/go/bin) + + +# create the go directory, set GOPATH, and put it on PATH +mkdir go +echo "setenv GOPATH /root/go" >> ~/.tcshrc +setenv GOPATH /root/go +echo "set path=($path $GOPATH/bin)" >> ~/.tcshrc + +source ~/.tcshrc + +# get the code and move into repo +set REPO=github.com/tendermint/tendermint +go get $REPO +cd $GOPATH/src/$REPO + +# build & install master +git checkout $BRANCH +gmake get_tools +gmake get_vendor_deps +gmake install + +# the binary is located in $GOPATH/bin +# run `source ~/.profile` or reset your terminal +# to persist the changes diff --git a/scripts/install_tendermint.sh b/scripts/install/install_tendermint_ubuntu.sh similarity index 100% rename from scripts/install_tendermint.sh rename to scripts/install/install_tendermint_ubuntu.sh From 9481cabd5011b5b8cb51e1467aa033de93845797 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jun 2018 20:45:20 -0700 Subject: [PATCH 29/30] fixes from review --- consensus/replay.go | 6 ++++-- p2p/pex/pex_reactor.go | 2 +- types/protobuf.go | 31 +++++++++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/consensus/replay.go b/consensus/replay.go index c0c300b37..13ec9e403 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -280,7 +280,9 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight return nil, err } - // update the state + // if the app returned validators + // or consensus params, update the state + // with the them if len(res.Validators) > 0 { vals, err := types.PB2TM.Validators(res.Validators) if err != nil { @@ -289,7 +291,7 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight state.Validators = types.NewValidatorSet(vals) } if res.ConsensusParams != nil { - // TODO + state.ConsensusParams = types.PB2TM.ConsensusParams(res.ConsensusParams) } sm.SaveState(h.stateDB, state) } diff --git a/p2p/pex/pex_reactor.go b/p2p/pex/pex_reactor.go index 457e54278..27ed422c5 100644 --- a/p2p/pex/pex_reactor.go +++ b/p2p/pex/pex_reactor.go @@ -267,7 +267,7 @@ func (r *PEXReactor) receiveRequest(src Peer) error { now := time.Now() minInterval := r.minReceiveRequestInterval() if now.Sub(lastReceived) < minInterval { - return fmt.Errorf("Peer (%v) send next PEX request too soon. lastReceived: %v, now: %v, minInterval: %v. Disconnecting", + return fmt.Errorf("Peer (%v) sent next PEX request too soon. lastReceived: %v, now: %v, minInterval: %v. Disconnecting", src.ID(), lastReceived, now, diff --git a/types/protobuf.go b/types/protobuf.go index 90ec8dab3..eb684ae7d 100644 --- a/types/protobuf.go +++ b/types/protobuf.go @@ -38,7 +38,7 @@ func (tm2pb) Header(header *Header) abci.Header { Time: header.Time.Unix(), NumTxs: int32(header.NumTxs), // XXX: overflow - TotalTxs: header.NumTxs, + TotalTxs: header.TotalTxs, LastBlockHash: header.LastBlockID.Hash, ValidatorsHash: header.ValidatorsHash, @@ -48,6 +48,7 @@ func (tm2pb) Header(header *Header) abci.Header { } } +// XXX: panics on unknown pubkey type func (tm2pb) Validator(val *Validator) abci.Validator { return abci.Validator{ Address: val.PubKey.Address(), @@ -56,6 +57,8 @@ func (tm2pb) Validator(val *Validator) abci.Validator { } } +// XXX: panics on nil or unknown pubkey type +// TODO: add cases when new pubkey types are added to go-crypto func (tm2pb) PubKey(pubKey crypto.PubKey) abci.PubKey { switch pk := pubKey.(type) { case crypto.PubKeyEd25519: @@ -73,6 +76,7 @@ func (tm2pb) PubKey(pubKey crypto.PubKey) abci.PubKey { } } +// XXX: panics on nil or unknown pubkey type func (tm2pb) Validators(vals *ValidatorSet) []abci.Validator { validators := make([]abci.Validator, len(vals.Validators)) for i, val := range vals.Validators { @@ -101,6 +105,7 @@ func (tm2pb) ConsensusParams(params *ConsensusParams) *abci.ConsensusParams { // ABCI Evidence includes information from the past that's not included in the evidence itself // so Evidence types stays compact. +// XXX: panics on nil or unknown pubkey type func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.Evidence { _, val := valSet.GetByAddress(ev.Address()) if val == nil { @@ -113,7 +118,8 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci. switch ev.(type) { case *DuplicateVoteEvidence: evType = ABCIEvidenceTypeDuplicateVote - case *MockGoodEvidence, MockGoodEvidence: + case MockGoodEvidence: + // XXX: not great to have test types in production paths ... evType = ABCIEvidenceTypeMockGood default: panic(fmt.Sprintf("Unknown evidence type: %v %v", ev, reflect.TypeOf(ev))) @@ -128,6 +134,7 @@ func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci. } } +// XXX: panics on nil or unknown pubkey type func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci.Validator { pubkeyABCI := TM2PB.PubKey(pubkey) return abci.Validator{ @@ -192,3 +199,23 @@ func (pb2tm) Validators(vals []abci.Validator) ([]*Validator, error) { } return tmVals, nil } + +func (pb2tm) ConsensusParams(csp *abci.ConsensusParams) ConsensusParams { + return ConsensusParams{ + BlockSize: BlockSize{ + MaxBytes: int(csp.BlockSize.MaxBytes), // XXX + MaxTxs: int(csp.BlockSize.MaxTxs), // XXX + MaxGas: csp.BlockSize.MaxGas, + }, + TxSize: TxSize{ + MaxBytes: int(csp.TxSize.MaxBytes), // XXX + MaxGas: csp.TxSize.MaxGas, + }, + BlockGossip: BlockGossip{ + BlockPartSizeBytes: int(csp.BlockGossip.BlockPartSizeBytes), // XXX + }, + // TODO: EvidenceParams: EvidenceParams{ + // MaxAge: int(csp.Evidence.MaxAge), // XXX + // }, + } +} From 76c82fd433d147545b95743774635482823bbc10 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jun 2018 20:49:00 -0700 Subject: [PATCH 30/30] add more tests --- types/protobuf_test.go | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 types/protobuf_test.go diff --git a/types/protobuf_test.go b/types/protobuf_test.go new file mode 100644 index 000000000..9f3b31873 --- /dev/null +++ b/types/protobuf_test.go @@ -0,0 +1,69 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" + abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" +) + +func TestABCIPubKey(t *testing.T) { + pkEd := crypto.GenPrivKeyEd25519().PubKey() + pkSecp := crypto.GenPrivKeySecp256k1().PubKey() + testABCIPubKey(t, pkEd, ABCIPubKeyTypeEd25519) + testABCIPubKey(t, pkSecp, ABCIPubKeyTypeSecp256k1) +} + +func testABCIPubKey(t *testing.T, pk crypto.PubKey, typeStr string) { + abciPubKey := TM2PB.PubKey(pk) + pk2, err := PB2TM.PubKey(abciPubKey) + assert.Nil(t, err) + assert.Equal(t, pk, pk2) +} + +func TestABCIValidators(t *testing.T) { + pkEd := crypto.GenPrivKeyEd25519().PubKey() + + // correct validator + tmValExpected := &Validator{ + Address: pkEd.Address(), + PubKey: pkEd, + VotingPower: 10, + } + + tmVal := &Validator{ + Address: pkEd.Address(), + PubKey: pkEd, + VotingPower: 10, + } + + abciVal := TM2PB.Validator(tmVal) + tmVals, err := PB2TM.Validators([]abci.Validator{abciVal}) + assert.Nil(t, err) + assert.Equal(t, tmValExpected, tmVals[0]) + + // val with address + tmVal.Address = pkEd.Address() + + abciVal = TM2PB.Validator(tmVal) + tmVals, err = PB2TM.Validators([]abci.Validator{abciVal}) + assert.Nil(t, err) + assert.Equal(t, tmValExpected, tmVals[0]) + + // val with incorrect address + abciVal = TM2PB.Validator(tmVal) + abciVal.Address = []byte("incorrect!") + tmVals, err = PB2TM.Validators([]abci.Validator{abciVal}) + assert.NotNil(t, err) + assert.Nil(t, tmVals) +} + +func TestABCIConsensusParams(t *testing.T) { + cp := DefaultConsensusParams() + cp.EvidenceParams.MaxAge = 0 // TODO add this to ABCI + abciCP := TM2PB.ConsensusParams(cp) + cp2 := PB2TM.ConsensusParams(abciCP) + + assert.Equal(t, *cp, cp2) +}