@ -2,6 +2,7 @@ package consensus
import (
import (
"bytes"
"bytes"
"context"
"fmt"
"fmt"
"testing"
"testing"
"time"
"time"
@ -9,6 +10,7 @@ import (
cstypes "github.com/tendermint/tendermint/consensus/types"
cstypes "github.com/tendermint/tendermint/consensus/types"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
cmn "github.com/tendermint/tmlibs/common"
tmpubsub "github.com/tendermint/tmlibs/pubsub"
)
)
func init ( ) {
func init ( ) {
@ -56,8 +58,8 @@ func TestProposerSelection0(t *testing.T) {
cs1 , vss := randConsensusState ( 4 )
cs1 , vss := randConsensusState ( 4 )
height , round := cs1 . Height , cs1 . Round
height , round := cs1 . Height , cs1 . Round
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
startTestRound ( cs1 , height , round )
startTestRound ( cs1 , height , round )
@ -89,7 +91,7 @@ func TestProposerSelection0(t *testing.T) {
func TestProposerSelection2 ( t * testing . T ) {
func TestProposerSelection2 ( t * testing . T ) {
cs1 , vss := randConsensusState ( 4 ) // test needs more work for more than 3 validators
cs1 , vss := randConsensusState ( 4 ) // test needs more work for more than 3 validators
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
// this time we jump in at round 2
// this time we jump in at round 2
incrementRound ( vss [ 1 : ] ... )
incrementRound ( vss [ 1 : ] ... )
@ -121,7 +123,7 @@ func TestEnterProposeNoPrivValidator(t *testing.T) {
height , round := cs . Height , cs . Round
height , round := cs . Height , cs . Round
// Listen for propose timeout event
// Listen for propose timeout event
timeoutCh := subscribeToEvent ( cs . evsw , "tester" , types . EventStringTimeoutPropose ( ) , 1 )
timeoutCh := subscribe ( cs . eventBus , types . EventQueryTimeoutPropose )
startTestRound ( cs , height , round )
startTestRound ( cs , height , round )
@ -146,8 +148,8 @@ func TestEnterProposeYesPrivValidator(t *testing.T) {
// Listen for propose timeout event
// Listen for propose timeout event
timeoutCh := subscribeToEvent ( cs . evsw , "tester" , types . EventStringTimeoutPropose ( ) , 1 )
proposalCh := subscribeToEvent ( cs . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
timeoutCh := subscribe ( cs . eventBus , types . EventQueryTimeoutPropose )
proposalCh := subscribe ( cs . eventBus , types . EventQueryCompleteProposal )
cs . enterNewRound ( height , round )
cs . enterNewRound ( height , round )
cs . startRoutines ( 3 )
cs . startRoutines ( 3 )
@ -183,8 +185,8 @@ func TestBadProposal(t *testing.T) {
partSize := cs1 . state . Params . BlockPartSizeBytes
partSize := cs1 . state . Params . BlockPartSizeBytes
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
voteCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringVote ( ) , 1 )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
voteCh := subscribe ( cs1 . eventBus , types . EventQueryVote )
propBlock , _ := cs1 . createProposalBlock ( ) //changeProposer(t, cs1, vs2)
propBlock , _ := cs1 . createProposalBlock ( ) //changeProposer(t, cs1, vs2)
@ -238,9 +240,9 @@ func TestFullRound1(t *testing.T) {
cs , vss := randConsensusState ( 1 )
cs , vss := randConsensusState ( 1 )
height , round := cs . Height , cs . Round
height , round := cs . Height , cs . Round
voteCh := subscribeToEvent ( cs . evsw , "tester" , types . EventStringVote ( ) , 0 )
propCh := subscribeToEvent ( cs . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
newRoundCh := subscribeToEvent ( cs . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
voteCh := subscribe ( cs . eventBus , types . EventQueryVote )
propCh := subscribe ( cs . eventBus , types . EventQueryCompleteProposal )
newRoundCh := subscribe ( cs . eventBus , types . EventQueryNewRound )
startTestRound ( cs , height , round )
startTestRound ( cs , height , round )
@ -251,8 +253,6 @@ func TestFullRound1(t *testing.T) {
propBlockHash := re . ( types . TMEventData ) . Unwrap ( ) . ( types . EventDataRoundState ) . RoundState . ( * cstypes . RoundState ) . ProposalBlock . Hash ( )
propBlockHash := re . ( types . TMEventData ) . Unwrap ( ) . ( types . EventDataRoundState ) . RoundState . ( * cstypes . RoundState ) . ProposalBlock . Hash ( )
<- voteCh // wait for prevote
<- voteCh // wait for prevote
// NOTE: voteChan cap of 0 ensures we can complete this
// before consensus can move to the next height (and cause a race condition)
validatePrevote ( t , cs , round , vss [ 0 ] , propBlockHash )
validatePrevote ( t , cs , round , vss [ 0 ] , propBlockHash )
<- voteCh // wait for precommit
<- voteCh // wait for precommit
@ -268,7 +268,7 @@ func TestFullRoundNil(t *testing.T) {
cs , vss := randConsensusState ( 1 )
cs , vss := randConsensusState ( 1 )
height , round := cs . Height , cs . Round
height , round := cs . Height , cs . Round
voteCh := subscribeToEvent ( cs . evsw , "tester" , types . EventStringVote ( ) , 1 )
voteCh := subscribe ( cs . eventBus , types . EventQueryVote )
cs . enterPrevote ( height , round )
cs . enterPrevote ( height , round )
cs . startRoutines ( 4 )
cs . startRoutines ( 4 )
@ -287,8 +287,8 @@ func TestFullRound2(t *testing.T) {
vs2 := vss [ 1 ]
vs2 := vss [ 1 ]
height , round := cs1 . Height , cs1 . Round
height , round := cs1 . Height , cs1 . Round
voteCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringVote ( ) , 1 )
newBlockCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewBlock ( ) , 1 )
voteCh := subscribe ( cs1 . eventBus , types . EventQueryVote )
newBlockCh := subscribe ( cs1 . eventBus , types . EventQueryNewBlock )
// start round and wait for propose and prevote
// start round and wait for propose and prevote
startTestRound ( cs1 , height , round )
startTestRound ( cs1 , height , round )
@ -330,11 +330,11 @@ func TestLockNoPOL(t *testing.T) {
partSize := cs1 . state . Params . BlockPartSizeBytes
partSize := cs1 . state . Params . BlockPartSizeBytes
timeoutProposeCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutPropose ( ) , 1 )
timeoutWaitCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutWait ( ) , 1 )
voteCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringVote ( ) , 1 )
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
timeoutProposeCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutPropose )
timeoutWaitCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutWait )
voteCh := subscribe ( cs1 . eventBus , types . EventQueryVote )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
/ *
/ *
Round1 ( cs1 , B ) // B B // B B2
Round1 ( cs1 , B ) // B B // B B2
@ -496,12 +496,12 @@ func TestLockPOLRelock(t *testing.T) {
partSize := cs1 . state . Params . BlockPartSizeBytes
partSize := cs1 . state . Params . BlockPartSizeBytes
timeoutProposeCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutPropose ( ) , 1 )
timeoutWaitCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutWait ( ) , 1 )
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
voteCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringVote ( ) , 1 )
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
newBlockCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewBlockHeader ( ) , 1 )
timeoutProposeCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutPropose )
timeoutWaitCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutWait )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
voteCh := subscribe ( cs1 . eventBus , types . EventQueryVote )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
newBlockCh := subscribe ( cs1 . eventBus , types . EventQueryNewBlockHeader )
// everything done from perspective of cs1
// everything done from perspective of cs1
@ -609,11 +609,11 @@ func TestLockPOLUnlock(t *testing.T) {
partSize := cs1 . state . Params . BlockPartSizeBytes
partSize := cs1 . state . Params . BlockPartSizeBytes
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
timeoutProposeCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutPropose ( ) , 1 )
timeoutWaitCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutWait ( ) , 1 )
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
unlockCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringUnlock ( ) , 1 )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
timeoutProposeCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutPropose )
timeoutWaitCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutWait )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
unlockCh := subscribe ( cs1 . eventBus , types . EventQueryUnlock )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
// everything done from perspective of cs1
// everything done from perspective of cs1
@ -704,10 +704,10 @@ func TestLockPOLSafety1(t *testing.T) {
partSize := cs1 . state . Params . BlockPartSizeBytes
partSize := cs1 . state . Params . BlockPartSizeBytes
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
timeoutProposeCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutPropose ( ) , 1 )
timeoutWaitCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutWait ( ) , 1 )
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
timeoutProposeCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutPropose )
timeoutWaitCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutWait )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
// start round and wait for propose and prevote
// start round and wait for propose and prevote
@ -802,7 +802,7 @@ func TestLockPOLSafety1(t *testing.T) {
// we should prevote what we're locked on
// we should prevote what we're locked on
validatePrevote ( t , cs1 , 2 , vss [ 0 ] , propBlockHash )
validatePrevote ( t , cs1 , 2 , vss [ 0 ] , propBlockHash )
newStepCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRoundStep ( ) , 1 )
newStepCh := subscribe ( cs1 . eventBus , types . EventQueryNewRoundStep )
// add prevotes from the earlier round
// add prevotes from the earlier round
addVotes ( cs1 , prevotes ... )
addVotes ( cs1 , prevotes ... )
@ -825,11 +825,11 @@ func TestLockPOLSafety2(t *testing.T) {
partSize := cs1 . state . Params . BlockPartSizeBytes
partSize := cs1 . state . Params . BlockPartSizeBytes
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
timeoutProposeCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutPropose ( ) , 1 )
timeoutWaitCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutWait ( ) , 1 )
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
unlockCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringUnlock ( ) , 1 )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
timeoutProposeCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutPropose )
timeoutWaitCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutWait )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
unlockCh := subscribe ( cs1 . eventBus , types . EventQueryUnlock )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
// the block for R0: gets polkad but we miss it
// the block for R0: gets polkad but we miss it
@ -919,9 +919,9 @@ func TestSlashingPrevotes(t *testing.T) {
vs2 := vss [ 1 ]
vs2 := vss [ 1 ]
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
timeoutWaitCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutWait ( ) , 1 )
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
timeoutWaitCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutWait )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
// start round and wait for propose and prevote
// start round and wait for propose and prevote
@ -954,9 +954,9 @@ func TestSlashingPrecommits(t *testing.T) {
vs2 := vss [ 1 ]
vs2 := vss [ 1 ]
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
timeoutWaitCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutWait ( ) , 1 )
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
timeoutWaitCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutWait )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
// start round and wait for propose and prevote
// start round and wait for propose and prevote
@ -1000,10 +1000,10 @@ func TestHalt1(t *testing.T) {
partSize := cs1 . state . Params . BlockPartSizeBytes
partSize := cs1 . state . Params . BlockPartSizeBytes
proposalCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringCompleteProposal ( ) , 1 )
timeoutWaitCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringTimeoutWait ( ) , 1 )
newRoundCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewRound ( ) , 1 )
newBlockCh := subscribeToEvent ( cs1 . evsw , "tester" , types . EventStringNewBlock ( ) , 1 )
proposalCh := subscribe ( cs1 . eventBus , types . EventQueryCompleteProposal )
timeoutWaitCh := subscribe ( cs1 . eventBus , types . EventQueryTimeoutWait )
newRoundCh := subscribe ( cs1 . eventBus , types . EventQueryNewRound )
newBlockCh := subscribe ( cs1 . eventBus , types . EventQueryNewBlock )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
voteCh := subscribeToVoter ( cs1 , cs1 . privValidator . GetAddress ( ) )
// start round and wait for propose and prevote
// start round and wait for propose and prevote
@ -1057,3 +1057,20 @@ func TestHalt1(t *testing.T) {
panic ( "expected height to increment" )
panic ( "expected height to increment" )
}
}
}
}
// subscribe subscribes test client to the given query and returns a channel with cap = 1.
func subscribe ( eventBus * types . EventBus , q tmpubsub . Query ) <- chan interface { } {
out := make ( chan interface { } , 1 )
err := eventBus . Subscribe ( context . Background ( ) , testSubscriber , q , out )
if err != nil {
panic ( fmt . Sprintf ( "failed to subscribe %s to %v" , testSubscriber , q ) )
}
return out
}
// discardFromChan reads n values from the channel.
func discardFromChan ( ch <- chan interface { } , n int ) {
for i := 0 ; i < n ; i ++ {
<- ch
}
}