From 206b96c313f33755cc723d0ef496010220a4a7c2 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Wed, 9 Oct 2024 19:31:41 +0200 Subject: [PATCH] test: v3 e2e upgrade (#3910) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/celestiaorg/celestia-app/issues/3772 Opens https://github.com/celestiaorg/celestia-app/issues/3947 ## Testing ``` make test-e2e MajorUpgradeToV3 test-e2e2024/10/08 22:36:00 --- ✅ PASS: MajorUpgradeToV3 ``` --------- Co-authored-by: Rootul P --- test/cmd/txsim/cli.go | 13 ++- test/e2e/benchmark/benchmark.go | 9 +- test/e2e/main.go | 1 + test/e2e/major_upgrade_v2.go | 3 +- test/e2e/major_upgrade_v3.go | 95 ++++++++++++++++++++ test/e2e/minor_version_compatibility.go | 3 +- test/e2e/simple.go | 4 +- test/e2e/testnet/key_generator.go | 37 ++++++++ test/e2e/testnet/node.go | 21 ++--- test/e2e/testnet/testnet.go | 112 ++++++++++++++---------- test/e2e/testnet/txsimNode.go | 55 ++++++++---- test/e2e/testnet/util.go | 32 ------- test/txsim/upgrade.go | 50 ++++++----- 13 files changed, 303 insertions(+), 132 deletions(-) create mode 100644 test/e2e/major_upgrade_v3.go create mode 100644 test/e2e/testnet/key_generator.go diff --git a/test/cmd/txsim/cli.go b/test/cmd/txsim/cli.go index bf334437c4..55cac6d4fd 100644 --- a/test/cmd/txsim/cli.go +++ b/test/cmd/txsim/cli.go @@ -41,6 +41,7 @@ var ( stake, stakeValue, blob int useFeegrant, suppressLogs bool upgradeSchedule string + blobShareVersion int ) func main() { @@ -102,8 +103,8 @@ well funded account that can act as the master account. The command runs until a masterAccName = os.Getenv(TxsimMasterAccName) } - if stake == 0 && send == 0 && blob == 0 { - return errors.New("no sequences specified. Use --stake, --send or --blob") + if stake == 0 && send == 0 && blob == 0 && upgradeSchedule == "" { + return errors.New("no sequences specified. Use --stake, --send, --upgrade-schedule or --blob") } // setup the sequences @@ -128,7 +129,12 @@ well funded account that can act as the master account. The command runs until a return fmt.Errorf("invalid blob amounts: %w", err) } - sequences = append(sequences, txsim.NewBlobSequence(sizes, blobsPerPFB).Clone(blob)...) + sequence := txsim.NewBlobSequence(sizes, blobsPerPFB) + if blobShareVersion >= 0 { + sequence.WithShareVersion(uint8(blobShareVersion)) + } + + sequences = append(sequences, sequence.Clone(blob)...) } upgradeScheduleMap, err := parseUpgradeSchedule(upgradeSchedule) @@ -210,6 +216,7 @@ func flags() *flag.FlagSet { flags.StringVar(&blobAmounts, "blob-amounts", "1", "range of blobs per PFB specified as a single value or a min-max range (e.g., 10 or 5-10). A single value indicates the exact number of blobs to be created.") flags.BoolVar(&useFeegrant, "feegrant", false, "use the feegrant module to pay for fees") flags.BoolVar(&suppressLogs, "suppressLogs", false, "disable logging") + flags.IntVar(&blobShareVersion, "blob-share-version", -1, "optionally specify a share version to use for the blob sequences") return flags } diff --git a/test/e2e/benchmark/benchmark.go b/test/e2e/benchmark/benchmark.go index 81b2748cb1..83843549ea 100644 --- a/test/e2e/benchmark/benchmark.go +++ b/test/e2e/benchmark/benchmark.go @@ -56,11 +56,16 @@ func (b *BenchmarkTest) SetupNodes() error { // create tx clients and point them to the validators log.Println("Creating tx clients") - err = b.CreateTxClients(ctx, b.manifest.TxClientVersion, + err = b.CreateTxClients( + ctx, + b.manifest.TxClientVersion, b.manifest.BlobSequences, b.manifest.BlobSizes, b.manifest.BlobsPerSeq, - b.manifest.TxClientsResource, gRPCEndpoints) + b.manifest.TxClientsResource, + gRPCEndpoints, + map[int64]uint64{}, // upgrade schedule + ) testnet.NoError("failed to create tx clients", err) log.Println("Setting up testnet") diff --git a/test/e2e/main.go b/test/e2e/main.go index 0928779dbb..f58cd67526 100644 --- a/test/e2e/main.go +++ b/test/e2e/main.go @@ -23,6 +23,7 @@ func main() { tests := []Test{ {"MinorVersionCompatibility", MinorVersionCompatibility}, {"MajorUpgradeToV2", MajorUpgradeToV2}, + {"MajorUpgradeToV3", MajorUpgradeToV3}, {"E2ESimple", E2ESimple}, } diff --git a/test/e2e/major_upgrade_v2.go b/test/e2e/major_upgrade_v2.go index f2d1a43b21..de4fd79709 100644 --- a/test/e2e/major_upgrade_v2.go +++ b/test/e2e/major_upgrade_v2.go @@ -52,7 +52,8 @@ func MajorUpgradeToV2(logger *log.Logger) error { logger.Println("Creating txsim") endpoints, err := testNet.RemoteGRPCEndpoints(ctx) testnet.NoError("failed to get remote gRPC endpoints", err) - err = testNet.CreateTxClient(ctx, "txsim", testnet.TxsimVersion, 1, "100-2000", 100, testnet.DefaultResources, endpoints[0]) + upgradeSchedule := map[int64]uint64{} + err = testNet.CreateTxClient(ctx, "txsim", testnet.TxsimVersion, 1, "100-2000", 100, testnet.DefaultResources, endpoints[0], upgradeSchedule) testnet.NoError("failed to create tx client", err) logger.Println("Setting up testnet") diff --git a/test/e2e/major_upgrade_v3.go b/test/e2e/major_upgrade_v3.go new file mode 100644 index 0000000000..22723125f2 --- /dev/null +++ b/test/e2e/major_upgrade_v3.go @@ -0,0 +1,95 @@ +package main + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/celestiaorg/celestia-app/v3/app" + v2 "github.com/celestiaorg/celestia-app/v3/pkg/appconsts/v2" + v3 "github.com/celestiaorg/celestia-app/v3/pkg/appconsts/v3" + "github.com/celestiaorg/celestia-app/v3/test/e2e/testnet" +) + +func MajorUpgradeToV3(logger *log.Logger) error { + numNodes := 4 + upgradeHeightV3 := int64(20) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + logger.Println("Creating testnet") + testNet, err := testnet.New(ctx, "MajorUpgradeToV3", seed, nil, "test") + testnet.NoError("failed to create testnet", err) + + defer testNet.Cleanup(ctx) + + // HACKHACK: use a version of celestia-app built from a commit on this PR. + // This can be removed after the PR is merged to main and we override the + // upgrade height delay to one block in a new Docker image. + version := "1a20c01" + + logger.Println("Running major upgrade to v3 test", "version", version) + + consensusParams := app.DefaultConsensusParams() + consensusParams.Version.AppVersion = v2.Version // Start the test on v2 + testNet.SetConsensusParams(consensusParams) + + preloader, err := testNet.NewPreloader() + testnet.NoError("failed to create preloader", err) + + err = preloader.AddImage(ctx, testnet.DockerImageName(version)) + testnet.NoError("failed to add image", err) + defer func() { _ = preloader.EmptyImages(ctx) }() + + logger.Println("Creating genesis nodes") + for i := 0; i < numNodes; i++ { + err := testNet.CreateGenesisNode(ctx, version, 10000000, 0, testnet.DefaultResources, true) + testnet.NoError("failed to create genesis node", err) + } + + logger.Println("Creating txsim") + endpoints, err := testNet.RemoteGRPCEndpoints(ctx) + testnet.NoError("failed to get remote gRPC endpoints", err) + upgradeSchedule := map[int64]uint64{ + upgradeHeightV3: v3.Version, + } + + err = testNet.CreateTxClient(ctx, "txsim", version, 1, "100-2000", 100, testnet.DefaultResources, endpoints[0], upgradeSchedule) + testnet.NoError("failed to create tx client", err) + + logger.Println("Setting up testnet") + testnet.NoError("Failed to setup testnet", testNet.Setup(ctx)) + logger.Println("Starting testnet") + testnet.NoError("Failed to start testnet", testNet.Start(ctx)) + + timer := time.NewTimer(10 * time.Minute) + defer timer.Stop() + ticker := time.NewTicker(3 * time.Second) + defer ticker.Stop() + + logger.Println("waiting for upgrade") + for _, node := range testNet.Nodes() { + client, err := node.Client() + testnet.NoError("failed to get client", err) + + upgradeComplete := false + lastHeight := int64(0) + for !upgradeComplete { + select { + case <-timer.C: + return fmt.Errorf("failed to upgrade to v3, last height: %d", lastHeight) + case <-ticker.C: + resp, err := client.Header(ctx, nil) + testnet.NoError("failed to get header", err) + if resp.Header.Version.App == v3.Version { + upgradeComplete = true + } + logger.Printf("height %v", resp.Header.Height) + lastHeight = resp.Header.Height + } + } + } + + return nil +} diff --git a/test/e2e/minor_version_compatibility.go b/test/e2e/minor_version_compatibility.go index afa8158d0b..fbd7fb971f 100644 --- a/test/e2e/minor_version_compatibility.go +++ b/test/e2e/minor_version_compatibility.go @@ -63,7 +63,8 @@ func MinorVersionCompatibility(logger *log.Logger) error { logger.Println("Creating txsim") endpoints, err := testNet.RemoteGRPCEndpoints(ctx) testnet.NoError("failed to get remote gRPC endpoints", err) - err = testNet.CreateTxClient(ctx, "txsim", testnet.TxsimVersion, 1, "100-2000", 100, testnet.DefaultResources, endpoints[0]) + upgradeSchedule := map[int64]uint64{} + err = testNet.CreateTxClient(ctx, "txsim", testnet.TxsimVersion, 1, "100-2000", 100, testnet.DefaultResources, endpoints[0], upgradeSchedule) testnet.NoError("failed to create tx client", err) // start the testnet diff --git a/test/e2e/simple.go b/test/e2e/simple.go index e065467f1c..242c4ecde2 100644 --- a/test/e2e/simple.go +++ b/test/e2e/simple.go @@ -35,8 +35,8 @@ func E2ESimple(logger *log.Logger) error { logger.Println("Creating txsim") endpoints, err := testNet.RemoteGRPCEndpoints(ctx) testnet.NoError("failed to get remote gRPC endpoints", err) - err = testNet.CreateTxClient(ctx, "txsim", testnet.TxsimVersion, 10, - "100-2000", 100, testnet.DefaultResources, endpoints[0]) + upgradeSchedule := map[int64]uint64{} + err = testNet.CreateTxClient(ctx, "txsim", testnet.TxsimVersion, 10, "100-2000", 100, testnet.DefaultResources, endpoints[0], upgradeSchedule) testnet.NoError("failed to create tx client", err) logger.Println("Setting up testnets") diff --git a/test/e2e/testnet/key_generator.go b/test/e2e/testnet/key_generator.go new file mode 100644 index 0000000000..cfaa39e866 --- /dev/null +++ b/test/e2e/testnet/key_generator.go @@ -0,0 +1,37 @@ +package testnet + +import ( + "io" + "math/rand" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" +) + +type keyGenerator struct { + random *rand.Rand +} + +func newKeyGenerator(seed int64) *keyGenerator { + return &keyGenerator{ + random: rand.New(rand.NewSource(seed)), //nolint:gosec + } +} + +func (g *keyGenerator) Generate(keyType string) crypto.PrivKey { + seed := make([]byte, ed25519.SeedSize) + + _, err := io.ReadFull(g.random, seed) + if err != nil { + panic(err) // this shouldn't happen + } + switch keyType { + case "secp256k1": + return secp256k1.GenPrivKeySecp256k1(seed) + case "", "ed25519": + return ed25519.GenPrivKeyFromSecret(seed) + default: + panic("KeyType not supported") // should not make it this far + } +} diff --git a/test/e2e/testnet/node.go b/test/e2e/testnet/node.go index 71a82d3a75..cf96ee905d 100644 --- a/test/e2e/testnet/node.go +++ b/test/e2e/testnet/node.go @@ -59,8 +59,7 @@ type Node struct { // PullRoundStateTraces retrieves the round state traces from a node. // It will save them to the provided path. -func (n *Node) PullRoundStateTraces(path string) ([]trace.Event[schema.RoundState], error, -) { +func (n *Node) PullRoundStateTraces(path string) ([]trace.Event[schema.RoundState], error) { addr := n.AddressTracing() log.Info().Str("Address", addr).Msg("Pulling round state traces") @@ -73,8 +72,7 @@ func (n *Node) PullRoundStateTraces(path string) ([]trace.Event[schema.RoundStat // PullBlockSummaryTraces retrieves the block summary traces from a node. // It will save them to the provided path. -func (n *Node) PullBlockSummaryTraces(path string) ([]trace.Event[schema.BlockSummary], error, -) { +func (n *Node) PullBlockSummaryTraces(path string) ([]trace.Event[schema.BlockSummary], error) { addr := n.AddressTracing() log.Info().Str("Address", addr).Msg("Pulling block summary traces") @@ -99,11 +97,14 @@ type Resources struct { func NewNode( ctx context.Context, - name, version string, - startHeight, selfDelegation int64, + name string, + version string, + startHeight int64, + selfDelegation int64, peers []string, - signerKey, networkKey crypto.PrivKey, - upgradeHeight int64, + signerKey crypto.PrivKey, + networkKey crypto.PrivKey, + upgradeHeightV2 int64, resources Resources, grafana *GrafanaInfo, kn *knuu.Knuu, @@ -159,8 +160,8 @@ func NewNode( if disableBBR { args = append(args, "--force-no-bbr") } - if upgradeHeight != 0 { - args = append(args, fmt.Sprintf("--v2-upgrade-height=%d", upgradeHeight)) + if upgradeHeightV2 != 0 { + args = append(args, fmt.Sprintf("--v2-upgrade-height=%d", upgradeHeightV2)) } if err := knInstance.Build().SetArgs(args...); err != nil { diff --git a/test/e2e/testnet/testnet.go b/test/e2e/testnet/testnet.go index fc1ed6f67e..159d59ab96 100644 --- a/test/e2e/testnet/testnet.go +++ b/test/e2e/testnet/testnet.go @@ -30,10 +30,7 @@ type Testnet struct { knuu *knuu.Knuu } -func New(ctx context.Context, name string, seed int64, grafana *GrafanaInfo, chainID string, - genesisModifiers ...genesis.Modifier) ( - *Testnet, error, -) { +func New(ctx context.Context, name string, seed int64, grafana *GrafanaInfo, chainID string, genesisModifiers ...genesis.Modifier) (*Testnet, error) { identifier := fmt.Sprintf("%s_%s", name, time.Now().Format("20060102_150405")) kn, err := knuu.New(ctx, knuu.Options{ Scope: identifier, @@ -83,14 +80,10 @@ func (t *Testnet) SetConsensusMaxBlockSize(size int64) { t.genesis.ConsensusParams.Block.MaxBytes = size } -func (t *Testnet) CreateGenesisNode(ctx context.Context, version string, selfDelegation, upgradeHeight int64, resources Resources, disableBBR bool) error { +func (t *Testnet) CreateGenesisNode(ctx context.Context, version string, selfDelegation, upgradeHeightV2 int64, resources Resources, disableBBR bool) error { signerKey := t.keygen.Generate(ed25519Type) networkKey := t.keygen.Generate(ed25519Type) - node, err := NewNode(ctx, - fmt.Sprintf("val%d", len(t.nodes)), version, 0, - selfDelegation, nil, signerKey, networkKey, - upgradeHeight, resources, t.grafana, t.knuu, disableBBR, - ) + node, err := NewNode(ctx, fmt.Sprintf("val%d", len(t.nodes)), version, 0, selfDelegation, nil, signerKey, networkKey, upgradeHeightV2, resources, t.grafana, t.knuu, disableBBR) if err != nil { return err } @@ -101,9 +94,9 @@ func (t *Testnet) CreateGenesisNode(ctx context.Context, version string, selfDel return nil } -func (t *Testnet) CreateGenesisNodes(ctx context.Context, num int, version string, selfDelegation, upgradeHeight int64, resources Resources, disableBBR bool) error { +func (t *Testnet) CreateGenesisNodes(ctx context.Context, num int, version string, selfDelegation, upgradeHeightV2 int64, resources Resources, disableBBR bool) error { for i := 0; i < num; i++ { - if err := t.CreateGenesisNode(ctx, version, selfDelegation, upgradeHeight, resources, disableBBR); err != nil { + if err := t.CreateGenesisNode(ctx, version, selfDelegation, upgradeHeightV2, resources, disableBBR); err != nil { return err } } @@ -117,11 +110,11 @@ func (t *Testnet) CreateTxClients(ctx context.Context, blobPerSequence int, resources Resources, grpcEndpoints []string, + upgradeSchedule map[int64]uint64, ) error { for i, grpcEndpoint := range grpcEndpoints { name := fmt.Sprintf("txsim%d", i) - err := t.CreateTxClient(ctx, name, version, sequences, - blobRange, blobPerSequence, resources, grpcEndpoint) + err := t.CreateTxClient(ctx, name, version, sequences, blobRange, blobPerSequence, resources, grpcEndpoint, upgradeSchedule) if err != nil { log.Err(err).Str("name", name). Str("grpc endpoint", grpcEndpoint). @@ -136,46 +129,76 @@ func (t *Testnet) CreateTxClients(ctx context.Context, return nil } -// CreateTxClient creates a txsim node and sets it up -// name: name of the txsim knuu instance -// version: version of the txsim docker image to be pulled from the registry -// specified by txsimDockerSrcURL -// seed: seed for the txsim -// sequences: number of sequences to be run by the txsim -// blobRange: range of blob sizes to be used by the txsim in bytes -// pollTime: time in seconds between each sequence -// resources: resources to be allocated to the txsim -// grpcEndpoint: grpc endpoint of the node to which the txsim will connect and send transactions +// CreateTxClient creates a txsim node and sets it up. +// +// Parameters: +// ctx: Context for managing the lifecycle. +// name: Name of the txsim knuu instance. +// version: Version of the txsim Docker image to pull. +// blobSequences: Number of blob sequences to run by the txsim. +// blobRange: Range of blob sizes in bytes used by the txsim. +// blobPerSequence: Number of blobs per sequence. +// resources: Resources allocated to the txsim. +// grpcEndpoint: gRPC endpoint of the node for transaction submission. +// upgradeSchedule: Map from height to version for scheduled upgrades (v3 and onwards). func (t *Testnet) CreateTxClient( ctx context.Context, - name, version string, - sequences int, + name string, + version string, + blobSequences int, blobRange string, blobPerSequence int, resources Resources, grpcEndpoint string, + upgradeSchedule map[int64]uint64, ) error { - // create an account, and store it in a temp directory and add the account as genesis account to - // the testnet txsimKeyringDir := filepath.Join(os.TempDir(), name) - log.Info(). - Str("name", name). - Str("directory", txsimKeyringDir). - Msg("txsim keyring directory created") - _, err := t.CreateAccount(name, 1e16, txsimKeyringDir) + defer os.RemoveAll(txsimKeyringDir) + + config := encoding.MakeConfig(app.ModuleEncodingRegisters...).Codec + txsimKeyring, err := keyring.New(app.Name, keyring.BackendTest, txsimKeyringDir, nil, config) if err != nil { - return err + return fmt.Errorf("failed to create keyring: %w", err) } - // Create a txsim node using the key stored in the txsimKeyringDir - txsim, err := CreateTxClient(ctx, name, version, grpcEndpoint, t.seed, - sequences, blobRange, blobPerSequence, 1, resources, txsimRootDir, t.knuu) + key, _, err := txsimKeyring.NewMnemonic(name, keyring.English, "", "", hd.Secp256k1) + if err != nil { + return fmt.Errorf("failed to create mnemonic: %w", err) + } + pk, err := key.GetPubKey() + if err != nil { + return fmt.Errorf("failed to get public key: %w", err) + } + err = t.genesis.AddAccount(genesis.Account{ + PubKey: pk, + Balance: 1e16, + Name: name, + }) + if err != nil { + return fmt.Errorf("failed to add account to genesis: %w", err) + } + + // Copy the keys from the genesis keyring to the txsim keyring so that txsim + // can submit MsgSignalVersion on behalf of the validators. + for _, node := range t.Nodes() { + armor, err := t.Genesis().Keyring().ExportPrivKeyArmor(node.Name, "") + if err != nil { + return fmt.Errorf("failed to export key: %w", err) + } + err = txsimKeyring.ImportPrivKey(node.Name, armor, "") + if err != nil { + return fmt.Errorf("failed to import key: %w", err) + } + } + + txsim, err := CreateTxClient(ctx, name, version, grpcEndpoint, t.seed, blobSequences, blobRange, blobPerSequence, 1, resources, txsimKeyringDir, t.knuu, upgradeSchedule) if err != nil { log.Err(err). Str("name", name). Msg("error creating txsim") return err } + err = txsim.Instance.Build().Commit(ctx) if err != nil { log.Err(err). @@ -185,7 +208,7 @@ func (t *Testnet) CreateTxClient( } // copy over the keyring directory to the txsim instance - err = txsim.Instance.Storage().AddFolder(txsimKeyringDir, txsimRootDir, "10001:10001") + err = txsim.Instance.Storage().AddFolder(txsimKeyringDir, txsimKeyringDir, "10001:10001") if err != nil { log.Err(err). Str("directory", txsimKeyringDir). @@ -234,8 +257,7 @@ func (t *Testnet) CreateAccount(name string, tokens int64, txsimKeyringDir strin if txsimKeyringDir == "" { kr = keyring.NewInMemory(cdc) } else { // create a keyring with the specified directory - kr, err = keyring.New(app.Name, keyring.BackendTest, - txsimKeyringDir, nil, cdc) + kr, err = keyring.New(app.Name, keyring.BackendTest, txsimKeyringDir, nil, cdc) if err != nil { return nil, err } @@ -268,11 +290,7 @@ func (t *Testnet) CreateAccount(name string, tokens int64, txsimKeyringDir strin func (t *Testnet) CreateNode(ctx context.Context, version string, startHeight, upgradeHeight int64, resources Resources, disableBBR bool) error { signerKey := t.keygen.Generate(ed25519Type) networkKey := t.keygen.Generate(ed25519Type) - node, err := NewNode(ctx, - fmt.Sprintf("val%d", len(t.nodes)), version, - startHeight, 0, nil, signerKey, networkKey, - upgradeHeight, resources, t.grafana, t.knuu, disableBBR, - ) + node, err := NewNode(ctx, fmt.Sprintf("val%d", len(t.nodes)), version, startHeight, 0, nil, signerKey, networkKey, upgradeHeight, resources, t.grafana, t.knuu, disableBBR) if err != nil { return err } @@ -457,3 +475,7 @@ func (t *Testnet) Node(i int) *Node { func (t *Testnet) Nodes() []*Node { return t.nodes } + +func (t *Testnet) Genesis() *genesis.Genesis { + return t.genesis +} diff --git a/test/e2e/testnet/txsimNode.go b/test/e2e/testnet/txsimNode.go index 25a17f6d15..bfa21da875 100644 --- a/test/e2e/testnet/txsimNode.go +++ b/test/e2e/testnet/txsimNode.go @@ -4,7 +4,9 @@ package testnet import ( "context" "fmt" + "strings" + "github.com/celestiaorg/go-square/v2/share" "github.com/celestiaorg/knuu/pkg/instance" "github.com/celestiaorg/knuu/pkg/knuu" "github.com/rs/zerolog/log" @@ -23,20 +25,23 @@ type TxSim struct { Instance *instance.Instance } +// CreateTxClient returns a new TxSim instance. func CreateTxClient( ctx context.Context, - name, version string, + name string, + version string, endpoint string, seed int64, - sequences int, + blobSequences int, blobRange string, blobsPerSeq int, pollTime int, resources Resources, volumePath string, knuu *knuu.Knuu, + upgradeSchedule map[int64]uint64, ) (*TxSim, error) { - txIns, err := knuu.NewInstance(name) + instance, err := knuu.NewInstance(name) if err != nil { return nil, err } @@ -45,7 +50,7 @@ func CreateTxClient( Str("name", name). Str("image", image). Msg("setting image for tx client") - err = txIns.Build().SetImage(ctx, image) + err = instance.Build().SetImage(ctx, image) if err != nil { log.Err(err). Str("name", name). @@ -53,33 +58,53 @@ func CreateTxClient( Msg("failed to set image for tx client") return nil, err } - err = txIns.Resources().SetMemory(resources.MemoryRequest, resources.MemoryLimit) + err = instance.Resources().SetMemory(resources.MemoryRequest, resources.MemoryLimit) if err != nil { return nil, err } - err = txIns.Resources().SetCPU(resources.CPU) + err = instance.Resources().SetCPU(resources.CPU) if err != nil { return nil, err } - err = txIns.Storage().AddVolumeWithOwner(volumePath, resources.Volume, 10001) + err = instance.Storage().AddVolumeWithOwner(volumePath, resources.Volume, 10001) if err != nil { return nil, err } args := []string{ - fmt.Sprintf("-grpc-endpoint %s", endpoint), - fmt.Sprintf("-poll-time %ds", pollTime), - fmt.Sprintf("-seed %d ", seed), - fmt.Sprintf("-blob %d ", sequences), - fmt.Sprintf("-blob-amounts %d ", blobsPerSeq), - fmt.Sprintf("-blob-sizes %s ", blobRange), + fmt.Sprintf("--key-path %s", volumePath), + fmt.Sprintf("--grpc-endpoint %s", endpoint), + fmt.Sprintf("--poll-time %ds", pollTime), + fmt.Sprintf("--seed %d", seed), + fmt.Sprintf("--blob %d", blobSequences), + fmt.Sprintf("--blob-amounts %d", blobsPerSeq), + fmt.Sprintf("--blob-sizes %s", blobRange), + fmt.Sprintf("--upgrade-schedule %s", stringifyUpgradeSchedule(upgradeSchedule)), + fmt.Sprintf("--blob-share-version %d", share.ShareVersionZero), } - if err := txIns.Build().SetArgs(args...); err != nil { + if err := instance.Build().SetArgs(args...); err != nil { return nil, err } + log.Info(). + Str("name", name). + Str("image", image). + Str("args", strings.Join(args, " ")). + Msg("created tx client") + return &TxSim{ Name: name, - Instance: txIns, + Instance: instance, }, nil } + +func stringifyUpgradeSchedule(schedule map[int64]uint64) string { + if schedule == nil { + return "" + } + scheduleParts := make([]string, 0, len(schedule)) + for height, version := range schedule { + scheduleParts = append(scheduleParts, fmt.Sprintf("%d:%d", height, version)) + } + return strings.Join(scheduleParts, ",") +} diff --git a/test/e2e/testnet/util.go b/test/e2e/testnet/util.go index 0d89494858..edf89aceda 100644 --- a/test/e2e/testnet/util.go +++ b/test/e2e/testnet/util.go @@ -1,43 +1,11 @@ package testnet import ( - "io" - "math/rand" "os" "github.com/rs/zerolog/log" - "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/crypto/ed25519" - "github.com/tendermint/tendermint/crypto/secp256k1" ) -type keyGenerator struct { - random *rand.Rand -} - -func newKeyGenerator(seed int64) *keyGenerator { - return &keyGenerator{ - random: rand.New(rand.NewSource(seed)), //nolint:gosec - } -} - -func (g *keyGenerator) Generate(keyType string) crypto.PrivKey { - seed := make([]byte, ed25519.SeedSize) - - _, err := io.ReadFull(g.random, seed) - if err != nil { - panic(err) // this shouldn't happen - } - switch keyType { - case "secp256k1": - return secp256k1.GenPrivKeySecp256k1(seed) - case "", "ed25519": - return ed25519.GenPrivKeyFromSecret(seed) - default: - panic("KeyType not supported") // should not make it this far - } -} - type GrafanaInfo struct { Endpoint string Username string diff --git a/test/txsim/upgrade.go b/test/txsim/upgrade.go index 0811f32232..e2015b98d1 100644 --- a/test/txsim/upgrade.go +++ b/test/txsim/upgrade.go @@ -15,17 +15,24 @@ var _ Sequence = &UpgradeSequence{} const fundsForUpgrade = 100_000 -// UpgradeSequence simulates an upgrade proposal and voting process +// UpgradeSequence simulates a sequence of validators submitting +// MsgSignalVersions for a particular version and then eventually a +// MsgTryUpgrade. type UpgradeSequence struct { - voted map[string]bool - height int64 - version uint64 - account types.AccAddress + // signalled is a map from validator address to a boolean indicating if they have signalled. + signalled map[string]bool + // height is the first height at which the upgrade sequence is run. + height int64 + // version is the version that validators are signalling for. + version uint64 + // account is the address of the account that submits the MsgTryUpgrade. + account types.AccAddress + // hasUpgraded is true if the MsgTryUpgrade has been submitted. hasUpgraded bool } func NewUpgradeSequence(version uint64, height int64) *UpgradeSequence { - return &UpgradeSequence{version: version, height: height, voted: make(map[string]bool)} + return &UpgradeSequence{version: version, height: height, signalled: make(map[string]bool)} } func (s *UpgradeSequence) Clone(_ int) []Sequence { @@ -52,29 +59,30 @@ func (s *UpgradeSequence) Next(ctx context.Context, querier grpc.ClientConn, _ * return Operation{}, errors.New("no validators found") } + delay := uint64(0) + // apply a delay to the first signal only + if len(s.signalled) == 0 { + delay = uint64(s.height) + } + // Choose a random validator to be the authority - var msg types.Msg for _, validator := range validatorsResp.Validators { - if !s.voted[validator.OperatorAddress] { - msg = &signaltypes.MsgSignalVersion{ + if !s.signalled[validator.OperatorAddress] { + s.signalled[validator.OperatorAddress] = true + msg := &signaltypes.MsgSignalVersion{ ValidatorAddress: validator.OperatorAddress, Version: s.version, } - s.voted[validator.OperatorAddress] = true + return Operation{ + Msgs: []types.Msg{msg}, + Delay: delay, + }, nil } } - // if all validators have voted, we can now try to upgrade. - if msg == nil { - msg = signaltypes.NewMsgTryUpgrade(s.account) - s.hasUpgraded = true - } - - delay := uint64(0) - // apply a delay to the first sequence only - if len(s.voted) == 0 { - delay = uint64(s.height) - } + // if all validators have voted, we can now try to upgrade. + s.hasUpgraded = true + msg := signaltypes.NewMsgTryUpgrade(s.account) return Operation{ Msgs: []types.Msg{msg}, Delay: delay,