You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
5.5 KiB

  1. package consensus
  2. import (
  3. "fmt"
  4. "sync"
  5. "testing"
  6. "time"
  7. "github.com/tendermint/tendermint/config/tendermint_test"
  8. "github.com/tendermint/go-events"
  9. "github.com/tendermint/go-p2p"
  10. "github.com/tendermint/tendermint/types"
  11. "github.com/tendermint/tmsp/example/dummy"
  12. )
  13. func init() {
  14. config = tendermint_test.ResetConfig("consensus_reactor_test")
  15. }
  16. //----------------------------------------------
  17. // in-process testnets
  18. // Ensure a testnet makes blocks
  19. func TestReactor(t *testing.T) {
  20. N := 4
  21. css := randConsensusNet(N, "consensus_reactor_test", crankTimeoutPropose, newMockTickerFunc(true))
  22. reactors := make([]*ConsensusReactor, N)
  23. eventChans := make([]chan interface{}, N)
  24. for i := 0; i < N; i++ {
  25. reactors[i] = NewConsensusReactor(css[i], false)
  26. eventSwitch := events.NewEventSwitch()
  27. _, err := eventSwitch.Start()
  28. if err != nil {
  29. t.Fatalf("Failed to start switch: %v", err)
  30. }
  31. reactors[i].SetEventSwitch(eventSwitch)
  32. eventChans[i] = subscribeToEvent(eventSwitch, "tester", types.EventStringNewBlock(), 1)
  33. }
  34. // make connected switches and start all reactors
  35. p2p.MakeConnectedSwitches(N, func(i int, s *p2p.Switch) *p2p.Switch {
  36. s.AddReactor("CONSENSUS", reactors[i])
  37. return s
  38. }, p2p.Connect2Switches)
  39. // wait till everyone makes the first new block
  40. timeoutWaitGroup(t, N, func(wg *sync.WaitGroup, j int) {
  41. <-eventChans[j]
  42. wg.Done()
  43. })
  44. }
  45. //-------------------------------------------------------------
  46. // ensure we can make blocks despite cycling a validator set
  47. func TestValidatorSetChanges(t *testing.T) {
  48. nPeers := 8
  49. nVals := 4
  50. css := randConsensusNetWithPeers(nVals, nPeers, "consensus_val_set_changes_test", crankTimeoutPropose, newMockTickerFunc(true))
  51. reactors := make([]*ConsensusReactor, nPeers)
  52. eventChans := make([]chan interface{}, nPeers)
  53. for i := 0; i < nPeers; i++ {
  54. reactors[i] = NewConsensusReactor(css[i], true) // so we dont start the consensus states
  55. eventSwitch := events.NewEventSwitch()
  56. _, err := eventSwitch.Start()
  57. if err != nil {
  58. t.Fatalf("Failed to start switch: %v", err)
  59. }
  60. reactors[i].SetEventSwitch(eventSwitch)
  61. eventChans[i] = subscribeToEventRespond(eventSwitch, "tester", types.EventStringNewBlock())
  62. }
  63. p2p.MakeConnectedSwitches(nPeers, func(i int, s *p2p.Switch) *p2p.Switch {
  64. s.AddReactor("CONSENSUS", reactors[i])
  65. return s
  66. }, p2p.Connect2Switches)
  67. // now that everyone is connected, start the state machines
  68. // (otherwise, we could block forever in firing new block while a peer is trying to
  69. // access state info for AddPeer)
  70. for i := 0; i < nPeers; i++ {
  71. s := reactors[i].conS.GetState()
  72. reactors[i].SwitchToConsensus(s)
  73. }
  74. // map of active validators
  75. activeVals := make(map[string]struct{})
  76. for i := 0; i < nVals; i++ {
  77. activeVals[string(css[i].privValidator.GetAddress())] = struct{}{}
  78. }
  79. // wait till everyone makes block 1
  80. timeoutWaitGroup(t, nPeers, func(wg *sync.WaitGroup, j int) {
  81. <-eventChans[j]
  82. eventChans[j] <- struct{}{}
  83. wg.Done()
  84. })
  85. newValidatorPubKey := css[nVals].privValidator.(*types.PrivValidator).PubKey
  86. newValidatorTx := dummy.MakeValSetChangeTx(newValidatorPubKey.Bytes(), uint64(testMinPower))
  87. // wait till everyone makes block 2
  88. // ensure the commit includes all validators
  89. // send newValTx to change vals in block 3
  90. waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, newValidatorTx)
  91. // wait till everyone makes block 3.
  92. // it includes the commit for block 2, which is by the original validator set
  93. waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
  94. // wait till everyone makes block 4.
  95. // it includes the commit for block 3, which is by the original validator set
  96. waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
  97. // the commits for block 4 should be with the updated validator set
  98. activeVals[string(newValidatorPubKey.Address())] = struct{}{}
  99. // wait till everyone makes block 5
  100. // it includes the commit for block 4, which should have the updated validator set
  101. waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css)
  102. // TODO: test more changes!
  103. }
  104. func waitForAndValidateBlock(t *testing.T, n int, activeVals map[string]struct{}, eventChans []chan interface{}, css []*ConsensusState, txs ...[]byte) {
  105. timeoutWaitGroup(t, n, func(wg *sync.WaitGroup, j int) {
  106. newBlockI := <-eventChans[j]
  107. newBlock := newBlockI.(types.EventDataNewBlock).Block
  108. log.Info("Got block", "height", newBlock.Height, "validator", j)
  109. err := validateBlock(newBlock, activeVals)
  110. if err != nil {
  111. t.Fatal(err)
  112. }
  113. for _, tx := range txs {
  114. css[j].mempool.CheckTx(tx, nil)
  115. }
  116. eventChans[j] <- struct{}{}
  117. wg.Done()
  118. })
  119. }
  120. // expects high synchrony!
  121. func validateBlock(block *types.Block, activeVals map[string]struct{}) error {
  122. if block.LastCommit.Size() != len(activeVals) {
  123. return fmt.Errorf("Commit size doesn't match number of active validators. Got %d, expected %d", block.LastCommit.Size(), len(activeVals))
  124. }
  125. for _, vote := range block.LastCommit.Precommits {
  126. if _, ok := activeVals[string(vote.ValidatorAddress)]; !ok {
  127. return fmt.Errorf("Found vote for unactive validator %X", vote.ValidatorAddress)
  128. }
  129. }
  130. return nil
  131. }
  132. func timeoutWaitGroup(t *testing.T, n int, f func(*sync.WaitGroup, int)) {
  133. wg := new(sync.WaitGroup)
  134. wg.Add(n)
  135. for i := 0; i < n; i++ {
  136. go f(wg, i)
  137. }
  138. // Make wait into a channel
  139. done := make(chan struct{})
  140. go func() {
  141. wg.Wait()
  142. close(done)
  143. }()
  144. tick := time.NewTicker(time.Second * 3)
  145. select {
  146. case <-done:
  147. case <-tick.C:
  148. t.Fatalf("Timed out waiting for all validators to commit a block")
  149. }
  150. }