diff --git a/blocks/vote.go b/blocks/vote.go index 041657096..94ee854af 100644 --- a/blocks/vote.go +++ b/blocks/vote.go @@ -2,6 +2,7 @@ package blocks import ( "errors" + "fmt" "io" . "github.com/tendermint/tendermint/binary" @@ -56,3 +57,20 @@ func (v *Vote) GetSignature() Signature { func (v *Vote) SetSignature(sig Signature) { v.Signature = sig } + +func (v *Vote) String() string { + blockHash := v.BlockHash + if len(v.BlockHash) == 0 { + blockHash = make([]byte, 6) // for printing + } + switch v.Type { + case VoteTypeBare: + return fmt.Sprintf("Vote{%v/%v:%X:%v}", v.Height, v.Round, blockHash, v.SignerId) + case VoteTypePrecommit: + return fmt.Sprintf("Precommit{%v/%v:%X:%v}", v.Height, v.Round, blockHash, v.SignerId) + case VoteTypeCommit: + return fmt.Sprintf("Commit{%v/%v:%X:%v}", v.Height, v.Round, v.BlockHash[:6], v.SignerId) + default: + panic("Unknown vote type") + } +} diff --git a/common/bit_array.go b/common/bit_array.go index d771c4c39..1070018fa 100644 --- a/common/bit_array.go +++ b/common/bit_array.go @@ -4,6 +4,7 @@ import ( "io" "math" "math/rand" + "strings" . "github.com/tendermint/tendermint/binary" ) @@ -153,3 +154,33 @@ func (bA BitArray) PickRarest(counts []int) (rarest int, ok bool) { } return } + +func (bA BitArray) String() string { + return bA.StringWithIndent("") +} + +func (bA BitArray) StringWithIndent(indent string) string { + lines := []string{} + bits := "" + for i := 0; i < len(bA)*64; i++ { + if bA.GetIndex(uint(i)) { + bits += "X" + } else { + bits += "_" + } + if i%100 == 99 { + lines = append(lines, bits) + bits = "" + } + if i%10 == 9 { + bits += " " + } + if i%50 == 49 { + bits += " " + } + } + if len(bits) > 0 { + lines = append(lines, bits) + } + return strings.Join(lines, indent) +} diff --git a/consensus/state.go b/consensus/state.go index a590b9213..df75d0aa0 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -142,9 +142,9 @@ func (cs *ConsensusState) setupRound(round uint16) { cs.ProposalPOL = nil cs.ProposalPOLPartSet = nil cs.Votes = NewVoteSet(cs.Height, round, VoteTypeBare, validators) - cs.Votes.AddVotesFromCommits(cs.Commits) + cs.Votes.AddFromCommits(cs.Commits) cs.Precommits = NewVoteSet(cs.Height, round, VoteTypePrecommit, validators) - cs.Precommits.AddVotesFromCommits(cs.Commits) + cs.Precommits.AddFromCommits(cs.Commits) } func (cs *ConsensusState) SetStep(step byte) { @@ -289,15 +289,15 @@ func (cs *ConsensusState) AddVote(vote *Vote) (added bool, err error) { switch vote.Type { case VoteTypeBare: // Votes checks for height+round match. - return cs.Votes.AddVote(vote) + return cs.Votes.Add(vote) case VoteTypePrecommit: // Precommits checks for height+round match. - return cs.Precommits.AddVote(vote) + return cs.Precommits.Add(vote) case VoteTypeCommit: // Commits checks for height match. - cs.Votes.AddVote(vote) - cs.Precommits.AddVote(vote) - return cs.Commits.AddVote(vote) + cs.Votes.Add(vote) + cs.Precommits.Add(vote) + return cs.Commits.Add(vote) default: panic("Unknown vote type") } diff --git a/consensus/vote_set.go b/consensus/vote_set.go index 8dd2b8855..62501fa1d 100644 --- a/consensus/vote_set.go +++ b/consensus/vote_set.go @@ -2,7 +2,8 @@ package consensus import ( "bytes" - + "fmt" + "strings" "sync" "time" @@ -50,7 +51,7 @@ func NewVoteSet(height uint32, round uint16, type_ byte, vset *ValidatorSet) *Vo // True if added, false if not. // Returns ErrVote[UnexpectedPhase|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature] -func (vs *VoteSet) AddVote(vote *Vote) (bool, error) { +func (vs *VoteSet) Add(vote *Vote) (bool, error) { vs.mtx.Lock() defer vs.mtx.Unlock() @@ -109,7 +110,7 @@ func (vs *VoteSet) addVote(vote *Vote) (bool, error) { } // Assumes that commits VoteSet is valid. -func (vs *VoteSet) AddVotesFromCommits(commits *VoteSet) { +func (vs *VoteSet) AddFromCommits(commits *VoteSet) { commitVotes := commits.AllVotes() for _, commit := range commitVotes { if commit.Round < vs.round { @@ -177,3 +178,26 @@ func (vs *VoteSet) MakePOL() *POL { } return pol } + +func (vs *VoteSet) String() string { + return vs.StringWithIndent("") +} + +func (vs *VoteSet) StringWithIndent(indent string) string { + vs.mtx.Lock() + defer vs.mtx.Unlock() + + voteStrings := make([]string, len(vs.votes)) + for _, vote := range vs.votes { + voteStrings[vote.SignerId] = vote.String() + } + return fmt.Sprintf(`VoteSet{ +%s H:%v R:%v T:%v +%s %v +%s %v +%s}`, + indent, vs.height, vs.round, vs.type_, + indent, strings.Join(voteStrings, "\n"+indent+" "), + indent, vs.votesBitArray, + indent) +} diff --git a/consensus/vote_set_test.go b/consensus/vote_set_test.go index 3d378138f..c8db9e670 100644 --- a/consensus/vote_set_test.go +++ b/consensus/vote_set_test.go @@ -1,6 +1,7 @@ package consensus import ( + . "github.com/tendermint/tendermint/blocks" . "github.com/tendermint/tendermint/state" "testing" @@ -15,8 +16,33 @@ func makeValidator(id uint64, votingPower uint64) (*Validator, *PrivAccount) { }, privAccount } +func makeVoteSet(numValidators int, votingPower uint64) (*VoteSet, *ValidatorSet, []*PrivAccount) { + vals := make([]*Validator, numValidators) + privAccounts := make([]*PrivAccount, numValidators) + for i := 0; i < numValidators; i++ { + val, privAccount := makeValidator(uint64(i), votingPower) + vals[i] = val + privAccounts[i] = privAccount + } + valSet := NewValidatorSet(vals) + return NewVoteSet(0, 0, VoteTypeBare, valSet), valSet, privAccounts +} + func TestAddVote(t *testing.T) { - // XXX + voteSet, valSet, privAccounts := makeVoteSet(10, 1) + vote := &Vote{Height: 0, Round: 0, Type: VoteTypeBare, BlockHash: nil} + + t.Logf(">> %v", voteSet) + t.Logf(">> %v", valSet) + t.Logf(">> %v", privAccounts) + + privAccounts[0].Sign(vote) + voteSet.Add(vote) + + t.Logf(">> %v", voteSet) + t.Logf(">> %v", valSet) + t.Logf(">> %v", privAccounts) + } func Test2_3Majority(t *testing.T) { diff --git a/state/account.go b/state/account.go index d099155d0..ec4450a14 100644 --- a/state/account.go +++ b/state/account.go @@ -39,6 +39,9 @@ func (account Account) VerifyBytes(msg []byte, sig Signature) bool { if sig.SignerId != account.Id { panic("account.id doesn't match sig.signerid") } + if len(sig.Bytes) == 0 { + panic("signature is empty") + } v1 := &crypto.Verify{ Message: msg, PubKey: account.PubKey, @@ -57,7 +60,7 @@ func (account Account) Verify(o Signable) bool { } func (account Account) String() string { - return fmt.Sprintf("Account{%v:%X}", account.Id, account.PubKey) + return fmt.Sprintf("Account{%v:%X}", account.Id, account.PubKey[:6]) } //-----------------------------------------------------------------------------