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.

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