@ -21,6 +21,7 @@ import (
cfg "github.com/tendermint/tendermint/config"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
mempl "github.com/tendermint/tendermint/mempool"
"github.com/tendermint/tendermint/p2p"
sm "github.com/tendermint/tendermint/state"
@ -34,9 +35,14 @@ func init() {
//----------------------------------------------
// in-process testnets
func startConsensusNet ( t * testing . T , css [ ] * ConsensusState , N int ) ( [ ] * ConsensusReactor , [ ] chan interface { } , [ ] * types . EventBus ) {
func startConsensusNet ( t * testing . T , css [ ] * ConsensusState , N int ) (
[ ] * ConsensusReactor ,
[ ] * tmpubsub . Subscription ,
[ ] * types . EventBus ,
) {
var err error
reactors := make ( [ ] * ConsensusReactor , N )
eventChans := make ( [ ] chan interface { } , N )
eventSub s := make ( [ ] * tmpubsub . Subscription , N )
eventBuses := make ( [ ] * types . EventBus , N )
for i := 0 ; i < N ; i ++ {
/ * logger , err := tmflags . ParseLogLevel ( "consensus:info,*:error" , logger , "info" )
@ -48,8 +54,7 @@ func startConsensusNet(t *testing.T, css []*ConsensusState, N int) ([]*Consensus
eventBuses [ i ] = css [ i ] . eventBus
reactors [ i ] . SetEventBus ( eventBuses [ i ] )
eventChans [ i ] = make ( chan interface { } , 1 )
err := eventBuses [ i ] . Subscribe ( context . Background ( ) , testSubscriber , types . EventQueryNewBlock , eventChans [ i ] )
eventSubs [ i ] , err = eventBuses [ i ] . Subscribe ( context . Background ( ) , testSubscriber , types . EventQueryNewBlock )
require . NoError ( t , err )
}
// make connected switches and start all reactors
@ -67,7 +72,7 @@ func startConsensusNet(t *testing.T, css []*ConsensusState, N int) ([]*Consensus
s := reactors [ i ] . conS . GetState ( )
reactors [ i ] . SwitchToConsensus ( s , 0 )
}
return reactors , eventChan s , eventBuses
return reactors , eventSub s , eventBuses
}
func stopConsensusNet ( logger log . Logger , reactors [ ] * ConsensusReactor , eventBuses [ ] * types . EventBus ) {
@ -87,11 +92,11 @@ func stopConsensusNet(logger log.Logger, reactors []*ConsensusReactor, eventBuse
func TestReactorBasic ( t * testing . T ) {
N := 4
css := randConsensusNet ( N , "consensus_reactor_test" , newMockTickerFunc ( true ) , newCounter )
reactors , eventChan s , eventBuses := startConsensusNet ( t , css , N )
reactors , eventSub s , eventBuses := startConsensusNet ( t , css , N )
defer stopConsensusNet ( log . TestingLogger ( ) , reactors , eventBuses )
// wait till everyone makes the first new block
timeoutWaitGroup ( t , N , func ( j int ) {
<- eventChan s [ j ]
<- eventSub s [ j ] . Out ( )
} , css )
}
@ -163,20 +168,20 @@ func TestReactorWithEvidence(t *testing.T) {
css [ i ] = cs
}
reactors , eventChan s , eventBuses := startConsensusNet ( t , css , nValidators )
reactors , eventSub s , eventBuses := startConsensusNet ( t , css , nValidators )
defer stopConsensusNet ( log . TestingLogger ( ) , reactors , eventBuses )
// wait till everyone makes the first new block with no evidence
timeoutWaitGroup ( t , nValidators , func ( j int ) {
blockI := <- eventChan s [ j ]
block := blockI . ( types . EventDataNewBlock ) . Block
blockI := <- eventSub s [ j ] . Out ( )
block := blockI . Msg . ( types . EventDataNewBlock ) . Block
assert . True ( t , len ( block . Evidence . Evidence ) == 0 )
} , css )
// second block should have evidence
timeoutWaitGroup ( t , nValidators , func ( j int ) {
blockI := <- eventChan s [ j ]
block := blockI . ( types . EventDataNewBlock ) . Block
blockI := <- eventSub s [ j ] . Out ( )
block := blockI . Msg . ( types . EventDataNewBlock ) . Block
assert . True ( t , len ( block . Evidence . Evidence ) > 0 )
} , css )
}
@ -221,7 +226,7 @@ func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
func ( c * cfg . Config ) {
c . Consensus . CreateEmptyBlocks = false
} )
reactors , eventChan s , eventBuses := startConsensusNet ( t , css , N )
reactors , eventSub s , eventBuses := startConsensusNet ( t , css , N )
defer stopConsensusNet ( log . TestingLogger ( ) , reactors , eventBuses )
// send a tx
@ -231,7 +236,7 @@ func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
// wait till everyone makes the first new block
timeoutWaitGroup ( t , N , func ( j int ) {
<- eventChan s [ j ]
<- eventSub s [ j ] . Out ( )
} , css )
}
@ -239,12 +244,12 @@ func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
func TestReactorRecordsVotesAndBlockParts ( t * testing . T ) {
N := 4
css := randConsensusNet ( N , "consensus_reactor_test" , newMockTickerFunc ( true ) , newCounter )
reactors , eventChan s , eventBuses := startConsensusNet ( t , css , N )
reactors , eventSub s , eventBuses := startConsensusNet ( t , css , N )
defer stopConsensusNet ( log . TestingLogger ( ) , reactors , eventBuses )
// wait till everyone makes the first new block
timeoutWaitGroup ( t , N , func ( j int ) {
<- eventChan s [ j ]
<- eventSub s [ j ] . Out ( )
} , css )
// Get peer
@ -263,7 +268,7 @@ func TestReactorVotingPowerChange(t *testing.T) {
nVals := 4
logger := log . TestingLogger ( )
css := randConsensusNet ( nVals , "consensus_voting_power_changes_test" , newMockTickerFunc ( true ) , newPersistentKVStore )
reactors , eventChan s , eventBuses := startConsensusNet ( t , css , nVals )
reactors , eventSub s , eventBuses := startConsensusNet ( t , css , nVals )
defer stopConsensusNet ( logger , reactors , eventBuses )
// map of active validators
@ -275,7 +280,7 @@ func TestReactorVotingPowerChange(t *testing.T) {
// wait till everyone makes block 1
timeoutWaitGroup ( t , nVals , func ( j int ) {
<- eventChan s [ j ]
<- eventSub s [ j ] . Out ( )
} , css )
//---------------------------------------------------------------------------
@ -286,10 +291,10 @@ func TestReactorVotingPowerChange(t *testing.T) {
updateValidatorTx := kvstore . MakeValSetChangeTx ( val1PubKeyABCI , 25 )
previousTotalVotingPower := css [ 0 ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( )
waitForAndValidateBlock ( t , nVals , activeVals , eventChan s , css , updateValidatorTx )
waitForAndValidateBlockWithTx ( t , nVals , activeVals , eventChan s , css , updateValidatorTx )
waitForAndValidateBlock ( t , nVals , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nVals , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nVals , activeVals , eventSub s , css , updateValidatorTx )
waitForAndValidateBlockWithTx ( t , nVals , activeVals , eventSub s , css , updateValidatorTx )
waitForAndValidateBlock ( t , nVals , activeVals , eventSub s , css )
waitForAndValidateBlock ( t , nVals , activeVals , eventSub s , css )
if css [ 0 ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( ) == previousTotalVotingPower {
t . Fatalf ( "expected voting power to change (before: %d, after: %d)" , previousTotalVotingPower , css [ 0 ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( ) )
@ -298,10 +303,10 @@ func TestReactorVotingPowerChange(t *testing.T) {
updateValidatorTx = kvstore . MakeValSetChangeTx ( val1PubKeyABCI , 2 )
previousTotalVotingPower = css [ 0 ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( )
waitForAndValidateBlock ( t , nVals , activeVals , eventChan s , css , updateValidatorTx )
waitForAndValidateBlockWithTx ( t , nVals , activeVals , eventChan s , css , updateValidatorTx )
waitForAndValidateBlock ( t , nVals , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nVals , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nVals , activeVals , eventSub s , css , updateValidatorTx )
waitForAndValidateBlockWithTx ( t , nVals , activeVals , eventSub s , css , updateValidatorTx )
waitForAndValidateBlock ( t , nVals , activeVals , eventSub s , css )
waitForAndValidateBlock ( t , nVals , activeVals , eventSub s , css )
if css [ 0 ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( ) == previousTotalVotingPower {
t . Fatalf ( "expected voting power to change (before: %d, after: %d)" , previousTotalVotingPower , css [ 0 ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( ) )
@ -310,10 +315,10 @@ func TestReactorVotingPowerChange(t *testing.T) {
updateValidatorTx = kvstore . MakeValSetChangeTx ( val1PubKeyABCI , 26 )
previousTotalVotingPower = css [ 0 ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( )
waitForAndValidateBlock ( t , nVals , activeVals , eventChan s , css , updateValidatorTx )
waitForAndValidateBlockWithTx ( t , nVals , activeVals , eventChan s , css , updateValidatorTx )
waitForAndValidateBlock ( t , nVals , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nVals , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nVals , activeVals , eventSub s , css , updateValidatorTx )
waitForAndValidateBlockWithTx ( t , nVals , activeVals , eventSub s , css , updateValidatorTx )
waitForAndValidateBlock ( t , nVals , activeVals , eventSub s , css )
waitForAndValidateBlock ( t , nVals , activeVals , eventSub s , css )
if css [ 0 ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( ) == previousTotalVotingPower {
t . Fatalf ( "expected voting power to change (before: %d, after: %d)" , previousTotalVotingPower , css [ 0 ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( ) )
@ -327,7 +332,7 @@ func TestReactorValidatorSetChanges(t *testing.T) {
logger := log . TestingLogger ( )
reactors , eventChan s , eventBuses := startConsensusNet ( t , css , nPeers )
reactors , eventSub s , eventBuses := startConsensusNet ( t , css , nPeers )
defer stopConsensusNet ( logger , reactors , eventBuses )
// map of active validators
@ -339,7 +344,7 @@ func TestReactorValidatorSetChanges(t *testing.T) {
// wait till everyone makes block 1
timeoutWaitGroup ( t , nPeers , func ( j int ) {
<- eventChan s [ j ]
<- eventSub s [ j ] . Out ( )
} , css )
//---------------------------------------------------------------------------
@ -352,22 +357,22 @@ func TestReactorValidatorSetChanges(t *testing.T) {
// wait till everyone makes block 2
// ensure the commit includes all validators
// send newValTx to change vals in block 3
waitForAndValidateBlock ( t , nPeers , activeVals , eventChan s , css , newValidatorTx1 )
waitForAndValidateBlock ( t , nPeers , activeVals , eventSub s , css , newValidatorTx1 )
// wait till everyone makes block 3.
// it includes the commit for block 2, which is by the original validator set
waitForAndValidateBlockWithTx ( t , nPeers , activeVals , eventChan s , css , newValidatorTx1 )
waitForAndValidateBlockWithTx ( t , nPeers , activeVals , eventSub s , css , newValidatorTx1 )
// wait till everyone makes block 4.
// it includes the commit for block 3, which is by the original validator set
waitForAndValidateBlock ( t , nPeers , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nPeers , activeVals , eventSub s , css )
// the commits for block 4 should be with the updated validator set
activeVals [ string ( newValidatorPubKey1 . Address ( ) ) ] = struct { } { }
// wait till everyone makes block 5
// it includes the commit for block 4, which should have the updated validator set
waitForBlockWithUpdatedValsAndValidateIt ( t , nPeers , activeVals , eventChan s , css )
waitForBlockWithUpdatedValsAndValidateIt ( t , nPeers , activeVals , eventSub s , css )
//---------------------------------------------------------------------------
logger . Info ( "---------------------------- Testing changing the voting power of one validator" )
@ -377,10 +382,10 @@ func TestReactorValidatorSetChanges(t *testing.T) {
updateValidatorTx1 := kvstore . MakeValSetChangeTx ( updatePubKey1ABCI , 25 )
previousTotalVotingPower := css [ nVals ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( )
waitForAndValidateBlock ( t , nPeers , activeVals , eventChan s , css , updateValidatorTx1 )
waitForAndValidateBlockWithTx ( t , nPeers , activeVals , eventChan s , css , updateValidatorTx1 )
waitForAndValidateBlock ( t , nPeers , activeVals , eventChan s , css )
waitForBlockWithUpdatedValsAndValidateIt ( t , nPeers , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nPeers , activeVals , eventSub s , css , updateValidatorTx1 )
waitForAndValidateBlockWithTx ( t , nPeers , activeVals , eventSub s , css , updateValidatorTx1 )
waitForAndValidateBlock ( t , nPeers , activeVals , eventSub s , css )
waitForBlockWithUpdatedValsAndValidateIt ( t , nPeers , activeVals , eventSub s , css )
if css [ nVals ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( ) == previousTotalVotingPower {
t . Errorf ( "expected voting power to change (before: %d, after: %d)" , previousTotalVotingPower , css [ nVals ] . GetRoundState ( ) . LastValidators . TotalVotingPower ( ) )
@ -397,12 +402,12 @@ func TestReactorValidatorSetChanges(t *testing.T) {
newVal3ABCI := types . TM2PB . PubKey ( newValidatorPubKey3 )
newValidatorTx3 := kvstore . MakeValSetChangeTx ( newVal3ABCI , testMinPower )
waitForAndValidateBlock ( t , nPeers , activeVals , eventChan s , css , newValidatorTx2 , newValidatorTx3 )
waitForAndValidateBlockWithTx ( t , nPeers , activeVals , eventChan s , css , newValidatorTx2 , newValidatorTx3 )
waitForAndValidateBlock ( t , nPeers , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nPeers , activeVals , eventSub s , css , newValidatorTx2 , newValidatorTx3 )
waitForAndValidateBlockWithTx ( t , nPeers , activeVals , eventSub s , css , newValidatorTx2 , newValidatorTx3 )
waitForAndValidateBlock ( t , nPeers , activeVals , eventSub s , css )
activeVals [ string ( newValidatorPubKey2 . Address ( ) ) ] = struct { } { }
activeVals [ string ( newValidatorPubKey3 . Address ( ) ) ] = struct { } { }
waitForBlockWithUpdatedValsAndValidateIt ( t , nPeers , activeVals , eventChan s , css )
waitForBlockWithUpdatedValsAndValidateIt ( t , nPeers , activeVals , eventSub s , css )
//---------------------------------------------------------------------------
logger . Info ( "---------------------------- Testing removing two validators at once" )
@ -410,12 +415,12 @@ func TestReactorValidatorSetChanges(t *testing.T) {
removeValidatorTx2 := kvstore . MakeValSetChangeTx ( newVal2ABCI , 0 )
removeValidatorTx3 := kvstore . MakeValSetChangeTx ( newVal3ABCI , 0 )
waitForAndValidateBlock ( t , nPeers , activeVals , eventChan s , css , removeValidatorTx2 , removeValidatorTx3 )
waitForAndValidateBlockWithTx ( t , nPeers , activeVals , eventChan s , css , removeValidatorTx2 , removeValidatorTx3 )
waitForAndValidateBlock ( t , nPeers , activeVals , eventChan s , css )
waitForAndValidateBlock ( t , nPeers , activeVals , eventSub s , css , removeValidatorTx2 , removeValidatorTx3 )
waitForAndValidateBlockWithTx ( t , nPeers , activeVals , eventSub s , css , removeValidatorTx2 , removeValidatorTx3 )
waitForAndValidateBlock ( t , nPeers , activeVals , eventSub s , css )
delete ( activeVals , string ( newValidatorPubKey2 . Address ( ) ) )
delete ( activeVals , string ( newValidatorPubKey3 . Address ( ) ) )
waitForBlockWithUpdatedValsAndValidateIt ( t , nPeers , activeVals , eventChan s , css )
waitForBlockWithUpdatedValsAndValidateIt ( t , nPeers , activeVals , eventSub s , css )
}
// Check we can make blocks with skip_timeout_commit=false
@ -427,23 +432,30 @@ func TestReactorWithTimeoutCommit(t *testing.T) {
css [ i ] . config . SkipTimeoutCommit = false
}
reactors , eventChan s , eventBuses := startConsensusNet ( t , css , N - 1 )
reactors , eventSub s , eventBuses := startConsensusNet ( t , css , N - 1 )
defer stopConsensusNet ( log . TestingLogger ( ) , reactors , eventBuses )
// wait till everyone makes the first new block
timeoutWaitGroup ( t , N - 1 , func ( j int ) {
<- eventChan s [ j ]
<- eventSub s [ j ] . Out ( )
} , css )
}
func waitForAndValidateBlock ( t * testing . T , n int , activeVals map [ string ] struct { } , eventChans [ ] chan interface { } , css [ ] * ConsensusState , txs ... [ ] byte ) {
func waitForAndValidateBlock (
t * testing . T ,
n int ,
activeVals map [ string ] struct { } ,
eventSubs [ ] * tmpubsub . Subscription ,
css [ ] * ConsensusState ,
txs ... [ ] byte ,
) {
timeoutWaitGroup ( t , n , func ( j int ) {
css [ j ] . Logger . Debug ( "waitForAndValidateBlock" )
newBlockI , ok := <- eventChans [ j ]
newBlockI , ok := <- eventSub s [ j ] . Out ( )
if ! ok {
return
}
newBlock := newBlockI . ( types . EventDataNewBlock ) . Block
newBlock := newBlockI . Msg . ( types . EventDataNewBlock ) . Block
css [ j ] . Logger . Debug ( "waitForAndValidateBlock: Got block" , "height" , newBlock . Height )
err := validateBlock ( newBlock , activeVals )
assert . Nil ( t , err )
@ -454,17 +466,24 @@ func waitForAndValidateBlock(t *testing.T, n int, activeVals map[string]struct{}
} , css )
}
func waitForAndValidateBlockWithTx ( t * testing . T , n int , activeVals map [ string ] struct { } , eventChans [ ] chan interface { } , css [ ] * ConsensusState , txs ... [ ] byte ) {
func waitForAndValidateBlockWithTx (
t * testing . T ,
n int ,
activeVals map [ string ] struct { } ,
eventSubs [ ] * tmpubsub . Subscription ,
css [ ] * ConsensusState ,
txs ... [ ] byte ,
) {
timeoutWaitGroup ( t , n , func ( j int ) {
ntxs := 0
BLOCK_TX_LOOP :
for {
css [ j ] . Logger . Debug ( "waitForAndValidateBlockWithTx" , "ntxs" , ntxs )
newBlockI , ok := <- eventChans [ j ]
newBlockI , ok := <- eventSub s [ j ] . Out ( )
if ! ok {
return
}
newBlock := newBlockI . ( types . EventDataNewBlock ) . Block
newBlock := newBlockI . Msg . ( types . EventDataNewBlock ) . Block
css [ j ] . Logger . Debug ( "waitForAndValidateBlockWithTx: Got block" , "height" , newBlock . Height )
err := validateBlock ( newBlock , activeVals )
assert . Nil ( t , err )
@ -485,18 +504,24 @@ func waitForAndValidateBlockWithTx(t *testing.T, n int, activeVals map[string]st
} , css )
}
func waitForBlockWithUpdatedValsAndValidateIt ( t * testing . T , n int , updatedVals map [ string ] struct { } , eventChans [ ] chan interface { } , css [ ] * ConsensusState ) {
func waitForBlockWithUpdatedValsAndValidateIt (
t * testing . T ,
n int ,
updatedVals map [ string ] struct { } ,
eventSubs [ ] * tmpubsub . Subscription ,
css [ ] * ConsensusState ,
) {
timeoutWaitGroup ( t , n , func ( j int ) {
var newBlock * types . Block
LOOP :
for {
css [ j ] . Logger . Debug ( "waitForBlockWithUpdatedValsAndValidateIt" )
newBlockI , ok := <- eventChan s [ j ]
newBlockI , ok := <- eventSub s [ j ] . Out ( )
if ! ok {
return
}
newBlock = newBlockI . ( types . EventDataNewBlock ) . Block
newBlock = newBlockI . Msg . ( types . EventDataNewBlock ) . Block
if newBlock . LastCommit . Size ( ) == len ( updatedVals ) {
css [ j ] . Logger . Debug ( "waitForBlockWithUpdatedValsAndValidateIt: Got block" , "height" , newBlock . Height )
break LOOP