Browse Source

Refactor consensus/vote_set_test.go

pull/9/head
Jae Kwon 10 years ago
parent
commit
70eb75dca7
9 changed files with 103 additions and 88 deletions
  1. +1
    -1
      cmd/daemon.go
  2. +79
    -75
      consensus/vote_set_test.go
  3. +2
    -2
      mempool/mempool.go
  4. +3
    -3
      state/genesis.go
  5. +1
    -0
      state/state.go
  6. +14
    -4
      state/state_test.go
  7. +1
    -1
      state/test.go
  8. +1
    -1
      state/validator.go
  9. +1
    -1
      state/validator_set.go

+ 1
- 1
cmd/daemon.go View File

@ -33,7 +33,7 @@ func NewNode() *Node {
stateDB := db_.NewMemDB() // TODO configurable db.
state := state_.LoadState(stateDB)
if state == nil {
state = state_.GenesisStateFromFile(stateDB, config.GenesisFile())
state = state_.MakeGenesisStateFromFile(stateDB, config.GenesisFile())
state.Save()
}


+ 79
- 75
consensus/vote_set_test.go View File

@ -6,12 +6,54 @@ import (
. "github.com/tendermint/tendermint/block"
. "github.com/tendermint/tendermint/common"
. "github.com/tendermint/tendermint/common/test"
"github.com/tendermint/tendermint/state"
"testing"
)
// NOTE: see consensus/test.go for common test methods.
// Convenience: Return new vote with different height
func withHeight(vote *Vote, height uint) *Vote {
vote = vote.Copy()
vote.Height = height
return vote
}
// Convenience: Return new vote with different round
func withRound(vote *Vote, round uint) *Vote {
vote = vote.Copy()
vote.Round = round
return vote
}
// Convenience: Return new vote with different type
func withType(vote *Vote, type_ byte) *Vote {
vote = vote.Copy()
vote.Type = type_
return vote
}
// Convenience: Return new vote with different blockHash
func withBlockHash(vote *Vote, blockHash []byte) *Vote {
vote = vote.Copy()
vote.BlockHash = blockHash
return vote
}
// Convenience: Return new vote with different blockParts
func withBlockParts(vote *Vote, blockParts PartSetHeader) *Vote {
vote = vote.Copy()
vote.BlockParts = blockParts
return vote
}
func signAddVote(privVal *state.PrivValidator, vote *Vote, voteSet *VoteSet) (bool, error) {
vote.Signature = privVal.SignVoteUnsafe(vote)
added, _, err := voteSet.Add(privVal.Address, vote)
return added, err
}
func TestAddVote(t *testing.T) {
height, round := uint(1), uint(0)
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
@ -31,8 +73,7 @@ func TestAddVote(t *testing.T) {
}
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
vote.Signature = val0.SignVoteUnsafe(vote)
voteSet.Add(val0.Address, vote)
signAddVote(val0, vote, voteSet)
if voteSet.GetByAddress(val0.Address) == nil {
t.Errorf("Expected GetByAddress(val0.Address) to be present")
@ -50,12 +91,11 @@ func Test2_3Majority(t *testing.T) {
height, round := uint(1), uint(0)
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
// 6 out of 10 voted for nil.
voteProto := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
for i := 0; i < 6; i++ {
vote := voteProto.Copy()
vote.Signature = privValidators[i].SignVoteUnsafe(vote)
voteSet.Add(privValidators[i].Address, vote)
signAddVote(privValidators[i], vote, voteSet)
}
hash, header, ok := voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok {
@ -64,10 +104,7 @@ func Test2_3Majority(t *testing.T) {
// 7th validator voted for some blockhash
{
vote := voteProto.Copy()
vote.BlockHash = CRandBytes(32)
vote.Signature = privValidators[6].SignVoteUnsafe(vote)
voteSet.Add(privValidators[6].Address, vote)
signAddVote(privValidators[6], withBlockHash(vote, RandBytes(32)), voteSet)
hash, header, ok = voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok {
t.Errorf("There should be no 2/3 majority")
@ -76,10 +113,7 @@ func Test2_3Majority(t *testing.T) {
// 8th validator voted for nil.
{
vote := voteProto.Copy()
vote.BlockHash = nil
vote.Signature = privValidators[7].SignVoteUnsafe(vote)
voteSet.Add(privValidators[7].Address, vote)
signAddVote(privValidators[7], vote, voteSet)
hash, header, ok = voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || !ok {
t.Errorf("There should be 2/3 majority for nil")
@ -95,12 +129,11 @@ func Test2_3MajorityRedux(t *testing.T) {
blockPartsTotal := uint(123)
blockParts := PartSetHeader{blockPartsTotal, CRandBytes(32)}
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockParts: blockParts}
// 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()
vote.Signature = privValidators[i].SignVoteUnsafe(vote)
voteSet.Add(privValidators[i].Address, vote)
signAddVote(privValidators[i], vote, voteSet)
}
hash, header, ok := voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok {
@ -109,9 +142,7 @@ func Test2_3MajorityRedux(t *testing.T) {
// 67th validator voted for nil
{
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil, BlockParts: PartSetHeader{}}
vote.Signature = privValidators[66].SignVoteUnsafe(vote)
voteSet.Add(privValidators[66].Address, vote)
signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet)
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")
@ -120,9 +151,8 @@ func Test2_3MajorityRedux(t *testing.T) {
// 68th validator voted for a different BlockParts PartSetHeader
{
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockParts: PartSetHeader{blockPartsTotal, CRandBytes(32)}}
vote.Signature = privValidators[67].SignVoteUnsafe(vote)
voteSet.Add(privValidators[67].Address, vote)
blockParts := PartSetHeader{blockPartsTotal, CRandBytes(32)}
signAddVote(privValidators[67], withBlockParts(vote, blockParts), voteSet)
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")
@ -131,9 +161,8 @@ func Test2_3MajorityRedux(t *testing.T) {
// 69th validator voted for different BlockParts Total
{
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: blockHash, BlockParts: PartSetHeader{blockPartsTotal + 1, blockParts.Hash}}
vote.Signature = privValidators[68].SignVoteUnsafe(vote)
voteSet.Add(privValidators[68].Address, vote)
blockParts := PartSetHeader{blockPartsTotal + 1, blockParts.Hash}
signAddVote(privValidators[68], withBlockParts(vote, blockParts), voteSet)
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")
@ -142,9 +171,7 @@ func Test2_3MajorityRedux(t *testing.T) {
// 70th validator voted for different BlockHash
{
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: CRandBytes(32), BlockParts: blockParts}
vote.Signature = privValidators[69].SignVoteUnsafe(vote)
voteSet.Add(privValidators[69].Address, vote)
signAddVote(privValidators[69], withBlockHash(vote, RandBytes(32)), voteSet)
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")
@ -153,9 +180,7 @@ func Test2_3MajorityRedux(t *testing.T) {
// 71st validator voted for the right BlockHash & BlockParts
{
vote := voteProto.Copy()
vote.Signature = privValidators[70].SignVoteUnsafe(vote)
voteSet.Add(privValidators[70].Address, vote)
signAddVote(privValidators[70], vote, voteSet)
hash, header, ok = voteSet.TwoThirdsMajority()
if !bytes.Equal(hash, blockHash) || !header.Equals(blockParts) || !ok {
t.Errorf("There should be 2/3 majority")
@ -169,40 +194,31 @@ func TestBadVotes(t *testing.T) {
// val0 votes for nil.
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
vote.Signature = privValidators[0].SignVoteUnsafe(vote)
added, _, err := voteSet.Add(privValidators[0].Address, vote)
added, err := signAddVote(privValidators[0], vote, voteSet)
if !added || err != nil {
t.Errorf("Expected Add() to succeed")
}
// val0 votes again for some block.
vote = &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: CRandBytes(32)}
vote.Signature = privValidators[0].SignVoteUnsafe(vote)
added, _, err = voteSet.Add(privValidators[0].Address, vote)
added, err = signAddVote(privValidators[0], withBlockHash(vote, RandBytes(32)), voteSet)
if added || err == nil {
t.Errorf("Expected Add() to fail, dupeout.")
}
// val1 votes on another height
vote = &Vote{Height: height + 1, Round: round, Type: VoteTypePrevote, BlockHash: nil}
vote.Signature = privValidators[1].SignVoteUnsafe(vote)
added, _, err = voteSet.Add(privValidators[1].Address, vote)
added, err = signAddVote(privValidators[1], withHeight(vote, height+1), voteSet)
if added {
t.Errorf("Expected Add() to fail, wrong height")
}
// val2 votes on another round
vote = &Vote{Height: height, Round: round + 1, Type: VoteTypePrevote, BlockHash: nil}
vote.Signature = privValidators[2].SignVoteUnsafe(vote)
added, _, err = voteSet.Add(privValidators[2].Address, vote)
added, err = signAddVote(privValidators[2], withRound(vote, round+1), voteSet)
if added {
t.Errorf("Expected Add() to fail, wrong round")
}
// val3 votes of another type.
vote = &Vote{Height: height, Round: round, Type: VoteTypePrecommit, BlockHash: nil}
vote.Signature = privValidators[3].SignVoteUnsafe(vote)
added, _, err = voteSet.Add(privValidators[3].Address, vote)
added, err = signAddVote(privValidators[3], withType(vote, VoteTypePrecommit), voteSet)
if added {
t.Errorf("Expected Add() to fail, wrong type")
}
@ -213,11 +229,9 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
// val0, val1, val2, val3, val4, val5 vote for nil.
voteProto := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
vote := &Vote{Height: height, Round: round, Type: VoteTypePrevote, BlockHash: nil}
for i := 0; i < 6; i++ {
vote := voteProto.Copy()
vote.Signature = privValidators[i].SignVoteUnsafe(vote)
voteSet.Add(privValidators[i].Address, vote)
signAddVote(privValidators[i], vote, voteSet)
}
hash, header, ok := voteSet.TwoThirdsMajority()
if hash != nil || !header.IsZero() || ok {
@ -225,41 +239,36 @@ func TestAddCommitsToPrevoteVotes(t *testing.T) {
}
// Attempt to add a commit from val6 at a previous height
vote := &Vote{Height: height - 1, Round: round, Type: VoteTypeCommit, BlockHash: nil}
vote.Signature = privValidators[6].SignVoteUnsafe(vote)
added, _, _ := voteSet.Add(privValidators[6].Address, vote)
vote = &Vote{Height: height - 1, Round: round, Type: VoteTypeCommit, BlockHash: nil}
added, _ := signAddVote(privValidators[6], vote, voteSet)
if added {
t.Errorf("Expected Add() to fail, wrong height.")
}
// Attempt to add a commit from val6 at a later round
vote = &Vote{Height: height, Round: round + 1, Type: VoteTypeCommit, BlockHash: nil}
vote.Signature = privValidators[6].SignVoteUnsafe(vote)
added, _, _ = voteSet.Add(privValidators[6].Address, vote)
added, _ = signAddVote(privValidators[6], vote, voteSet)
if added {
t.Errorf("Expected Add() to fail, cannot add future round vote.")
}
// Attempt to add a commit from val6 for currrent height/round.
vote = &Vote{Height: height, Round: round, Type: VoteTypeCommit, BlockHash: nil}
vote.Signature = privValidators[6].SignVoteUnsafe(vote)
added, _, err := voteSet.Add(privValidators[6].Address, vote)
added, err := signAddVote(privValidators[6], vote, voteSet)
if added || err == nil {
t.Errorf("Expected Add() to fail, only prior round commits can be added.")
}
// Add commit from val6 at a previous round
vote = &Vote{Height: height, Round: round - 1, Type: VoteTypeCommit, BlockHash: nil}
vote.Signature = privValidators[6].SignVoteUnsafe(vote)
added, _, err = voteSet.Add(privValidators[6].Address, vote)
added, err = signAddVote(privValidators[6], vote, voteSet)
if !added || err != nil {
t.Errorf("Expected Add() to succeed, commit for prior rounds are relevant.")
}
// Also add commit from val7 for previous round.
vote = &Vote{Height: height, Round: round - 2, Type: VoteTypeCommit, BlockHash: nil}
vote.Signature = privValidators[7].SignVoteUnsafe(vote)
added, _, err = voteSet.Add(privValidators[7].Address, vote)
added, err = signAddVote(privValidators[7], vote, voteSet)
if !added || err != nil {
t.Errorf("Expected Add() to succeed. err: %v", err)
}
@ -277,13 +286,12 @@ func TestMakeValidation(t *testing.T) {
voteSet, _, privValidators := randVoteSet(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,
vote := &Vote{Height: height, Round: round, Type: VoteTypeCommit,
BlockHash: blockHash, BlockParts: blockParts}
// 6 out of 10 voted for some block.
for i := 0; i < 6; i++ {
vote := voteProto.Copy()
vote.Signature = privValidators[i].SignVoteUnsafe(vote)
voteSet.Add(privValidators[i].Address, vote)
signAddVote(privValidators[i], vote, voteSet)
}
// MakeValidation should fail.
@ -291,18 +299,14 @@ func TestMakeValidation(t *testing.T) {
// 7th voted for some other block.
{
vote := &Vote{Height: height, Round: round, Type: VoteTypeCommit,
BlockHash: CRandBytes(32),
BlockParts: PartSetHeader{123, CRandBytes(32)}}
vote.Signature = privValidators[6].SignVoteUnsafe(vote)
voteSet.Add(privValidators[6].Address, vote)
vote := withBlockHash(vote, RandBytes(32))
vote = withBlockParts(vote, PartSetHeader{123, RandBytes(32)})
signAddVote(privValidators[6], vote, voteSet)
}
// The 8th voted like everyone else.
{
vote := voteProto.Copy()
vote.Signature = privValidators[7].SignVoteUnsafe(vote)
voteSet.Add(privValidators[7].Address, vote)
signAddVote(privValidators[7], vote, voteSet)
}
validation := voteSet.MakeValidation()


+ 2
- 2
mempool/mempool.go View File

@ -2,8 +2,8 @@
Mempool receives new transactions and applies them to the latest committed state.
If the transaction is acceptable, then it broadcasts the tx to peers.
When this node happens to be the next proposer, it simply takes the recently
modified state (and the associated transactions) and use that as the proposal.
When this node happens to be the next proposer, it simply uses the recently
modified state (and the associated transactions) to construct a proposal.
*/
package mempool


+ 3
- 3
state/genesis.go View File

@ -27,16 +27,16 @@ func GenesisDocFromJSON(jsonBlob []byte) (genState *GenesisDoc) {
return
}
func GenesisStateFromFile(db db_.DB, genDocFile string) *State {
func MakeGenesisStateFromFile(db db_.DB, genDocFile string) *State {
jsonBlob, err := ioutil.ReadFile(genDocFile)
if err != nil {
Panicf("Couldn't read GenesisDoc file: %v", err)
}
genDoc := GenesisDocFromJSON(jsonBlob)
return GenesisState(db, genDoc)
return MakeGenesisState(db, genDoc)
}
func GenesisState(db db_.DB, genDoc *GenesisDoc) *State {
func MakeGenesisState(db db_.DB, genDoc *GenesisDoc) *State {
if len(genDoc.Validators) == 0 {
panic("Must have some validators")
}


+ 1
- 0
state/state.go View File

@ -629,6 +629,7 @@ func (s *State) Hash() []byte {
s.BondedValidators,
s.UnbondingValidators,
s.accounts,
s.validatorInfos,
}
return merkle.HashFromHashables(hashables)
}

+ 14
- 4
state/state_test.go View File

@ -12,7 +12,7 @@ import (
)
func TestCopyState(t *testing.T) {
// Generate a state
// Generate a random state
s0, privAccounts, _ := RandGenesisState(10, true, 1000, 5, true, 1000)
s0Hash := s0.Hash()
if len(s0Hash) == 0 {
@ -29,19 +29,23 @@ func TestCopyState(t *testing.T) {
acc0Address := privAccounts[0].PubKey.Address()
acc := s0.GetAccount(acc0Address)
acc.Balance += 1
// The account balance shouldn't have changed yet.
if s0.GetAccount(acc0Address).Balance == acc.Balance {
t.Error("Account balance changed unexpectedly")
}
// Setting, however, should change the balance.
s0.SetAccount(acc)
if s0.GetAccount(acc0Address).Balance != acc.Balance {
t.Error("Account balance wasn't set")
}
// How that the state changed, the hash should change too.
// Now that the state changed, the hash should change too.
if bytes.Equal(s0Hash, s0.Hash()) {
t.Error("Expected state hash to have changed")
}
// The s0Copy shouldn't have changed though.
if !bytes.Equal(s0Hash, s0Copy.Hash()) {
t.Error("Expected state copy hash to have not changed")
@ -52,6 +56,7 @@ func TestGenesisSaveLoad(t *testing.T) {
// Generate a state, save & load it.
s0, _, _ := RandGenesisState(10, true, 1000, 5, true, 1000)
// Mutate the state to append one empty block.
block := &Block{
Header: &Header{
@ -70,7 +75,8 @@ func TestGenesisSaveLoad(t *testing.T) {
},
}
blockParts := NewPartSetFromData(BinaryBytes(block))
// The second argument to AppendBlock() is false,
// The last argument to AppendBlock() is `false`,
// which sets Block.Header.StateHash.
err := s0.Copy().AppendBlock(block, blockParts.Header(), false)
if err != nil {
@ -79,6 +85,7 @@ func TestGenesisSaveLoad(t *testing.T) {
if len(block.Header.StateHash) == 0 {
t.Error("Expected StateHash but got nothing.")
}
// Now append the block to s0.
// This time we also check the StateHash (as computed above).
err = s0.AppendBlock(block, blockParts.Header(), true)
@ -108,6 +115,7 @@ func TestGenesisSaveLoad(t *testing.T) {
if !bytes.Equal(s0.LastBlockHash, s1.LastBlockHash) {
t.Error("LastBlockHash mismatch")
}
// Compare state merkle trees
if s0.BondedValidators.Size() != s1.BondedValidators.Size() {
t.Error("BondedValidators Size mismatch")
@ -130,6 +138,9 @@ func TestGenesisSaveLoad(t *testing.T) {
if !bytes.Equal(s0.accounts.Hash(), s1.accounts.Hash()) {
t.Error("Accounts mismatch")
}
if !bytes.Equal(s0.validatorInfos.Hash(), s1.validatorInfos.Hash()) {
t.Error("Accounts mismatch")
}
}
func TestTxSequence(t *testing.T) {
@ -285,6 +296,5 @@ func TestTxs(t *testing.T) {
}
// TODO UnbondTx.
// TODO NameTx.
}

+ 1
- 1
state/test.go View File

@ -70,7 +70,7 @@ func RandGenesisState(numAccounts int, randBalance bool, minBalance uint64, numV
privValidators[i] = privVal
}
sort.Sort(PrivValidatorsByAddress(privValidators))
s0 := GenesisState(db, &GenesisDoc{
s0 := MakeGenesisState(db, &GenesisDoc{
GenesisTime: time.Now(),
Accounts: accounts,
Validators: validators,


+ 1
- 1
state/validator.go View File

@ -10,7 +10,7 @@ import (
. "github.com/tendermint/tendermint/block"
)
// Persistent static data for each Validator
// Persistent (mostly) static data for each Validator
type ValidatorInfo struct {
Address []byte
PubKey PubKeyEd25519


+ 1
- 1
state/validator_set.go View File

@ -12,7 +12,7 @@ import (
// ValidatorSet represent a set of *Validator at a given height.
// The validators can be fetched by address or index.
// The index is in order of .Address, so the index are the same
// The index is in order of .Address, so the indices are fixed
// for all rounds of a given blockchain height.
// On the other hand, the .AccumPower of each validator and
// the designated .Proposer() of a set changes every round,


Loading…
Cancel
Save