mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-31 21:27:04 +00:00
Merge branch 'feature/abci++vef' into cal/finalize-block
This commit is contained in:
@@ -2,8 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
e2e "github.com/tendermint/tendermint/test/e2e/pkg"
|
||||
@@ -19,26 +21,28 @@ import (
|
||||
//
|
||||
// Metrics are based of the `benchmarkLength`, the amount of consecutive blocks
|
||||
// sampled from in the testnet
|
||||
func Benchmark(testnet *e2e.Testnet, benchmarkLength int64) error {
|
||||
block, _, err := waitForHeight(testnet, 0)
|
||||
func Benchmark(ctx context.Context, testnet *e2e.Testnet, benchmarkLength int64) error {
|
||||
block, _, err := waitForHeight(ctx, testnet, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("Beginning benchmark period...", "height", block.Height)
|
||||
startAt := time.Now()
|
||||
|
||||
// wait for the length of the benchmark period in blocks to pass. We allow 5 seconds for each block
|
||||
// which should be sufficient.
|
||||
waitingTime := time.Duration(benchmarkLength*5) * time.Second
|
||||
endHeight, err := waitForAllNodes(testnet, block.Height+benchmarkLength, waitingTime)
|
||||
endHeight, err := waitForAllNodes(ctx, testnet, block.Height+benchmarkLength, waitingTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dur := time.Since(startAt)
|
||||
|
||||
logger.Info("Ending benchmark period", "height", endHeight)
|
||||
|
||||
// fetch a sample of blocks
|
||||
blocks, err := fetchBlockChainSample(testnet, benchmarkLength)
|
||||
blocks, err := fetchBlockChainSample(ctx, testnet, benchmarkLength)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -46,18 +50,29 @@ func Benchmark(testnet *e2e.Testnet, benchmarkLength int64) error {
|
||||
// slice into time intervals and collate data
|
||||
timeIntervals := splitIntoBlockIntervals(blocks)
|
||||
testnetStats := extractTestnetStats(timeIntervals)
|
||||
testnetStats.populateTxns(blocks)
|
||||
testnetStats.totalTime = dur
|
||||
testnetStats.startHeight = blocks[0].Header.Height
|
||||
testnetStats.endHeight = blocks[len(blocks)-1].Header.Height
|
||||
|
||||
// print and return
|
||||
logger.Info(testnetStats.String())
|
||||
logger.Info(testnetStats.OutputJSON(testnet))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *testnetStats) populateTxns(blocks []*types.BlockMeta) {
|
||||
t.numtxns = 0
|
||||
for _, b := range blocks {
|
||||
t.numtxns += int64(b.NumTxs)
|
||||
}
|
||||
}
|
||||
|
||||
type testnetStats struct {
|
||||
startHeight int64
|
||||
endHeight int64
|
||||
|
||||
numtxns int64
|
||||
totalTime time.Duration
|
||||
// average time to produce a block
|
||||
mean time.Duration
|
||||
// standard deviation of block production
|
||||
@@ -68,6 +83,28 @@ type testnetStats struct {
|
||||
min time.Duration
|
||||
}
|
||||
|
||||
func (t *testnetStats) OutputJSON(net *e2e.Testnet) string {
|
||||
jsn, err := json.Marshal(map[string]interface{}{
|
||||
"case": filepath.Base(net.File),
|
||||
"start_height": t.startHeight,
|
||||
"end_height": t.endHeight,
|
||||
"blocks": t.endHeight - t.startHeight,
|
||||
"stddev": t.std,
|
||||
"mean": t.mean.Seconds(),
|
||||
"max": t.max.Seconds(),
|
||||
"min": t.min.Seconds(),
|
||||
"size": len(net.Nodes),
|
||||
"txns": t.numtxns,
|
||||
"dur": t.totalTime.Seconds(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return string(jsn)
|
||||
}
|
||||
|
||||
func (t *testnetStats) String() string {
|
||||
return fmt.Sprintf(`Benchmarked from height %v to %v
|
||||
Mean Block Interval: %v
|
||||
@@ -86,7 +123,7 @@ func (t *testnetStats) String() string {
|
||||
|
||||
// fetchBlockChainSample waits for `benchmarkLength` amount of blocks to pass, fetching
|
||||
// all of the headers for these blocks from an archive node and returning it.
|
||||
func fetchBlockChainSample(testnet *e2e.Testnet, benchmarkLength int64) ([]*types.BlockMeta, error) {
|
||||
func fetchBlockChainSample(ctx context.Context, testnet *e2e.Testnet, benchmarkLength int64) ([]*types.BlockMeta, error) {
|
||||
var blocks []*types.BlockMeta
|
||||
|
||||
// Find the first archive node
|
||||
@@ -97,7 +134,6 @@ func fetchBlockChainSample(testnet *e2e.Testnet, benchmarkLength int64) ([]*type
|
||||
}
|
||||
|
||||
// find the latest height
|
||||
ctx := context.Background()
|
||||
s, err := c.Status(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -82,7 +82,7 @@ func InjectEvidence(ctx context.Context, r *rand.Rand, testnet *e2e.Testnet, amo
|
||||
|
||||
// wait for the node to reach the height above the forged height so that
|
||||
// it is able to validate the evidence
|
||||
_, err = waitForNode(targetNode, waitHeight, time.Minute)
|
||||
_, err = waitForNode(ctx, targetNode, waitHeight, time.Minute)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -110,7 +110,7 @@ func InjectEvidence(ctx context.Context, r *rand.Rand, testnet *e2e.Testnet, amo
|
||||
|
||||
// wait for the node to reach the height above the forged height so that
|
||||
// it is able to validate the evidence
|
||||
_, err = waitForNode(targetNode, blockRes.Block.Height+2, 30*time.Second)
|
||||
_, err = waitForNode(ctx, targetNode, blockRes.Block.Height+2, 30*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+64
-18
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
e2e "github.com/tendermint/tendermint/test/e2e/pkg"
|
||||
"github.com/tendermint/tendermint/test/e2e/pkg/infra"
|
||||
"github.com/tendermint/tendermint/test/e2e/pkg/infra/docker"
|
||||
)
|
||||
|
||||
const randomSeed = 2308084734268
|
||||
@@ -26,6 +29,7 @@ type CLI struct {
|
||||
root *cobra.Command
|
||||
testnet *e2e.Testnet
|
||||
preserve bool
|
||||
infp infra.Provider
|
||||
}
|
||||
|
||||
// NewCLI sets up the CLI.
|
||||
@@ -41,19 +45,57 @@ func NewCLI() *CLI {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
testnet, err := e2e.LoadTestnet(file)
|
||||
m, err := e2e.LoadManifest(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
inft, err := cmd.Flags().GetString("infrastructure-type")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ifd e2e.InfrastructureData
|
||||
switch inft {
|
||||
case "docker":
|
||||
var err error
|
||||
ifd, err = e2e.NewDockerInfrastructureData(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "digital-ocean":
|
||||
p, err := cmd.Flags().GetString("infrastructure-data")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p == "" {
|
||||
return errors.New("'--infrastructure-data' must be set when using the 'digital-ocean' infrastructure-type")
|
||||
}
|
||||
ifd, err = e2e.InfrastructureDataFromFile(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing infrastructure data: %s", err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown infrastructure type '%s'", inft)
|
||||
}
|
||||
|
||||
testnet, err := e2e.LoadTestnet(file, ifd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading testnet: %s", err)
|
||||
}
|
||||
|
||||
cli.testnet = testnet
|
||||
cli.infp = &infra.NoopProvider{}
|
||||
if inft == "docker" {
|
||||
cli.infp = &docker.Provider{Testnet: testnet}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := Cleanup(cli.testnet); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Setup(cli.testnet); err != nil {
|
||||
if err := Setup(cli.testnet, cli.infp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -70,19 +112,19 @@ func NewCLI() *CLI {
|
||||
chLoadResult <- err
|
||||
}()
|
||||
|
||||
if err := Start(cli.testnet); err != nil {
|
||||
if err := Start(cmd.Context(), cli.testnet); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := Wait(cli.testnet, 5); err != nil { // allow some txs to go through
|
||||
if err := Wait(cmd.Context(), cli.testnet, 5); err != nil { // allow some txs to go through
|
||||
return err
|
||||
}
|
||||
|
||||
if cli.testnet.HasPerturbations() {
|
||||
if err := Perturb(cli.testnet); err != nil {
|
||||
if err := Perturb(cmd.Context(), cli.testnet); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Wait(cli.testnet, 5); err != nil { // allow some txs to go through
|
||||
if err := Wait(cmd.Context(), cli.testnet, 5); err != nil { // allow some txs to go through
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -91,7 +133,7 @@ func NewCLI() *CLI {
|
||||
if err := InjectEvidence(ctx, r, cli.testnet, cli.testnet.Evidence); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Wait(cli.testnet, 5); err != nil { // ensure chain progress
|
||||
if err := Wait(cmd.Context(), cli.testnet, 5); err != nil { // ensure chain progress
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -100,7 +142,7 @@ func NewCLI() *CLI {
|
||||
if err := <-chLoadResult; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Wait(cli.testnet, 5); err != nil { // wait for network to settle before tests
|
||||
if err := Wait(cmd.Context(), cli.testnet, 5); err != nil { // wait for network to settle before tests
|
||||
return err
|
||||
}
|
||||
if err := Test(cli.testnet); err != nil {
|
||||
@@ -118,6 +160,10 @@ func NewCLI() *CLI {
|
||||
cli.root.PersistentFlags().StringP("file", "f", "", "Testnet TOML manifest")
|
||||
_ = cli.root.MarkPersistentFlagRequired("file")
|
||||
|
||||
cli.root.PersistentFlags().StringP("infrastructure-type", "", "docker", "Backing infrastructure used to run the testnet. Either 'digital-ocean' or 'docker'")
|
||||
|
||||
cli.root.PersistentFlags().StringP("infrastructure-data", "", "", "path to the json file containing the infrastructure data. Only used if the 'infrastructure-type' is set to a value other than 'docker'")
|
||||
|
||||
cli.root.Flags().BoolVarP(&cli.preserve, "preserve", "p", false,
|
||||
"Preserves the running of the test net after tests are completed")
|
||||
|
||||
@@ -125,7 +171,7 @@ func NewCLI() *CLI {
|
||||
Use: "setup",
|
||||
Short: "Generates the testnet directory and configuration",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return Setup(cli.testnet)
|
||||
return Setup(cli.testnet, cli.infp)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -135,12 +181,12 @@ func NewCLI() *CLI {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
_, err := os.Stat(cli.testnet.Dir)
|
||||
if os.IsNotExist(err) {
|
||||
err = Setup(cli.testnet)
|
||||
err = Setup(cli.testnet, cli.infp)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return Start(cli.testnet)
|
||||
return Start(cmd.Context(), cli.testnet)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -148,7 +194,7 @@ func NewCLI() *CLI {
|
||||
Use: "perturb",
|
||||
Short: "Perturbs the Docker testnet, e.g. by restarting or disconnecting nodes",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return Perturb(cli.testnet)
|
||||
return Perturb(cmd.Context(), cli.testnet)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -156,7 +202,7 @@ func NewCLI() *CLI {
|
||||
Use: "wait",
|
||||
Short: "Waits for a few blocks to be produced and all nodes to catch up",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return Wait(cli.testnet, 5)
|
||||
return Wait(cmd.Context(), cli.testnet, 5)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -258,12 +304,12 @@ Does not run any perbutations.
|
||||
if err := Cleanup(cli.testnet); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Setup(cli.testnet); err != nil {
|
||||
if err := Setup(cli.testnet, cli.infp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chLoadResult := make(chan error)
|
||||
ctx, loadCancel := context.WithCancel(context.Background())
|
||||
ctx, loadCancel := context.WithCancel(cmd.Context())
|
||||
defer loadCancel()
|
||||
go func() {
|
||||
err := Load(ctx, cli.testnet, 1)
|
||||
@@ -273,16 +319,16 @@ Does not run any perbutations.
|
||||
chLoadResult <- err
|
||||
}()
|
||||
|
||||
if err := Start(cli.testnet); err != nil {
|
||||
if err := Start(cmd.Context(), cli.testnet); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := Wait(cli.testnet, 5); err != nil { // allow some txs to go through
|
||||
if err := Wait(cmd.Context(), cli.testnet, 5); err != nil { // allow some txs to go through
|
||||
return err
|
||||
}
|
||||
|
||||
// we benchmark performance over the next 100 blocks
|
||||
if err := Benchmark(cli.testnet, 100); err != nil {
|
||||
if err := Benchmark(cmd.Context(), cli.testnet, 100); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -10,10 +11,10 @@ import (
|
||||
)
|
||||
|
||||
// Perturbs a running testnet.
|
||||
func Perturb(testnet *e2e.Testnet) error {
|
||||
func Perturb(ctx context.Context, testnet *e2e.Testnet) error {
|
||||
for _, node := range testnet.Nodes {
|
||||
for _, perturbation := range node.Perturbations {
|
||||
_, err := PerturbNode(node, perturbation)
|
||||
_, err := PerturbNode(ctx, node, perturbation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -25,7 +26,7 @@ func Perturb(testnet *e2e.Testnet) error {
|
||||
|
||||
// PerturbNode perturbs a node with a given perturbation, returning its status
|
||||
// after recovering.
|
||||
func PerturbNode(node *e2e.Node, perturbation e2e.Perturbation) (*rpctypes.ResultStatus, error) {
|
||||
func PerturbNode(ctx context.Context, node *e2e.Node, perturbation e2e.Perturbation) (*rpctypes.ResultStatus, error) {
|
||||
testnet := node.Testnet
|
||||
switch perturbation {
|
||||
case e2e.PerturbationDisconnect:
|
||||
@@ -67,7 +68,7 @@ func PerturbNode(node *e2e.Node, perturbation e2e.Perturbation) (*rpctypes.Resul
|
||||
return nil, fmt.Errorf("unexpected perturbation %q", perturbation)
|
||||
}
|
||||
|
||||
status, err := waitForNode(node, 0, 20*time.Second)
|
||||
status, err := waitForNode(ctx, node, 0, 20*time.Second)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+65
-46
@@ -15,7 +15,7 @@ import (
|
||||
// waitForHeight waits for the network to reach a certain height (or above),
|
||||
// returning the highest height seen. Errors if the network is not making
|
||||
// progress at all.
|
||||
func waitForHeight(testnet *e2e.Testnet, height int64) (*types.Block, *types.BlockID, error) {
|
||||
func waitForHeight(ctx context.Context, testnet *e2e.Testnet, height int64) (*types.Block, *types.BlockID, error) {
|
||||
var (
|
||||
err error
|
||||
maxResult *rpctypes.ResultBlock
|
||||
@@ -23,73 +23,92 @@ func waitForHeight(testnet *e2e.Testnet, height int64) (*types.Block, *types.Blo
|
||||
lastIncrease = time.Now()
|
||||
)
|
||||
|
||||
timer := time.NewTimer(0)
|
||||
defer timer.Stop()
|
||||
for {
|
||||
for _, node := range testnet.Nodes {
|
||||
if node.Mode == e2e.ModeSeed {
|
||||
continue
|
||||
}
|
||||
client, ok := clients[node.Name]
|
||||
if !ok {
|
||||
client, err = node.Client()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, nil, ctx.Err()
|
||||
case <-timer.C:
|
||||
for _, node := range testnet.Nodes {
|
||||
if node.Stateless() {
|
||||
continue
|
||||
}
|
||||
client, ok := clients[node.Name]
|
||||
if !ok {
|
||||
client, err = node.Client()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
clients[node.Name] = client
|
||||
}
|
||||
|
||||
subctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel()
|
||||
result, err := client.Block(subctx, nil)
|
||||
if err == context.DeadlineExceeded || err == context.Canceled {
|
||||
return nil, nil, ctx.Err()
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
clients[node.Name] = client
|
||||
if result.Block != nil && (maxResult == nil || result.Block.Height >= maxResult.Block.Height) {
|
||||
maxResult = result
|
||||
lastIncrease = time.Now()
|
||||
}
|
||||
if maxResult != nil && maxResult.Block.Height >= height {
|
||||
return maxResult.Block, &maxResult.BlockID, nil
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
defer cancel()
|
||||
result, err := client.Block(ctx, nil)
|
||||
if err != nil {
|
||||
continue
|
||||
if len(clients) == 0 {
|
||||
return nil, nil, errors.New("unable to connect to any network nodes")
|
||||
}
|
||||
if result.Block != nil && (maxResult == nil || result.Block.Height >= maxResult.Block.Height) {
|
||||
maxResult = result
|
||||
lastIncrease = time.Now()
|
||||
}
|
||||
if maxResult != nil && maxResult.Block.Height >= height {
|
||||
return maxResult.Block, &maxResult.BlockID, nil
|
||||
if time.Since(lastIncrease) >= 20*time.Second {
|
||||
if maxResult == nil {
|
||||
return nil, nil, errors.New("chain stalled at unknown height")
|
||||
}
|
||||
return nil, nil, fmt.Errorf("chain stalled at height %v", maxResult.Block.Height)
|
||||
}
|
||||
timer.Reset(1 * time.Second)
|
||||
}
|
||||
|
||||
if len(clients) == 0 {
|
||||
return nil, nil, errors.New("unable to connect to any network nodes")
|
||||
}
|
||||
if time.Since(lastIncrease) >= 20*time.Second {
|
||||
if maxResult == nil {
|
||||
return nil, nil, errors.New("chain stalled at unknown height")
|
||||
}
|
||||
return nil, nil, fmt.Errorf("chain stalled at height %v", maxResult.Block.Height)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// waitForNode waits for a node to become available and catch up to the given block height.
|
||||
func waitForNode(node *e2e.Node, height int64, timeout time.Duration) (*rpctypes.ResultStatus, error) {
|
||||
func waitForNode(ctx context.Context, node *e2e.Node, height int64, timeout time.Duration) (*rpctypes.ResultStatus, error) {
|
||||
client, err := node.Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
for {
|
||||
status, err := client.Status(ctx)
|
||||
switch {
|
||||
case errors.Is(err, context.DeadlineExceeded):
|
||||
return nil, fmt.Errorf("timed out waiting for %v to reach height %v", node.Name, height)
|
||||
case errors.Is(err, context.Canceled):
|
||||
return nil, err
|
||||
case err == nil && status.SyncInfo.LatestBlockHeight >= height:
|
||||
return status, nil
|
||||
}
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
timer := time.NewTimer(0)
|
||||
defer timer.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case <-timer.C:
|
||||
subctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
status, err := client.Status(subctx)
|
||||
switch {
|
||||
case errors.Is(err, context.DeadlineExceeded):
|
||||
return nil, fmt.Errorf("timed out waiting for %v to reach height %v", node.Name, height)
|
||||
case errors.Is(err, context.Canceled):
|
||||
return nil, err
|
||||
case err == nil && status.SyncInfo.LatestBlockHeight >= height:
|
||||
return status, nil
|
||||
}
|
||||
|
||||
timer.Reset(300 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// waitForAllNodes waits for all nodes to become available and catch up to the given block height.
|
||||
func waitForAllNodes(testnet *e2e.Testnet, height int64, timeout time.Duration) (int64, error) {
|
||||
func waitForAllNodes(ctx context.Context, testnet *e2e.Testnet, height int64, timeout time.Duration) (int64, error) {
|
||||
var lastHeight int64
|
||||
|
||||
for _, node := range testnet.Nodes {
|
||||
@@ -97,7 +116,7 @@ func waitForAllNodes(testnet *e2e.Testnet, height int64, timeout time.Duration)
|
||||
continue
|
||||
}
|
||||
|
||||
status, err := waitForNode(node, height, timeout)
|
||||
status, err := waitForNode(ctx, node, height, timeout)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
@@ -23,6 +21,7 @@ import (
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
e2e "github.com/tendermint/tendermint/test/e2e/pkg"
|
||||
"github.com/tendermint/tendermint/test/e2e/pkg/infra"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
@@ -39,7 +38,7 @@ const (
|
||||
)
|
||||
|
||||
// Setup sets up the testnet configuration.
|
||||
func Setup(testnet *e2e.Testnet) error {
|
||||
func Setup(testnet *e2e.Testnet, infp infra.Provider) error {
|
||||
logger.Info("setup", "msg", log.NewLazySprintf("Generating testnet files in %q", testnet.Dir))
|
||||
|
||||
err := os.MkdirAll(testnet.Dir, os.ModePerm)
|
||||
@@ -47,11 +46,7 @@ func Setup(testnet *e2e.Testnet) error {
|
||||
return err
|
||||
}
|
||||
|
||||
compose, err := MakeDockerCompose(testnet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(filepath.Join(testnet.Dir, "docker-compose.yml"), compose, 0o644) //nolint:gosec
|
||||
err = infp.Setup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -126,70 +121,6 @@ func Setup(testnet *e2e.Testnet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeDockerCompose generates a Docker Compose config for a testnet.
|
||||
func MakeDockerCompose(testnet *e2e.Testnet) ([]byte, error) {
|
||||
// Must use version 2 Docker Compose format, to support IPv6.
|
||||
tmpl, err := template.New("docker-compose").Funcs(template.FuncMap{
|
||||
"misbehaviorsToString": func(misbehaviors map[int64]string) string {
|
||||
str := ""
|
||||
for height, misbehavior := range misbehaviors {
|
||||
// after the first behavior set, a comma must be prepended
|
||||
if str != "" {
|
||||
str += ","
|
||||
}
|
||||
heightString := strconv.Itoa(int(height))
|
||||
str += misbehavior + "," + heightString
|
||||
}
|
||||
return str
|
||||
},
|
||||
}).Parse(`version: '2.4'
|
||||
|
||||
networks:
|
||||
{{ .Name }}:
|
||||
labels:
|
||||
e2e: true
|
||||
driver: bridge
|
||||
{{- if .IPv6 }}
|
||||
enable_ipv6: true
|
||||
{{- end }}
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: {{ .IP }}
|
||||
|
||||
services:
|
||||
{{- range .Nodes }}
|
||||
{{ .Name }}:
|
||||
labels:
|
||||
e2e: true
|
||||
container_name: {{ .Name }}
|
||||
image: tendermint/e2e-node
|
||||
{{- if eq .ABCIProtocol "builtin" }}
|
||||
entrypoint: /usr/bin/entrypoint-builtin
|
||||
{{- end }}
|
||||
init: true
|
||||
ports:
|
||||
- 26656
|
||||
- {{ if .ProxyPort }}{{ .ProxyPort }}:{{ end }}26657
|
||||
- 6060
|
||||
volumes:
|
||||
- ./{{ .Name }}:/tendermint
|
||||
networks:
|
||||
{{ $.Name }}:
|
||||
ipv{{ if $.IPv6 }}6{{ else }}4{{ end}}_address: {{ .IP }}
|
||||
|
||||
{{end}}`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = tmpl.Execute(&buf, testnet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// MakeGenesis generates a genesis document.
|
||||
func MakeGenesis(testnet *e2e.Testnet) (types.GenesisDoc, error) {
|
||||
genesis := types.GenesisDoc{
|
||||
@@ -327,6 +258,7 @@ func MakeAppConfig(node *e2e.Node) ([]byte, error) {
|
||||
"dir": "data/app",
|
||||
"listen": AppAddressUNIX,
|
||||
"mode": node.Mode,
|
||||
"sync_app": node.SyncApp,
|
||||
"proxy_port": node.ProxyPort,
|
||||
"protocol": "socket",
|
||||
"persist_interval": node.PersistInterval,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
@@ -9,7 +10,7 @@ import (
|
||||
e2e "github.com/tendermint/tendermint/test/e2e/pkg"
|
||||
)
|
||||
|
||||
func Start(testnet *e2e.Testnet) error {
|
||||
func Start(ctx context.Context, testnet *e2e.Testnet) error {
|
||||
if len(testnet.Nodes) == 0 {
|
||||
return fmt.Errorf("no nodes in testnet")
|
||||
}
|
||||
@@ -46,7 +47,7 @@ func Start(testnet *e2e.Testnet) error {
|
||||
if err := execCompose(testnet.Dir, "up", "-d", node.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := waitForNode(node, 0, 15*time.Second); err != nil {
|
||||
if _, err := waitForNode(ctx, node, 0, 15*time.Second); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("start", "msg", log.NewLazySprintf("Node %v up on http://127.0.0.1:%v", node.Name, node.ProxyPort))
|
||||
@@ -60,7 +61,7 @@ func Start(testnet *e2e.Testnet) error {
|
||||
"nodes", len(testnet.Nodes)-len(nodeQueue),
|
||||
"pending", len(nodeQueue))
|
||||
|
||||
block, blockID, err := waitForHeight(testnet, networkHeight)
|
||||
block, blockID, err := waitForHeight(ctx, testnet, networkHeight)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -90,7 +91,7 @@ func Start(testnet *e2e.Testnet) error {
|
||||
"node", node.Name,
|
||||
"height", networkHeight)
|
||||
|
||||
if _, _, err := waitForHeight(testnet, networkHeight); err != nil {
|
||||
if _, _, err := waitForHeight(ctx, testnet, networkHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -100,7 +101,7 @@ func Start(testnet *e2e.Testnet) error {
|
||||
if err := execCompose(testnet.Dir, "up", "-d", node.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
status, err := waitForNode(node, node.StartAt, 3*time.Minute)
|
||||
status, err := waitForNode(ctx, node, node.StartAt, 3*time.Minute)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@@ -9,18 +10,18 @@ import (
|
||||
|
||||
// Wait waits for a number of blocks to be produced, and for all nodes to catch
|
||||
// up with it.
|
||||
func Wait(testnet *e2e.Testnet, blocks int64) error {
|
||||
block, _, err := waitForHeight(testnet, 0)
|
||||
func Wait(ctx context.Context, testnet *e2e.Testnet, blocks int64) error {
|
||||
block, _, err := waitForHeight(ctx, testnet, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return WaitUntil(testnet, block.Height+blocks)
|
||||
return WaitUntil(ctx, testnet, block.Height+blocks)
|
||||
}
|
||||
|
||||
// WaitUntil waits until a given height has been reached.
|
||||
func WaitUntil(testnet *e2e.Testnet, height int64) error {
|
||||
func WaitUntil(ctx context.Context, testnet *e2e.Testnet, height int64) error {
|
||||
logger.Info("wait until", "msg", log.NewLazySprintf("Waiting for all nodes to reach height %v...", height))
|
||||
_, err := waitForAllNodes(testnet, height, waitingTime(len(testnet.Nodes)))
|
||||
_, err := waitForAllNodes(ctx, testnet, height, waitingTime(len(testnet.Nodes)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user