From e13c1ab7358c8c1fede53ee757d26466dab9ce2a Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 31 May 2018 11:09:37 -0400 Subject: [PATCH 01/18] 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 fff269b6..104c99a0 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 0c34ea03..43b273f9 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 02/18] update types --- types/protobuf.go | 51 ++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/types/protobuf.go b/types/protobuf.go index e7ae20e3..828294d8 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 03/18] more types --- types/protobuf.go | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/types/protobuf.go b/types/protobuf.go index 828294d8..bb7b7107 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 04/18] state compiles --- state/execution.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/state/execution.go b/state/execution.go index 77091159..45f3daab 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 05/18] 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 45f3daab..86da99c5 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 bb7b7107..48cc0202 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 06/18] 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 13d665f7..a51c07bb 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 4f834346..57204b01 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 38bed4ac..f61af15f 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 5da57665..a8b5c9b2 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 48cc0202..2e772faf 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 07/18] 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 b6c7f9a6..2d14f35f 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 49769537..464456ca 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 2e772faf..a0347450 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 08/18] 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 86da99c5..052510e8 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 2d14f35f..e31a0fd1 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 e0b7fe9e..f7202197 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 a0347450..20cf8a56 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 09/18] 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 058bf1e7..0d997119 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 a51c07bb..c4ee2d32 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 e0f8a4b9..2836110c 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 052510e8..b65c2ebd 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 10/18] 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 104c99a0..199a5298 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 43b273f9..94bc945c 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 11/18] 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 | 56 ++++++++++++++------------- 9 files changed, 160 insertions(+), 125 deletions(-) diff --git a/consensus/replay.go b/consensus/replay.go index c4ee2d32..b30a1f15 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 b65c2ebd..370fa095 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 e31a0fd1..b520b0c1 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 60acf9e1..2164d699 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 0726b61e..ac133aff 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 f7202197..b4695b07 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 ee7f44a5..1a823df0 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 f2b1f91b..5bbb2a37 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 20cf8a56..608ebb65 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) { - case *DuplicateVoteEvidence: - return abci.Evidence{ - Type: "duplicate/vote", - Validator: abci.Validator{ - Address: ev.Address(), - // TODO - }, - Height: ev.Height(), - // 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_))) +// 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: + abciEvidence.Type = "duplicate/vote" + case *MockGoodEvidence, MockGoodEvidence: + abciEvidence.Type = "mock/good" + default: + 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 12/18] 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 a8f559f6..d3be8c35 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 13/18] fix fmt --- types/evidence.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/evidence.go b/types/evidence.go index 1a823df0..10907869 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 14/18] update abci --- Gopkg.lock | 10 ++-------- Gopkg.toml | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 199a5298..6bfcbc9e 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 94bc945c..f0e8ab5b 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 15/18] 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 608ebb65..dd9d8bb6 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 16/18] 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 370fa095..9ffd2be7 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 dd9d8bb6..00e36215 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 17/18] 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 6bfcbc9e..5413c3a0 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 9ffd2be7..435b29ee 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 ac133aff..84a4cc82 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 18/18] 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 5413c3a0..20ae605a 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 f0e8ab5b..f95fb296 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 00e36215..bfe3df34 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, } }