Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add command testnet inplace #1

Merged
merged 1 commit into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
81 changes: 81 additions & 0 deletions ignite/cmd/testnet_inplace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package ignitecmd

import (
"github.com/ignite/cli/v29/ignite/pkg/cliui"
"github.com/ignite/cli/v29/ignite/services/chain"
"github.com/spf13/cobra"
)

func NewTestNetInPlace() *cobra.Command {
c := &cobra.Command{
Use: "in-place",
Short: "Run simulation testing for the blockchain",
Long: "Run simulation testing for the blockchain. It sends many randomized-input messages of each module to a simulated node and checks if invariants break",
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 chainInplace(cmd, session)
}

func chainInplace(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
}

var acc string
for _, i := range cfg.Accounts {
acc = acc + "," + i.Address
}

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

args := chain.InplaceArgs{
NewChainID: chainID,
NewOperatorAddress: cfg.Validators[0].OperatorAddress,
AcountsToFund: acc,
}
return c.TestNetInPlace(cmd.Context(), args)
}
2 changes: 2 additions & 0 deletions ignite/config/chain/v1/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ type Validator struct {
// Name is the name of the validator.
Name string `yaml:"name" doc:"Name of the validator."`

OperatorAddress string `yaml:"operatoraddress" doc:"OperatorAddress of the validator."`

// Bonded is how much the validator has staked.
Bonded string `yaml:"bonded" doc:"Amount staked by the validator."`

Expand Down
46 changes: 46 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 Expand Up @@ -186,6 +190,22 @@ func (c ChainCmd) InitCommand(moniker string) step.Option {
return c.daemonCommand(command)
}

// TestnetInPlaceCommand.
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)
}

// AddKeyCommand returns the command to add a new key in the chain keyring.
func (c ChainCmd) AddKeyCommand(accountName, coinType, accountNumber, addressIndex string) step.Option {
command := []string{
Expand Down Expand Up @@ -401,6 +421,32 @@ func GentxWithSecurityContact(securityContact string) GentxOption {
}
}

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)
}
}

func (c ChainCmd) IsAutoChainIDDetectionEnabled() bool {
return c.isAutoChainIDDetectionEnabled
}
Expand Down
9 changes: 9 additions & 0 deletions ignite/pkg/chaincmd/runner/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ 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 {
fmt.Println("Press Ctrl + C to stop the running testnet process.")
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.AcountsToFund),
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
36 changes: 36 additions & 0 deletions ignite/services/chain/testnet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package chain

import (
"context"
chainconfig "github.com/ignite/cli/v29/ignite/config/chain"
"os"
)

type InplaceArgs struct {
NewChainID string
NewOperatorAddress string
PrvKeyValidator string
AcountsToFund 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
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cmd

import (
"encoding/base64"
"fmt"
"io"
"strings"
Expand All @@ -10,7 +9,6 @@ import (
"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
"github.com/cometbft/cometbft/crypto"
tmd25519 "github.com/cometbft/cometbft/crypto/ed25519"
"github.com/cometbft/cometbft/libs/bytes"
tmos "github.com/cometbft/cometbft/libs/os"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
Expand All @@ -36,37 +34,33 @@ const (
)

var (
flagValidatorPrivKey = "validator-privkey"
flagAccountsToFund = "accounts-to-fund"
flagAccountsToFund = "accounts-to-fund"
)

type valArgs struct {
newValAddr bytes.HexBytes
newOperatorAddress string
newValPubKey crypto.PubKey
validatorConsPrivKey crypto.PrivKey
accountsToFund []sdk.AccAddress
upgradeToTrigger string
homeDir string
newValAddr bytes.HexBytes
newOperatorAddress string
newValPubKey crypto.PubKey
accountsToFund []sdk.AccAddress
upgradeToTrigger string
homeDir string
}

func NewTestnetCmd(addStartFlags servertypes.ModuleInitFlags) *cobra.Command {
cmd := server.InPlaceTestnetCreator(newTestnetApp)
addStartFlags(cmd)
cmd.Use = "testnet [newChainID] [newOperatorAddress]"
cmd.Short = "Updates chain's application and consensus state with provided validator info and starts the node"
cmd.Long = `The test command modifies both application and consensus stores within a local mainnet node and starts the node,
with the aim of facilitating testing procedures. This command replaces existing validator data with updated information,
thereby removing the old validator set and introducing a new set suitable for local testing purposes. By altering the state extracted from the mainnet node,
it enables developers to configure their local environments to reflect mainnet conditions more accurately.

Example:
appd testnet testing-1 cosmosvaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4mq79dm --home $HOME/.appd/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq,cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x" [other_server_start_flags]
appd in-place-testnet testing-1 cosmosvaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4mq79dm --home $HOME/.appd/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq,cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x" [other_server_start_flags]
`

cmd.Example = `appd testnet testing-1 cosmosvaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4mq79dm --home $HOME/.appd/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq,cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x"`
cmd.Example = `appd in-place-testnet testing-1 cosmosvaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4mq79dm --home $HOME/.appd/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq,cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x"`

cmd.Flags().String(flagValidatorPrivKey, "", "Validator tendermint/PrivKeyEd25519 consensus private key from the priv_validato_key.json file")
cmd.Flags().String(flagAccountsToFund, "", "Comma-separated list of account addresses that will be funded for testing purposes")
return cmd
}
Expand Down Expand Up @@ -256,17 +250,6 @@ func getCommandArgs(appOpts servertypes.AppOptions) (valArgs, error) {
}
args.upgradeToTrigger = upgradeToTrigger

// validate and set validator privkey
validatorPrivKey := cast.ToString(appOpts.Get(flagValidatorPrivKey))
if validatorPrivKey == "" {
return args, fmt.Errorf("invalid validator private key")
}
decPrivKey, err := base64.StdEncoding.DecodeString(validatorPrivKey)
if err != nil {
return args, fmt.Errorf("cannot decode validator private key %w", err)
}
args.validatorConsPrivKey = tmd25519.PrivKey([]byte(decPrivKey))

// validate and set accounts to fund
accountsString := cast.ToString(appOpts.Get(flagAccountsToFund))

Expand Down
Loading