func waitForHeight(ctx context.Context, testnet *e2e.Testnet, height int64) (*types.Block, *types.BlockID, error) {
	var (
		err             error
		clients         = map[string]*rpchttp.HTTP{}
		lastHeight      int64
		lastIncrease    = time.Now()
		nodesAtHeight   = map[string]struct{}{}
		numRunningNodes int
	)
	if height == 0 {
		height = testnet.InitialHeight
	}
	for _, node := range testnet.Nodes {
		if node.Stateless() {
			continue
		}
		if node.HasStarted {
			numRunningNodes++
		}
	}
	timer := time.NewTimer(0)
	defer timer.Stop()
	for {
		select {
		case <-ctx.Done():
			return nil, nil, ctx.Err()
		case <-timer.C:
			for _, node := range testnet.Nodes {
				if _, ok := nodesAtHeight[node.Name]; ok {
					continue
				}
				if node.Stateless() {
					continue
				}
				if !node.HasStarted {
					continue
				}
				client, ok := clients[node.Name]
				if !ok {
					client, err = node.Client()
					if err != nil {
						continue
					}
					clients[node.Name] = client
				}
				wctx, cancel := context.WithTimeout(ctx, 10*time.Second)
				defer cancel()
				result, err := client.Status(wctx)
				if err != nil {
					continue
				}
				if result.SyncInfo.LatestBlockHeight > lastHeight {
					lastHeight = result.SyncInfo.LatestBlockHeight
					lastIncrease = time.Now()
				}
				if result.SyncInfo.LatestBlockHeight >= height {
					nodesAtHeight[node.Name] = struct{}{}
					if numRunningNodes > len(nodesAtHeight) {
						continue
					}
					for _, c := range clients {
						result, err := c.Block(ctx, &height)
						if err != nil || result == nil || result.Block == nil {
							continue
						}
						return result.Block, &result.BlockID, err
					}
				}
			}
			if len(clients) == 0 {
				return nil, nil, errors.New("unable to connect to any network nodes")
			}
			if time.Since(lastIncrease) >= time.Minute {
				if lastHeight == 0 {
					return nil, nil, errors.New("chain stalled at unknown height (most likely upon starting)")
				}
				return nil, nil, fmt.Errorf("chain stalled at height %v [%d of %d nodes %+v]",
					lastHeight,
					len(nodesAtHeight),
					numRunningNodes,
					nodesAtHeight)
			}
			timer.Reset(1 * time.Second)
		}
	}
}
waitForHeight waits for the network to reach a certain height (or above),
returning the block at the height seen. Errors if the network is not making
progress at all.
If height == 0, the initial height of the test network is used as the target.
package main
import (
	"context"
	"errors"
	"fmt"
	"time"
	rpchttp "github.com/tendermint/tendermint/rpc/client/http"
	rpctypes "github.com/tendermint/tendermint/rpc/coretypes"
	e2e "github.com/tendermint/tendermint/test/e2e/pkg"
	"github.com/tendermint/tendermint/types"
)