Skip to content

Commit

Permalink
feat: int in-place testnet creation (#4297)
Browse files Browse the repository at this point in the history
  • Loading branch information
likesToEatFish authored Sep 3, 2024
1 parent 35b9a26 commit f7618d3
Show file tree
Hide file tree
Showing 14 changed files with 605 additions and 2 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [#4111](https://github.com/ignite/cli/pull/4111) Remove vuex generation
- [#4113](https://github.com/ignite/cli/pull/4113) Generate chain config documentation automatically
- [#4131](https://github.com/ignite/cli/pull/4131) Support `bytes` as data type in the `scaffold` commands
- [#4297](https://github.com/ignite/cli/pull/4297) Add in-place testnet creation command for apps.
- [#4300](https://github.com/ignite/cli/pull/4300) Only panics the module in the most top function level
- [#4327](https://github.com/ignite/cli/pull/4327) Use the TxConfig from simState instead create a new one
- [#4326](https://github.com/ignite/cli/pull/4326) fAdd `buf.build` version to `ignite version` command
Expand Down
70 changes: 70 additions & 0 deletions docs/docs/03-CLI-Commands/01-cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ To get started, create a blockchain:
* [ignite relayer](#ignite-relayer) - Connect blockchains with an IBC relayer
* [ignite scaffold](#ignite-scaffold) - Create a new blockchain, module, message, query, and more
* [ignite version](#ignite-version) - Print the current build information
* [ignite testnet](#ignite-testnet) - Start a testnet local


## ignite account
Expand Down Expand Up @@ -3658,3 +3659,72 @@ ignite version [flags]

* [ignite](#ignite) - Ignite CLI offers everything you need to scaffold, test, build, and launch your blockchain


## ignite testnet

Start a testnet local

**Synopsis**

The commands in this namespace allow you to start your local testnet for development purposes. Currently there is only one feature to create a testnet from any state network (including mainnet).


The "in-place" command is used to create and start a testnet from current local net state(including mainnet).
After using this command in the repo containing the config.yml file, the network will start.
We can create a testnet from the local network state and mint additional coins for the desired accounts from the config.yml file.

During development, in-place allows you to quickly reboot the chain from a multi-node network state to a node you have full control over.

**SEE ALSO**

* [ignite testnet in-place](#ignite-testnet-in-place) - Create and start a testnet from current local net state


## ignite testnet in-place

Create and start a testnet from current local net state

**Synopsis**

The "in-place" command is used to create and start a testnet from current local net state(including mainnet).

We can create a testnet from the local network state and mint additional coins for the desired accounts from the config.yml file.

During development, in-place allows you to quickly reboot the chain from a multi-node network state to a node you have full control over.

By default, the data directory will be initialized in $HOME/.mychain, where "mychain" is the name of the project. To set a custom data directory use the --home flag or set the value in config.yml:

validators:
- name: alice
bonded: '100000000stake'
home: "~/.customdir"

Get mint coin just add account in config.yml file:

accounts:
- name: charlie
coins:
- 20000token
- 200000000stake


```
ignite chain debug [flags]
```

**Options**

```
-h, --help help for debug
-p, --path string path of the app (default ".")
```

**Options inherited from parent commands**

```
-c, --config string path to Ignite config file (default: ./config.yml)
```

**SEE ALSO**

* [ignite](#ignite) - Ignite CLI offers everything you need to scaffold, test, build, start testnet and launch your blockchain
1 change: 1 addition & 0 deletions ignite/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ To get started, create a blockchain:
NewApp(),
NewDoctor(),
NewCompletionCmd(),
NewTestnet(),
)
c.AddCommand(deprecated()...)
c.SetContext(ctx)
Expand Down
24 changes: 24 additions & 0 deletions ignite/cmd/testnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ignitecmd

import (
"github.com/spf13/cobra"
)

// NewTestnet returns a command that groups scaffolding related sub commands.
func NewTestnet() *cobra.Command {
c := &cobra.Command{
Use: "testnet [command]",
Short: "Start a testnet local",
Long: `Start a testnet local
`,
Aliases: []string{"s"},
Args: cobra.ExactArgs(1),
}

c.AddCommand(
NewTestnetInPlace(),
)

return c
}
129 changes: 129 additions & 0 deletions ignite/cmd/testnet_inplace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package ignitecmd

import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/spf13/cobra"

"github.com/ignite/cli/v29/ignite/pkg/cliui"
"github.com/ignite/cli/v29/ignite/pkg/cosmosaccount"
"github.com/ignite/cli/v29/ignite/pkg/errors"
"github.com/ignite/cli/v29/ignite/services/chain"
)

func NewTestnetInPlace() *cobra.Command {
c := &cobra.Command{
Use: "in-place",
Short: "Create and start a testnet from current local net state",
Long: `Testnet in-place command is used to create and start a testnet from current local net state(including mainnet).
After using this command in the repo containing the config.yml file, the network will start.
We can create a testnet from the local network state and mint additional coins for the desired accounts from the config.yml file.`,
Args: cobra.NoArgs,
RunE: testnetInPlaceHandler,
}
flagSetPath(c)
flagSetClearCache(c)
c.Flags().AddFlagSet(flagSetHome())
c.Flags().AddFlagSet(flagSetCheckDependencies())
c.Flags().AddFlagSet(flagSetSkipProto())
c.Flags().AddFlagSet(flagSetVerbose())

c.Flags().Bool(flagQuitOnFail, false, "quit program if the app fails to start")
return c
}

func testnetInPlaceHandler(cmd *cobra.Command, _ []string) error {
session := cliui.New(
cliui.WithVerbosity(getVerbosity(cmd)),
)
defer session.End()

// Otherwise run the serve command directly
return testnetInplace(cmd, session)
}

func testnetInplace(cmd *cobra.Command, session *cliui.Session) error {
chainOption := []chain.Option{
chain.WithOutputer(session),
chain.CollectEvents(session.EventBus()),
chain.CheckCosmosSDKVersion(),
}

if flagGetCheckDependencies(cmd) {
chainOption = append(chainOption, chain.CheckDependencies())
}

// check if custom config is defined
config, _ := cmd.Flags().GetString(flagConfig)
if config != "" {
chainOption = append(chainOption, chain.ConfigFile(config))
}

c, err := chain.NewWithHomeFlags(cmd, chainOption...)
if err != nil {
return err
}

cfg, err := c.Config()
if err != nil {
return err
}
home, err := c.Home()
if err != nil {
return err
}
keyringBackend, err := c.KeyringBackend()
if err != nil {
return err
}
ca, err := cosmosaccount.New(
cosmosaccount.WithKeyringBackend(cosmosaccount.KeyringBackend(keyringBackend)),
cosmosaccount.WithHome(home),
)
if err != nil {
return err
}

var (
operatorAddress sdk.ValAddress
accounts string
accErr *cosmosaccount.AccountDoesNotExistError
)
for _, acc := range cfg.Accounts {
sdkAcc, err := ca.GetByName(acc.Name)
if errors.As(err, &accErr) {
sdkAcc, _, err = ca.Create(acc.Name)
}
if err != nil {
return err
}

sdkAddr, err := sdkAcc.Address(getAddressPrefix(cmd))
if err != nil {
return err
}
if len(cfg.Validators) == 0 {
return errors.Errorf("no validators found for account %s", sdkAcc.Name)
}
if cfg.Validators[0].Name == acc.Name {
accAddr, err := sdk.AccAddressFromBech32(sdkAddr)
if err != nil {
return err
}
operatorAddress = sdk.ValAddress(accAddr)
}
accounts = accounts + "," + sdkAddr
}

chainID, err := c.ID()
if err != nil {
return err
}

args := chain.InPlaceArgs{
NewChainID: chainID,
NewOperatorAddress: operatorAddress.String(),
AccountsToFund: accounts,
}
return c.TestnetInPlace(cmd.Context(), args)
}
4 changes: 4 additions & 0 deletions ignite/pkg/chaincmd/chaincmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
commandUnsafeReset = "unsafe-reset-all"
commandExport = "export"
commandTendermint = "tendermint"
commandTestnetInPlace = "in-place-testnet"

optionHome = "--home"
optionNode = "--node"
Expand Down Expand Up @@ -55,6 +56,9 @@ const (
optionBroadcastMode = "--broadcast-mode"
optionAccount = "--account"
optionIndex = "--index"
optionValidatorPrivateKey = "--validator-privkey"
optionAccountToFund = "--accounts-to-fund"
optionSkipConfirmation = "--skip-confirmation"

constTendermint = "tendermint"
constJSON = "json"
Expand Down
47 changes: 47 additions & 0 deletions ignite/pkg/chaincmd/in-place-testnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package chaincmd

import (
"github.com/ignite/cli/v29/ignite/pkg/cmdrunner/step"
)

type InPlaceOption func([]string) []string

func InPlaceWithPrvKey(prvKey string) InPlaceOption {
return func(s []string) []string {
if len(prvKey) > 0 {
return append(s, optionValidatorPrivateKey, prvKey)
}
return s
}
}

func InPlaceWithAccountToFund(accounts string) InPlaceOption {
return func(s []string) []string {
if len(accounts) > 0 {
return append(s, optionAccountToFund, accounts)
}
return s
}
}

func InPlaceWithSkipConfirmation() InPlaceOption {
return func(s []string) []string {
return append(s, optionSkipConfirmation)
}
}

// TestnetInPlaceCommand return command to start testnet in-place.
func (c ChainCmd) TestnetInPlaceCommand(newChainID, newOperatorAddress string, options ...InPlaceOption) step.Option {
command := []string{
commandTestnetInPlace,
newChainID,
newOperatorAddress,
}

// Apply the options provided by the user
for _, apply := range options {
command = apply(command)
}

return c.daemonCommand(command)
}
12 changes: 12 additions & 0 deletions ignite/pkg/chaincmd/runner/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ func NewKV(key, value string) KV {

var gentxRe = regexp.MustCompile(`(?m)"(.+?)"`)

func (r Runner) InPlace(ctx context.Context, newChainID, newOperatorAddress string, options ...chaincmd.InPlaceOption) error {
runOptions := runOptions{
stdout: os.Stdout,
stderr: os.Stderr,
}
return r.run(
ctx,
runOptions,
r.chainCmd.TestnetInPlaceCommand(newChainID, newOperatorAddress, options...),
)
}

// Gentx generates a genesis tx carrying a self delegation.
func (r Runner) Gentx(
ctx context.Context,
Expand Down
11 changes: 11 additions & 0 deletions ignite/services/chain/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ func (c Chain) Gentx(ctx context.Context, runner chaincmdrunner.Runner, v Valida
)
}

func (c Chain) InPlace(ctx context.Context, runner chaincmdrunner.Runner, args InPlaceArgs) error {
err := runner.InPlace(ctx,
args.NewChainID,
args.NewOperatorAddress,
chaincmd.InPlaceWithPrvKey(args.PrvKeyValidator),
chaincmd.InPlaceWithAccountToFund(args.AccountsToFund),
chaincmd.InPlaceWithSkipConfirmation(),
)
return err
}

// Start wraps the "appd start" command to begin running a chain from the daemon.
func (c Chain) Start(ctx context.Context, runner chaincmdrunner.Runner, cfg *chainconfig.Config) error {
validator, err := chainconfig.FirstValidator(cfg)
Expand Down
37 changes: 37 additions & 0 deletions ignite/services/chain/testnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package chain

import (
"context"
"os"

chainconfig "github.com/ignite/cli/v29/ignite/config/chain"
)

type InPlaceArgs struct {
NewChainID string
NewOperatorAddress string
PrvKeyValidator string
AccountsToFund string
}

func (c Chain) TestnetInPlace(ctx context.Context, args InPlaceArgs) error {
commands, err := c.Commands(ctx)
if err != nil {
return err
}

// make sure that config.yml exists
if c.options.ConfigFile != "" {
if _, err := os.Stat(c.options.ConfigFile); err != nil {
return err
}
} else if _, err := chainconfig.LocateDefault(c.app.Path); err != nil {
return err
}

err = c.InPlace(ctx, commands, args)
if err != nil {
return err
}
return nil
}
Loading

0 comments on commit f7618d3

Please sign in to comment.