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.

167 lines
4.0 KiB

  1. package main
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "time"
  7. rpchttp "github.com/tendermint/tendermint/rpc/client/http"
  8. rpctypes "github.com/tendermint/tendermint/rpc/core/types"
  9. e2e "github.com/tendermint/tendermint/test/e2e/pkg"
  10. "github.com/tendermint/tendermint/types"
  11. )
  12. // waitForHeight waits for the network to reach a certain height (or above),
  13. // returning the highest height seen. Errors if the network is not making
  14. // progress at all.
  15. func waitForHeight(testnet *e2e.Testnet, height int64) (*types.Block, *types.BlockID, error) {
  16. var (
  17. err error
  18. maxResult *rpctypes.ResultBlock
  19. clients = map[string]*rpchttp.HTTP{}
  20. lastIncrease = time.Now()
  21. nodesAtHeight = map[string]struct{}{}
  22. numRunningNodes int
  23. )
  24. for _, node := range testnet.Nodes {
  25. if node.Mode == e2e.ModeSeed {
  26. continue
  27. }
  28. if node.Mode == e2e.ModeLight {
  29. continue
  30. }
  31. if node.HasStarted {
  32. numRunningNodes++
  33. }
  34. }
  35. for {
  36. for _, node := range testnet.Nodes {
  37. // skip nodes that have reached the target height
  38. if _, ok := nodesAtHeight[node.Name]; ok {
  39. continue
  40. }
  41. if node.Mode == e2e.ModeSeed {
  42. continue
  43. }
  44. if node.Mode == e2e.ModeLight {
  45. continue
  46. }
  47. if !node.HasStarted {
  48. continue
  49. }
  50. // cache the clients
  51. client, ok := clients[node.Name]
  52. if !ok {
  53. client, err = node.Client()
  54. if err != nil {
  55. continue
  56. }
  57. clients[node.Name] = client
  58. }
  59. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  60. defer cancel()
  61. result, err := client.Block(ctx, nil)
  62. if err != nil {
  63. continue
  64. }
  65. if result.Block != nil && (maxResult == nil || result.Block.Height > maxResult.Block.Height) {
  66. maxResult = result
  67. lastIncrease = time.Now()
  68. }
  69. if maxResult != nil && maxResult.Block.Height >= height {
  70. // the node has achieved the target height!
  71. // add this node to the set of target
  72. // height nodes
  73. nodesAtHeight[node.Name] = struct{}{}
  74. // if not all of the nodes that we
  75. // have clients for have reached the
  76. // target height, keep trying.
  77. if numRunningNodes > len(nodesAtHeight) {
  78. continue
  79. }
  80. // return once all nodes have reached
  81. // the target height.
  82. return maxResult.Block, &maxResult.BlockID, nil
  83. }
  84. }
  85. if len(clients) == 0 {
  86. return nil, nil, errors.New("unable to connect to any network nodes")
  87. }
  88. if time.Since(lastIncrease) >= time.Minute {
  89. if maxResult == nil {
  90. return nil, nil, errors.New("chain stalled at unknown height")
  91. }
  92. return nil, nil, fmt.Errorf("chain stalled at height %v [%d of %d nodes]",
  93. maxResult.Block.Height,
  94. len(nodesAtHeight),
  95. numRunningNodes)
  96. }
  97. time.Sleep(1 * time.Second)
  98. }
  99. }
  100. // waitForNode waits for a node to become available and catch up to the given block height.
  101. func waitForNode(node *e2e.Node, height int64, timeout time.Duration) (*rpctypes.ResultStatus, error) {
  102. if node.Mode == e2e.ModeSeed {
  103. return nil, nil
  104. }
  105. client, err := node.Client()
  106. if err != nil {
  107. return nil, err
  108. }
  109. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  110. defer cancel()
  111. for {
  112. status, err := client.Status(ctx)
  113. switch {
  114. case errors.Is(err, context.DeadlineExceeded):
  115. return nil, fmt.Errorf("timed out waiting for %v to reach height %v", node.Name, height)
  116. case errors.Is(err, context.Canceled):
  117. return nil, err
  118. case err == nil && status.SyncInfo.LatestBlockHeight >= height:
  119. return status, nil
  120. }
  121. time.Sleep(300 * time.Millisecond)
  122. }
  123. }
  124. // waitForAllNodes waits for all nodes to become available and catch up to the given block height.
  125. func waitForAllNodes(testnet *e2e.Testnet, height int64, timeout time.Duration) (int64, error) {
  126. var lastHeight int64
  127. for _, node := range testnet.Nodes {
  128. if node.Mode == e2e.ModeSeed {
  129. continue
  130. }
  131. status, err := waitForNode(node, height, timeout)
  132. if err != nil {
  133. return 0, err
  134. }
  135. if status.SyncInfo.LatestBlockHeight > lastHeight {
  136. lastHeight = status.SyncInfo.LatestBlockHeight
  137. }
  138. }
  139. return lastHeight, nil
  140. }