Browse Source

addVote takes index

pull/142/head
Ethan Buchman 9 years ago
parent
commit
2b8157ce2a
6 changed files with 149 additions and 100 deletions
  1. +2
    -2
      consensus/height_vote_set.go
  2. +12
    -9
      consensus/reactor.go
  3. +54
    -82
      consensus/state.go
  4. +75
    -1
      consensus/test.go
  5. +0
    -1
      rpc/core_client/ws_client.go
  6. +6
    -5
      types/vote_set.go

+ 2
- 2
consensus/height_vote_set.go View File

@ -88,7 +88,7 @@ func (hvs *HeightVoteSet) addRound(round int) {
// Duplicate votes return added=false, err=nil.
// By convention, peerKey is "" if origin is self.
func (hvs *HeightVoteSet) AddByAddress(address []byte, vote *types.Vote, peerKey string) (added bool, index int, err error) {
func (hvs *HeightVoteSet) AddByIndex(valIndex int, vote *types.Vote, peerKey string) (added bool, address []byte, err error) {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
voteSet := hvs.getVoteSet(vote.Round, vote.Type)
@ -104,7 +104,7 @@ func (hvs *HeightVoteSet) AddByAddress(address []byte, vote *types.Vote, peerKey
}
return
}
added, index, err = voteSet.AddByAddress(address, vote)
added, address, err = voteSet.AddByIndex(valIndex, vote)
return
}


+ 12
- 9
consensus/reactor.go View File

@ -137,8 +137,7 @@ func (conR *ConsensusReactor) Receive(chID byte, peer *p2p.Peer, msgBytes []byte
return
}
// Get round state
rs := conR.conS.GetRoundState()
// Get peer states
ps := peer.Data.Get(PeerStateKey).(*PeerState)
_, msg, err := DecodeMessage(msgBytes)
if err != nil {
@ -146,13 +145,13 @@ func (conR *ConsensusReactor) Receive(chID byte, peer *p2p.Peer, msgBytes []byte
// TODO punish peer?
return
}
log.Debug("Receive", "channel", chID, "peer", peer, "msg", msg, "rsHeight", rs.Height)
log.Debug("Receive", "channel", chId, "peer", peer, "msg", msg)
switch chID {
case StateChannel:
switch msg := msg.(type) {
case *NewRoundStepMessage:
ps.ApplyNewRoundStepMessage(msg, rs)
ps.ApplyNewRoundStepMessage(msg)
case *CommitStepMessage:
ps.ApplyCommitStepMessage(msg)
case *HasVoteMessage:
@ -189,15 +188,19 @@ func (conR *ConsensusReactor) Receive(chID byte, peer *p2p.Peer, msgBytes []byte
vote, valIndex := msg.Vote, msg.ValidatorIndex
// attempt to add the vote and dupeout the validator if its a duplicate signature
added, err := conR.conS.TryAddVote(rs, vote, valIndex, peer.Key)
added, err := conR.conS.TryAddVote(valIndex, vote, peer.Key)
if err == ErrAddingVote {
// TODO: punish peer
} else if err != nil {
return
}
ps.EnsureVoteBitArrays(rs.Height, rs.Validators.Size())
ps.EnsureVoteBitArrays(rs.Height-1, rs.LastCommit.Size())
cs := conR.conS
cs.mtx.Lock()
height, valSize, lastCommitSize := cs.Height, cs.Validators.Size(), cs.LastCommit.Size()
cs.mtx.Unlock()
ps.EnsureVoteBitArrays(height, valSize)
ps.EnsureVoteBitArrays(height-1, lastCommitSize)
ps.SetHasVote(vote, valIndex)
if added {
@ -208,7 +211,7 @@ func (conR *ConsensusReactor) Receive(chID byte, peer *p2p.Peer, msgBytes []byte
}
default:
// TODO: should these be punishable?
// don't punish (leave room for soft upgrades)
log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg)))
}
default:
@ -793,7 +796,7 @@ func (ps *PeerState) setHasVote(height int, round int, type_ byte, index int) {
}
}
func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage, rs *RoundState) {
func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage) {
ps.mtx.Lock()
defer ps.mtx.Unlock()


+ 54
- 82
consensus/state.go View File

@ -180,6 +180,7 @@ var (
ErrInvalidProposalSignature = errors.New("Error invalid proposal signature")
ErrInvalidProposalPOLRound = errors.New("Error invalid proposal POL round")
ErrAddingVote = errors.New("Error adding vote")
ErrVoteHeightMismatch = errors.New("Error vote height mismatch")
)
//-----------------------------------------------------------------------------
@ -300,7 +301,7 @@ type ConsensusState struct {
evsw events.Fireable
evc *events.EventCache // set in stageBlock and passed into state
timeoutChan chan TimeoutEvent // RoundState instead?
timeoutChan chan TimeoutEvent // so we can track timeouts
timeoutQuitChan chan struct{}
}
@ -499,7 +500,7 @@ func (cs *ConsensusState) EnterNewRound(height int, round int) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
if cs.Height != height || round < cs.Round || (cs.Round == round && cs.Step != RoundStepNewHeight) {
log.Info(Fmt("EnterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
log.Debug(Fmt("EnterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return
}
if now := time.Now(); cs.StartTime.After(now) {
@ -538,39 +539,29 @@ func (cs *ConsensusState) EnterPropose(height int, round int) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPropose <= cs.Step) {
log.Info(Fmt("EnterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
log.Debug(Fmt("EnterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return
}
log.Info(Fmt("EnterPropose(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
var enterPrevote = make(chan struct{}, 1)
defer func() {
// Done EnterPropose:
cs.Round = round
cs.Step = RoundStepPropose
enterPrevote <- struct{}{}
cs.newStepCh <- cs.getRoundState()
// If we have the whole proposal + POL, then goto Prevote now.
// else, we'll EnterPrevote when the rest of the proposal is received (in AddProposalBlockPart),
// or else after timeoutPropose
if cs.isProposalComplete() {
go cs.EnterPrevote(height, cs.Round)
}
}()
// EnterPrevote after timeoutPropose or if the proposal is complete
// This step times out after `timeoutPropose`
go func() {
ticker := time.NewTicker(timeoutPropose)
LOOP:
for {
select {
case <-ticker.C:
enterPrevote <- struct{}{}
cs.timeoutChan <- TimeoutEvent{RoundStepPropose, height, round}
break LOOP
case <-enterPrevote:
// If we already have the proposal + POL, then goto Prevote
if cs.isProposalComplete() {
break LOOP
}
}
}
cs.newStepCh <- cs.getRoundState()
go cs.EnterPrevote(height, round)
time.Sleep(timeoutPropose)
cs.EnterPrevote(height, round)
}()
// Nothing more to do if we're not a validator
@ -582,7 +573,7 @@ func (cs *ConsensusState) EnterPropose(height int, round int) {
log.Info("EnterPropose: Not our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator)
} else {
log.Info("EnterPropose: Our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator)
cs.decideProposal(height, round) // if this takes longer than timeoutPropose we'll catch it in a later EnterPropose
cs.decideProposal(height, round)
}
}
@ -633,8 +624,7 @@ func (cs *ConsensusState) isProposalComplete() bool {
}
// Create the next block to propose and return it.
// NOTE: make it side-effect free for clarity.
// XXX: where are the side-effects?
// NOTE: keep it side-effect free for clarity.
func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts *types.PartSet) {
var validation *types.Validation
if cs.Height == 1 {
@ -688,7 +678,7 @@ func (cs *ConsensusState) EnterPrevote(height int, round int) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrevote <= cs.Step) {
log.Info(Fmt("EnterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
log.Debug(Fmt("EnterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return
}
log.Info(Fmt("EnterPrevote(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
@ -742,7 +732,7 @@ func (cs *ConsensusState) EnterPrevoteWait(height int, round int) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrevoteWait <= cs.Step) {
log.Info(Fmt("EnterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
log.Debug(Fmt("EnterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return
}
if !cs.Votes.Prevotes(round).HasTwoThirdsAny() {
@ -766,15 +756,14 @@ func (cs *ConsensusState) EnterPrevoteWait(height int, round int) {
// Enter: +2/3 precomits for block or nil.
// Enter: `timeoutPrevote` after any +2/3 prevotes.
// Enter: any +2/3 precommits for next round.
// Lock & precommit the ProposalBlock if we have enough prevotes for it,
// Lock & precommit the ProposalBlock if we have enough prevotes for it (a POL in this round)
// else, unlock an existing lock and precommit nil if +2/3 of prevotes were nil,
// else, precommit nil otherwise.
// NOTE: we don't precommit our locked block (unless theres another POL for it) because it complicates unlocking and accountability
func (cs *ConsensusState) EnterPrecommit(height int, round int) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrecommit <= cs.Step) {
log.Info(Fmt("EnterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
log.Debug(Fmt("EnterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return
}
log.Info(Fmt("EnterPrecommit(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
@ -792,9 +781,7 @@ func (cs *ConsensusState) EnterPrecommit(height int, round int) {
hash, partsHeader, ok := cs.Votes.Prevotes(round).TwoThirdsMajority()
// If we don't have two thirds of prevotes, just precommit nil
// NOTE: alternatively, if we have seen a POL since our last precommit,
// we could precommit that
// If we don't have two thirds of prevotes, we must precommit nil
if !ok {
if cs.LockedBlock != nil {
log.Info("EnterPrecommit: No +2/3 prevotes during EnterPrecommit while we're locked. Precommitting nil")
@ -814,7 +801,7 @@ func (cs *ConsensusState) EnterPrecommit(height int, round int) {
log.Info("EnterPrecommit: +2/3 prevoted for nil.")
} else {
log.Info("EnterPrecommit: +2/3 prevoted for nil. Unlocking")
cs.LockedRound = 0 //XXX: should be this round
cs.LockedRound = 0
cs.LockedBlock = nil
cs.LockedBlockParts = nil
}
@ -834,7 +821,7 @@ func (cs *ConsensusState) EnterPrecommit(height int, round int) {
// If +2/3 prevoted for proposal block, stage and precommit it
if cs.ProposalBlock.HashesTo(hash) {
log.Info("EnterPrecommit: +2/3 prevoted proposal block.", "hash", fmt.Sprintf("%X", hash))
log.Info("EnterPrecommit: +2/3 prevoted proposal block.", "hash", hash)
// Validate the block.
if err := cs.stageBlock(cs.ProposalBlock, cs.ProposalBlockParts); err != nil {
PanicConsensus(Fmt("EnterPrecommit: +2/3 prevoted for an invalid block: %v", err))
@ -872,7 +859,7 @@ func (cs *ConsensusState) EnterPrecommitWait(height int, round int) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrecommitWait <= cs.Step) {
log.Info(Fmt("EnterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
log.Debug(Fmt("EnterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
return
}
if !cs.Votes.Precommits(round).HasTwoThirdsAny() {
@ -902,7 +889,7 @@ func (cs *ConsensusState) EnterCommit(height int, commitRound int) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
if cs.Height != height || RoundStepCommit <= cs.Step {
log.Info(Fmt("EnterCommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step))
log.Debug(Fmt("EnterCommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step))
return
}
log.Info(Fmt("EnterCommit(%v/%v). Current: %v/%v/%v", height, commitRound, cs.Height, cs.Round, cs.Step))
@ -924,20 +911,10 @@ func (cs *ConsensusState) EnterCommit(height int, commitRound int) {
// The Locked* fields no longer matter.
// Move them over to ProposalBlock if they match the commit hash,
// otherwise they can now be cleared.
// XXX: can't we just wait to clear them in updateToState ?
// XXX: it's causing a race condition in tests where they get cleared
// before we can check the lock!
// otherwise they'll be cleared in updateToState.
if cs.LockedBlock.HashesTo(hash) {
cs.ProposalBlock = cs.LockedBlock
cs.ProposalBlockParts = cs.LockedBlockParts
/*cs.LockedRound = 0
cs.LockedBlock = nil
cs.LockedBlockParts = nil*/
} else {
/*cs.LockedRound = 0
cs.LockedBlock = nil
cs.LockedBlockParts = nil*/
}
// If we don't have the block being committed, set up to get it.
@ -977,7 +954,7 @@ func (cs *ConsensusState) FinalizeCommit(height, round int) {
defer cs.mtx.Unlock()
if cs.Height != height || cs.Step != RoundStepCommit {
log.Info(Fmt("FinalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step))
log.Debug(Fmt("FinalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step))
return
}
@ -1078,7 +1055,6 @@ func (cs *ConsensusState) AddProposalBlockPart(height int, part *types.Part) (ad
log.Info("Received complete proposal", "hash", cs.ProposalBlock.Hash())
if cs.Step == RoundStepPropose && cs.isProposalComplete() {
// Move onto the next step
// XXX: isn't this unecessary since propose will either do this or timeout into it
go cs.EnterPrevote(height, cs.Round)
} else if cs.Step == RoundStepCommit {
// If we're waiting on the proposal block...
@ -1089,35 +1065,23 @@ func (cs *ConsensusState) AddProposalBlockPart(height int, part *types.Part) (ad
return added, nil
}
func (cs *ConsensusState) AddVote(address []byte, vote *types.Vote, peerKey string) (added bool, index int, err error) {
func (cs *ConsensusState) AddVote(valIndex int, vote *types.Vote, peerKey string) (added bool, address []byte, err error) {
cs.mtx.Lock()
defer cs.mtx.Unlock()
return cs.addVote(address, vote, peerKey)
return cs.addVote(valIndex, vote, peerKey)
}
// Attempt to add the vote. if its a duplicate signature, dupeout the validator
func (cs *ConsensusState) TryAddVote(rs *RoundState, vote *types.Vote, valIndex int, peerKey string) (bool, error) {
var validators *types.ValidatorSet
if rs.Height == vote.Height {
validators = rs.Validators
} else if rs.Height == vote.Height+1 {
if !(rs.Step == RoundStepNewHeight && vote.Type == types.VoteTypePrecommit) {
return false, fmt.Errorf("TryAddVote: Wrong height, not a LastCommit straggler commit.")
}
validators = rs.LastValidators
} else {
return false, fmt.Errorf("TryAddVote: Wrong height. Not necessarily a bad peer.")
}
// We have vote/validators. Height may not be rs.Height
address, _ := validators.GetByIndex(valIndex)
added, index, err := cs.AddVote(address, vote, peerKey)
_ = index // should be same as valIndex
func (cs *ConsensusState) TryAddVote(valIndex int, vote *types.Vote, peerKey string) (bool, error) {
added, address, err := cs.AddVote(valIndex, vote, peerKey)
if err != nil {
// If conflicting sig, broadcast evidence tx for slashing. Else punish peer.
if errDupe, ok := err.(*types.ErrVoteConflictingSignature); ok {
// If the vote height is off, we'll just ignore it,
// But if it's a conflicting sig, broadcast evidence tx for slashing
// and otherwise punish peer.
if err == ErrVoteHeightMismatch {
return added, err
} else if errDupe, ok := err.(*types.ErrVoteConflictingSignature); ok {
log.Warn("Found conflicting vote. Publish evidence")
evidenceTx := &types.DupeoutTx{
Address: address,
@ -1137,12 +1101,17 @@ func (cs *ConsensusState) TryAddVote(rs *RoundState, vote *types.Vote, valIndex
//-----------------------------------------------------------------------------
func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey string) (added bool, index int, err error) {
func (cs *ConsensusState) addVote(valIndex int, vote *types.Vote, peerKey string) (added bool, address []byte, err error) {
log.Debug("addVote", "voteHeight", vote.Height, "voteType", vote.Type, "csHeight", cs.Height)
// A precommit for the previous height?
if vote.Height+1 == cs.Height && vote.Type == types.VoteTypePrecommit {
added, index, err = cs.LastCommit.AddByAddress(address, vote)
if vote.Height+1 == cs.Height {
if !(cs.Step == RoundStepNewHeight && vote.Type == types.VoteTypePrecommit) {
// TODO: give the reason ..
// fmt.Errorf("TryAddVote: Wrong height, not a LastCommit straggler commit.")
return added, nil, ErrVoteHeightMismatch
}
added, address, err = cs.LastCommit.AddByIndex(valIndex, vote)
if added {
log.Info(Fmt("Added to lastPrecommits: %v", cs.LastCommit.StringShort()))
}
@ -1152,7 +1121,7 @@ func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey stri
// A prevote/precommit for this height?
if vote.Height == cs.Height {
height := cs.Height
added, index, err = cs.Votes.AddByAddress(address, vote, peerKey)
added, address, err = cs.Votes.AddByIndex(valIndex, vote, peerKey)
if added {
switch vote.Type {
case types.VoteTypePrevote:
@ -1167,7 +1136,7 @@ func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey stri
hash, _, ok := prevotes.TwoThirdsMajority()
if ok && !cs.LockedBlock.HashesTo(hash) {
log.Notice("Unlocking because of POL.", "lockedRound", cs.LockedRound, "POLRound", vote.Round)
cs.LockedRound = 0 // XXX: shouldn't we set this to the current round?
cs.LockedRound = 0
cs.LockedBlock = nil
cs.LockedBlockParts = nil
}
@ -1214,8 +1183,10 @@ func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey stri
PanicSanity(Fmt("Unexpected vote type %X", vote.Type)) // Should not happen.
}
}
// Either duplicate, or error upon cs.Votes.AddByAddress()
// Either duplicate, or error upon cs.Votes.AddByIndex()
return
} else {
err = ErrVoteHeightMismatch
}
// Height mismatch, bad peer?
@ -1270,7 +1241,9 @@ func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.Part
}
vote, err := cs.signVote(type_, hash, header)
if err == nil {
_, _, err := cs.addVote(cs.privValidator.Address, vote, "")
// NOTE: store our index in the cs so we don't have to do this every time
valIndex, _ := cs.Validators.GetByAddress(cs.privValidator.Address)
_, _, err := cs.addVote(valIndex, vote, "")
log.Notice("Signed and added vote", "height", cs.Height, "round", cs.Round, "vote", vote, "error", err)
return vote
} else {
@ -1333,7 +1306,6 @@ func (cs *ConsensusState) logTimeouts(timeoutChan chan TimeoutEvent, quitChan <-
select {
case timeout := <-timeoutChan:
log.Info("Timeout in consensus state", "height", timeout.Height, "round", timeout.Round, "step", timeout.Type.String())
timeoutChan <- timeout
case <-quitChan:
return


+ 75
- 1
consensus/test.go View File

@ -17,9 +17,47 @@ import (
//-------------------------------------------------------------------------------
// utils
func changeProposer(t *testing.T, perspectiveOf, newProposer *ConsensusState) *types.Block {
_, v1 := perspectiveOf.Validators.GetByAddress(perspectiveOf.privValidator.Address)
v1.Accum, v1.VotingPower = 0, 0
if updated := perspectiveOf.Validators.Update(v1); !updated {
t.Fatal("failed to update validator")
}
_, v2 := perspectiveOf.Validators.GetByAddress(newProposer.privValidator.Address)
v2.Accum, v2.VotingPower = 100, 100
if updated := perspectiveOf.Validators.Update(v2); !updated {
t.Fatal("failed to update validator")
}
// make the proposal
propBlock, _ := newProposer.createProposalBlock()
if propBlock == nil {
t.Fatal("Failed to create proposal block with cs2")
}
return propBlock
}
func fixVotingPower(t *testing.T, cs1 *ConsensusState, addr2 []byte) {
_, v1 := cs1.Validators.GetByAddress(cs1.privValidator.Address)
_, v2 := cs1.Validators.GetByAddress(addr2)
v1.Accum, v1.VotingPower = v2.Accum, v2.VotingPower
if updated := cs1.Validators.Update(v1); !updated {
t.Fatal("failed to update validator")
}
}
func addVoteToFromMany(to *ConsensusState, votes []*types.Vote, froms ...*ConsensusState) {
if len(votes) != len(froms) {
panic("len(votes) and len(froms) must match")
}
for i, from := range froms {
addVoteToFrom(to, from, votes[i])
}
}
func addVoteToFrom(to, from *ConsensusState, vote *types.Vote) {
valIndex, _ := to.Validators.GetByAddress(from.privValidator.Address)
added, err := to.TryAddVote(to.GetRoundState(), vote, valIndex, "")
added, err := to.TryAddVote(valIndex, vote, "")
if _, ok := err.(*types.ErrVoteConflictingSignature); ok {
// let it fly
} else if !added {
@ -37,7 +75,22 @@ func signVote(from *ConsensusState, voteType byte, hash []byte, header types.Par
return vote
}
func signVoteMany(voteType byte, hash []byte, header types.PartSetHeader, css ...*ConsensusState) []*types.Vote {
votes := make([]*types.Vote, len(css))
for i, cs := range css {
votes[i] = signVote(cs, voteType, hash, header)
}
return votes
}
// add vote to one cs from another
func signAddVoteToFromMany(voteType byte, to *ConsensusState, hash []byte, header types.PartSetHeader, froms ...*ConsensusState) {
for _, from := range froms {
vote := signVote(from, voteType, hash, header)
addVoteToFrom(to, from, vote)
}
}
func signAddVoteToFrom(voteType byte, to, from *ConsensusState, hash []byte, header types.PartSetHeader) *types.Vote {
vote := signVote(from, voteType, hash, header)
addVoteToFrom(to, from, vote)
@ -81,6 +134,12 @@ func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *types
}
}
func incrementRound(css ...*ConsensusState) {
for _, cs := range css {
cs.Round += 1
}
}
func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *types.PrivValidator, votedBlockHash, lockedBlockHash []byte) {
precommits := cs.Votes.Precommits(thisRound)
var vote *types.Vote
@ -110,6 +169,20 @@ func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound in
}
func validatePrevoteAndPrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *types.PrivValidator, votedBlockHash, lockedBlockHash []byte, f func()) {
// verify the prevote
validatePrevote(t, cs, thisRound, privVal, votedBlockHash)
if f != nil {
f()
}
// wait to finish precommit
<-cs.NewStepCh()
// verify precommit
cs.mtx.Lock()
validatePrecommit(t, cs, thisRound, lockRound, privVal, votedBlockHash, lockedBlockHash)
cs.mtx.Unlock()
}
func simpleConsensusState(nValidators int) ([]*ConsensusState, []*types.PrivValidator) {
// Get State
state, privAccs, privVals := sm.RandGenesisState(10, true, 1000, nValidators, false, 10)
@ -131,6 +204,7 @@ func simpleConsensusState(nValidators int) ([]*ConsensusState, []*types.PrivVali
// Make ConsensusReactor
cs := NewConsensusState(state, blockStore, mempoolReactor)
cs.SetPrivValidator(privVals[i])
// read off the NewHeightStep
<-cs.NewStepCh()


+ 0
- 1
rpc/core_client/ws_client.go View File

@ -7,7 +7,6 @@ import (
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/gorilla/websocket"
. "github.com/tendermint/tendermint/common"
_ "github.com/tendermint/tendermint/config/tendermint_test"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/rpc/types"
"github.com/tendermint/tendermint/wire"


+ 6
- 5
types/vote_set.go View File

@ -85,7 +85,7 @@ func (voteSet *VoteSet) Size() int {
// Otherwise returns err=ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
// Duplicate votes return added=false, err=nil.
// NOTE: vote should not be mutated after adding.
func (voteSet *VoteSet) AddByIndex(valIndex int, vote *Vote) (added bool, index int, err error) {
func (voteSet *VoteSet) AddByIndex(valIndex int, vote *Vote) (added bool, address []byte, err error) {
voteSet.mtx.Lock()
defer voteSet.mtx.Unlock()
@ -109,14 +109,15 @@ func (voteSet *VoteSet) AddByAddress(address []byte, vote *Vote) (added bool, in
return voteSet.addVote(val, valIndex, vote)
}
func (voteSet *VoteSet) addByIndex(valIndex int, vote *Vote) (bool, int, error) {
func (voteSet *VoteSet) addByIndex(valIndex int, vote *Vote) (added bool, address []byte, err error) {
// Ensure that signer is a validator.
_, val := voteSet.valSet.GetByIndex(valIndex)
address, val := voteSet.valSet.GetByIndex(valIndex)
if val == nil {
return false, 0, ErrVoteInvalidAccount
return false, nil, ErrVoteInvalidAccount
}
return voteSet.addVote(val, valIndex, vote)
added, _, err = voteSet.addVote(val, valIndex, vote)
return
}
func (voteSet *VoteSet) addVote(val *Validator, valIndex int, vote *Vote) (bool, int, error) {


Loading…
Cancel
Save