diff --git a/blockchain/store_test.go b/blockchain/store_test.go index 9c8fdb23..e1a63270 100644 --- a/blockchain/store_test.go +++ b/blockchain/store_test.go @@ -69,7 +69,7 @@ var ( partSet = block.MakePartSet(2) part1 = partSet.GetPart(0) part2 = partSet.GetPart(1) - seenCommit1 = &types.Commit{Precommits: []*types.Vote{{Height: 10, + seenCommit1 = &types.Commit{Precommits: []*types.UnsignedVote{{Height: 10, Timestamp: tmtime.Now()}}} ) @@ -90,7 +90,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) { // save a block block := makeBlock(bs.Height()+1, state) validPartSet := block.MakePartSet(2) - seenCommit := &types.Commit{Precommits: []*types.Vote{{Height: 10, + seenCommit := &types.Commit{Precommits: []*types.UnsignedVote{{Height: 10, Timestamp: tmtime.Now()}}} bs.SaveBlock(block, partSet, seenCommit) require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed") @@ -110,7 +110,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) { // End of setup, test data - commitAtH10 := &types.Commit{Precommits: []*types.Vote{{Height: 10, + commitAtH10 := &types.Commit{Precommits: []*types.UnsignedVote{{Height: 10, Timestamp: tmtime.Now()}}} tuples := []struct { block *types.Block @@ -334,7 +334,7 @@ func TestBlockFetchAtHeight(t *testing.T) { block := makeBlock(bs.Height()+1, state) partSet := block.MakePartSet(2) - seenCommit := &types.Commit{Precommits: []*types.Vote{{Height: 10, + seenCommit := &types.Commit{Precommits: []*types.UnsignedVote{{Height: 10, Timestamp: tmtime.Now()}}} bs.SaveBlock(block, partSet, seenCommit) diff --git a/consensus/common_test.go b/consensus/common_test.go index d7e66148..b2aeea2c 100644 --- a/consensus/common_test.go +++ b/consensus/common_test.go @@ -70,8 +70,8 @@ func NewValidatorStub(privValidator types.PrivValidator, valIndex int) *validato } } -func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) { - vote := &types.Vote{ +func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartSetHeader) (*types.UnsignedVote, error) { + vote := &types.UnsignedVote{ ValidatorIndex: vs.Index, ValidatorAddress: vs.PrivValidator.GetAddress(), Height: vs.Height, @@ -85,7 +85,7 @@ func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartS } // Sign vote for type/hash/header -func signVote(vs *validatorStub, voteType byte, hash []byte, header types.PartSetHeader) *types.Vote { +func signVote(vs *validatorStub, voteType byte, hash []byte, header types.PartSetHeader) *types.UnsignedVote { v, err := vs.signVote(voteType, hash, header) if err != nil { panic(fmt.Errorf("failed to sign vote: %v", err)) @@ -93,8 +93,8 @@ func signVote(vs *validatorStub, voteType byte, hash []byte, header types.PartSe return v } -func signVotes(voteType byte, hash []byte, header types.PartSetHeader, vss ...*validatorStub) []*types.Vote { - votes := make([]*types.Vote, len(vss)) +func signVotes(voteType byte, hash []byte, header types.PartSetHeader, vss ...*validatorStub) []*types.UnsignedVote { + votes := make([]*types.UnsignedVote, len(vss)) for i, vs := range vss { votes[i] = signVote(vs, voteType, hash, header) } @@ -137,7 +137,7 @@ func decideProposal(cs1 *ConsensusState, vs *validatorStub, height int64, round return } -func addVotes(to *ConsensusState, votes ...*types.Vote) { +func addVotes(to *ConsensusState, votes ...*types.UnsignedVote) { for _, vote := range votes { to.peerMsgQueue <- msgInfo{Msg: &VoteMessage{vote}} } @@ -150,7 +150,7 @@ func signAddVotes(to *ConsensusState, voteType byte, hash []byte, header types.P func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *validatorStub, blockHash []byte) { prevotes := cs.Votes.Prevotes(round) - var vote *types.Vote + var vote *types.UnsignedVote if vote = prevotes.GetByAddress(privVal.GetAddress()); vote == nil { panic("Failed to find prevote from validator") } @@ -167,7 +167,7 @@ func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *valid func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorStub, blockHash []byte) { votes := cs.LastCommit - var vote *types.Vote + var vote *types.UnsignedVote if vote = votes.GetByAddress(privVal.GetAddress()); vote == nil { panic("Failed to find precommit from validator") } @@ -178,7 +178,7 @@ func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorS func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) { precommits := cs.Votes.Precommits(thisRound) - var vote *types.Vote + var vote *types.UnsignedVote if vote = precommits.GetByAddress(privVal.GetAddress()); vote == nil { panic("Failed to find precommit from validator") } diff --git a/consensus/reactor.go b/consensus/reactor.go index 6ba81726..474e1589 100644 --- a/consensus/reactor.go +++ b/consensus/reactor.go @@ -359,7 +359,7 @@ func (conR *ConsensusReactor) subscribeToBroadcastEvents() { conR.conS.evsw.AddListenerForEvent(subscriber, types.EventVote, func(data tmevents.EventData) { - conR.broadcastHasVoteMessage(data.(*types.Vote)) + conR.broadcastHasVoteMessage(data.(*types.UnsignedVote)) }) conR.conS.evsw.AddListenerForEvent(subscriber, types.EventProposalHeartbeat, @@ -391,7 +391,7 @@ func (conR *ConsensusReactor) broadcastNewRoundStepMessages(rs *cstypes.RoundSta } // Broadcasts HasVoteMessage to peers that care. -func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote) { +func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.UnsignedVote) { msg := &HasVoteMessage{ Height: vote.Height, Round: vote.Round, @@ -953,7 +953,7 @@ func (ps *PeerState) PickSendVote(votes types.VoteSetReader) bool { // PickVoteToSend picks a vote to send to the peer. // Returns true if a vote was picked. // NOTE: `votes` must be the correct Size() for the Height(). -func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.Vote, ok bool) { +func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.UnsignedVote, ok bool) { ps.mtx.Lock() defer ps.mtx.Unlock() @@ -1083,7 +1083,7 @@ func (ps *PeerState) ensureVoteBitArrays(height int64, numValidators int) { // RecordVote updates internal statistics for this peer by recording the vote. // It returns the total number of votes (1 per block). This essentially means // the number of blocks for which peer has been sending us votes. -func (ps *PeerState) RecordVote(vote *types.Vote) int { +func (ps *PeerState) RecordVote(vote *types.UnsignedVote) int { ps.mtx.Lock() defer ps.mtx.Unlock() @@ -1131,7 +1131,7 @@ func (ps *PeerState) BlockPartsSent() int { } // SetHasVote sets the given vote as known by the peer -func (ps *PeerState) SetHasVote(vote *types.Vote) { +func (ps *PeerState) SetHasVote(vote *types.UnsignedVote) { ps.mtx.Lock() defer ps.mtx.Unlock() @@ -1299,7 +1299,7 @@ func RegisterConsensusMessages(cdc *amino.Codec) { cdc.RegisterConcrete(&ProposalMessage{}, "tendermint/Proposal", nil) cdc.RegisterConcrete(&ProposalPOLMessage{}, "tendermint/ProposalPOL", nil) cdc.RegisterConcrete(&BlockPartMessage{}, "tendermint/BlockPart", nil) - cdc.RegisterConcrete(&VoteMessage{}, "tendermint/Vote", nil) + cdc.RegisterConcrete(&VoteMessage{}, "tendermint/UnsignedVote", nil) cdc.RegisterConcrete(&HasVoteMessage{}, "tendermint/HasVote", nil) cdc.RegisterConcrete(&VoteSetMaj23Message{}, "tendermint/VoteSetMaj23", nil) cdc.RegisterConcrete(&VoteSetBitsMessage{}, "tendermint/VoteSetBits", nil) @@ -1390,12 +1390,12 @@ func (m *BlockPartMessage) String() string { // VoteMessage is sent when voting for a proposal (or lack thereof). type VoteMessage struct { - Vote *types.Vote + Vote *types.UnsignedVote } // String returns a string representation. func (m *VoteMessage) String() string { - return fmt.Sprintf("[Vote %v]", m.Vote) + return fmt.Sprintf("[UnsignedVote %v]", m.Vote) } //------------------------------------- diff --git a/consensus/reactor_test.go b/consensus/reactor_test.go index 98b058b8..8e3a0cbc 100644 --- a/consensus/reactor_test.go +++ b/consensus/reactor_test.go @@ -317,7 +317,7 @@ func TestReactorRecordsVotes(t *testing.T) { _, val := css[0].state.Validators.GetByIndex(0) // 1) new vote - vote := &types.Vote{ + vote := &types.UnsignedVote{ ValidatorIndex: 0, ValidatorAddress: val.Address, Height: 2, diff --git a/consensus/replay.go b/consensus/replay.go index c92654f2..925ff4f5 100644 --- a/consensus/replay.go +++ b/consensus/replay.go @@ -78,7 +78,7 @@ func (cs *ConsensusState) readReplayMessage(msg *TimedWALMessage, newStepCh chan cs.Logger.Info("Replay: BlockPart", "height", msg.Height, "round", msg.Round, "peer", peerID) case *VoteMessage: v := msg.Vote - cs.Logger.Info("Replay: Vote", "height", v.Height, "round", v.Round, "type", v.Type, + cs.Logger.Info("Replay: UnsignedVote", "height", v.Height, "round", v.Round, "type", v.Type, "blockID", v.BlockID, "peer", peerID) } diff --git a/consensus/replay_test.go b/consensus/replay_test.go index 7a828da6..2b50023e 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -541,11 +541,11 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) { if err != nil { return nil, nil, err } - case *types.Vote: + case *types.UnsignedVote: if p.Type == types.VoteTypePrecommit { thisBlockCommit = &types.Commit{ BlockID: p.BlockID, - Precommits: []*types.Vote{p}, + Precommits: []*types.UnsignedVote{p}, } } } diff --git a/consensus/state.go b/consensus/state.go index bee0f893..c10c5db5 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -357,7 +357,7 @@ func (cs *ConsensusState) OpenWAL(walFile string) (WAL, error) { // TODO: should these return anything or let callers just use events? // AddVote inputs a vote. -func (cs *ConsensusState) AddVote(vote *types.Vote, peerID p2p.ID) (added bool, err error) { +func (cs *ConsensusState) AddVote(vote *types.UnsignedVote, peerID p2p.ID) (added bool, err error) { if peerID == "" { cs.internalMsgQueue <- msgInfo{&VoteMessage{vote}, ""} } else { @@ -961,7 +961,6 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts return block, parts } - // Enter: `timeoutPropose` after entering Propose. // Enter: proposal block and POL is ready. // Enter: any +2/3 prevotes for future round. @@ -1352,7 +1351,7 @@ func (cs *ConsensusState) recordMetrics(height int64, block *types.Block) { missingValidators := 0 missingValidatorsPower := int64(0) for i, val := range cs.Validators.Validators { - var vote *types.Vote + var vote *types.UnsignedVote if i < len(block.LastCommit.Precommits) { vote = block.LastCommit.Precommits[i] } @@ -1488,7 +1487,7 @@ func (cs *ConsensusState) addProposalBlockPart(msg *BlockPartMessage, peerID p2p } // Attempt to add the vote. if its a duplicate signature, dupeout the validator -func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) error { +func (cs *ConsensusState) tryAddVote(vote *types.UnsignedVote, peerID p2p.ID) error { _, err := cs.addVote(vote, peerID) if err != nil { // If the vote height is off, we'll just ignore it, @@ -1515,7 +1514,7 @@ func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) error { //----------------------------------------------------------------------------- -func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool, err error) { +func (cs *ConsensusState) addVote(vote *types.UnsignedVote, peerID p2p.ID) (added bool, err error) { cs.Logger.Debug("addVote", "voteHeight", vote.Height, "voteType", vote.Type, "valIndex", vote.ValidatorIndex, "csHeight", cs.Height) // A precommit for the previous height? @@ -1549,7 +1548,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool, // Not necessarily a bad peer, but not favourable behaviour. if vote.Height != cs.Height { err = ErrVoteHeightMismatch - cs.Logger.Info("Vote ignored and not added", "voteHeight", vote.Height, "csHeight", cs.Height, "err", err) + cs.Logger.Info("UnsignedVote ignored and not added", "voteHeight", vote.Height, "csHeight", cs.Height, "err", err) return } @@ -1653,11 +1652,11 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool, return } -func (cs *ConsensusState) signVote(type_ byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) { +func (cs *ConsensusState) signVote(type_ byte, hash []byte, header types.PartSetHeader) (*types.UnsignedVote, error) { addr := cs.privValidator.GetAddress() valIndex, _ := cs.Validators.GetByAddress(addr) - vote := &types.Vote{ + vote := &types.UnsignedVote{ ValidatorAddress: addr, ValidatorIndex: valIndex, Height: cs.Height, @@ -1688,7 +1687,7 @@ func (cs *ConsensusState) voteTime() time.Time { } // sign the vote and publish on internalMsgQueue -func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.PartSetHeader) *types.Vote { +func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.PartSetHeader) *types.UnsignedVote { // if we don't have a key or we're not in the validator set, do nothing if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetAddress()) { return nil diff --git a/consensus/types/height_vote_set.go b/consensus/types/height_vote_set.go index 1c8ac67c..021ea5d4 100644 --- a/consensus/types/height_vote_set.go +++ b/consensus/types/height_vote_set.go @@ -109,7 +109,7 @@ func (hvs *HeightVoteSet) addRound(round int) { // Duplicate votes return added=false, err=nil. // By convention, peerID is "" if origin is self. -func (hvs *HeightVoteSet) AddVote(vote *types.Vote, peerID p2p.ID) (added bool, err error) { +func (hvs *HeightVoteSet) AddVote(vote *types.UnsignedVote, peerID p2p.ID) (added bool, err error) { hvs.mtx.Lock() defer hvs.mtx.Unlock() if !types.IsVoteTypeValid(vote.Type) { diff --git a/consensus/types/height_vote_set_test.go b/consensus/types/height_vote_set_test.go index 5f469221..6381d09b 100644 --- a/consensus/types/height_vote_set_test.go +++ b/consensus/types/height_vote_set_test.go @@ -48,9 +48,9 @@ func TestPeerCatchupRounds(t *testing.T) { } -func makeVoteHR(t *testing.T, height int64, round int, privVals []types.PrivValidator, valIndex int) *types.Vote { +func makeVoteHR(t *testing.T, height int64, round int, privVals []types.PrivValidator, valIndex int) *types.UnsignedVote { privVal := privVals[valIndex] - vote := &types.Vote{ + vote := &types.UnsignedVote{ ValidatorAddress: privVal.GetAddress(), ValidatorIndex: valIndex, Height: height, diff --git a/consensus/types/round_state_test.go b/consensus/types/round_state_test.go index a330981f..6695b429 100644 --- a/consensus/types/round_state_test.go +++ b/consensus/types/round_state_test.go @@ -16,7 +16,7 @@ func BenchmarkRoundStateDeepCopy(b *testing.B) { // Random validators nval, ntxs := 100, 100 vset, _ := types.RandValidatorSet(nval, 1) - precommits := make([]*types.Vote, nval) + precommits := make([]*types.UnsignedVote, nval) blockID := types.BlockID{ Hash: cmn.RandBytes(20), PartsHeader: types.PartSetHeader{ @@ -25,7 +25,7 @@ func BenchmarkRoundStateDeepCopy(b *testing.B) { } sig := make([]byte, ed25519.SignatureSize) for i := 0; i < nval; i++ { - precommits[i] = &types.Vote{ + precommits[i] = &types.UnsignedVote{ ValidatorAddress: types.Address(cmn.RandBytes(20)), Timestamp: tmtime.Now(), BlockID: blockID, diff --git a/lite/helpers.go b/lite/helpers.go index 16d22e70..a6ebf035 100644 --- a/lite/helpers.go +++ b/lite/helpers.go @@ -70,7 +70,7 @@ func (pkz privKeys) ToValidators(init, inc int64) *types.ValidatorSet { // signHeader properly signs the header with all keys from first to last exclusive. func (pkz privKeys) signHeader(header *types.Header, first, last int) *types.Commit { - votes := make([]*types.Vote, len(pkz)) + votes := make([]*types.UnsignedVote, len(pkz)) // We need this list to keep the ordering. vset := pkz.ToValidators(1, 0) @@ -88,10 +88,10 @@ func (pkz privKeys) signHeader(header *types.Header, first, last int) *types.Com return res } -func makeVote(header *types.Header, valset *types.ValidatorSet, key crypto.PrivKey) *types.Vote { +func makeVote(header *types.Header, valset *types.ValidatorSet, key crypto.PrivKey) *types.UnsignedVote { addr := key.PubKey().Address() idx, _ := valset.GetByAddress(addr) - vote := &types.Vote{ + vote := &types.UnsignedVote{ ValidatorAddress: addr, ValidatorIndex: idx, Height: header.Height, diff --git a/privval/priv_validator.go b/privval/priv_validator.go index 3ba0519c..eef6de8b 100644 --- a/privval/priv_validator.go +++ b/privval/priv_validator.go @@ -23,7 +23,7 @@ const ( stepPrecommit int8 = 3 ) -func voteToStep(vote *types.Vote) int8 { +func voteToStep(vote *types.UnsignedVote) int8 { switch vote.Type { case types.VoteTypePrevote: return stepPrevote @@ -150,7 +150,7 @@ func (pv *FilePV) Reset() { // SignVote signs a canonical representation of the vote, along with the // chainID. Implements PrivValidator. -func (pv *FilePV) SignVote(chainID string, vote *types.Vote) error { +func (pv *FilePV) SignVote(chainID string, vote *types.UnsignedVote) error { pv.mtx.Lock() defer pv.mtx.Unlock() if err := pv.signVote(chainID, vote); err != nil { @@ -201,7 +201,7 @@ func (pv *FilePV) checkHRS(height int64, round int, step int8) (bool, error) { // signVote checks if the vote is good to sign and sets the vote signature. // It may need to set the timestamp as well if the vote is otherwise the same as // a previously signed vote (ie. we crashed after signing but before the vote hit the WAL). -func (pv *FilePV) signVote(chainID string, vote *types.Vote) error { +func (pv *FilePV) signVote(chainID string, vote *types.UnsignedVote) error { height, round, step := vote.Height, vote.Round, voteToStep(vote) signBytes := vote.SignBytes(chainID) diff --git a/privval/priv_validator_test.go b/privval/priv_validator_test.go index 404ff770..e0b30730 100644 --- a/privval/priv_validator_test.go +++ b/privval/priv_validator_test.go @@ -113,7 +113,7 @@ func TestSignVote(t *testing.T) { assert.NoError(err, "expected no error on signing same vote") // now try some bad votes - cases := []*types.Vote{ + cases := []*types.UnsignedVote{ newVote(privVal.Address, 0, height, round-1, voteType, block1), // round regression newVote(privVal.Address, 0, height-1, round, voteType, block1), // height regression newVote(privVal.Address, 0, height-2, round+4, voteType, block1), // height regression and different round @@ -229,8 +229,8 @@ func TestDifferByTimestamp(t *testing.T) { } } -func newVote(addr types.Address, idx int, height int64, round int, typ byte, blockID types.BlockID) *types.Vote { - return &types.Vote{ +func newVote(addr types.Address, idx int, height int64, round int, typ byte, blockID types.BlockID) *types.UnsignedVote { + return &types.UnsignedVote{ ValidatorAddress: addr, ValidatorIndex: idx, Height: height, diff --git a/privval/socket.go b/privval/socket.go index d5ede471..6fb177c0 100644 --- a/privval/socket.go +++ b/privval/socket.go @@ -149,8 +149,8 @@ func (sc *SocketPV) getPubKey() (crypto.PubKey, error) { } // SignVote implements PrivValidator. -func (sc *SocketPV) SignVote(chainID string, vote *types.Vote) error { - err := writeMsg(sc.conn, &SignVoteMsg{Vote: vote}) +func (sc *SocketPV) SignVote(chainID string, vote *types.UnsignedVote) (*types.SignedVote, error) { + err := writeMsg(sc.conn, &SignVoteRequest{Vote: vote}) if err != nil { return err } @@ -160,7 +160,7 @@ func (sc *SocketPV) SignVote(chainID string, vote *types.Vote) error { return err } - *vote = *res.(*SignVoteMsg).Vote + *vote = *res.(*SignVoteRequest).Vote return nil } @@ -462,9 +462,9 @@ func (rs *RemoteSigner) handleConnection(conn net.Conn) { var p crypto.PubKey p = rs.privVal.GetPubKey() res = &PubKeyMsg{p} - case *SignVoteMsg: + case *SignVoteRequest: err = rs.privVal.SignVote(rs.chainID, r.Vote) - res = &SignVoteMsg{r.Vote} + res = &SignVoteRequest{r.Vote} case *SignProposalMsg: err = rs.privVal.SignProposal(rs.chainID, r.Proposal) res = &SignProposalMsg{r.Proposal} @@ -496,7 +496,8 @@ type SocketPVMsg interface{} func RegisterSocketPVMsg(cdc *amino.Codec) { cdc.RegisterInterface((*SocketPVMsg)(nil), nil) cdc.RegisterConcrete(&PubKeyMsg{}, "tendermint/socketpv/PubKeyMsg", nil) - cdc.RegisterConcrete(&SignVoteMsg{}, "tendermint/socketpv/SignVoteMsg", nil) + cdc.RegisterConcrete(&SignVoteRequest{}, "tendermint/socketpv/SignVoteRequest", nil) + cdc.RegisterConcrete(&SignedVoteReply{}, "tendermint/socketpv/SignVoteReply", nil) cdc.RegisterConcrete(&SignProposalMsg{}, "tendermint/socketpv/SignProposalMsg", nil) cdc.RegisterConcrete(&SignHeartbeatMsg{}, "tendermint/socketpv/SignHeartbeatMsg", nil) } @@ -506,9 +507,16 @@ type PubKeyMsg struct { PubKey crypto.PubKey } -// SignVoteMsg is a PrivValidatorSocket message containing a vote. -type SignVoteMsg struct { - Vote *types.Vote +// SignVoteRequest is a PrivValidatorSocket message containing a vote. +type SignVoteRequest struct { + Vote *types.UnsignedVote +} + +// SignVoteReply is a PrivValidatorSocket message containing a signed vote and potential +// errors returned by the (remote) signer. +type SignedVoteReply struct { + Vote *types.SignedVote + Error *types.Error } // SignProposalMsg is a PrivValidatorSocket message containing a Proposal. diff --git a/privval/socket_test.go b/privval/socket_test.go index 461ce3f8..5cd2200b 100644 --- a/privval/socket_test.go +++ b/privval/socket_test.go @@ -80,8 +80,8 @@ func TestSocketPVVote(t *testing.T) { ts = time.Now() vType = types.VoteTypePrecommit - want = &types.Vote{Timestamp: ts, Type: vType} - have = &types.Vote{Timestamp: ts, Type: vType} + want = &types.UnsignedVote{Timestamp: ts, Type: vType} + have = &types.UnsignedVote{Timestamp: ts, Type: vType} ) defer sc.Stop() defer rs.Stop() diff --git a/rpc/core/consensus.go b/rpc/core/consensus.go index 193fbd28..0ac3cae4 100644 --- a/rpc/core/consensus.go +++ b/rpc/core/consensus.go @@ -125,7 +125,7 @@ func Validators(heightPtr *int64) (*ctypes.ResultValidators, error) { // "commit_round": -1, // "last_commit": { // "votes": [ -// "Vote{0:B5B3D40BE539 7184/00/2(Precommit) 14F946FA7EF0 /702B1B1A602A.../ @ 2018-05-12T20:57:27.342Z}" +// "UnsignedVote{0:B5B3D40BE539 7184/00/2(Precommit) 14F946FA7EF0 /702B1B1A602A.../ @ 2018-05-12T20:57:27.342Z}" // ], // "votes_bit_array": "x", // "peer_maj_23s": {} @@ -243,11 +243,11 @@ func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) { // { // "round": 0, // "prevotes": [ -// "nil-Vote" +// "nil-UnsignedVote" // ], // "prevotes_bit_array": "BA{1:_} 0/10 = 0.00", // "precommits": [ -// "nil-Vote" +// "nil-UnsignedVote" // ], // "precommits_bit_array": "BA{1:_} 0/10 = 0.00" // } diff --git a/state/execution.go b/state/execution.go index b4cdb7a3..a667c363 100644 --- a/state/execution.go +++ b/state/execution.go @@ -246,7 +246,7 @@ func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorS // Collect the vote info (list of validators and whether or not they signed). voteInfos := make([]abci.VoteInfo, len(lastValSet.Validators)) for i, val := range lastValSet.Validators { - var vote *types.Vote + var vote *types.UnsignedVote if i < len(block.LastCommit.Precommits) { vote = block.LastCommit.Precommits[i] } diff --git a/state/execution_test.go b/state/execution_test.go index e93c9bfd..82ac3fbd 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -64,17 +64,17 @@ func TestBeginBlockValidators(t *testing.T) { prevBlockID := types.BlockID{prevHash, prevParts} now := tmtime.Now() - vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit} - vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now} + vote0 := &types.UnsignedVote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit} + vote1 := &types.UnsignedVote{ValidatorIndex: 1, Timestamp: now} testCases := []struct { desc string - lastCommitPrecommits []*types.Vote + lastCommitPrecommits []*types.UnsignedVote expectedAbsentValidators []int }{ - {"none absent", []*types.Vote{vote0, vote1}, []int{}}, - {"one absent", []*types.Vote{vote0, nil}, []int{1}}, - {"multiple absent", []*types.Vote{nil, nil}, []int{0, 1}}, + {"none absent", []*types.UnsignedVote{vote0, vote1}, []int{}}, + {"one absent", []*types.UnsignedVote{vote0, nil}, []int{1}}, + {"multiple absent", []*types.UnsignedVote{nil, nil}, []int{0, 1}}, } for _, tc := range testCases { @@ -135,9 +135,9 @@ func TestBeginBlockByzantineValidators(t *testing.T) { types.TM2PB.Evidence(ev2, valSet, now)}}, } - vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit} - vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now} - votes := []*types.Vote{vote0, vote1} + vote0 := &types.UnsignedVote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit} + vote1 := &types.UnsignedVote{ValidatorIndex: 1, Timestamp: now} + votes := []*types.UnsignedVote{vote0, vote1} lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: votes} for _, tc := range testCases { diff --git a/types/block.go b/types/block.go index 951ad96f..e6a33393 100644 --- a/types/block.go +++ b/types/block.go @@ -332,18 +332,18 @@ type Commit struct { // NOTE: The Precommits are in order of address to preserve the bonded ValidatorSet order. // Any peer with a block can gossip precommits by index with a peer without recalculating the // active ValidatorSet. - BlockID BlockID `json:"block_id"` - Precommits []*Vote `json:"precommits"` + BlockID BlockID `json:"block_id"` + Precommits []*SignedVote `json:"precommits"` // Volatile - firstPrecommit *Vote + firstPrecommit *SignedVote hash cmn.HexBytes bitArray *cmn.BitArray } // FirstPrecommit returns the first non-nil precommit in the commit. // If all precommits are nil, it returns an empty precommit with height 0. -func (commit *Commit) FirstPrecommit() *Vote { +func (commit *Commit) FirstPrecommit() *SignedVote { if len(commit.Precommits) == 0 { return nil } @@ -356,8 +356,12 @@ func (commit *Commit) FirstPrecommit() *Vote { return precommit } } - return &Vote{ - Type: VoteTypePrecommit, + return &SignedVote{ + // TODO(ismail): That is confusing; does the caller expect a signed pre-commit or not? + // looks like this is always unsigned (check how this is reflected in the spec) + Vote: &UnsignedVote{ + Type: VoteTypePrecommit, + }, } } @@ -366,7 +370,7 @@ func (commit *Commit) Height() int64 { if len(commit.Precommits) == 0 { return 0 } - return commit.FirstPrecommit().Height + return commit.FirstPrecommit().Vote.Height } // Round returns the round of the commit @@ -374,7 +378,7 @@ func (commit *Commit) Round() int { if len(commit.Precommits) == 0 { return 0 } - return commit.FirstPrecommit().Round + return commit.FirstPrecommit().Vote.Round } // Type returns the vote type of the commit, which is always VoteTypePrecommit @@ -404,7 +408,7 @@ func (commit *Commit) BitArray() *cmn.BitArray { } // GetByIndex returns the vote corresponding to a given validator index -func (commit *Commit) GetByIndex(index int) *Vote { +func (commit *Commit) GetByIndex(index int) *SignedVote { return commit.Precommits[index] } @@ -427,23 +431,23 @@ func (commit *Commit) ValidateBasic() error { // Validate the precommits. for _, precommit := range commit.Precommits { // It's OK for precommits to be missing. - if precommit == nil { + if precommit == nil || precommit.Vote == nil { continue } // Ensure that all votes are precommits. - if precommit.Type != VoteTypePrecommit { + if precommit.Vote.Type != VoteTypePrecommit { return fmt.Errorf("Invalid commit vote. Expected precommit, got %v", - precommit.Type) + precommit.Vote.Type) } // Ensure that all heights are the same. - if precommit.Height != height { + if precommit.Vote.Height != height { return fmt.Errorf("Invalid commit precommit height. Expected %v, got %v", - height, precommit.Height) + height, precommit.Vote.Height) } // Ensure that all rounds are the same. - if precommit.Round != round { + if precommit.Vote.Round != round { return fmt.Errorf("Invalid commit precommit round. Expected %v, got %v", - round, precommit.Round) + round, precommit.Vote.Round) } } return nil @@ -471,7 +475,7 @@ func (commit *Commit) StringIndented(indent string) string { } precommitStrings := make([]string, len(commit.Precommits)) for i, precommit := range commit.Precommits { - precommitStrings[i] = precommit.String() + precommitStrings[i] = precommit.Vote.String() } return fmt.Sprintf(`Commit{ %s BlockID: %v diff --git a/types/block_test.go b/types/block_test.go index c2a73bf8..8a0bd52f 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -221,17 +221,17 @@ func TestCommitValidateBasic(t *testing.T) { // tamper with types commit = randCommit() - commit.Precommits[0].Type = VoteTypePrevote + commit.Precommits[0].Vote.Type = VoteTypePrevote assert.Error(t, commit.ValidateBasic()) // tamper with height commit = randCommit() - commit.Precommits[0].Height = int64(100) + commit.Precommits[0].Vote.Height = int64(100) assert.Error(t, commit.ValidateBasic()) // tamper with round commit = randCommit() - commit.Precommits[0].Round = 100 + commit.Precommits[0].Vote.Round = 100 assert.Error(t, commit.ValidateBasic()) } diff --git a/types/events.go b/types/events.go index 09f7216e..f7150197 100644 --- a/types/events.go +++ b/types/events.go @@ -24,7 +24,7 @@ const ( EventTx = "Tx" EventUnlock = "Unlock" EventValidatorSetUpdates = "ValidatorSetUpdates" - EventVote = "Vote" + EventVote = "UnsignedVote" ) /////////////////////////////////////////////////////////////////////////////// @@ -42,7 +42,7 @@ func RegisterEventDatas(cdc *amino.Codec) { cdc.RegisterConcrete(EventDataNewBlockHeader{}, "tendermint/event/NewBlockHeader", nil) cdc.RegisterConcrete(EventDataTx{}, "tendermint/event/Tx", nil) cdc.RegisterConcrete(EventDataRoundState{}, "tendermint/event/RoundState", nil) - cdc.RegisterConcrete(EventDataVote{}, "tendermint/event/Vote", nil) + cdc.RegisterConcrete(EventDataVote{}, "tendermint/event/UnsignedVote", nil) cdc.RegisterConcrete(EventDataProposalHeartbeat{}, "tendermint/event/ProposalHeartbeat", nil) cdc.RegisterConcrete(EventDataValidatorSetUpdates{}, "tendermint/event/ValidatorSetUpdates", nil) cdc.RegisterConcrete(EventDataString(""), "tendermint/event/ProposalString", nil) @@ -80,7 +80,7 @@ type EventDataRoundState struct { } type EventDataVote struct { - Vote *Vote + Vote *UnsignedVote } type EventDataString string diff --git a/types/evidence.go b/types/evidence.go index 3c988caf..3f620ab5 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -34,11 +34,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 - Hash() []byte // hash of the evidence - Verify(chainID string, pubKey crypto.PubKey) 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(pubKey crypto.PubKey) error // verify the evidence + Equal(Evidence) bool // check equality of evidence String() string } @@ -63,8 +63,8 @@ func MaxEvidenceBytesPerBlock(blockMaxBytes int) int { type DuplicateVoteEvidence struct { PubKey crypto.PubKey // TODO(ismail): this probably need to be `SignedVoteReply`s - VoteA *SignVoteReply - VoteB *SignVoteReply + VoteA *SignedVote + VoteB *SignedVote } // String returns a string representation of the evidence. @@ -90,7 +90,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, pubKey crypto.PubKey) error { +func (dve *DuplicateVoteEvidence) Verify(pubKey crypto.PubKey) error { // H/R/S must be the same if dve.VoteA.Vote.Height != dve.VoteB.Vote.Height || dve.VoteA.Vote.Round != dve.VoteB.Vote.Round || @@ -161,7 +161,7 @@ func (e MockGoodEvidence) Address() []byte { return e.Address_ } func (e MockGoodEvidence) Hash() []byte { return []byte(fmt.Sprintf("%d-%x", e.Height_, e.Address_)) } -func (e MockGoodEvidence) Verify(chainID string, pubKey crypto.PubKey) error { return nil } +func (e MockGoodEvidence) Verify(pubKey crypto.PubKey) error { return nil } func (e MockGoodEvidence) Equal(ev Evidence) bool { e2 := ev.(MockGoodEvidence) return e.Height_ == e2.Height_ && @@ -176,7 +176,7 @@ type MockBadEvidence struct { MockGoodEvidence } -func (e MockBadEvidence) Verify(chainID string, pubKey crypto.PubKey) error { +func (e MockBadEvidence) Verify(pubKey crypto.PubKey) error { return fmt.Errorf("MockBadEvidence") } func (e MockBadEvidence) Equal(ev Evidence) bool { diff --git a/types/evidence_test.go b/types/evidence_test.go index 68c68351..c7199b28 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -11,25 +11,26 @@ import ( ) type voteData struct { - vote1 *Vote - vote2 *Vote + vote1 *SignedVote + vote2 *SignedVote valid bool } -func makeVote(val PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID BlockID) *Vote { - v := &Vote{ +func makeVote(val PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID BlockID) *SignedVote { + v := &UnsignedVote{ ValidatorAddress: val.GetAddress(), ValidatorIndex: valIndex, Height: height, Round: round, Type: byte(step), BlockID: blockID, + ChainID: chainID, } - err := val.SignVote(chainID, v) + sv, err := val.SignVote(v) if err != nil { panic(err) } - return v + return sv } func TestEvidence(t *testing.T) { @@ -45,7 +46,7 @@ func TestEvidence(t *testing.T) { vote1 := makeVote(val, chainID, 0, 10, 2, 1, blockID) badVote := makeVote(val, chainID, 0, 10, 2, 1, blockID) - err := val2.SignVote(chainID, badVote) + signedBadVote, err := val2.SignVote(badVote.Vote) if err != nil { panic(err) } @@ -61,19 +62,21 @@ func TestEvidence(t *testing.T) { {vote1, makeVote(val, chainID, 0, 10, 3, 1, blockID2), false}, // wrong round {vote1, makeVote(val, chainID, 0, 10, 2, 2, blockID2), false}, // wrong step {vote1, makeVote(val2, chainID, 0, 10, 2, 1, blockID), false}, // wrong validator - {vote1, badVote, false}, // signed by wrong key + {vote1, signedBadVote, false}, // signed by wrong key } pubKey := val.GetPubKey() - for _, c := range cases { + for idx, c := range cases { + //fmt.Println(idx) ev := &DuplicateVoteEvidence{ VoteA: c.vote1, VoteB: c.vote2, } if c.valid { - assert.Nil(t, ev.Verify(chainID, pubKey), "evidence should be valid") + assert.NoError(t, ev.Verify(pubKey), "evidence should be valid") } else { - assert.NotNil(t, ev.Verify(chainID, pubKey), "evidence should be invalid") + t.Logf("idx=%v, err=%s", idx, ev.Verify(pubKey)) + assert.Error(t, ev.Verify(pubKey), "evidence should be invalid") } } } diff --git a/types/priv_validator.go b/types/priv_validator.go index f5ec04ee..18e96c36 100644 --- a/types/priv_validator.go +++ b/types/priv_validator.go @@ -14,7 +14,7 @@ type PrivValidator interface { GetAddress() Address // redundant since .PubKey().Address() GetPubKey() crypto.PubKey - SignVote(vote *Vote) (SignVoteReply, error) + SignVote(vote *UnsignedVote) (*SignedVote, error) SignProposal(chainID string, proposal *Proposal) error SignHeartbeat(chainID string, heartbeat *Heartbeat) error } @@ -62,16 +62,15 @@ func (pv *MockPV) GetPubKey() crypto.PubKey { } // Implements PrivValidator. -func (pv *MockPV) SignVote(vote *Vote) (SignVoteReply, error) { +func (pv *MockPV) SignVote(vote *UnsignedVote) (*SignedVote, error) { signBytes := vote.SignBytes() sig, err := pv.privKey.Sign(signBytes) if err != nil { - // TODO(ismail): encapsulate error into reply! - return SignVoteReply{}, err + return nil, err } - return SignVoteReply{ - Vote: *vote, + return &SignedVote{ + Vote: vote, Signature: sig, }, nil } diff --git a/types/test_util.go b/types/test_util.go index c7b47fbd..02fd22cb 100644 --- a/types/test_util.go +++ b/types/test_util.go @@ -11,7 +11,7 @@ func MakeCommit(blockID BlockID, height int64, round int, // all sign for i := 0; i < len(validators); i++ { - vote := &Vote{ + vote := &UnsignedVote{ ValidatorAddress: validators[i].GetAddress(), ValidatorIndex: i, Height: height, @@ -30,11 +30,11 @@ func MakeCommit(blockID BlockID, height int64, round int, return voteSet.MakeCommit(), nil } -func signAddVote(privVal PrivValidator, vote *Vote, voteSet *VoteSet) (signed bool, err error) { +func signAddVote(privVal PrivValidator, vote *UnsignedVote, voteSet *VoteSet) (signed bool, err error) { vote.ChainID = voteSet.ChainID() repl, err := privVal.SignVote(vote) if err != nil { return false, err } - return voteSet.AddVote(vote) + return voteSet.AddVote(repl) } diff --git a/types/validator_set.go b/types/validator_set.go index 67631bb3..44eb5194 100644 --- a/types/validator_set.go +++ b/types/validator_set.go @@ -273,26 +273,31 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height i round := commit.Round() for idx, precommit := range commit.Precommits { - if precommit == nil { + if precommit == nil || precommit.Vote == nil { continue // OK, some precommits can be missing. } - if precommit.Height != height { - return fmt.Errorf("Invalid commit -- wrong height: want %v got %v", height, precommit.Height) + if precommit.Vote.Height != height { + return fmt.Errorf("invalid commit -- wrong height: want %v got %v", height, precommit.Vote.Height) } - if precommit.Round != round { - return fmt.Errorf("Invalid commit -- wrong round: want %v got %v", round, precommit.Round) + if precommit.Vote.Round != round { + return fmt.Errorf("invalid commit -- wrong round: want %v got %v", round, precommit.Vote.Round) } - if precommit.Type != VoteTypePrecommit { - return fmt.Errorf("Invalid commit -- not precommit @ index %v", idx) + if precommit.Vote.Type != VoteTypePrecommit { + return fmt.Errorf("invalid commit -- not precommit @ index %v", idx) } _, val := vals.GetByIndex(idx) // Validate signature. - precommitSignBytes := precommit.SignBytes() + precommitSignBytes := precommit.Vote.SignBytes() if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) { - return fmt.Errorf("Invalid commit -- invalid signature: %v", precommit) + return fmt.Errorf("invalid commit -- invalid signature: %v", precommit) } + + if precommit.Vote.ChainID != chainID { + return fmt.Errorf("invalid commit -- chainId does not match: expected %v, got %v", chainID, precommit.Vote.ChainID) + } + // Good precommit! - if blockID.Equals(precommit.BlockID) { + if blockID.Equals(precommit.Vote.BlockID) { talliedVotingPower += val.VotingPower } else { // It's OK that the BlockID doesn't match. We include stray @@ -303,7 +308,7 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height i if talliedVotingPower > vals.TotalVotingPower()*2/3 { return nil } - return fmt.Errorf("Invalid commit -- insufficient voting power: got %v, needed %v", + return fmt.Errorf("invalid commit -- insufficient voting power: got %v, needed %v", talliedVotingPower, (vals.TotalVotingPower()*2/3 + 1)) } @@ -352,32 +357,32 @@ func (vals *ValidatorSet) VerifyFutureCommit(newSet *ValidatorSet, chainID strin round := commit.Round() for idx, precommit := range commit.Precommits { - if precommit == nil { + if precommit == nil || precommit.Vote == nil { continue } - if precommit.Height != height { - return cmn.NewError("Blocks don't match - %d vs %d", round, precommit.Round) + if precommit.Vote.Height != height { + return cmn.NewError("Blocks don't match - %d vs %d", round, precommit.Vote.Round) } - if precommit.Round != round { - return cmn.NewError("Invalid commit -- wrong round: %v vs %v", round, precommit.Round) + if precommit.Vote.Round != round { + return cmn.NewError("Invalid commit -- wrong round: %v vs %v", round, precommit.Vote.Round) } - if precommit.Type != VoteTypePrecommit { + if precommit.Vote.Type != VoteTypePrecommit { return cmn.NewError("Invalid commit -- not precommit @ index %v", idx) } // See if this validator is in oldVals. - idx, val := oldVals.GetByAddress(precommit.ValidatorAddress) + idx, val := oldVals.GetByAddress(precommit.Vote.ValidatorAddress) if val == nil || seen[idx] { continue // missing or double vote... } seen[idx] = true // Validate signature. - precommitSignBytes := precommit.SignBytes(chainID) + precommitSignBytes := precommit.Vote.SignBytes() if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) { return cmn.NewError("Invalid commit -- invalid signature: %v", precommit) } // Good precommit! - if blockID.Equals(precommit.BlockID) { + if blockID.Equals(precommit.Vote.BlockID) { oldVotingPower += val.VotingPower } else { // It's OK that the BlockID doesn't match. We include stray diff --git a/types/validator_set_test.go b/types/validator_set_test.go index e4111707..f579135d 100644 --- a/types/validator_set_test.go +++ b/types/validator_set_test.go @@ -379,7 +379,7 @@ func TestValidatorSetVerifyCommit(t *testing.T) { chainID := "mychainID" blockID := BlockID{Hash: []byte("hello")} height := int64(5) - vote := &Vote{ + vote := &UnsignedVote{ ValidatorAddress: v1.Address, ValidatorIndex: 0, Height: height, @@ -387,13 +387,14 @@ func TestValidatorSetVerifyCommit(t *testing.T) { Timestamp: tmtime.Now(), Type: VoteTypePrecommit, BlockID: blockID, + ChainID: chainID, } - sig, err := privKey.Sign(vote.SignBytes(chainID)) + sig, err := privKey.Sign(vote.SignBytes()) assert.NoError(t, err) - vote.Signature = sig + commit := &Commit{ BlockID: blockID, - Precommits: []*Vote{vote}, + Precommits: []*SignedVote{&SignedVote{Vote: vote, Signature: sig}}, } badChainID := "notmychainID" @@ -401,7 +402,7 @@ func TestValidatorSetVerifyCommit(t *testing.T) { badHeight := height + 1 badCommit := &Commit{ BlockID: blockID, - Precommits: []*Vote{nil}, + Precommits: []*SignedVote{nil}, } // test some error cases @@ -420,7 +421,7 @@ func TestValidatorSetVerifyCommit(t *testing.T) { for i, c := range cases { err := vset.VerifyCommit(c.chainID, c.blockID, c.height, c.commit) - assert.NotNil(t, err, i) + assert.NotNil(t, err, "test-case: %d", i) } // test a good one diff --git a/types/vote.go b/types/vote.go index c7be0805..cd5ad2b9 100644 --- a/types/vote.go +++ b/types/vote.go @@ -33,7 +33,7 @@ func (err *ErrVoteConflictingVotes) Error() string { return fmt.Sprintf("Conflicting votes from validator %v", err.PubKey.Address()) } -func NewConflictingVoteError(val *Validator, voteA, voteB *Vote) *ErrVoteConflictingVotes { +func NewConflictingVoteError(val *Validator, voteA, voteB *SignedVote) *ErrVoteConflictingVotes { return &ErrVoteConflictingVotes{ &DuplicateVoteEvidence{ PubKey: val.PubKey, @@ -65,7 +65,7 @@ func IsVoteTypeValid(type_ byte) bool { type Address = cmn.HexBytes // Represents a prevote, precommit, or commit vote from validators for consensus. -type Vote struct { +type UnsignedVote struct { ValidatorAddress Address `json:"validator_address"` ValidatorIndex int `json:"validator_index"` Height int64 `json:"height"` @@ -76,14 +76,9 @@ type Vote struct { ChainID string `json:"chain_id"` } -type SignVoteRequest struct { - Vote Vote -} - -type SignVoteReply struct { - Vote Vote +type SignedVote struct { + Vote *UnsignedVote Signature []byte - Err Error } type Error struct { @@ -91,7 +86,7 @@ type Error struct { Description string } -func (vote *Vote) SignBytes() []byte { +func (vote *UnsignedVote) SignBytes() []byte { bz, err := cdc.MarshalBinary(vote) if err != nil { panic(err) @@ -99,14 +94,14 @@ func (vote *Vote) SignBytes() []byte { return bz } -func (vote *Vote) Copy() *Vote { +func (vote *UnsignedVote) Copy() *UnsignedVote { voteCopy := *vote return &voteCopy } -func (vote *Vote) String() string { +func (vote *UnsignedVote) String() string { if vote == nil { - return "nil-Vote" + return "nil-UnsignedVote" } var typeString string switch vote.Type { @@ -118,20 +113,24 @@ func (vote *Vote) String() string { cmn.PanicSanity("Unknown vote type") } - return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}", + return fmt.Sprintf("UnsignedVote{%v:%X %v/%02d/%v(%v) %X @ %s}", vote.ValidatorIndex, cmn.Fingerprint(vote.ValidatorAddress), vote.Height, vote.Round, vote.Type, typeString, cmn.Fingerprint(vote.BlockID.Hash), - cmn.Fingerprint(vote.Signature), + // TODO(ismail): add corresponding + //cmn.Fingerprint(vote.Signature), CanonicalTime(vote.Timestamp)) } -func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error { - if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) { +func (vote *SignedVote) Verify(pubKey crypto.PubKey) error { + if vote == nil || vote.Vote == nil { + return errors.New("called verify on nil/empty SignedVote") + } + if !bytes.Equal(pubKey.Address(), vote.Vote.ValidatorAddress) { return ErrVoteInvalidValidatorAddress } - if !pubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) { + if !pubKey.VerifyBytes(vote.Vote.SignBytes(), vote.Signature) { return ErrVoteInvalidSignature } return nil diff --git a/types/vote_set.go b/types/vote_set.go index dbcacbbd..a6de16bb 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -60,7 +60,7 @@ type VoteSet struct { mtx sync.Mutex votesBitArray *cmn.BitArray - votes []*Vote // Primary votes to share + votes []*SignedVote // Primary votes to share sum int64 // Sum of voting power for seen votes, discounting conflicts maj23 *BlockID // First 2/3 majority seen votesByBlock map[string]*blockVotes // string(blockHash|blockParts) -> blockVotes @@ -79,7 +79,7 @@ func NewVoteSet(chainID string, height int64, round int, type_ byte, valSet *Val type_: type_, valSet: valSet, votesBitArray: cmn.NewBitArray(valSet.Size()), - votes: make([]*Vote, valSet.Size()), + votes: make([]*SignedVote, valSet.Size()), sum: 0, maj23: nil, votesByBlock: make(map[string]*blockVotes, valSet.Size()), @@ -127,8 +127,8 @@ func (voteSet *VoteSet) Size() int { // Conflicting votes return added=*, err=ErrVoteConflictingVotes. // NOTE: vote should not be mutated after adding. // NOTE: VoteSet must not be nil -// NOTE: Vote must not be nil -func (voteSet *VoteSet) AddVote(vote *Vote) (added bool, err error) { +// NOTE: UnsignedVote must not be nil +func (voteSet *VoteSet) AddVote(vote *SignedVote) (added bool, err error) { if voteSet == nil { cmn.PanicSanity("AddVote() on nil VoteSet") } @@ -139,13 +139,13 @@ func (voteSet *VoteSet) AddVote(vote *Vote) (added bool, err error) { } // NOTE: Validates as much as possible before attempting to verify the signature. -func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { - if vote == nil { +func (voteSet *VoteSet) addVote(vote *SignedVote) (added bool, err error) { + if vote == nil || vote.Vote == nil { return false, ErrVoteNil } - valIndex := vote.ValidatorIndex - valAddr := vote.ValidatorAddress - blockKey := vote.BlockID.Key() + valIndex := vote.Vote.ValidatorIndex + valAddr := vote.Vote.ValidatorAddress + blockKey := vote.Vote.BlockID.Key() // Ensure that validator index was set if valIndex < 0 { @@ -155,12 +155,12 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { } // Make sure the step matches. - if (vote.Height != voteSet.height) || - (vote.Round != voteSet.round) || - (vote.Type != voteSet.type_) { + if (vote.Vote.Height != voteSet.height) || + (vote.Vote.Round != voteSet.round) || + (vote.Vote.Type != voteSet.type_) { return false, errors.Wrapf(ErrVoteUnexpectedStep, "Got %d/%d/%d, expected %d/%d/%d", voteSet.height, voteSet.round, voteSet.type_, - vote.Height, vote.Round, vote.Type) + vote.Vote.Height, vote.Vote.Round, vote.Vote.Type) } // Ensure that signer is a validator. @@ -186,7 +186,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { } // Check signature. - if err := vote.Verify(voteSet.chainID, val.PubKey); err != nil { + if err := vote.Verify(val.PubKey); err != nil { return false, errors.Wrapf(err, "Failed to verify vote with ChainID %s and PubKey %s", voteSet.chainID, val.PubKey) } @@ -202,8 +202,8 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { } // Returns (vote, true) if vote exists for valIndex and blockKey. -func (voteSet *VoteSet) getVote(valIndex int, blockKey string) (vote *Vote, ok bool) { - if existing := voteSet.votes[valIndex]; existing != nil && existing.BlockID.Key() == blockKey { +func (voteSet *VoteSet) getVote(valIndex int, blockKey string) (vote *SignedVote, ok bool) { + if existing := voteSet.votes[valIndex]; existing != nil && existing.Vote != nil && existing.Vote.BlockID.Key() == blockKey { return existing, true } if existing := voteSet.votesByBlock[blockKey].getByIndex(valIndex); existing != nil { @@ -214,12 +214,12 @@ func (voteSet *VoteSet) getVote(valIndex int, blockKey string) (vote *Vote, ok b // Assumes signature is valid. // If conflicting vote exists, returns it. -func (voteSet *VoteSet) addVerifiedVote(vote *Vote, blockKey string, votingPower int64) (added bool, conflicting *Vote) { - valIndex := vote.ValidatorIndex +func (voteSet *VoteSet) addVerifiedVote(vote *SignedVote, blockKey string, votingPower int64) (added bool, conflicting *SignedVote) { + valIndex := vote.Vote.ValidatorIndex // Already exists in voteSet.votes? if existing := voteSet.votes[valIndex]; existing != nil { - if existing.BlockID.Equals(vote.BlockID) { + if existing.Vote.BlockID.Equals(vote.Vote.BlockID) { cmn.PanicSanity("addVerifiedVote does not expect duplicate votes") } else { conflicting = existing @@ -269,7 +269,7 @@ func (voteSet *VoteSet) addVerifiedVote(vote *Vote, blockKey string, votingPower if origSum < quorum && quorum <= votesByBlock.sum { // Only consider the first quorum reached if voteSet.maj23 == nil { - maj23BlockID := vote.BlockID + maj23BlockID := vote.Vote.BlockID voteSet.maj23 = &maj23BlockID // And also copy votes over to voteSet.votes for i, vote := range votesByBlock.votes { @@ -346,7 +346,7 @@ func (voteSet *VoteSet) BitArrayByBlockID(blockID BlockID) *cmn.BitArray { } // NOTE: if validator has conflicting votes, returns "canonical" vote -func (voteSet *VoteSet) GetByIndex(valIndex int) *Vote { +func (voteSet *VoteSet) GetByIndex(valIndex int) *SignedVote { if voteSet == nil { return nil } @@ -355,7 +355,7 @@ func (voteSet *VoteSet) GetByIndex(valIndex int) *Vote { return voteSet.votes[valIndex] } -func (voteSet *VoteSet) GetByAddress(address []byte) *Vote { +func (voteSet *VoteSet) GetByAddress(address []byte) *SignedVote { if voteSet == nil { return nil } @@ -433,10 +433,10 @@ func (voteSet *VoteSet) StringIndented(indent string) string { defer voteSet.mtx.Unlock() voteStrings := make([]string, len(voteSet.votes)) for i, vote := range voteSet.votes { - if vote == nil { - voteStrings[i] = "nil-Vote" + if vote == nil || vote.Vote == nil { + voteStrings[i] = "nil-UnsignedVote" } else { - voteStrings[i] = vote.String() + voteStrings[i] = vote.Vote.String() } } return fmt.Sprintf(`VoteSet{ @@ -498,10 +498,10 @@ func (voteSet *VoteSet) VoteStrings() []string { func (voteSet *VoteSet) voteStrings() []string { voteStrings := make([]string, len(voteSet.votes)) for i, vote := range voteSet.votes { - if vote == nil { + if vote == nil || vote.Vote == nil { voteStrings[i] = "nil-Vote" } else { - voteStrings[i] = vote.String() + voteStrings[i] = vote.Vote.String() } } return voteStrings @@ -541,7 +541,7 @@ func (voteSet *VoteSet) MakeCommit() *Commit { } // For every validator, get the precommit - votesCopy := make([]*Vote, len(voteSet.votes)) + votesCopy := make([]*SignedVote, len(voteSet.votes)) copy(votesCopy, voteSet.votes) return &Commit{ BlockID: *voteSet.maj23, @@ -560,7 +560,7 @@ func (voteSet *VoteSet) MakeCommit() *Commit { type blockVotes struct { peerMaj23 bool // peer claims to have maj23 bitArray *cmn.BitArray // valIndex -> hasVote? - votes []*Vote // valIndex -> *Vote + votes []*SignedVote // valIndex -> *UnsignedVote sum int64 // vote sum } @@ -568,13 +568,13 @@ func newBlockVotes(peerMaj23 bool, numValidators int) *blockVotes { return &blockVotes{ peerMaj23: peerMaj23, bitArray: cmn.NewBitArray(numValidators), - votes: make([]*Vote, numValidators), + votes: make([]*SignedVote, numValidators), sum: 0, } } -func (vs *blockVotes) addVerifiedVote(vote *Vote, votingPower int64) { - valIndex := vote.ValidatorIndex +func (vs *blockVotes) addVerifiedVote(vote *SignedVote, votingPower int64) { + valIndex := vote.Vote.ValidatorIndex if existing := vs.votes[valIndex]; existing == nil { vs.bitArray.SetIndex(valIndex, true) vs.votes[valIndex] = vote @@ -582,7 +582,7 @@ func (vs *blockVotes) addVerifiedVote(vote *Vote, votingPower int64) { } } -func (vs *blockVotes) getByIndex(index int) *Vote { +func (vs *blockVotes) getByIndex(index int) *SignedVote { if vs == nil { return nil } @@ -598,6 +598,6 @@ type VoteSetReader interface { Type() byte Size() int BitArray() *cmn.BitArray - GetByIndex(int) *Vote + GetByIndex(int) *UnsignedVote IsCommit() bool } diff --git a/types/vote_set_test.go b/types/vote_set_test.go index 995fb94b..9f6e9af9 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -17,7 +17,7 @@ func randVoteSet(height int64, round int, type_ byte, numValidators int, votingP } // Convenience: Return new vote with different validator address/index -func withValidator(vote *Vote, addr []byte, idx int) *Vote { +func withValidator(vote *UnsignedVote, addr []byte, idx int) *UnsignedVote { vote = vote.Copy() vote.ValidatorAddress = addr vote.ValidatorIndex = idx @@ -25,35 +25,35 @@ func withValidator(vote *Vote, addr []byte, idx int) *Vote { } // Convenience: Return new vote with different height -func withHeight(vote *Vote, height int64) *Vote { +func withHeight(vote *UnsignedVote, height int64) *UnsignedVote { vote = vote.Copy() vote.Height = height return vote } // Convenience: Return new vote with different round -func withRound(vote *Vote, round int) *Vote { +func withRound(vote *UnsignedVote, round int) *UnsignedVote { vote = vote.Copy() vote.Round = round return vote } // Convenience: Return new vote with different type -func withType(vote *Vote, type_ byte) *Vote { +func withType(vote *UnsignedVote, type_ byte) *UnsignedVote { vote = vote.Copy() vote.Type = type_ return vote } // Convenience: Return new vote with different blockHash -func withBlockHash(vote *Vote, blockHash []byte) *Vote { +func withBlockHash(vote *UnsignedVote, blockHash []byte) *UnsignedVote { vote = vote.Copy() vote.BlockID.Hash = blockHash return vote } // Convenience: Return new vote with different blockParts -func withBlockPartsHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote { +func withBlockPartsHeader(vote *UnsignedVote, blockPartsHeader PartSetHeader) *UnsignedVote { vote = vote.Copy() vote.BlockID.PartsHeader = blockPartsHeader return vote @@ -77,7 +77,7 @@ func TestAddVote(t *testing.T) { t.Errorf("There should be no 2/3 majority") } - vote := &Vote{ + vote := &UnsignedVote{ ValidatorAddress: val0.GetAddress(), ValidatorIndex: 0, // since privValidators are in order Height: height, @@ -107,7 +107,7 @@ func Test2_3Majority(t *testing.T) { height, round := int64(1), 0 voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1) - voteProto := &Vote{ + voteProto := &UnsignedVote{ ValidatorAddress: nil, // NOTE: must fill in ValidatorIndex: -1, // NOTE: must fill in Height: height, @@ -164,7 +164,7 @@ func Test2_3MajorityRedux(t *testing.T) { blockPartsTotal := 123 blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)} - voteProto := &Vote{ + voteProto := &UnsignedVote{ ValidatorAddress: nil, // NOTE: must fill in ValidatorIndex: -1, // NOTE: must fill in Height: height, @@ -259,7 +259,7 @@ func TestBadVotes(t *testing.T) { height, round := int64(1), 0 voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1) - voteProto := &Vote{ + voteProto := &UnsignedVote{ ValidatorAddress: nil, ValidatorIndex: -1, Height: height, @@ -321,7 +321,7 @@ func TestConflicts(t *testing.T) { blockHash1 := cmn.RandBytes(32) blockHash2 := cmn.RandBytes(32) - voteProto := &Vote{ + voteProto := &UnsignedVote{ ValidatorAddress: nil, ValidatorIndex: -1, Height: height, @@ -450,7 +450,7 @@ func TestMakeCommit(t *testing.T) { voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrecommit, 10, 1) blockHash, blockPartsHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)} - voteProto := &Vote{ + voteProto := &UnsignedVote{ ValidatorAddress: nil, ValidatorIndex: -1, Height: height, diff --git a/types/vote_test.go b/types/vote_test.go index 4f544935..04765e07 100644 --- a/types/vote_test.go +++ b/types/vote_test.go @@ -12,21 +12,21 @@ import ( tmtime "github.com/tendermint/tendermint/types/time" ) -func examplePrevote() *Vote { +func examplePrevote() *UnsignedVote { return exampleVote(VoteTypePrevote) } -func examplePrecommit() *Vote { +func examplePrecommit() *UnsignedVote { return exampleVote(VoteTypePrecommit) } -func exampleVote(t byte) *Vote { +func exampleVote(t byte) *UnsignedVote { var stamp, err = time.Parse(TimeFormat, "2017-12-25T03:00:01.234Z") if err != nil { panic(err) } - return &Vote{ + return &UnsignedVote{ ValidatorAddress: tmhash.Sum([]byte("validator_address")), ValidatorIndex: 56789, Height: 12345, @@ -40,18 +40,20 @@ func exampleVote(t byte) *Vote { Hash: tmhash.Sum([]byte("blockID_part_set_header_hash")), }, }, + ChainID: "test_chain_id", } } func TestVoteSignable(t *testing.T) { + t.Skip("TODO(ismail): switch to amino") vote := examplePrecommit() - signBytes := vote.SignBytes("test_chain_id") + signBytes := vote.SignBytes() signStr := string(signBytes) expected := `{"@chain_id":"test_chain_id","@type":"vote","block_id":{"hash":"8B01023386C371778ECB6368573E539AFC3CC860","parts":{"hash":"72DB3D959635DFF1BB567BEDAA70573392C51596","total":"1000000"}},"height":"12345","round":"2","timestamp":"2017-12-25T03:00:01.234Z","type":2}` if signStr != expected { // NOTE: when this fails, you probably want to fix up consensus/replay_test too - t.Errorf("Got unexpected sign string for Vote. Expected:\n%v\nGot:\n%v", expected, signStr) + t.Errorf("Got unexpected sign string for UnsignedVote. Expected:\n%v\nGot:\n%v", expected, signStr) } } @@ -60,25 +62,25 @@ func TestVoteVerifySignature(t *testing.T) { pubkey := privVal.GetPubKey() vote := examplePrecommit() - signBytes := vote.SignBytes("test_chain_id") + signBytes := vote.SignBytes() // sign it - err := privVal.SignVote("test_chain_id", vote) + signedVote, err := privVal.SignVote(vote) require.NoError(t, err) // verify the same vote - valid := pubkey.VerifyBytes(vote.SignBytes("test_chain_id"), vote.Signature) + valid := pubkey.VerifyBytes(vote.SignBytes(), signedVote.Signature) require.True(t, valid) // serialize, deserialize and verify again.... - precommit := new(Vote) - bs, err := cdc.MarshalBinary(vote) + precommit := new(SignedVote) + bs, err := cdc.MarshalBinary(signedVote) require.NoError(t, err) err = cdc.UnmarshalBinary(bs, &precommit) require.NoError(t, err) // verify the transmitted vote - newSignBytes := precommit.SignBytes("test_chain_id") + newSignBytes := precommit.Vote.SignBytes() require.Equal(t, string(signBytes), string(newSignBytes)) valid = pubkey.VerifyBytes(newSignBytes, precommit.Signature) require.True(t, valid) @@ -99,7 +101,7 @@ func TestIsVoteTypeValid(t *testing.T) { tt := tt t.Run(tt.name, func(st *testing.T) { if rs := IsVoteTypeValid(tt.in); rs != tt.out { - t.Errorf("Got unexpected Vote type. Expected:\n%v\nGot:\n%v", rs, tt.out) + t.Errorf("Got unexpected UnsignedVote type. Expected:\n%v\nGot:\n%v", rs, tt.out) } }) } @@ -111,20 +113,21 @@ func TestVoteVerify(t *testing.T) { vote := examplePrevote() vote.ValidatorAddress = pubkey.Address() + sv := &SignedVote{Vote: vote} - err := vote.Verify("test_chain_id", ed25519.GenPrivKey().PubKey()) + err := sv.Verify(ed25519.GenPrivKey().PubKey()) if assert.Error(t, err) { assert.Equal(t, ErrVoteInvalidValidatorAddress, err) } - err = vote.Verify("test_chain_id", pubkey) + err = sv.Verify(pubkey) if assert.Error(t, err) { assert.Equal(t, ErrVoteInvalidSignature, err) } } func TestMaxVoteBytes(t *testing.T) { - vote := &Vote{ + vote := &UnsignedVote{ ValidatorAddress: tmhash.Sum([]byte("validator_address")), ValidatorIndex: math.MaxInt64, Height: math.MaxInt64, @@ -141,11 +144,12 @@ func TestMaxVoteBytes(t *testing.T) { } privVal := NewMockPV() - err := privVal.SignVote("test_chain_id", vote) + sv, err := privVal.SignVote(vote) require.NoError(t, err) - bz, err := cdc.MarshalBinary(vote) + bz, err := cdc.MarshalBinary(sv) require.NoError(t, err) - + // TODO(ismail): if we include the chainId in the vote this varies ... + // we need a max size for chainId too assert.Equal(t, MaxVoteBytes, len(bz)) }