Browse Source

Validation tests

pull/9/head
Jae Kwon 10 years ago
parent
commit
b7b923cc6b
10 changed files with 279 additions and 97 deletions
  1. +8
    -9
      blocks/part_set.go
  2. +2
    -2
      blocks/part_set_test.go
  3. +5
    -0
      blocks/vote.go
  4. +14
    -0
      common/test/assert.go
  5. +47
    -32
      consensus/pol_test.go
  6. +12
    -21
      consensus/state_test.go
  7. +2
    -3
      consensus/test.go
  8. +5
    -1
      consensus/vote_set.go
  9. +181
    -28
      consensus/vote_set_test.go
  10. +3
    -1
      state/account.go

+ 8
- 9
blocks/part_set.go View File

@ -84,20 +84,20 @@ func (part *Part) StringWithIndent(indent string) string {
//------------------------------------- //-------------------------------------
type PartSetHeader struct { type PartSetHeader struct {
Hash []byte
Total uint16 Total uint16
Hash []byte
} }
func ReadPartSetHeader(r io.Reader, n *int64, err *error) PartSetHeader { func ReadPartSetHeader(r io.Reader, n *int64, err *error) PartSetHeader {
return PartSetHeader{ return PartSetHeader{
Hash: ReadByteSlice(r, n, err),
Total: ReadUInt16(r, n, err), Total: ReadUInt16(r, n, err),
Hash: ReadByteSlice(r, n, err),
} }
} }
func (psh PartSetHeader) WriteTo(w io.Writer) (n int64, err error) { func (psh PartSetHeader) WriteTo(w io.Writer) (n int64, err error) {
WriteByteSlice(w, psh.Hash, &n, &err)
WriteUInt16(w, psh.Total, &n, &err) WriteUInt16(w, psh.Total, &n, &err)
WriteByteSlice(w, psh.Hash, &n, &err)
return return
} }
@ -110,15 +110,14 @@ func (psh PartSetHeader) String() string {
} }
func (psh PartSetHeader) Equals(other PartSetHeader) bool { func (psh PartSetHeader) Equals(other PartSetHeader) bool {
return bytes.Equal(psh.Hash, other.Hash) &&
psh.Total == other.Total
return psh.Total == other.Total && bytes.Equal(psh.Hash, other.Hash)
} }
//------------------------------------- //-------------------------------------
type PartSet struct { type PartSet struct {
hash []byte
total uint16 total uint16
hash []byte
mtx sync.Mutex mtx sync.Mutex
parts []*Part parts []*Part
@ -148,8 +147,8 @@ func NewPartSetFromData(data []byte) *PartSet {
parts[i].Trail = merkle.HashTrailForIndex(hashTree, i) parts[i].Trail = merkle.HashTrailForIndex(hashTree, i)
} }
return &PartSet{ return &PartSet{
hash: hashTree[len(hashTree)/2],
total: uint16(total), total: uint16(total),
hash: hashTree[len(hashTree)/2],
parts: parts, parts: parts,
partsBitArray: partsBitArray, partsBitArray: partsBitArray,
count: uint16(total), count: uint16(total),
@ -159,8 +158,8 @@ func NewPartSetFromData(data []byte) *PartSet {
// Returns an empty PartSet ready to be populated. // Returns an empty PartSet ready to be populated.
func NewPartSetFromHeader(header PartSetHeader) *PartSet { func NewPartSetFromHeader(header PartSetHeader) *PartSet {
return &PartSet{ return &PartSet{
hash: header.Hash,
total: header.Total, total: header.Total,
hash: header.Hash,
parts: make([]*Part, header.Total), parts: make([]*Part, header.Total),
partsBitArray: NewBitArray(uint(header.Total)), partsBitArray: NewBitArray(uint(header.Total)),
count: 0, count: 0,
@ -172,8 +171,8 @@ func (ps *PartSet) Header() PartSetHeader {
return PartSetHeader{} return PartSetHeader{}
} else { } else {
return PartSetHeader{ return PartSetHeader{
Hash: ps.hash,
Total: ps.total, Total: ps.total,
Hash: ps.hash,
} }
} }
} }


+ 2
- 2
blocks/part_set_test.go View File

@ -25,7 +25,7 @@ func TestBasicPartSet(t *testing.T) {
} }
// Test adding parts to a new partSet. // Test adding parts to a new partSet.
partSet2 := NewPartSetFromHeader(PartSetHeader{partSet.Hash(), partSet.Total()})
partSet2 := NewPartSetFromHeader(partSet.Header())
for i := uint16(0); i < partSet.Total(); i++ { for i := uint16(0); i < partSet.Total(); i++ {
part := partSet.GetPart(i) part := partSet.GetPart(i)
@ -65,7 +65,7 @@ func TestWrongTrail(t *testing.T) {
partSet := NewPartSetFromData(data) partSet := NewPartSetFromData(data)
// Test adding a part with wrong data. // Test adding a part with wrong data.
partSet2 := NewPartSetFromHeader(PartSetHeader{partSet.Hash(), partSet.Total()})
partSet2 := NewPartSetFromHeader(partSet.Header())
// Test adding a part with wrong trail. // Test adding a part with wrong trail.
part := partSet.GetPart(0) part := partSet.GetPart(0)


+ 5
- 0
blocks/vote.go View File

@ -62,6 +62,11 @@ func (v *Vote) SetSignature(sig Signature) {
v.Signature = sig v.Signature = sig
} }
func (v *Vote) Copy() *Vote {
vCopy := *v
return &vCopy
}
func (v *Vote) String() string { func (v *Vote) String() string {
var typeString string var typeString string
switch v.Type { switch v.Type {


+ 14
- 0
common/test/assert.go View File

@ -0,0 +1,14 @@
package test
import (
"testing"
)
func AssertPanics(t *testing.T, msg string, f func()) {
defer func() {
if err := recover(); err == nil {
t.Errorf("Should have panic'd, but didn't: %v", msg)
}
}()
f()
}

+ 47
- 32
consensus/pol_test.go View File

@ -11,17 +11,19 @@ import (
// NOTE: see consensus/test.go for common test methods. // NOTE: see consensus/test.go for common test methods.
func TestVerifyVotes(t *testing.T) { func TestVerifyVotes(t *testing.T) {
_, valSet, privAccounts := makeVoteSet(0, 0, 10, 1)
height, round := uint32(1), uint16(0)
_, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// Make a POL with -2/3 votes. // Make a POL with -2/3 votes.
blockHash := RandBytes(32) blockHash := RandBytes(32)
pol := &POL{ pol := &POL{
Height: 0, Round: 0, BlockHash: blockHash,
Height: height, Round: round, BlockHash: blockHash,
} }
vote := &Vote{
Height: 0, Round: 0, Type: VoteTypePrevote, BlockHash: blockHash,
voteProto := &Vote{
Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash,
} }
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote) privAccounts[i].Sign(vote)
pol.Votes = append(pol.Votes, vote.Signature) pol.Votes = append(pol.Votes, vote.Signature)
} }
@ -32,6 +34,7 @@ func TestVerifyVotes(t *testing.T) {
} }
// Make a POL with +2/3 votes. // Make a POL with +2/3 votes.
vote := voteProto.Copy()
privAccounts[7].Sign(vote) privAccounts[7].Sign(vote)
pol.Votes = append(pol.Votes, vote.Signature) pol.Votes = append(pol.Votes, vote.Signature)
@ -42,17 +45,19 @@ func TestVerifyVotes(t *testing.T) {
} }
func TestVerifyInvalidVote(t *testing.T) { func TestVerifyInvalidVote(t *testing.T) {
_, valSet, privAccounts := makeVoteSet(0, 0, 10, 1)
height, round := uint32(1), uint16(0)
_, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// Make a POL with +2/3 votes with the wrong signature. // Make a POL with +2/3 votes with the wrong signature.
blockHash := RandBytes(32) blockHash := RandBytes(32)
pol := &POL{ pol := &POL{
Height: 0, Round: 0, BlockHash: blockHash,
Height: height, Round: round, BlockHash: blockHash,
} }
vote := &Vote{
Height: 0, Round: 0, Type: VoteTypePrevote, BlockHash: blockHash,
voteProto := &Vote{
Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash,
} }
for i := 0; i < 7; i++ { for i := 0; i < 7; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote) privAccounts[i].Sign(vote)
// Mutate the signature. // Mutate the signature.
vote.Signature.Bytes[0] += byte(0x01) vote.Signature.Bytes[0] += byte(0x01)
@ -66,19 +71,21 @@ func TestVerifyInvalidVote(t *testing.T) {
} }
func TestVerifyCommits(t *testing.T) { func TestVerifyCommits(t *testing.T) {
_, valSet, privAccounts := makeVoteSet(0, 2, 10, 1)
height, round := uint32(1), uint16(2)
_, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// Make a POL with +2/3 votes. // Make a POL with +2/3 votes.
blockHash := RandBytes(32) blockHash := RandBytes(32)
pol := &POL{ pol := &POL{
Height: 0, Round: 2, BlockHash: blockHash,
Height: height, Round: round, BlockHash: blockHash,
} }
vote := &Vote{
Height: 0, Round: 1, Type: VoteTypeCommit, BlockHash: blockHash,
voteProto := &Vote{
Height: height, Round: round - 1, Type: VoteTypeCommit, BlockHash: blockHash,
} }
for i := 0; i < 7; i++ { for i := 0; i < 7; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote) privAccounts[i].Sign(vote)
pol.Commits = append(pol.Commits, RoundSignature{1, vote.Signature})
pol.Commits = append(pol.Commits, RoundSignature{round - 1, vote.Signature})
} }
// Check that validation succeeds. // Check that validation succeeds.
@ -88,21 +95,23 @@ func TestVerifyCommits(t *testing.T) {
} }
func TestVerifyInvalidCommits(t *testing.T) { func TestVerifyInvalidCommits(t *testing.T) {
_, valSet, privAccounts := makeVoteSet(0, 2, 10, 1)
height, round := uint32(1), uint16(2)
_, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// Make a POL with +2/3 votes with the wrong signature. // Make a POL with +2/3 votes with the wrong signature.
blockHash := RandBytes(32) blockHash := RandBytes(32)
pol := &POL{ pol := &POL{
Height: 0, Round: 2, BlockHash: blockHash,
Height: height, Round: round, BlockHash: blockHash,
} }
vote := &Vote{
Height: 0, Round: 1, Type: VoteTypeCommit, BlockHash: blockHash,
voteProto := &Vote{
Height: height, Round: round - 1, Type: VoteTypeCommit, BlockHash: blockHash,
} }
for i := 0; i < 7; i++ { for i := 0; i < 7; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote) privAccounts[i].Sign(vote)
// Mutate the signature. // Mutate the signature.
vote.Signature.Bytes[0] += byte(0x01) vote.Signature.Bytes[0] += byte(0x01)
pol.Commits = append(pol.Commits, RoundSignature{1, vote.Signature})
pol.Commits = append(pol.Commits, RoundSignature{round - 1, vote.Signature})
} }
// Check that validation fails. // Check that validation fails.
@ -112,19 +121,21 @@ func TestVerifyInvalidCommits(t *testing.T) {
} }
func TestVerifyInvalidCommitRounds(t *testing.T) { func TestVerifyInvalidCommitRounds(t *testing.T) {
_, valSet, privAccounts := makeVoteSet(0, 2, 10, 1)
height, round := uint32(1), uint16(2)
_, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// Make a POL with +2/3 commits for the current round. // Make a POL with +2/3 commits for the current round.
blockHash := RandBytes(32) blockHash := RandBytes(32)
pol := &POL{ pol := &POL{
Height: 0, Round: 2, BlockHash: blockHash,
Height: height, Round: round, BlockHash: blockHash,
} }
vote := &Vote{
Height: 0, Round: 2, Type: VoteTypeCommit, BlockHash: blockHash,
voteProto := &Vote{
Height: height, Round: round, Type: VoteTypeCommit, BlockHash: blockHash,
} }
for i := 0; i < 7; i++ { for i := 0; i < 7; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote) privAccounts[i].Sign(vote)
pol.Commits = append(pol.Commits, RoundSignature{2, vote.Signature})
pol.Commits = append(pol.Commits, RoundSignature{round, vote.Signature})
} }
// Check that validation fails. // Check that validation fails.
@ -134,19 +145,21 @@ func TestVerifyInvalidCommitRounds(t *testing.T) {
} }
func TestVerifyInvalidCommitRounds2(t *testing.T) { func TestVerifyInvalidCommitRounds2(t *testing.T) {
_, valSet, privAccounts := makeVoteSet(0, 2, 10, 1)
height, round := uint32(1), uint16(2)
_, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// Make a POL with +2/3 commits for future round. // Make a POL with +2/3 commits for future round.
blockHash := RandBytes(32) blockHash := RandBytes(32)
pol := &POL{ pol := &POL{
Height: 0, Round: 2, BlockHash: blockHash,
Height: height, Round: round, BlockHash: blockHash,
} }
vote := &Vote{
Height: 0, Round: 3, Type: VoteTypeCommit, BlockHash: blockHash,
voteProto := &Vote{
Height: height, Round: round + 1, Type: VoteTypeCommit, BlockHash: blockHash,
} }
for i := 0; i < 7; i++ { for i := 0; i < 7; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote) privAccounts[i].Sign(vote)
pol.Commits = append(pol.Commits, RoundSignature{3, vote.Signature})
pol.Commits = append(pol.Commits, RoundSignature{round + 1, vote.Signature})
} }
// Check that validation fails. // Check that validation fails.
@ -156,17 +169,19 @@ func TestVerifyInvalidCommitRounds2(t *testing.T) {
} }
func TestReadWrite(t *testing.T) { func TestReadWrite(t *testing.T) {
_, valSet, privAccounts := makeVoteSet(0, 0, 10, 1)
height, round := uint32(1), uint16(2)
_, valSet, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// Make a POL with +2/3 votes. // Make a POL with +2/3 votes.
blockHash := RandBytes(32) blockHash := RandBytes(32)
pol := &POL{ pol := &POL{
Height: 0, Round: 0, BlockHash: blockHash,
Height: height, Round: round, BlockHash: blockHash,
} }
vote := &Vote{
Height: 0, Round: 0, Type: VoteTypePrevote, BlockHash: blockHash,
voteProto := &Vote{
Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash,
} }
for i := 0; i < 7; i++ { for i := 0; i < 7; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote) privAccounts[i].Sign(vote)
pol.Votes = append(pol.Votes, vote.Signature) pol.Votes = append(pol.Votes, vote.Signature)
} }


+ 12
- 21
consensus/state_test.go View File

@ -6,6 +6,7 @@ import (
. "github.com/tendermint/tendermint/blocks" . "github.com/tendermint/tendermint/blocks"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
. "github.com/tendermint/tendermint/common/test"
db_ "github.com/tendermint/tendermint/db" db_ "github.com/tendermint/tendermint/db"
"github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/mempool"
"github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/state"
@ -50,15 +51,6 @@ func makeConsensusState() (*ConsensusState, []*state.PrivAccount) {
return cs, privAccounts return cs, privAccounts
} }
func assertPanics(t *testing.T, msg string, f func()) {
defer func() {
if err := recover(); err == nil {
t.Errorf("Should have panic'd, but didn't: %v", msg)
}
}()
f()
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func TestSetupRound(t *testing.T) { func TestSetupRound(t *testing.T) {
@ -131,17 +123,16 @@ func TestRunActionPropose(t *testing.T) {
} }
} }
func checkRoundState(t *testing.T, cs *ConsensusState,
func checkRoundState(t *testing.T, rs *RoundState,
height uint32, round uint16, step RoundStep) { height uint32, round uint16, step RoundStep) {
rs := cs.GetRoundState()
if rs.Height != height { if rs.Height != height {
t.Errorf("cs.RoundState.Height should be %v, got %v", height, rs.Height)
t.Errorf("rs.Height should be %v, got %v", height, rs.Height)
} }
if rs.Round != round { if rs.Round != round {
t.Errorf("cs.RoundState.Round should be %v, got %v", round, rs.Round)
t.Errorf("rs.Round should be %v, got %v", round, rs.Round)
} }
if rs.Step != step { if rs.Step != step {
t.Errorf("cs.RoundState.Step should be %v, got %v", step, rs.Step)
t.Errorf("rs.Step should be %v, got %v", step, rs.Step)
} }
} }
@ -160,8 +151,8 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) {
<-cs.NewStepCh() // TODO: test this value too. <-cs.NewStepCh() // TODO: test this value too.
// Test RunActionPrecommit failures: // Test RunActionPrecommit failures:
assertPanics(t, "Wrong height ", func() { cs.RunActionPrecommit(2, 0) })
assertPanics(t, "Wrong round", func() { cs.RunActionPrecommit(1, 1) })
AssertPanics(t, "Wrong height ", func() { cs.RunActionPrecommit(2, 0) })
AssertPanics(t, "Wrong round", func() { cs.RunActionPrecommit(1, 1) })
cs.RunActionPrecommit(1, 0) cs.RunActionPrecommit(1, 0)
<-cs.NewStepCh() // TODO: test this value too. <-cs.NewStepCh() // TODO: test this value too.
if cs.Precommits.GetById(0) != nil { if cs.Precommits.GetById(0) != nil {
@ -187,11 +178,11 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) {
if cs.Precommits.GetById(0) == nil { if cs.Precommits.GetById(0) == nil {
t.Errorf("RunActionPrecommit should have succeeded") t.Errorf("RunActionPrecommit should have succeeded")
} }
checkRoundState(t, cs, 1, 0, RoundStepPrecommit)
checkRoundState(t, cs.GetRoundState(), 1, 0, RoundStepPrecommit)
// Test RunActionCommit failures: // Test RunActionCommit failures:
assertPanics(t, "Wrong height ", func() { cs.RunActionCommit(2) })
assertPanics(t, "Wrong round", func() { cs.RunActionCommit(1) })
AssertPanics(t, "Wrong height ", func() { cs.RunActionCommit(2) })
AssertPanics(t, "Wrong round", func() { cs.RunActionCommit(1) })
// Add at least +2/3 precommits. // Add at least +2/3 precommits.
for i := 0; i < 7; i++ { for i := 0; i < 7; i++ {
@ -212,7 +203,7 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) {
if cs.Commits.GetById(0) == nil { if cs.Commits.GetById(0) == nil {
t.Errorf("RunActionCommit should have succeeded") t.Errorf("RunActionCommit should have succeeded")
} }
checkRoundState(t, cs, 1, 0, RoundStepCommit)
checkRoundState(t, cs.GetRoundState(), 1, 0, RoundStepCommit)
// cs.CommitTime should still be zero // cs.CommitTime should still be zero
if !cs.CommitTime.IsZero() { if !cs.CommitTime.IsZero() {
@ -235,5 +226,5 @@ func TestRunActionPrecommitCommitFinalize(t *testing.T) {
// Test TryFinalizeCommit: // Test TryFinalizeCommit:
cs.TryFinalizeCommit(1) cs.TryFinalizeCommit(1)
<-cs.NewStepCh() // TODO: test this value too. <-cs.NewStepCh() // TODO: test this value too.
checkRoundState(t, cs, 2, 0, RoundStepNewHeight)
checkRoundState(t, cs.GetRoundState(), 2, 0, RoundStepNewHeight)
} }

+ 2
- 3
consensus/test.go View File

@ -1,7 +1,6 @@
package consensus package consensus
import ( import (
. "github.com/tendermint/tendermint/blocks"
"github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/state"
) )
@ -16,7 +15,7 @@ func makeValidator(id uint64, votingPower uint64) (*state.Validator, *state.Priv
}, privAccount }, privAccount
} }
func makeVoteSet(height uint32, round uint16, numValidators int, votingPower uint64) (*VoteSet, *state.ValidatorSet, []*state.PrivAccount) {
func makeVoteSet(height uint32, round uint16, type_ byte, numValidators int, votingPower uint64) (*VoteSet, *state.ValidatorSet, []*state.PrivAccount) {
vals := make([]*state.Validator, numValidators) vals := make([]*state.Validator, numValidators)
privAccounts := make([]*state.PrivAccount, numValidators) privAccounts := make([]*state.PrivAccount, numValidators)
for i := 0; i < numValidators; i++ { for i := 0; i < numValidators; i++ {
@ -25,5 +24,5 @@ func makeVoteSet(height uint32, round uint16, numValidators int, votingPower uin
privAccounts[i] = privAccount privAccounts[i] = privAccount
} }
valSet := state.NewValidatorSet(vals) valSet := state.NewValidatorSet(vals)
return NewVoteSet(height, round, VoteTypePrevote, valSet), valSet, privAccounts
return NewVoteSet(height, round, type_, valSet), valSet, privAccounts
} }

+ 5
- 1
consensus/vote_set.go View File

@ -36,6 +36,9 @@ type VoteSet struct {
// Constructs a new VoteSet struct used to accumulate votes for each round. // Constructs a new VoteSet struct used to accumulate votes for each round.
func NewVoteSet(height uint32, round uint16, type_ byte, vset *state.ValidatorSet) *VoteSet { func NewVoteSet(height uint32, round uint16, type_ byte, vset *state.ValidatorSet) *VoteSet {
if height == 0 {
panic("Cannot make VoteSet for height == 0, doesn't make sense.")
}
if type_ == VoteTypeCommit && round != 0 { if type_ == VoteTypeCommit && round != 0 {
panic("Expected round 0 for commit vote set") panic("Expected round 0 for commit vote set")
} }
@ -214,7 +217,7 @@ func (vs *VoteSet) MakePOL() *POL {
func (vs *VoteSet) MakeValidation() Validation { func (vs *VoteSet) MakeValidation() Validation {
if vs.type_ != VoteTypeCommit { if vs.type_ != VoteTypeCommit {
panic("Cannot MakeValidation() unless VoteSet.Type is VoteTypePrevote")
panic("Cannot MakeValidation() unless VoteSet.Type is VoteTypeCommit")
} }
vs.mtx.Lock() vs.mtx.Lock()
defer vs.mtx.Unlock() defer vs.mtx.Unlock()
@ -224,6 +227,7 @@ func (vs *VoteSet) MakeValidation() Validation {
rsigs := make([]RoundSignature, vs.vset.Size()) rsigs := make([]RoundSignature, vs.vset.Size())
vs.vset.Iterate(func(index uint, val *state.Validator) bool { vs.vset.Iterate(func(index uint, val *state.Validator) bool {
vote := vs.votes[val.Id] vote := vs.votes[val.Id]
if vote == nil { if vote == nil {
return false return false
} }


+ 181
- 28
consensus/vote_set_test.go View File

@ -1,8 +1,11 @@
package consensus package consensus
import ( import (
"bytes"
. "github.com/tendermint/tendermint/blocks" . "github.com/tendermint/tendermint/blocks"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
. "github.com/tendermint/tendermint/common/test"
"testing" "testing"
) )
@ -10,7 +13,8 @@ import (
// NOTE: see consensus/test.go for common test methods. // NOTE: see consensus/test.go for common test methods.
func TestAddVote(t *testing.T) { func TestAddVote(t *testing.T) {
voteSet, _, privAccounts := makeVoteSet(0, 0, 10, 1)
height, round := uint32(1), uint16(0)
voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// t.Logf(">> %v", voteSet) // t.Logf(">> %v", voteSet)
@ -25,7 +29,7 @@ func TestAddVote(t *testing.T) {
t.Errorf("There should be no 2/3 majority") t.Errorf("There should be no 2/3 majority")
} }
vote := &Vote{Height: 0, Round: 0, Type: VoteTypePrevote, BlockHash: nil}
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
privAccounts[0].Sign(vote) privAccounts[0].Sign(vote)
voteSet.Add(vote) voteSet.Add(vote)
@ -42,11 +46,13 @@ func TestAddVote(t *testing.T) {
} }
func Test2_3Majority(t *testing.T) { func Test2_3Majority(t *testing.T) {
voteSet, _, privAccounts := makeVoteSet(0, 0, 10, 1)
height, round := uint32(1), uint16(0)
voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// 6 out of 10 voted for nil. // 6 out of 10 voted for nil.
vote := &Vote{Height: 0, Round: 0, Type: VoteTypePrevote, BlockHash: nil}
voteProto := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote) privAccounts[i].Sign(vote)
voteSet.Add(vote) voteSet.Add(vote)
} }
@ -56,30 +62,112 @@ func Test2_3Majority(t *testing.T) {
} }
// 7th validator voted for some blockhash // 7th validator voted for some blockhash
vote.BlockHash = CRandBytes(32)
privAccounts[6].Sign(vote)
voteSet.Add(vote)
hash, header, ok = voteSet.TwoThirdsMajority()
{
vote := voteProto.Copy()
vote.BlockHash = CRandBytes(32)
privAccounts[6].Sign(vote)
voteSet.Add(vote)
hash, header, ok = voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok {
t.Errorf("There should be no 2/3 majority")
}
}
// 8th validator voted for nil.
{
vote := voteProto.Copy()
vote.BlockHash = nil
privAccounts[7].Sign(vote)
voteSet.Add(vote)
hash, header, ok = voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || !ok {
t.Errorf("There should be 2/3 majority for nil")
}
}
}
func Test2_3MajorityRedux(t *testing.T) {
height, round := uint32(1), uint16(0)
voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 100, 1)
blockHash := CRandBytes(32)
blockPartsTotal := uint16(123)
blockParts := PartSetHeader{blockPartsTotal, CRandBytes(32)}
// 66 out of 100 voted for nil.
voteProto := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockParts: blockParts}
for i := 0; i < 66; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote)
voteSet.Add(vote)
}
hash, header, ok := voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok { if hash != nil || !header.IsZero() || ok {
t.Errorf("There should be no 2/3 majority") t.Errorf("There should be no 2/3 majority")
} }
// 8th validator voted for nil.
vote.BlockHash = nil
privAccounts[7].Sign(vote)
voteSet.Add(vote)
hash, header, ok = voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || !ok {
t.Errorf("There should be 2/3 majority for nil")
// 67th validator voted for nil
{
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil, BlockParts: PartSetHeader{}}
privAccounts[66].Sign(vote)
voteSet.Add(vote)
hash, header, ok = voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok {
t.Errorf("There should be no 2/3 majority: last vote added was nil")
}
}
// 68th validator voted for a different BlockParts PartSetHeader
{
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockParts: PartSetHeader{blockPartsTotal, CRandBytes(32)}}
privAccounts[67].Sign(vote)
voteSet.Add(vote)
hash, header, ok = voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok {
t.Errorf("There should be no 2/3 majority: last vote added had different PartSetHeader Hash")
}
} }
// 69th validator voted for different BlockParts Total
{
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockParts: PartSetHeader{blockPartsTotal + 1, blockParts.Hash}}
privAccounts[68].Sign(vote)
voteSet.Add(vote)
hash, header, ok = voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok {
t.Errorf("There should be no 2/3 majority: last vote added had different PartSetHeader Total")
}
}
// 70th validator voted for different BlockHash
{
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: CRandBytes(32), BlockParts: blockParts}
privAccounts[69].Sign(vote)
voteSet.Add(vote)
hash, header, ok = voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok {
t.Errorf("There should be no 2/3 majority: last vote added had different BlockHash")
}
}
// 71st validator voted for the right BlockHash & BlockParts
{
vote := voteProto.Copy()
privAccounts[70].Sign(vote)
voteSet.Add(vote)
hash, header, ok = voteSet.TwoThirdsMajority()
if !bytes.Equal(hash, blockHash) || !header.Equals(blockParts) || !ok {
t.Errorf("There should be 2/3 majority")
}
}
} }
func TestBadVotes(t *testing.T) { func TestBadVotes(t *testing.T) {
voteSet, _, privAccounts := makeVoteSet(1, 0, 10, 1)
height, round := uint32(1), uint16(0)
voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// val0 votes for nil. // val0 votes for nil.
vote := &Vote{Height: 1, Round: 0, Type: VoteTypePrevote, BlockHash: nil}
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
privAccounts[0].Sign(vote) privAccounts[0].Sign(vote)
added, err := voteSet.Add(vote) added, err := voteSet.Add(vote)
if !added || err != nil { if !added || err != nil {
@ -87,7 +175,7 @@ func TestBadVotes(t *testing.T) {
} }
// val0 votes again for some block. // val0 votes again for some block.
vote = &Vote{Height: 1, Round: 0, Type: VoteTypePrevote, BlockHash: CRandBytes(32)}
vote = &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: CRandBytes(32)}
privAccounts[0].Sign(vote) privAccounts[0].Sign(vote)
added, err = voteSet.Add(vote) added, err = voteSet.Add(vote)
if added || err == nil { if added || err == nil {
@ -95,7 +183,7 @@ func TestBadVotes(t *testing.T) {
} }
// val1 votes on another height // val1 votes on another height
vote = &Vote{Height: 0, Round: 0, Type: VoteTypePrevote, BlockHash: nil}
vote = &Vote{Height: height + 1, Round: round, Type: VoteTypePrevote, BlockHash: nil}
privAccounts[1].Sign(vote) privAccounts[1].Sign(vote)
added, err = voteSet.Add(vote) added, err = voteSet.Add(vote)
if added { if added {
@ -103,7 +191,7 @@ func TestBadVotes(t *testing.T) {
} }
// val2 votes on another round // val2 votes on another round
vote = &Vote{Height: 1, Round: 1, Type: VoteTypePrevote, BlockHash: nil}
vote = &Vote{Height: height, Round: round + 1, Type: VoteTypePrevote, BlockHash: nil}
privAccounts[2].Sign(vote) privAccounts[2].Sign(vote)
added, err = voteSet.Add(vote) added, err = voteSet.Add(vote)
if added { if added {
@ -111,7 +199,7 @@ func TestBadVotes(t *testing.T) {
} }
// val3 votes of another type. // val3 votes of another type.
vote = &Vote{Height: 1, Round: 0, Type: VoteTypePrecommit, BlockHash: nil}
vote = &Vote{Height: height, Round: round, Type: VoteTypePrecommit, BlockHash: nil}
privAccounts[3].Sign(vote) privAccounts[3].Sign(vote)
added, err = voteSet.Add(vote) added, err = voteSet.Add(vote)
if added { if added {
@ -120,11 +208,13 @@ func TestBadVotes(t *testing.T) {
} }
func TestAddCommitsToPrevoteVotes(t *testing.T) { func TestAddCommitsToPrevoteVotes(t *testing.T) {
voteSet, _, privAccounts := makeVoteSet(1, 5, 10, 1)
height, round := uint32(2), uint16(5)
voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypePrevote, 10, 1)
// val0, val1, val2, val3, val4, val5 vote for nil. // val0, val1, val2, val3, val4, val5 vote for nil.
vote := &Vote{Height: 1, Round: 5, Type: VoteTypePrevote, BlockHash: nil}
voteProto := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote) privAccounts[i].Sign(vote)
voteSet.Add(vote) voteSet.Add(vote)
} }
@ -134,7 +224,7 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
} }
// Attempt to add a commit from val6 at a previous height // Attempt to add a commit from val6 at a previous height
vote = &Vote{Height: 0, Round: 5, Type: VoteTypeCommit, BlockHash: nil}
vote := &Vote{Height: height - 1, Round: round, Type: VoteTypeCommit, BlockHash: nil}
privAccounts[6].Sign(vote) privAccounts[6].Sign(vote)
added, _ := voteSet.Add(vote) added, _ := voteSet.Add(vote)
if added { if added {
@ -142,7 +232,7 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
} }
// Attempt to add a commit from val6 at a later round // Attempt to add a commit from val6 at a later round
vote = &Vote{Height: 1, Round: 6, Type: VoteTypeCommit, BlockHash: nil}
vote = &Vote{Height: height, Round: round + 1, Type: VoteTypeCommit, BlockHash: nil}
privAccounts[6].Sign(vote) privAccounts[6].Sign(vote)
added, _ = voteSet.Add(vote) added, _ = voteSet.Add(vote)
if added { if added {
@ -150,7 +240,7 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
} }
// Attempt to add a commit from val6 for currrent height/round. // Attempt to add a commit from val6 for currrent height/round.
vote = &Vote{Height: 1, Round: 5, Type: VoteTypeCommit, BlockHash: nil}
vote = &Vote{Height: height, Round: round, Type: VoteTypeCommit, BlockHash: nil}
privAccounts[6].Sign(vote) privAccounts[6].Sign(vote)
added, err := voteSet.Add(vote) added, err := voteSet.Add(vote)
if added || err == nil { if added || err == nil {
@ -158,7 +248,7 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
} }
// Add commit from val6 at a previous round // Add commit from val6 at a previous round
vote = &Vote{Height: 1, Round: 4, Type: VoteTypeCommit, BlockHash: nil}
vote = &Vote{Height: height, Round: round - 1, Type: VoteTypeCommit, BlockHash: nil}
privAccounts[6].Sign(vote) privAccounts[6].Sign(vote)
added, err = voteSet.Add(vote) added, err = voteSet.Add(vote)
if !added || err != nil { if !added || err != nil {
@ -166,7 +256,7 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
} }
// Also add commit from val7 for previous round. // Also add commit from val7 for previous round.
vote = &Vote{Height: 1, Round: 3, Type: VoteTypeCommit, BlockHash: nil}
vote = &Vote{Height: height, Round: round - 2, Type: VoteTypeCommit, BlockHash: nil}
privAccounts[7].Sign(vote) privAccounts[7].Sign(vote)
added, err = voteSet.Add(vote) added, err = voteSet.Add(vote)
if !added || err != nil { if !added || err != nil {
@ -180,3 +270,66 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
} }
} }
func TestMakeValidation(t *testing.T) {
height, round := uint32(1), uint16(0)
voteSet, _, privAccounts := makeVoteSet(height, round, VoteTypeCommit, 10, 1)
blockHash, blockParts := CRandBytes(32), PartSetHeader{123, CRandBytes(32)}
// 6 out of 10 voted for some block.
voteProto := &Vote{Height: height, Round: round, Type: VoteTypeCommit,
BlockHash: blockHash, BlockParts: blockParts}
for i := 0; i < 6; i++ {
vote := voteProto.Copy()
privAccounts[i].Sign(vote)
voteSet.Add(vote)
}
// MakeValidation should fail.
AssertPanics(t, "Doesn't have +2/3 majority", func() { voteSet.MakeValidation() })
// 7th voted for some other block.
{
vote := &Vote{Height: height, Round: round, Type: VoteTypeCommit,
BlockHash: CRandBytes(32),
BlockParts: PartSetHeader{123, CRandBytes(32)}}
privAccounts[6].Sign(vote)
voteSet.Add(vote)
}
// The 8th voted like everyone else.
{
vote := voteProto.Copy()
privAccounts[7].Sign(vote)
voteSet.Add(vote)
}
validation := voteSet.MakeValidation()
// Validation should have 10 elements
if len(validation.Commits) != 10 {
t.Errorf("Validation Commits should have the same number of commits as validators")
}
// Ensure that Validation commits are ordered.
for i, rsig := range validation.Commits {
if i < 6 || i == 7 {
if rsig.Round != round {
t.Errorf("Expected round %v but got %v", round, rsig.Round)
}
if rsig.SignerId != uint64(i) {
t.Errorf("Validation commit signer out of order. Expected %v, got %v", i, rsig.Signature)
}
vote := &Vote{Height: height, Round: rsig.Round, Type: VoteTypeCommit,
BlockHash: blockHash, BlockParts: blockParts,
Signature: rsig.Signature}
if !privAccounts[i].Verify(vote) {
t.Errorf("Validation commit did not verify")
}
} else {
if !rsig.IsZero() {
t.Errorf("Expected zero RoundSignature for the rest")
}
}
}
}

+ 3
- 1
state/account.go View File

@ -168,7 +168,9 @@ func (pa *PrivAccount) SignBytes(msg []byte) Signature {
} }
func (pa *PrivAccount) Sign(o Signable) { func (pa *PrivAccount) Sign(o Signable) {
o.SetSignature(Signature{}) // clear
if !o.GetSignature().IsZero() {
panic("Cannot sign: already signed")
}
msg := BinaryBytes(o) msg := BinaryBytes(o)
sig := pa.SignBytes(msg) sig := pa.SignBytes(msg)
o.SetSignature(sig) o.SetSignature(sig)


Loading…
Cancel
Save