diff --git a/chain/cosmos/chain_node.go b/chain/cosmos/chain_node.go index 88b9814a0..fd4c3d89e 100644 --- a/chain/cosmos/chain_node.go +++ b/chain/cosmos/chain_node.go @@ -886,7 +886,7 @@ func (tn *ChainNode) InitValidatorGenTx( if err := tn.CreateKey(ctx, valKey); err != nil { return err } - bech32, err := tn.KeyBech32(ctx, valKey) + bech32, err := tn.AccountKeyBech32(ctx, valKey) if err != nil { return err } @@ -925,12 +925,17 @@ func (tn *ChainNode) NodeID(ctx context.Context) (string, error) { } // KeyBech32 retrieves the named key's address in bech32 format from the node. -func (tn *ChainNode) KeyBech32(ctx context.Context, name string) (string, error) { +// bech is the bech32 prefix (acc|val|cons). If empty, defaults to the account key (same as "acc"). +func (tn *ChainNode) KeyBech32(ctx context.Context, name string, bech string) (string, error) { command := []string{tn.Chain.Config().Bin, "keys", "show", "--address", name, "--home", tn.HomeDir(), "--keyring-backend", keyring.BackendTest, } + if bech != "" { + command = append(command, "--bech", bech) + } + stdout, stderr, err := tn.Exec(ctx, command, nil) if err != nil { return "", fmt.Errorf("failed to show key %q (stderr=%q): %w", name, stderr, err) @@ -939,6 +944,11 @@ func (tn *ChainNode) KeyBech32(ctx context.Context, name string) (string, error) return string(bytes.TrimSuffix(stdout, []byte("\n"))), nil } +// AccountKeyBech32 retrieves the named key's address in bech32 account format. +func (tn *ChainNode) AccountKeyBech32(ctx context.Context, name string) (string, error) { + return tn.KeyBech32(ctx, name, "") +} + // PeerString returns the string for connecting the nodes passed in func (nodes ChainNodes) PeerString(ctx context.Context) string { addrs := make([]string, len(nodes)) diff --git a/chain/cosmos/cosmos_chain.go b/chain/cosmos/cosmos_chain.go index c9a239cc8..8d7e4739d 100644 --- a/chain/cosmos/cosmos_chain.go +++ b/chain/cosmos/cosmos_chain.go @@ -1,6 +1,7 @@ package cosmos import ( + "bytes" "context" "fmt" "io" @@ -213,7 +214,7 @@ func (c *CosmosChain) RecoverKey(ctx context.Context, keyName, mnemonic string) // Implements Chain interface func (c *CosmosChain) GetAddress(ctx context.Context, keyName string) ([]byte, error) { - b32Addr, err := c.getFullNode().KeyBech32(ctx, keyName) + b32Addr, err := c.getFullNode().AccountKeyBech32(ctx, keyName) if err != nil { return nil, err } @@ -541,21 +542,16 @@ func (c *CosmosChain) Start(testName string, ctx context.Context, additionalGene chainCfg := c.Config() genesisAmount := types.Coin{ - Amount: types.NewInt(1000000000000), + Amount: types.NewInt(10_000_000_000_000), Denom: chainCfg.Denom, } - genesisStakeAmount := types.Coin{ - Amount: types.NewInt(1000000000000), - Denom: "stake", - } - genesisSelfDelegation := types.Coin{ - Amount: types.NewInt(100000000000), - Denom: "stake", + Amount: types.NewInt(5_000_000_000_000), + Denom: chainCfg.Denom, } - genesisAmounts := []types.Coin{genesisAmount, genesisStakeAmount} + genesisAmounts := []types.Coin{genesisAmount} configFileOverrides := chainCfg.ConfigFileOverrides @@ -629,7 +625,7 @@ func (c *CosmosChain) Start(testName string, ctx context.Context, additionalGene for i := 1; i < len(c.Validators); i++ { validatorN := c.Validators[i] - bech32, err := validatorN.KeyBech32(ctx, valKey) + bech32, err := validatorN.AccountKeyBech32(ctx, valKey) if err != nil { return err } @@ -658,6 +654,8 @@ func (c *CosmosChain) Start(testName string, ctx context.Context, additionalGene return err } + genbz = bytes.ReplaceAll(genbz, []byte(`"stake"`), []byte(fmt.Sprintf(`"%s"`, chainCfg.Denom))) + if c.cfg.ModifyGenesis != nil { genbz, err = c.cfg.ModifyGenesis(chainCfg, genbz) if err != nil { @@ -665,9 +663,14 @@ func (c *CosmosChain) Start(testName string, ctx context.Context, additionalGene } } - // Provide EXPORT_GENESIS_FILE_PATH to help debug genesis file + // Provide EXPORT_GENESIS_FILE_PATH and EXPORT_GENESIS_CHAIN to help debug genesis file exportGenesis := os.Getenv("EXPORT_GENESIS_FILE_PATH") - if exportGenesis != "" { + exportGenesisChain := os.Getenv("EXPORT_GENESIS_CHAIN") + if exportGenesis != "" && exportGenesisChain == c.cfg.Name { + c.log.Debug("Exporting genesis file", + zap.String("chain", exportGenesisChain), + zap.String("path", exportGenesis), + ) _ = os.WriteFile(exportGenesis, genbz, 0600) } diff --git a/cmd/ibctest/ibctest_test.go b/cmd/ibctest/ibctest_test.go index c35d63980..720ed66fd 100644 --- a/cmd/ibctest/ibctest_test.go +++ b/cmd/ibctest/ibctest_test.go @@ -19,6 +19,7 @@ import ( "github.com/strangelove-ventures/ibctest/v5/internal/blockdb" blockdbtui "github.com/strangelove-ventures/ibctest/v5/internal/blockdb/tui" "github.com/strangelove-ventures/ibctest/v5/internal/version" + "github.com/strangelove-ventures/ibctest/v5/relayer" "github.com/strangelove-ventures/ibctest/v5/testreporter" "go.uber.org/zap" ) @@ -171,7 +172,7 @@ func configureTestReporter() error { func getRelayerFactory(name string, logger *zap.Logger) (ibctest.RelayerFactory, error) { switch name { case "rly", "cosmos/relayer": - return ibctest.NewBuiltinRelayerFactory(ibc.CosmosRly, logger), nil + return ibctest.NewBuiltinRelayerFactory(ibc.CosmosRly, logger, relayer.StartupFlags("-b", "100")), nil case "hermes": return ibctest.NewBuiltinRelayerFactory(ibc.Hermes, logger), nil default: diff --git a/examples/cosmos_chain_upgrade_ibc_test.go b/examples/cosmos_chain_upgrade_ibc_test.go index d7e0d7b9e..73bf56678 100644 --- a/examples/cosmos_chain_upgrade_ibc_test.go +++ b/examples/cosmos_chain_upgrade_ibc_test.go @@ -9,6 +9,7 @@ import ( "github.com/strangelove-ventures/ibctest/v5/chain/cosmos" "github.com/strangelove-ventures/ibctest/v5/conformance" "github.com/strangelove-ventures/ibctest/v5/ibc" + "github.com/strangelove-ventures/ibctest/v5/relayer" "github.com/strangelove-ventures/ibctest/v5/test" "github.com/strangelove-ventures/ibctest/v5/testreporter" "github.com/stretchr/testify/require" @@ -58,6 +59,7 @@ func CosmosChainUpgradeIBCTest(t *testing.T, chainName, initialVersion, upgradeV rf := ibctest.NewBuiltinRelayerFactory( ibc.CosmosRly, zaptest.NewLogger(t), + relayer.StartupFlags("-b", "100"), ) r := rf.Build(t, client, network) diff --git a/examples/interchain_queries_test.go b/examples/interchain_queries_test.go index 581baced8..fa6610f68 100644 --- a/examples/interchain_queries_test.go +++ b/examples/interchain_queries_test.go @@ -83,7 +83,7 @@ func TestInterchainQueries(t *testing.T) { r := ibctest.NewBuiltinRelayerFactory( ibc.CosmosRly, zaptest.NewLogger(t), - relayer.StartupFlags("-p", "events", "-b", "100"), + relayer.StartupFlags("-b", "100"), ).Build(t, client, network) // Build the network; spin up the chains and configure the relayer diff --git a/examples/packet_forward_test.go b/examples/packet_forward_test.go index 202c3c5b5..a40c12f81 100644 --- a/examples/packet_forward_test.go +++ b/examples/packet_forward_test.go @@ -28,8 +28,8 @@ func TestPacketForwardMiddleware(t *testing.T) { cf := ibctest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*ibctest.ChainSpec{ {Name: "gaia", ChainName: "gaia-fork", Version: "bugfix-replace_default_transfer_with_router_module"}, - {Name: "osmosis", ChainName: "osmosis", Version: "v7.3.0"}, - {Name: "juno", ChainName: "juno", Version: "v6.0.0"}, + {Name: "osmosis", ChainName: "osmosis", Version: "v11.0.1"}, + {Name: "juno", ChainName: "juno", Version: "v9.0.0"}, }) chains, err := cf.Chains(t.Name()) @@ -37,7 +37,10 @@ func TestPacketForwardMiddleware(t *testing.T) { gaia, osmosis, juno := chains[0], chains[1], chains[2] - r := ibctest.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t)).Build( + r := ibctest.NewBuiltinRelayerFactory( + ibc.CosmosRly, + zaptest.NewLogger(t), + ).Build( t, client, network, ) @@ -63,9 +66,10 @@ func TestPacketForwardMiddleware(t *testing.T) { }) require.NoError(t, ic.Build(ctx, eRep, ibctest.InterchainBuildOptions{ - TestName: t.Name(), - Client: client, - NetworkID: network, + TestName: t.Name(), + Client: client, + NetworkID: network, + BlockDatabaseFile: ibctest.DefaultBlockDatabaseFilepath(), SkipPathCreation: false, })) @@ -76,14 +80,14 @@ func TestPacketForwardMiddleware(t *testing.T) { const userFunds = int64(10_000_000_000) users := ibctest.GetAndFundTestUsers(t, ctx, t.Name(), userFunds, osmosis, gaia, juno) - channels, err := r.GetChannels(ctx, eRep, gaia.Config().ChainID) + osmoChannels, err := r.GetChannels(ctx, eRep, osmosis.Config().ChainID) require.NoError(t, err) - // Start the relayer on both paths - err = r.StartRelayer(ctx, eRep, pathOsmoHub) + junoChannels, err := r.GetChannels(ctx, eRep, juno.Config().ChainID) require.NoError(t, err) - err = r.StartRelayer(ctx, eRep, pathJunoHub) + // Start the relayer on both paths + err = r.StartRelayer(ctx, eRep, pathOsmoHub, pathJunoHub) require.NoError(t, err) t.Cleanup( @@ -96,9 +100,7 @@ func TestPacketForwardMiddleware(t *testing.T) { ) // Get original account balances - osmosisUser := users[0] - gaiaUser := users[1] - junoUser := users[2] + osmosisUser, gaiaUser, junoUser := users[0], users[1], users[2] osmosisBalOG, err := osmosis.GetBalance(ctx, osmosisUser.Bech32Address(osmosis.Config().Bech32Prefix), osmosis.Config().Denom) require.NoError(t, err) @@ -106,14 +108,16 @@ func TestPacketForwardMiddleware(t *testing.T) { // Send packet from Osmosis->Hub->Juno // receiver format: {intermediate_refund_address}|{foward_port}/{forward_channel}:{final_destination_address} const transferAmount int64 = 100000 - receiver := fmt.Sprintf("%s|%s/%s:%s", gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), channels[1].PortID, channels[1].ChannelID, junoUser.Bech32Address(juno.Config().Bech32Prefix)) + gaiaJunoChan := junoChannels[0].Counterparty + receiver := fmt.Sprintf("%s|%s/%s:%s", gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), gaiaJunoChan.PortID, gaiaJunoChan.ChannelID, junoUser.Bech32Address(juno.Config().Bech32Prefix)) transfer := ibc.WalletAmount{ Address: receiver, Denom: osmosis.Config().Denom, Amount: transferAmount, } - _, err = osmosis.SendIBCTransfer(ctx, channels[0].ChannelID, osmosisUser.KeyName, transfer, nil) + osmosisGaiaChan := osmoChannels[0] + _, err = osmosis.SendIBCTransfer(ctx, osmosisGaiaChan.ChannelID, osmosisUser.KeyName, transfer, nil) require.NoError(t, err) // Wait for transfer to be relayed @@ -126,8 +130,10 @@ func TestPacketForwardMiddleware(t *testing.T) { require.Equal(t, osmosisBalOG-transferAmount, osmosisBal) // Compose the prefixed denoms and ibc denom for asserting balances - firstHopDenom := transfertypes.GetPrefixedDenom(channels[0].Counterparty.PortID, channels[0].Counterparty.ChannelID, osmosis.Config().Denom) - secondHopDenom := transfertypes.GetPrefixedDenom(channels[1].Counterparty.PortID, channels[1].Counterparty.ChannelID, firstHopDenom) + gaiaOsmoChan := osmoChannels[0].Counterparty + junoGaiaChan := junoChannels[0] + firstHopDenom := transfertypes.GetPrefixedDenom(gaiaOsmoChan.PortID, gaiaOsmoChan.ChannelID, osmosis.Config().Denom) + secondHopDenom := transfertypes.GetPrefixedDenom(junoGaiaChan.Counterparty.PortID, junoGaiaChan.Counterparty.ChannelID, firstHopDenom) dstIbcDenom := transfertypes.ParseDenomTrace(secondHopDenom) // Check that the funds sent are present in the acc on juno @@ -136,14 +142,14 @@ func TestPacketForwardMiddleware(t *testing.T) { require.Equal(t, transferAmount, junoBal) // Send packet back from Juno->Hub->Osmosis - receiver = fmt.Sprintf("%s|%s/%s:%s", gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), channels[0].Counterparty.PortID, channels[0].Counterparty.ChannelID, osmosisUser.Bech32Address(osmosis.Config().Bech32Prefix)) + receiver = fmt.Sprintf("%s|%s/%s:%s", gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), gaiaOsmoChan.PortID, gaiaOsmoChan.ChannelID, osmosisUser.Bech32Address(osmosis.Config().Bech32Prefix)) transfer = ibc.WalletAmount{ Address: receiver, Denom: dstIbcDenom.IBCDenom(), Amount: transferAmount, } - _, err = juno.SendIBCTransfer(ctx, channels[1].Counterparty.ChannelID, junoUser.KeyName, transfer, nil) + _, err = juno.SendIBCTransfer(ctx, junoGaiaChan.ChannelID, junoUser.KeyName, transfer, nil) require.NoError(t, err) // Wait for transfer to be relayed @@ -162,14 +168,14 @@ func TestPacketForwardMiddleware(t *testing.T) { // Send a malformed packet with invalid receiver address from Osmosis->Hub->Juno // This should succeed in the first hop and fail to make the second hop; funds should end up in the intermediary account. - receiver = fmt.Sprintf("%s|%s/%s:%s", gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), channels[1].PortID, channels[1].ChannelID, "xyz1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq") + receiver = fmt.Sprintf("%s|%s/%s:%s", gaiaUser.Bech32Address(gaia.Config().Bech32Prefix), gaiaJunoChan.PortID, gaiaJunoChan.ChannelID, "xyz1t8eh66t2w5k67kwurmn5gqhtq6d2ja0vp7jmmq") transfer = ibc.WalletAmount{ Address: receiver, Denom: osmosis.Config().Denom, Amount: transferAmount, } - _, err = osmosis.SendIBCTransfer(ctx, channels[0].ChannelID, osmosisUser.KeyName, transfer, nil) + _, err = osmosis.SendIBCTransfer(ctx, osmosisGaiaChan.ChannelID, osmosisUser.KeyName, transfer, nil) require.NoError(t, err) // Wait for transfer to be relayed diff --git a/ibc/relayer.go b/ibc/relayer.go index d25ce6eaa..4aaba49ad 100644 --- a/ibc/relayer.go +++ b/ibc/relayer.go @@ -53,7 +53,7 @@ type Relayer interface { // After configuration is initialized, begin relaying. // This method is intended to create a background worker that runs the relayer. // You must call StopRelayer to cleanly stop the relaying. - StartRelayer(ctx context.Context, rep RelayerExecReporter, pathName string) error + StartRelayer(ctx context.Context, rep RelayerExecReporter, pathNames ...string) error // StopRelayer stops a relayer that started work through StartRelayer. StopRelayer(ctx context.Context, rep RelayerExecReporter) error diff --git a/interchain.go b/interchain.go index 9b0e17949..6fa5c821e 100644 --- a/interchain.go +++ b/interchain.go @@ -14,6 +14,7 @@ import ( "github.com/strangelove-ventures/ibctest/v5/ibc" "github.com/strangelove-ventures/ibctest/v5/testreporter" "go.uber.org/zap" + "golang.org/x/sync/errgroup" ) // Interchain represents a full IBC network, encompassing a collection of @@ -251,47 +252,61 @@ func (ic *Interchain) Build(ctx context.Context, rep *testreporter.RelayerExecRe // For every relayer link, teach the relayer about the link and create the link. for rp, link := range ic.links { - + rp := rp + link := link c0 := link.chains[0] c1 := link.chains[1] + if err := rp.Relayer.GeneratePath(ctx, rep, c0.Config().ChainID, c1.Config().ChainID, rp.Path); err != nil { return fmt.Errorf( "failed to generate path %s on relayer %s between chains %s and %s: %w", rp.Path, rp.Relayer, ic.chains[c0], ic.chains[c1], err, ) } + } - // If the user specifies a zero value CreateClientOptions struct then we fall back to the default - // client options. - if link.createClientOpts == (ibc.CreateClientOptions{}) { - link.createClientOpts = ibc.DefaultClientOpts() - } + // Now link the paths in parallel + // Creates clients, connections, and channels for each link/path. + var eg errgroup.Group + for rp, link := range ic.links { + rp := rp + link := link + c0 := link.chains[0] + c1 := link.chains[1] + eg.Go(func() error { + // If the user specifies a zero value CreateClientOptions struct then we fall back to the default + // client options. + if link.createClientOpts == (ibc.CreateClientOptions{}) { + link.createClientOpts = ibc.DefaultClientOpts() + } - // Check that the client creation options are valid and fully specified. - if err := link.createClientOpts.Validate(); err != nil { - return err - } + // Check that the client creation options are valid and fully specified. + if err := link.createClientOpts.Validate(); err != nil { + return err + } - // If the user specifies a zero value CreateChannelOptions struct then we fall back to the default - // channel options for an ics20 fungible token transfer channel. - if link.createChannelOpts == (ibc.CreateChannelOptions{}) { - link.createChannelOpts = ibc.DefaultChannelOpts() - } + // If the user specifies a zero value CreateChannelOptions struct then we fall back to the default + // channel options for an ics20 fungible token transfer channel. + if link.createChannelOpts == (ibc.CreateChannelOptions{}) { + link.createChannelOpts = ibc.DefaultChannelOpts() + } - // Check that the channel creation options are valid and fully specified. - if err := link.createChannelOpts.Validate(); err != nil { - return err - } + // Check that the channel creation options are valid and fully specified. + if err := link.createChannelOpts.Validate(); err != nil { + return err + } - if err := rp.Relayer.LinkPath(ctx, rep, rp.Path, link.createChannelOpts, link.createClientOpts); err != nil { - return fmt.Errorf( - "failed to link path %s on relayer %s between chains %s and %s: %w", - rp.Path, rp.Relayer, ic.chains[c0], ic.chains[c1], err, - ) - } + if err := rp.Relayer.LinkPath(ctx, rep, rp.Path, link.createChannelOpts, link.createClientOpts); err != nil { + return fmt.Errorf( + "failed to link path %s on relayer %s between chains %s and %s: %w", + rp.Path, rp.Relayer, ic.chains[c0], ic.chains[c1], err, + ) + } + return nil + }) } - return nil + return eg.Wait() } // WithLog sets the logger on the interchain object. @@ -325,7 +340,7 @@ func (ic *Interchain) genesisWalletAmounts(ctx context.Context) (map[ibc.Chain][ { Address: faucetAddresses[c], Denom: c.Config().Denom, - Amount: 10_000_000_000_000, // Faucet wallet gets 10t units of denom. + Amount: 100_000_000_000_000, // Faucet wallet gets 100T units of denom. }, } } diff --git a/interchain_test.go b/interchain_test.go index 9c26ba072..519964d77 100644 --- a/interchain_test.go +++ b/interchain_test.go @@ -204,7 +204,8 @@ func TestInterchain_CreateUser(t *testing.T) { require.NoError(t, err) require.NotEmpty(t, mnemonic) - user := ibctest.GetAndFundTestUserWithMnemonic(t, ctx, keyName, mnemonic, 10000, gaia0) + user, err := ibctest.GetAndFundTestUserWithMnemonic(ctx, keyName, mnemonic, 10000, gaia0) + require.NoError(t, err) require.NoError(t, test.WaitForBlocks(ctx, 2, gaia0)) require.NotEmpty(t, user.Address) require.NotEmpty(t, user.KeyName) diff --git a/relayer/docker.go b/relayer/docker.go index 5a6cb3187..a109c0dc4 100644 --- a/relayer/docker.go +++ b/relayer/docker.go @@ -337,8 +337,8 @@ func (r *DockerRelayer) UpdateClients(ctx context.Context, rep ibc.RelayerExecRe return res.Err } -func (r *DockerRelayer) StartRelayer(ctx context.Context, rep ibc.RelayerExecReporter, pathName string) error { - return r.createNodeContainer(ctx, pathName) +func (r *DockerRelayer) StartRelayer(ctx context.Context, rep ibc.RelayerExecReporter, pathNames ...string) error { + return r.createNodeContainer(ctx, pathNames...) } func (r *DockerRelayer) StopRelayer(ctx context.Context, rep ibc.RelayerExecReporter) error { @@ -433,10 +433,11 @@ func (r *DockerRelayer) pullContainerImageIfNecessary(containerImage ibc.DockerI return nil } -func (r *DockerRelayer) createNodeContainer(ctx context.Context, pathName string) error { +func (r *DockerRelayer) createNodeContainer(ctx context.Context, pathNames ...string) error { containerImage := r.containerImage() - containerName := fmt.Sprintf("%s-%s", r.c.Name(), pathName) - cmd := r.c.StartRelayer(pathName, r.HomeDir()) + joinedPaths := strings.Join(pathNames, ".") + containerName := fmt.Sprintf("%s-%s", r.c.Name(), joinedPaths) + cmd := r.c.StartRelayer(r.HomeDir(), pathNames...) r.log.Info( "Running command", zap.String("command", strings.Join(cmd, " ")), @@ -450,7 +451,7 @@ func (r *DockerRelayer) createNodeContainer(ctx context.Context, pathName string Entrypoint: []string{}, Cmd: cmd, - Hostname: r.HostName(pathName), + Hostname: r.HostName(joinedPaths), User: r.c.DockerUser(), Labels: map[string]string{dockerutil.CleanupLabel: r.testName}, @@ -648,6 +649,6 @@ type RelayerCommander interface { GetConnections(chainID, homeDir string) []string LinkPath(pathName, homeDir string, channelOpts ibc.CreateChannelOptions, clientOpts ibc.CreateClientOptions) []string RestoreKey(chainID, keyName, mnemonic, homeDir string) []string - StartRelayer(pathName, homeDir string) []string + StartRelayer(homeDir string, pathNames ...string) []string UpdateClients(pathName, homeDir string) []string } diff --git a/relayer/rly/cosmos_relayer.go b/relayer/rly/cosmos_relayer.go index c0b1173d9..ff4ec53b8 100644 --- a/relayer/rly/cosmos_relayer.go +++ b/relayer/rly/cosmos_relayer.go @@ -61,7 +61,7 @@ type CosmosRelayerChainConfig struct { const ( DefaultContainerImage = "ghcr.io/cosmos/relayer" - DefaultContainerVersion = "v2.0.0" + DefaultContainerVersion = "v2.1.0" ) // Capabilities returns the set of capabilities of the Cosmos relayer. @@ -210,12 +210,13 @@ func (commander) RestoreKey(chainID, keyName, mnemonic, homeDir string) []string } } -func (c commander) StartRelayer(pathName, homeDir string) []string { +func (c commander) StartRelayer(homeDir string, pathNames ...string) []string { cmd := []string{ - "rly", "start", pathName, "--debug", + "rly", "start", "--debug", "--home", homeDir, } cmd = append(cmd, c.extraStartFlags...) + cmd = append(cmd, pathNames...) return cmd } diff --git a/test_user.go b/test_user.go index cc487372d..72fb777f2 100644 --- a/test_user.go +++ b/test_user.go @@ -9,6 +9,7 @@ import ( "github.com/strangelove-ventures/ibctest/v5/internal/dockerutil" "github.com/strangelove-ventures/ibctest/v5/test" "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" ) // generateUserWallet creates a new user wallet with the given key name on the given chain. @@ -38,25 +39,27 @@ func generateUserWallet(ctx context.Context, keyName, mnemonic string, chain ibc // and funds it with the native chain denom. // The caller should wait for some blocks to complete before the funds will be accessible. func GetAndFundTestUserWithMnemonic( - t *testing.T, ctx context.Context, keyNamePrefix, mnemonic string, amount int64, chain ibc.Chain, -) *ibc.Wallet { +) (*ibc.Wallet, error) { chainCfg := chain.Config() keyName := fmt.Sprintf("%s-%s-%s", keyNamePrefix, chainCfg.ChainID, dockerutil.RandLowerCaseLetterString(3)) user, err := generateUserWallet(ctx, keyName, mnemonic, chain) - require.NoError(t, err, "failed to get source user wallet") + if err != nil { + return nil, fmt.Errorf("failed to get source user wallet: %w", err) + } err = chain.SendFunds(ctx, FaucetAccountKeyName, ibc.WalletAmount{ Address: user.Bech32Address(chainCfg.Bech32Prefix), Amount: amount, Denom: chainCfg.Denom, }) - require.NoError(t, err, "failed to get funds from faucet") - - return user + if err != nil { + return nil, fmt.Errorf("failed to get funds from faucet: %w", err) + } + return user, nil } // GetAndFundTestUsers generates and funds chain users with the native chain denom. @@ -68,11 +71,21 @@ func GetAndFundTestUsers( amount int64, chains ...ibc.Chain, ) []*ibc.Wallet { - var users []*ibc.Wallet - for _, chain := range chains { - user := GetAndFundTestUserWithMnemonic(t, ctx, keyNamePrefix, "", amount, chain) - users = append(users, user) + users := make([]*ibc.Wallet, len(chains)) + var eg errgroup.Group + for i, chain := range chains { + i := i + chain := chain + eg.Go(func() error { + user, err := GetAndFundTestUserWithMnemonic(ctx, keyNamePrefix, "", amount, chain) + if err != nil { + return err + } + users[i] = user + return nil + }) } + require.NoError(t, eg.Wait()) // TODO(nix 05-17-2022): Map with generics once using go 1.18 chainHeights := make([]test.ChainHeighter, len(chains))