From 490cb6f14c8b9f07754c86913ee6d0e53eb594f0 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 9 Aug 2024 17:22:04 +0700 Subject: [PATCH 01/26] int in-place testnet creation --- ignite/templates/app/files/app/app.go.plush | 203 ++++++++++++++++++ .../cmd/commands.go.plush | 103 ++++++++- ignite/templates/app/files/go.mod.plush | 2 + 3 files changed, 307 insertions(+), 1 deletion(-) diff --git a/ignite/templates/app/files/app/app.go.plush b/ignite/templates/app/files/app/app.go.plush index 504a3b392f..12a22222d2 100644 --- a/ignite/templates/app/files/app/app.go.plush +++ b/ignite/templates/app/files/app/app.go.plush @@ -6,6 +6,7 @@ import ( clienthelpers "cosmossdk.io/client/v2/helpers" "cosmossdk.io/depinject" "cosmossdk.io/log" + "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" circuitkeeper "cosmossdk.io/x/circuit/keeper" evidencekeeper "cosmossdk.io/x/evidence/keeper" @@ -33,12 +34,17 @@ import ( _ "github.com/cosmos/ibc-go/modules/capability" // import for side-effects _ "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts" // import for side-effects _ "github.com/cosmos/ibc-go/v8/modules/apps/29-fee" // import for side-effects + "github.com/cometbft/cometbft/crypto" + "github.com/cometbft/cometbft/libs/bytes" + tmos "github.com/cometbft/cometbft/libs/os" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/runtime" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" @@ -55,6 +61,7 @@ import ( consensuskeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/cosmos/cosmos-sdk/x/gov" @@ -63,11 +70,14 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" groupkeeper "github.com/cosmos/cosmos-sdk/x/group/keeper" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" icacontrollerkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/keeper" icahostkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" @@ -403,3 +413,196 @@ func BlockedAddresses() map[string]bool { } return result } + +// InitAppForTestnet is broken down into two sections: +// Required Changes: Changes that, if not made, will cause the testnet to halt or panic +// Optional Changes: Changes to customize the testnet to one's liking (lower vote times, fund accounts, etc) +func InitAppForTestnet(app *App, newValAddr bytes.HexBytes, newValPubKey crypto.PubKey, newOperatorAddress, upgradeToTrigger string) *App { + // + // Required Changes: + // + + ctx := app.BaseApp.NewUncachedContext(true, tmproto.Header{}) + pubkey := &ed25519.PubKey{Key: newValPubKey.Bytes()} + pubkeyAny, err := codectypes.NewAnyWithValue(pubkey) + if err != nil { + tmos.Exit(err.Error()) + } + + // STAKING + // + + // Create Validator struct for our new validator. + _, bz, err := bech32.DecodeAndConvert(newOperatorAddress) + if err != nil { + tmos.Exit(err.Error()) + } + bech32Addr, err := bech32.ConvertAndEncode("cosmosvaloper", bz) + if err != nil { + tmos.Exit(err.Error()) + } + newVal := stakingtypes.Validator{ + OperatorAddress: bech32Addr, + ConsensusPubkey: pubkeyAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: math.NewInt(900000000000000), + DelegatorShares: math.LegacyMustNewDecFromStr("10000000"), + Description: stakingtypes.Description{ + Moniker: "Testnet Validator", + }, + Commission: stakingtypes.Commission{ + CommissionRates: stakingtypes.CommissionRates{ + Rate: math.LegacyMustNewDecFromStr("0.05"), + MaxRate: math.LegacyMustNewDecFromStr("0.1"), + MaxChangeRate: math.LegacyMustNewDecFromStr("0.05"), + }, + }, + MinSelfDelegation: math.OneInt(), + } + + validator, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(newVal.GetOperator()) + if err != nil { + tmos.Exit(err.Error()) + } + + // Remove all validators from power store + stakingKey := app.GetKey(stakingtypes.ModuleName) + stakingStore := ctx.KVStore(stakingKey) + iterator, err := app.StakingKeeper.ValidatorsPowerStoreIterator(ctx) + if err != nil { + tmos.Exit(err.Error()) + } + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Remove all valdiators from last validators store + iterator, err = app.StakingKeeper.LastValidatorsIterator(ctx) + if err != nil { + tmos.Exit(err.Error()) + } + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Remove all validators from validators store + iterator = stakingStore.Iterator(stakingtypes.ValidatorsKey, storetypes.PrefixEndBytes(stakingtypes.ValidatorsKey)) + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Remove all validators from unbonding queue + iterator = stakingStore.Iterator(stakingtypes.ValidatorQueueKey, storetypes.PrefixEndBytes(stakingtypes.ValidatorQueueKey)) + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Add our validator to power and last validators store + app.StakingKeeper.SetValidator(ctx, newVal) + err = app.StakingKeeper.SetValidatorByConsAddr(ctx, newVal) + if err != nil { + tmos.Exit(err.Error()) + } + app.StakingKeeper.SetValidatorByPowerIndex(ctx, newVal) + app.StakingKeeper.SetLastValidatorPower(ctx, validator, 0) + if err := app.StakingKeeper.Hooks().AfterValidatorCreated(ctx, validator); err != nil { + panic(err) + } + + // DISTRIBUTION + // + + // Initialize records for this validator across all distribution stores + app.DistrKeeper.SetValidatorHistoricalRewards(ctx, validator, 0, distrtypes.NewValidatorHistoricalRewards(sdk.DecCoins{}, 1)) + app.DistrKeeper.SetValidatorCurrentRewards(ctx, validator, distrtypes.NewValidatorCurrentRewards(sdk.DecCoins{}, 1)) + app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, validator, distrtypes.InitialValidatorAccumulatedCommission()) + app.DistrKeeper.SetValidatorOutstandingRewards(ctx, validator, distrtypes.ValidatorOutstandingRewards{Rewards: sdk.DecCoins{}}) + + // SLASHING + // + + // Set validator signing info for our new validator. + newConsAddr := sdk.ConsAddress(newValAddr.Bytes()) + newValidatorSigningInfo := slashingtypes.ValidatorSigningInfo{ + Address: newConsAddr.String(), + StartHeight: app.LastBlockHeight() - 1, + Tombstoned: false, + } + app.SlashingKeeper.SetValidatorSigningInfo(ctx, newConsAddr, newValidatorSigningInfo) + + // + // Optional Changes: + // + + // BANK + // + + defaultCoins := sdk.NewCoins( + sdk.NewInt64Coin("stake", 1000000000)) + + // account was generated from the following mnmenic: + // ==============account 1================================== + // mnemonic: "heart regret vivid nominee race scatter version coyote milk cherry axis mirror risk beef only elevator salon exact tomato lesson approve ridge cross capable" + // address:"cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq" + // ==============account 2================================== + // mnemonic:"soap step crash ceiling path virtual this armor accident pond share track spice woman vault discover share holiday inquiry oak shine scrub bulb arrive" + // address:"cosmos1w7f3xx7e75p4l7qdym5msqem9rd4dyc4752spg" + // ==============account 3================================== + // mnemonic:"travel jelly basic visa apart kidney piano lumber elevator fat unknown guard matter used high drastic umbrella humble crush stock banner enlist mule unique" + // address:"cosmos1g9v3zjt6rfkwm4s8sw9wu4jgz9me8pn27f8nyc" + // ==============account 4================================== + // mnemonic:"improve fun aim fringe machine shed repair olympic copper buddy road used trial liquid energy diamond orange lock time exact away change icon spike" + // address:"cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x" + + localAccounts := []sdk.AccAddress{ + sdk.MustAccAddressFromBech32("cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq"), + sdk.MustAccAddressFromBech32("cosmos1w7f3xx7e75p4l7qdym5msqem9rd4dyc4752spg"), + sdk.MustAccAddressFromBech32("cosmos1g9v3zjt6rfkwm4s8sw9wu4jgz9me8pn27f8nyc"), + sdk.MustAccAddressFromBech32("cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x"), + } + + // Fund local accounts + for _, account := range localAccounts { + err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, defaultCoins) + if err != nil { + tmos.Exit(err.Error()) + } + err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, account, defaultCoins) + if err != nil { + tmos.Exit(err.Error()) + } + } + + // Fund edgenet faucet + faucetCoins := sdk.NewCoins( + sdk.NewInt64Coin("stake", 1000000000000)) + err = app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, faucetCoins) + if err != nil { + tmos.Exit(err.Error()) + } + err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, sdk.MustAccAddressFromBech32("cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq"), faucetCoins) + if err != nil { + tmos.Exit(err.Error()) + } + + // Mars bank account + marsCoins := sdk.NewCoins( + sdk.NewInt64Coin("stake", 10000000000000), + sdk.NewInt64Coin("ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858", 3000000000000), + sdk.NewInt64Coin("ibc/EA1D43981D5C9A1C4AAEA9C23BB1D4FA126BA9BC7020A25E0AE4AA841EA25DC5", 3000000000000000000)) + err = app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, marsCoins) + if err != nil { + tmos.Exit(err.Error()) + } + err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, sdk.MustAccAddressFromBech32("cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq"), marsCoins) + if err != nil { + tmos.Exit(err.Error()) + } + + return app +} \ No newline at end of file diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush index 685899a07d..735122982a 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush @@ -3,10 +3,19 @@ package cmd import ( "errors" "io" + "path/filepath" + + "github.com/cometbft/cometbft/crypto" + "github.com/cometbft/cometbft/libs/bytes" "cosmossdk.io/log" + "cosmossdk.io/store" + "cosmossdk.io/store/snapshots" + snapshottypes "cosmossdk.io/store/snapshots/types" + storetypes "cosmossdk.io/store/types" confixcmd "cosmossdk.io/tools/confix/cmd" dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/debug" "github.com/cosmos/cosmos-sdk/client/flags" @@ -22,6 +31,8 @@ import ( authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/spf13/cast" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -43,6 +54,7 @@ func initRootCmd( server.AddCommands(rootCmd, app.DefaultNodeHome, newApp, appExport, addModuleInitFlags) + server.AddTestnetCreatorCommand(rootCmd, newTestnetApp, addModuleInitFlags) // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( server.StatusCommand(), @@ -124,7 +136,66 @@ func newApp( traceStore io.Writer, appOpts servertypes.AppOptions, ) servertypes.Application { - baseappOptions := server.DefaultBaseappOptions(appOpts) + var cache storetypes.MultiStorePersistentCache + + if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) { + cache = store.NewCommitKVStoreCacheManager() + } + + skipUpgradeHeights := make(map[int64]bool) + for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + + pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) + if err != nil { + panic(err) + } + + snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") + snapshotDB, err := dbm.NewDB("metadata", server.GetAppDBBackend(appOpts), snapshotDir) + if err != nil { + panic(err) + } + snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) + if err != nil { + panic(err) + } + + snapshotOptions := snapshottypes.NewSnapshotOptions( + cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval)), + cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent)), + ) + + homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) + chainID := cast.ToString(appOpts.Get(flags.FlagChainID)) + + if chainID == "" { + // fallback to genesis chain-id + genDocFile := filepath.Join(homeDir, cast.ToString(appOpts.Get("genesis_file"))) + appGenesis, err := genutiltypes.AppGenesisFromFile(genDocFile) + if err != nil { + panic(err) + } + + chainID = appGenesis.ChainID + } + + baseappOptions := []func(*baseapp.BaseApp){ + baseapp.SetPruning(pruningOpts), + baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), + baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), + baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), + baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))), + baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), + baseapp.SetInterBlockCache(cache), + baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), + baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), + baseapp.SetSnapshot(snapshotStore, snapshotOptions), + baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), + baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))), + baseapp.SetChainID(chainID), + } app, err := app.New( logger, db, traceStore, true, @@ -186,4 +257,34 @@ func appExport( } return bApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) +} + +// newTestnetApp starts by running the normal newApp method. From there, the app interface returned is modified in order +// for a testnet to be created from the provided app. +func newTestnetApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { + // Create an app and type cast to an App + newApp := newApp(logger, db, traceStore, appOpts) + testApp, ok := newApp.(*app.App) + if !ok { + panic("app created from newApp is not of type App") + } + + newValAddr, ok := appOpts.Get(server.KeyNewValAddr).(bytes.HexBytes) + if !ok { + panic("newValAddr is not of type bytes.HexBytes") + } + newValPubKey, ok := appOpts.Get(server.KeyUserPubKey).(crypto.PubKey) + if !ok { + panic("newValPubKey is not of type crypto.PubKey") + } + newOperatorAddress, ok := appOpts.Get(server.KeyNewOpAddr).(string) + if !ok { + panic("newOperatorAddress is not of type string") + } + upgradeToTrigger, ok := appOpts.Get(server.KeyTriggerTestnetUpgrade).(string) + if !ok { + panic("upgradeToTrigger is not of type string") + } + + return app.InitAppForTestnet(testApp, newValAddr, newValPubKey, newOperatorAddress, upgradeToTrigger) } \ No newline at end of file diff --git a/ignite/templates/app/files/go.mod.plush b/ignite/templates/app/files/go.mod.plush index bfa98c6e80..d05ec9b04a 100644 --- a/ignite/templates/app/files/go.mod.plush +++ b/ignite/templates/app/files/go.mod.plush @@ -17,6 +17,7 @@ require ( cosmossdk.io/depinject v1.0.0-alpha.4 cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.3.1 + cosmossdk.io/math v1.3.0 cosmossdk.io/store v1.1.0 cosmossdk.io/tools/confix v0.1.1 cosmossdk.io/x/circuit v0.1.0 @@ -39,6 +40,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 + github.com/spf13/cast v1.6.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 From 6e51b12b57ddcf34f4f7d76c261430c73c4160a2 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Mon, 12 Aug 2024 10:53:07 +0700 Subject: [PATCH 02/26] takes many arguments for command and move dependencies to testnet file --- ignite/templates/app/files/app/app.go.plush | 203 ------------ .../cmd/commands.go.plush | 35 +-- .../cmd/testnet.go.plush | 291 ++++++++++++++++++ 3 files changed, 292 insertions(+), 237 deletions(-) create mode 100644 ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush diff --git a/ignite/templates/app/files/app/app.go.plush b/ignite/templates/app/files/app/app.go.plush index 12a22222d2..5d3293fc45 100644 --- a/ignite/templates/app/files/app/app.go.plush +++ b/ignite/templates/app/files/app/app.go.plush @@ -6,7 +6,6 @@ import ( clienthelpers "cosmossdk.io/client/v2/helpers" "cosmossdk.io/depinject" "cosmossdk.io/log" - "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" circuitkeeper "cosmossdk.io/x/circuit/keeper" evidencekeeper "cosmossdk.io/x/evidence/keeper" @@ -34,17 +33,12 @@ import ( _ "github.com/cosmos/ibc-go/modules/capability" // import for side-effects _ "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts" // import for side-effects _ "github.com/cosmos/ibc-go/v8/modules/apps/29-fee" // import for side-effects - "github.com/cometbft/cometbft/crypto" - "github.com/cometbft/cometbft/libs/bytes" - tmos "github.com/cometbft/cometbft/libs/os" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/runtime" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" @@ -61,7 +55,6 @@ import ( consensuskeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/cosmos/cosmos-sdk/x/gov" @@ -70,14 +63,11 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" groupkeeper "github.com/cosmos/cosmos-sdk/x/group/keeper" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" - minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" icacontrollerkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/keeper" icahostkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" @@ -412,197 +402,4 @@ func BlockedAddresses() map[string]bool { } } return result -} - -// InitAppForTestnet is broken down into two sections: -// Required Changes: Changes that, if not made, will cause the testnet to halt or panic -// Optional Changes: Changes to customize the testnet to one's liking (lower vote times, fund accounts, etc) -func InitAppForTestnet(app *App, newValAddr bytes.HexBytes, newValPubKey crypto.PubKey, newOperatorAddress, upgradeToTrigger string) *App { - // - // Required Changes: - // - - ctx := app.BaseApp.NewUncachedContext(true, tmproto.Header{}) - pubkey := &ed25519.PubKey{Key: newValPubKey.Bytes()} - pubkeyAny, err := codectypes.NewAnyWithValue(pubkey) - if err != nil { - tmos.Exit(err.Error()) - } - - // STAKING - // - - // Create Validator struct for our new validator. - _, bz, err := bech32.DecodeAndConvert(newOperatorAddress) - if err != nil { - tmos.Exit(err.Error()) - } - bech32Addr, err := bech32.ConvertAndEncode("cosmosvaloper", bz) - if err != nil { - tmos.Exit(err.Error()) - } - newVal := stakingtypes.Validator{ - OperatorAddress: bech32Addr, - ConsensusPubkey: pubkeyAny, - Jailed: false, - Status: stakingtypes.Bonded, - Tokens: math.NewInt(900000000000000), - DelegatorShares: math.LegacyMustNewDecFromStr("10000000"), - Description: stakingtypes.Description{ - Moniker: "Testnet Validator", - }, - Commission: stakingtypes.Commission{ - CommissionRates: stakingtypes.CommissionRates{ - Rate: math.LegacyMustNewDecFromStr("0.05"), - MaxRate: math.LegacyMustNewDecFromStr("0.1"), - MaxChangeRate: math.LegacyMustNewDecFromStr("0.05"), - }, - }, - MinSelfDelegation: math.OneInt(), - } - - validator, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(newVal.GetOperator()) - if err != nil { - tmos.Exit(err.Error()) - } - - // Remove all validators from power store - stakingKey := app.GetKey(stakingtypes.ModuleName) - stakingStore := ctx.KVStore(stakingKey) - iterator, err := app.StakingKeeper.ValidatorsPowerStoreIterator(ctx) - if err != nil { - tmos.Exit(err.Error()) - } - for ; iterator.Valid(); iterator.Next() { - stakingStore.Delete(iterator.Key()) - } - iterator.Close() - - // Remove all valdiators from last validators store - iterator, err = app.StakingKeeper.LastValidatorsIterator(ctx) - if err != nil { - tmos.Exit(err.Error()) - } - for ; iterator.Valid(); iterator.Next() { - stakingStore.Delete(iterator.Key()) - } - iterator.Close() - - // Remove all validators from validators store - iterator = stakingStore.Iterator(stakingtypes.ValidatorsKey, storetypes.PrefixEndBytes(stakingtypes.ValidatorsKey)) - for ; iterator.Valid(); iterator.Next() { - stakingStore.Delete(iterator.Key()) - } - iterator.Close() - - // Remove all validators from unbonding queue - iterator = stakingStore.Iterator(stakingtypes.ValidatorQueueKey, storetypes.PrefixEndBytes(stakingtypes.ValidatorQueueKey)) - for ; iterator.Valid(); iterator.Next() { - stakingStore.Delete(iterator.Key()) - } - iterator.Close() - - // Add our validator to power and last validators store - app.StakingKeeper.SetValidator(ctx, newVal) - err = app.StakingKeeper.SetValidatorByConsAddr(ctx, newVal) - if err != nil { - tmos.Exit(err.Error()) - } - app.StakingKeeper.SetValidatorByPowerIndex(ctx, newVal) - app.StakingKeeper.SetLastValidatorPower(ctx, validator, 0) - if err := app.StakingKeeper.Hooks().AfterValidatorCreated(ctx, validator); err != nil { - panic(err) - } - - // DISTRIBUTION - // - - // Initialize records for this validator across all distribution stores - app.DistrKeeper.SetValidatorHistoricalRewards(ctx, validator, 0, distrtypes.NewValidatorHistoricalRewards(sdk.DecCoins{}, 1)) - app.DistrKeeper.SetValidatorCurrentRewards(ctx, validator, distrtypes.NewValidatorCurrentRewards(sdk.DecCoins{}, 1)) - app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, validator, distrtypes.InitialValidatorAccumulatedCommission()) - app.DistrKeeper.SetValidatorOutstandingRewards(ctx, validator, distrtypes.ValidatorOutstandingRewards{Rewards: sdk.DecCoins{}}) - - // SLASHING - // - - // Set validator signing info for our new validator. - newConsAddr := sdk.ConsAddress(newValAddr.Bytes()) - newValidatorSigningInfo := slashingtypes.ValidatorSigningInfo{ - Address: newConsAddr.String(), - StartHeight: app.LastBlockHeight() - 1, - Tombstoned: false, - } - app.SlashingKeeper.SetValidatorSigningInfo(ctx, newConsAddr, newValidatorSigningInfo) - - // - // Optional Changes: - // - - // BANK - // - - defaultCoins := sdk.NewCoins( - sdk.NewInt64Coin("stake", 1000000000)) - - // account was generated from the following mnmenic: - // ==============account 1================================== - // mnemonic: "heart regret vivid nominee race scatter version coyote milk cherry axis mirror risk beef only elevator salon exact tomato lesson approve ridge cross capable" - // address:"cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq" - // ==============account 2================================== - // mnemonic:"soap step crash ceiling path virtual this armor accident pond share track spice woman vault discover share holiday inquiry oak shine scrub bulb arrive" - // address:"cosmos1w7f3xx7e75p4l7qdym5msqem9rd4dyc4752spg" - // ==============account 3================================== - // mnemonic:"travel jelly basic visa apart kidney piano lumber elevator fat unknown guard matter used high drastic umbrella humble crush stock banner enlist mule unique" - // address:"cosmos1g9v3zjt6rfkwm4s8sw9wu4jgz9me8pn27f8nyc" - // ==============account 4================================== - // mnemonic:"improve fun aim fringe machine shed repair olympic copper buddy road used trial liquid energy diamond orange lock time exact away change icon spike" - // address:"cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x" - - localAccounts := []sdk.AccAddress{ - sdk.MustAccAddressFromBech32("cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq"), - sdk.MustAccAddressFromBech32("cosmos1w7f3xx7e75p4l7qdym5msqem9rd4dyc4752spg"), - sdk.MustAccAddressFromBech32("cosmos1g9v3zjt6rfkwm4s8sw9wu4jgz9me8pn27f8nyc"), - sdk.MustAccAddressFromBech32("cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x"), - } - - // Fund local accounts - for _, account := range localAccounts { - err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, defaultCoins) - if err != nil { - tmos.Exit(err.Error()) - } - err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, account, defaultCoins) - if err != nil { - tmos.Exit(err.Error()) - } - } - - // Fund edgenet faucet - faucetCoins := sdk.NewCoins( - sdk.NewInt64Coin("stake", 1000000000000)) - err = app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, faucetCoins) - if err != nil { - tmos.Exit(err.Error()) - } - err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, sdk.MustAccAddressFromBech32("cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq"), faucetCoins) - if err != nil { - tmos.Exit(err.Error()) - } - - // Mars bank account - marsCoins := sdk.NewCoins( - sdk.NewInt64Coin("stake", 10000000000000), - sdk.NewInt64Coin("ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858", 3000000000000), - sdk.NewInt64Coin("ibc/EA1D43981D5C9A1C4AAEA9C23BB1D4FA126BA9BC7020A25E0AE4AA841EA25DC5", 3000000000000000000)) - err = app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, marsCoins) - if err != nil { - tmos.Exit(err.Error()) - } - err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, sdk.MustAccAddressFromBech32("cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq"), marsCoins) - if err != nil { - tmos.Exit(err.Error()) - } - - return app } \ No newline at end of file diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush index 735122982a..b5d8f5b633 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush @@ -5,9 +5,6 @@ import ( "io" "path/filepath" - "github.com/cometbft/cometbft/crypto" - "github.com/cometbft/cometbft/libs/bytes" - "cosmossdk.io/log" "cosmossdk.io/store" "cosmossdk.io/store/snapshots" @@ -46,6 +43,7 @@ func initRootCmd( ) { rootCmd.AddCommand( genutilcli.InitCmd(basicManager, app.DefaultNodeHome), + NewTestnetCmd(addModuleInitFlags), debug.Cmd(), confixcmd.ConfigCommand(), pruning.Cmd(newApp, app.DefaultNodeHome), @@ -54,7 +52,6 @@ func initRootCmd( server.AddCommands(rootCmd, app.DefaultNodeHome, newApp, appExport, addModuleInitFlags) - server.AddTestnetCreatorCommand(rootCmd, newTestnetApp, addModuleInitFlags) // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( server.StatusCommand(), @@ -258,33 +255,3 @@ func appExport( return bApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) } - -// newTestnetApp starts by running the normal newApp method. From there, the app interface returned is modified in order -// for a testnet to be created from the provided app. -func newTestnetApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { - // Create an app and type cast to an App - newApp := newApp(logger, db, traceStore, appOpts) - testApp, ok := newApp.(*app.App) - if !ok { - panic("app created from newApp is not of type App") - } - - newValAddr, ok := appOpts.Get(server.KeyNewValAddr).(bytes.HexBytes) - if !ok { - panic("newValAddr is not of type bytes.HexBytes") - } - newValPubKey, ok := appOpts.Get(server.KeyUserPubKey).(crypto.PubKey) - if !ok { - panic("newValPubKey is not of type crypto.PubKey") - } - newOperatorAddress, ok := appOpts.Get(server.KeyNewOpAddr).(string) - if !ok { - panic("newOperatorAddress is not of type string") - } - upgradeToTrigger, ok := appOpts.Get(server.KeyTriggerTestnetUpgrade).(string) - if !ok { - panic("upgradeToTrigger is not of type string") - } - - return app.InitAppForTestnet(testApp, newValAddr, newValPubKey, newOperatorAddress, upgradeToTrigger) -} \ No newline at end of file diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush new file mode 100644 index 0000000000..976fec638e --- /dev/null +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush @@ -0,0 +1,291 @@ +package cmd + +import ( + "encoding/base64" + "fmt" + "io" + "strings" + + "cosmossdk.io/log" + "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" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/client/flags" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/spf13/cast" + "github.com/spf13/cobra" + + "<%= ModulePath %>/app" +) + +const ( + valVotingPower int64 = 900000000000000 +) + +var ( + flagValidatorPrivKey = "validator-privkey" + 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 +} + +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] + ` + + cmd.Example = `appd 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 +} + +// newTestnetApp starts by running the normal newApp method. From there, the app interface returned is modified in order +// for a testnet to be created from the provided app. +func newTestnetApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { + // Create an app and type cast to an App + newApp := newApp(logger, db, traceStore, appOpts) + testApp, ok := newApp.(*app.App) + if !ok { + panic("app created from newApp is not of type App") + } + + // Get command args + args, err := getCommandArgs(appOpts) + if err != nil { + panic(err) + } + + return initAppForTestnet(testApp, args) +} + +// InitAppForTestnet is broken down into two sections: +// Required Changes: Changes that, if not made, will cause the testnet to halt or panic +// Optional Changes: Changes to customize the testnet to one's liking (lower vote times, fund accounts, etc) +func initAppForTestnet(app *app.App, args valArgs) *app.App { + // + // Required Changes: + // + ctx := app.BaseApp.NewUncachedContext(true, tmproto.Header{}) + + pubkey := &ed25519.PubKey{Key: args.newValPubKey.Bytes()} + pubkeyAny, err := codectypes.NewAnyWithValue(pubkey) + if err != nil { + tmos.Exit(err.Error()) + } + + // STAKING + // + + // Create Validator struct for our new validator. + newVal := stakingtypes.Validator{ + OperatorAddress: args.newOperatorAddress, + ConsensusPubkey: pubkeyAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: math.NewInt(valVotingPower), + DelegatorShares: math.LegacyMustNewDecFromStr("10000000"), + Description: stakingtypes.Description{ + Moniker: "Testnet Validator", + }, + Commission: stakingtypes.Commission{ + CommissionRates: stakingtypes.CommissionRates{ + Rate: math.LegacyMustNewDecFromStr("0.05"), + MaxRate: math.LegacyMustNewDecFromStr("0.1"), + MaxChangeRate: math.LegacyMustNewDecFromStr("0.05"), + }, + }, + MinSelfDelegation: math.OneInt(), + } + + validator, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(newVal.GetOperator()) + if err != nil { + tmos.Exit(err.Error()) + } + + // Remove all validators from power store + stakingKey := app.GetKey(stakingtypes.ModuleName) + stakingStore := ctx.KVStore(stakingKey) + iterator, err := app.StakingKeeper.ValidatorsPowerStoreIterator(ctx) + if err != nil { + tmos.Exit(err.Error()) + } + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Remove all valdiators from last validators store + iterator, err = app.StakingKeeper.LastValidatorsIterator(ctx) + if err != nil { + tmos.Exit(err.Error()) + } + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Remove all validators from validators store + iterator = stakingStore.Iterator(stakingtypes.ValidatorsKey, storetypes.PrefixEndBytes(stakingtypes.ValidatorsKey)) + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Remove all validators from unbonding queue + iterator = stakingStore.Iterator(stakingtypes.ValidatorQueueKey, storetypes.PrefixEndBytes(stakingtypes.ValidatorQueueKey)) + for ; iterator.Valid(); iterator.Next() { + stakingStore.Delete(iterator.Key()) + } + iterator.Close() + + // Add our validator to power and last validators store + app.StakingKeeper.SetValidator(ctx, newVal) + err = app.StakingKeeper.SetValidatorByConsAddr(ctx, newVal) + if err != nil { + tmos.Exit(err.Error()) + } + app.StakingKeeper.SetValidatorByPowerIndex(ctx, newVal) + app.StakingKeeper.SetLastValidatorPower(ctx, validator, 0) + if err := app.StakingKeeper.Hooks().AfterValidatorCreated(ctx, validator); err != nil { + tmos.Exit(err.Error()) + } + + // DISTRIBUTION + // + + // Initialize records for this validator across all distribution stores + app.DistrKeeper.SetValidatorHistoricalRewards(ctx, validator, 0, distrtypes.NewValidatorHistoricalRewards(sdk.DecCoins{}, 1)) + app.DistrKeeper.SetValidatorCurrentRewards(ctx, validator, distrtypes.NewValidatorCurrentRewards(sdk.DecCoins{}, 1)) + app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, validator, distrtypes.InitialValidatorAccumulatedCommission()) + app.DistrKeeper.SetValidatorOutstandingRewards(ctx, validator, distrtypes.ValidatorOutstandingRewards{Rewards: sdk.DecCoins{}}) + + // SLASHING + // + + // Set validator signing info for our new validator. + newConsAddr := sdk.ConsAddress(args.newValAddr.Bytes()) + newValidatorSigningInfo := slashingtypes.ValidatorSigningInfo{ + Address: newConsAddr.String(), + StartHeight: app.LastBlockHeight() - 1, + Tombstoned: false, + } + app.SlashingKeeper.SetValidatorSigningInfo(ctx, newConsAddr, newValidatorSigningInfo) + + // + // Optional Changes: + // + + // BANK + // + bondDenom, err := app.StakingKeeper.BondDenom(ctx) + if err != nil { + tmos.Exit(err.Error()) + } + + defaultCoins := sdk.NewCoins(sdk.NewInt64Coin(bondDenom, 1000000000)) + + // Fund local accounts + for _, account := range args.accountsToFund { + err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, defaultCoins) + if err != nil { + tmos.Exit(err.Error()) + } + err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, account, defaultCoins) + if err != nil { + tmos.Exit(err.Error()) + } + } + + return app +} + +// parse the input flags and returns valArgs +func getCommandArgs(appOpts servertypes.AppOptions) (valArgs, error) { + args := valArgs{} + + newValAddr, ok := appOpts.Get(server.KeyNewValAddr).(bytes.HexBytes) + if !ok { + panic("newValAddr is not of type bytes.HexBytes") + } + args.newValAddr = newValAddr + newValPubKey, ok := appOpts.Get(server.KeyUserPubKey).(crypto.PubKey) + if !ok { + panic("newValPubKey is not of type crypto.PubKey") + } + args.newValPubKey = newValPubKey + newOperatorAddress, ok := appOpts.Get(server.KeyNewOpAddr).(string) + if !ok { + panic("newOperatorAddress is not of type string") + } + args.newOperatorAddress = newOperatorAddress + upgradeToTrigger, ok := appOpts.Get(server.KeyTriggerTestnetUpgrade).(string) + if !ok { + panic("upgradeToTrigger is not of type string") + } + 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)) + + for _, account := range strings.Split(accountsString, ",") { + if account != "" { + addr, err := sdk.AccAddressFromBech32(account) + if err != nil { + return args, fmt.Errorf("invalid bech32 address format %w", err) + } + args.accountsToFund = append(args.accountsToFund, addr) + } + } + + // home dir + homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) + if homeDir == "" { + return args, fmt.Errorf("invalid home dir") + } + args.homeDir = homeDir + + return args, nil +} From 21bc6c258b4adb9e3324d704e39c7b127c06f0b8 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Mon, 12 Aug 2024 14:08:28 +0700 Subject: [PATCH 03/26] changelog --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index 189ce57dc2..b7812ca2e2 100644 --- a/changelog.md +++ b/changelog.md @@ -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. ### Changes From 6e3c919719b44d389ae51d16c0fa0af03c241807 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Tue, 13 Aug 2024 14:12:48 +0700 Subject: [PATCH 04/26] add command testnet inplace --- ignite/cmd/cmd.go | 1 + ignite/cmd/testnet.go | 24 ++++++ ignite/cmd/testnet_inplace.go | 81 +++++++++++++++++++ ignite/config/chain/v1/validator.go | 2 + ignite/pkg/chaincmd/chaincmd.go | 46 +++++++++++ ignite/pkg/chaincmd/runner/chain.go | 9 +++ ignite/services/chain/runtime.go | 11 +++ ignite/services/chain/testnet.go | 36 +++++++++ .../cmd/testnet.go.plush | 35 +++----- 9 files changed, 219 insertions(+), 26 deletions(-) create mode 100644 ignite/cmd/testnet.go create mode 100644 ignite/cmd/testnet_inplace.go create mode 100644 ignite/services/chain/testnet.go diff --git a/ignite/cmd/cmd.go b/ignite/cmd/cmd.go index 2ebb8b06ac..a0ea53a332 100644 --- a/ignite/cmd/cmd.go +++ b/ignite/cmd/cmd.go @@ -89,6 +89,7 @@ To get started, create a blockchain: NewApp(), NewDoctor(), NewCompletionCmd(), + NewTestNet(), ) c.AddCommand(deprecated()...) c.SetContext(ctx) diff --git a/ignite/cmd/testnet.go b/ignite/cmd/testnet.go new file mode 100644 index 0000000000..f2e8edb2f3 --- /dev/null +++ b/ignite/cmd/testnet.go @@ -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 +} diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go new file mode 100644 index 0000000000..f4a5044009 --- /dev/null +++ b/ignite/cmd/testnet_inplace.go @@ -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) +} diff --git a/ignite/config/chain/v1/validator.go b/ignite/config/chain/v1/validator.go index 9ee1e51103..259b60c255 100644 --- a/ignite/config/chain/v1/validator.go +++ b/ignite/config/chain/v1/validator.go @@ -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."` diff --git a/ignite/pkg/chaincmd/chaincmd.go b/ignite/pkg/chaincmd/chaincmd.go index 7034b789e5..5be1c5b9df 100644 --- a/ignite/pkg/chaincmd/chaincmd.go +++ b/ignite/pkg/chaincmd/chaincmd.go @@ -27,6 +27,7 @@ const ( commandUnsafeReset = "unsafe-reset-all" commandExport = "export" commandTendermint = "tendermint" + commandTestNetInPlace = "in-place-testnet" optionHome = "--home" optionNode = "--node" @@ -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" @@ -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{ @@ -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 } diff --git a/ignite/pkg/chaincmd/runner/chain.go b/ignite/pkg/chaincmd/runner/chain.go index 7e60719713..5102e2319e 100644 --- a/ignite/pkg/chaincmd/runner/chain.go +++ b/ignite/pkg/chaincmd/runner/chain.go @@ -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, diff --git a/ignite/services/chain/runtime.go b/ignite/services/chain/runtime.go index ac18fb23f8..5c7f94d5ef 100644 --- a/ignite/services/chain/runtime.go +++ b/ignite/services/chain/runtime.go @@ -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) diff --git a/ignite/services/chain/testnet.go b/ignite/services/chain/testnet.go new file mode 100644 index 0000000000..35910933f0 --- /dev/null +++ b/ignite/services/chain/testnet.go @@ -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 +} diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush index 976fec638e..84e2634c59 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush @@ -1,7 +1,6 @@ package cmd import ( - "encoding/base64" "fmt" "io" "strings" @@ -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" @@ -36,24 +34,21 @@ 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, @@ -61,12 +56,11 @@ thereby removing the old validator set and introducing a new set suitable for lo 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 } @@ -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)) From 376beb4e7291834c1748a5c11975ffb3e8e66e3f Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Tue, 13 Aug 2024 14:49:42 +0700 Subject: [PATCH 05/26] updates --- ignite/cmd/testnet_inplace.go | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index f4a5044009..2911ef9e9c 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -9,10 +9,29 @@ import ( 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, + Short: "Create and start a testnet from current local state", + Long: `Testnet in-place command is used to create and start a testnet from current local state. + After utilizing this command the network will start. We can create testnet from mainnet state and mint more coins for accounts from config.yml file. + + In the config.yml file, there should be at least the address account to fund, operator address, home of the local state node. + + For example: + + Configuration acounts to fund: + accounts: + - name: alice + address: "cosmos1wa3u4knw74r598quvzydvca42qsmk6jrzmgy07" + - name: bob + address: "cosmos10uls38gddhhlywla0sjlvqg8pjvcffx4lu25c4" + + Configuration validators: + validators: + - name: alice + operatoraddress: cosmosvaloper1wa3u4knw74r598quvzydvca42qsmk6jr80u3rd + home: "$HOME/.testchaind/validator1" + `, + Args: cobra.NoArgs, + RunE: testnetInPlaceHandler, } flagSetPath(c) flagSetClearCache(c) @@ -32,10 +51,10 @@ func testnetInPlaceHandler(cmd *cobra.Command, _ []string) error { defer session.End() // Otherwise run the serve command directly - return chainInplace(cmd, session) + return testnetInplace(cmd, session) } -func chainInplace(cmd *cobra.Command, session *cliui.Session) error { +func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { chainOption := []chain.Option{ chain.WithOutputer(session), chain.CollectEvents(session.EventBus()), From 6976bc36a989f8ee1adf0c634c3e047f437af663 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 16 Aug 2024 10:36:34 +0700 Subject: [PATCH 06/26] minor --- .../{{binaryNamePrefix}}d/cmd/testnet.go.plush | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush index 84e2634c59..6bfddd5d66 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush @@ -53,13 +53,9 @@ func NewTestnetCmd(addStartFlags servertypes.ModuleInitFlags) *cobra.Command { 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. +it enables developers to configure their local environments to reflect mainnet conditions more accurately.` -Example: - 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 in-place-testnet testing-1 cosmosvaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4mq79dm --home $HOME/.appd/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq,cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x"` + cmd.Example = fmt.Sprintf(`%sd in-place-testnet testing-1 cosmosvaloper1w7f3xx7e75p4l7qdym5msqem9rd4dyc4mq79dm --home $HOME/.%sd/validator1 --validator-privkey=6dq+/KHNvyiw2TToCgOpUpQKIzrLs69Rb8Az39xvmxPHNoPxY1Cil8FY+4DhT9YwD6s0tFABMlLcpaylzKKBOg== --accounts-to-fund="cosmos1f7twgcq4ypzg7y24wuywy06xmdet8pc4473tnq,cosmos1qvuhm5m644660nd8377d6l7yz9e9hhm9evmx3x"`, "<%= ModulePath %>", "<%= ModulePath %>") cmd.Flags().String(flagAccountsToFund, "", "Comma-separated list of account addresses that will be funded for testing purposes") return cmd @@ -84,11 +80,7 @@ func newTestnetApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts s return initAppForTestnet(testApp, args) } -// InitAppForTestnet is broken down into two sections: -// Required Changes: Changes that, if not made, will cause the testnet to halt or panic -// Optional Changes: Changes to customize the testnet to one's liking (lower vote times, fund accounts, etc) func initAppForTestnet(app *app.App, args valArgs) *app.App { - // // Required Changes: // ctx := app.BaseApp.NewUncachedContext(true, tmproto.Header{}) @@ -197,10 +189,6 @@ func initAppForTestnet(app *app.App, args valArgs) *app.App { } app.SlashingKeeper.SetValidatorSigningInfo(ctx, newConsAddr, newValidatorSigningInfo) - // - // Optional Changes: - // - // BANK // bondDenom, err := app.StakingKeeper.BondDenom(ctx) From 27d7fddb675a32b8712205e9c35f401b6c78b078 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 16 Aug 2024 10:41:28 +0700 Subject: [PATCH 07/26] split InPlaceOption to another file --- ignite/pkg/chaincmd/chaincmd.go | 26 ------------------------ ignite/pkg/chaincmd/in-place-testnet.go | 27 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 26 deletions(-) create mode 100644 ignite/pkg/chaincmd/in-place-testnet.go diff --git a/ignite/pkg/chaincmd/chaincmd.go b/ignite/pkg/chaincmd/chaincmd.go index 5be1c5b9df..f21102eae6 100644 --- a/ignite/pkg/chaincmd/chaincmd.go +++ b/ignite/pkg/chaincmd/chaincmd.go @@ -421,32 +421,6 @@ 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 } diff --git a/ignite/pkg/chaincmd/in-place-testnet.go b/ignite/pkg/chaincmd/in-place-testnet.go new file mode 100644 index 0000000000..1085321db6 --- /dev/null +++ b/ignite/pkg/chaincmd/in-place-testnet.go @@ -0,0 +1,27 @@ +package chaincmd + +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) + } +} From 2a1904452bc0a77ba6163a5a40a4318eca6c6a5a Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 16 Aug 2024 12:27:42 +0700 Subject: [PATCH 08/26] remove OperatorAddress and use normal accounts --- ignite/cmd/testnet_inplace.go | 21 +++++++++++++++------ ignite/config/chain/v1/validator.go | 2 -- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index 2911ef9e9c..d85b835151 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -1,6 +1,8 @@ package ignitecmd import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v29/ignite/pkg/cliui" "github.com/ignite/cli/v29/ignite/services/chain" "github.com/spf13/cobra" @@ -80,10 +82,17 @@ func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { if err != nil { return err } - - var acc string - for _, i := range cfg.Accounts { - acc = acc + "," + i.Address + var operatorAddress sdk.ValAddress + var accounts string + for _, acc := range cfg.Accounts { + if cfg.Validators[0].Name == acc.Name { + accAddr, err := sdk.AccAddressFromBech32(acc.Address) + if err != nil { + return err + } + operatorAddress = sdk.ValAddress(accAddr) + } + accounts = accounts + "," + acc.Address } chainID, err := c.ID() @@ -93,8 +102,8 @@ func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { args := chain.InplaceArgs{ NewChainID: chainID, - NewOperatorAddress: cfg.Validators[0].OperatorAddress, - AcountsToFund: acc, + NewOperatorAddress: operatorAddress.String(), + AcountsToFund: accounts, } return c.TestNetInPlace(cmd.Context(), args) } diff --git a/ignite/config/chain/v1/validator.go b/ignite/config/chain/v1/validator.go index 259b60c255..9ee1e51103 100644 --- a/ignite/config/chain/v1/validator.go +++ b/ignite/config/chain/v1/validator.go @@ -9,8 +9,6 @@ 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."` From 6faece18346796e955041ec36bf2c946f9e1d981 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 16 Aug 2024 12:57:32 +0700 Subject: [PATCH 09/26] minor --- ignite/cmd/testnet_inplace.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index d85b835151..df8cc4b9c3 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -29,7 +29,6 @@ func NewTestNetInPlace() *cobra.Command { Configuration validators: validators: - name: alice - operatoraddress: cosmosvaloper1wa3u4knw74r598quvzydvca42qsmk6jr80u3rd home: "$HOME/.testchaind/validator1" `, Args: cobra.NoArgs, From 48ae91a0e8fa0640528e41beac7e9078fea1ccb7 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 16 Aug 2024 22:19:45 +0700 Subject: [PATCH 10/26] updates --- ignite/cmd/testnet_inplace.go | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index df8cc4b9c3..676d0ca7e5 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ignite/cli/v29/ignite/pkg/cliui" + "github.com/ignite/cli/v29/ignite/pkg/cosmosaccount" "github.com/ignite/cli/v29/ignite/services/chain" "github.com/spf13/cobra" ) @@ -81,17 +82,44 @@ func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { if err != nil { return err } + home, err := c.Home() + if err != nil { + return err + } + keyringbankend, err := c.KeyringBackend() + if err != nil { + return err + } + ca, err := cosmosaccount.New( + cosmosaccount.WithKeyringBackend(cosmosaccount.KeyringBackend(keyringbankend)), + cosmosaccount.WithHome(home), + ) + if err != nil { + return err + } + var operatorAddress sdk.ValAddress var accounts string for _, acc := range cfg.Accounts { + var sdkAcc cosmosaccount.Account + if sdkAcc, err = ca.GetByName(acc.Name); err != nil { + sdkAcc, _, err = ca.Create(acc.Name) + if err != nil { + return err + } + } + sdkAddr, err := sdkAcc.Address(getAddressPrefix(cmd)) + if err != nil { + return err + } if cfg.Validators[0].Name == acc.Name { - accAddr, err := sdk.AccAddressFromBech32(acc.Address) + accAddr, err := sdk.AccAddressFromBech32(sdkAddr) if err != nil { return err } operatorAddress = sdk.ValAddress(accAddr) } - accounts = accounts + "," + acc.Address + accounts = accounts + "," + sdkAddr } chainID, err := c.ID() From 75c501616d3c964531217ed3e66d226b7de1d3b7 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 16 Aug 2024 22:21:47 +0700 Subject: [PATCH 11/26] minor --- ignite/cmd/testnet_inplace.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index 676d0ca7e5..71fdbdc3d3 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -15,22 +15,6 @@ func NewTestNetInPlace() *cobra.Command { Short: "Create and start a testnet from current local state", Long: `Testnet in-place command is used to create and start a testnet from current local state. After utilizing this command the network will start. We can create testnet from mainnet state and mint more coins for accounts from config.yml file. - - In the config.yml file, there should be at least the address account to fund, operator address, home of the local state node. - - For example: - - Configuration acounts to fund: - accounts: - - name: alice - address: "cosmos1wa3u4knw74r598quvzydvca42qsmk6jrzmgy07" - - name: bob - address: "cosmos10uls38gddhhlywla0sjlvqg8pjvcffx4lu25c4" - - Configuration validators: - validators: - - name: alice - home: "$HOME/.testchaind/validator1" `, Args: cobra.NoArgs, RunE: testnetInPlaceHandler, From 7bd349028449618060b13db45d848a16c25f9d97 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Wed, 28 Aug 2024 23:11:30 +0700 Subject: [PATCH 12/26] updates docs --- docs/docs/03-CLI-Commands/01-cli-commands.md | 70 ++++++++++++++++++++ ignite/cmd/testnet_inplace.go | 8 +-- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/docs/docs/03-CLI-Commands/01-cli-commands.md b/docs/docs/03-CLI-Commands/01-cli-commands.md index e15f6b37a1..f029a32fad 100644 --- a/docs/docs/03-CLI-Commands/01-cli-commands.md +++ b/docs/docs/03-CLI-Commands/01-cli-commands.md @@ -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 @@ -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 \ No newline at end of file diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index 71fdbdc3d3..a539080ac7 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -12,10 +12,10 @@ import ( func NewTestNetInPlace() *cobra.Command { c := &cobra.Command{ Use: "in-place", - Short: "Create and start a testnet from current local state", - Long: `Testnet in-place command is used to create and start a testnet from current local state. - After utilizing this command the network will start. We can create testnet from mainnet state and mint more coins for accounts from config.yml file. - `, + 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, } From 0f4b8c64f380446b629eb2087304c053e85bf1b5 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Thu, 29 Aug 2024 11:05:27 +0700 Subject: [PATCH 13/26] minor typo --- ignite/cmd/cmd.go | 2 +- ignite/cmd/testnet.go | 6 +++--- ignite/cmd/testnet_inplace.go | 4 ++-- ignite/pkg/chaincmd/chaincmd.go | 4 ++-- ignite/services/chain/testnet.go | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ignite/cmd/cmd.go b/ignite/cmd/cmd.go index a0ea53a332..e2ab8930b8 100644 --- a/ignite/cmd/cmd.go +++ b/ignite/cmd/cmd.go @@ -89,7 +89,7 @@ To get started, create a blockchain: NewApp(), NewDoctor(), NewCompletionCmd(), - NewTestNet(), + NewTestnet(), ) c.AddCommand(deprecated()...) c.SetContext(ctx) diff --git a/ignite/cmd/testnet.go b/ignite/cmd/testnet.go index f2e8edb2f3..03e0068c06 100644 --- a/ignite/cmd/testnet.go +++ b/ignite/cmd/testnet.go @@ -4,8 +4,8 @@ import ( "github.com/spf13/cobra" ) -// NewTestNet returns a command that groups scaffolding related sub commands. -func NewTestNet() *cobra.Command { +// 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", @@ -17,7 +17,7 @@ func NewTestNet() *cobra.Command { } c.AddCommand( - NewTestNetInPlace(), + NewTestnetInPlace(), ) return c diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index a539080ac7..02fec3d71d 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/cobra" ) -func NewTestNetInPlace() *cobra.Command { +func NewTestnetInPlace() *cobra.Command { c := &cobra.Command{ Use: "in-place", Short: "Create and start a testnet from current local net state", @@ -116,5 +116,5 @@ func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { NewOperatorAddress: operatorAddress.String(), AcountsToFund: accounts, } - return c.TestNetInPlace(cmd.Context(), args) + return c.TestnetInPlace(cmd.Context(), args) } diff --git a/ignite/pkg/chaincmd/chaincmd.go b/ignite/pkg/chaincmd/chaincmd.go index f21102eae6..304064f67e 100644 --- a/ignite/pkg/chaincmd/chaincmd.go +++ b/ignite/pkg/chaincmd/chaincmd.go @@ -27,7 +27,7 @@ const ( commandUnsafeReset = "unsafe-reset-all" commandExport = "export" commandTendermint = "tendermint" - commandTestNetInPlace = "in-place-testnet" + commandTestnetInPlace = "in-place-testnet" optionHome = "--home" optionNode = "--node" @@ -193,7 +193,7 @@ func (c ChainCmd) InitCommand(moniker string) step.Option { // TestnetInPlaceCommand. func (c ChainCmd) TestnetInPlaceCommand(newChainID, newOperatorAddress string, options ...InPlaceOption) step.Option { command := []string{ - commandTestNetInPlace, + commandTestnetInPlace, newChainID, newOperatorAddress, } diff --git a/ignite/services/chain/testnet.go b/ignite/services/chain/testnet.go index 35910933f0..0415fc493a 100644 --- a/ignite/services/chain/testnet.go +++ b/ignite/services/chain/testnet.go @@ -13,7 +13,7 @@ type InplaceArgs struct { AcountsToFund string } -func (c Chain) TestNetInPlace(ctx context.Context, args InplaceArgs) error { +func (c Chain) TestnetInPlace(ctx context.Context, args InplaceArgs) error { commands, err := c.Commands(ctx) if err != nil { return err From 7b93ce15822d15b4de172a631a858f1c12072eee Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Thu, 29 Aug 2024 11:31:43 +0700 Subject: [PATCH 14/26] revert baseappOptions --- .../cmd/commands.go.plush | 61 +------------------ 1 file changed, 1 insertion(+), 60 deletions(-) diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush index b5d8f5b633..d9f4695bf8 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush @@ -133,66 +133,7 @@ func newApp( traceStore io.Writer, appOpts servertypes.AppOptions, ) servertypes.Application { - var cache storetypes.MultiStorePersistentCache - - if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) { - cache = store.NewCommitKVStoreCacheManager() - } - - skipUpgradeHeights := make(map[int64]bool) - for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { - skipUpgradeHeights[int64(h)] = true - } - - pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) - if err != nil { - panic(err) - } - - snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") - snapshotDB, err := dbm.NewDB("metadata", server.GetAppDBBackend(appOpts), snapshotDir) - if err != nil { - panic(err) - } - snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) - if err != nil { - panic(err) - } - - snapshotOptions := snapshottypes.NewSnapshotOptions( - cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval)), - cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent)), - ) - - homeDir := cast.ToString(appOpts.Get(flags.FlagHome)) - chainID := cast.ToString(appOpts.Get(flags.FlagChainID)) - - if chainID == "" { - // fallback to genesis chain-id - genDocFile := filepath.Join(homeDir, cast.ToString(appOpts.Get("genesis_file"))) - appGenesis, err := genutiltypes.AppGenesisFromFile(genDocFile) - if err != nil { - panic(err) - } - - chainID = appGenesis.ChainID - } - - baseappOptions := []func(*baseapp.BaseApp){ - baseapp.SetPruning(pruningOpts), - baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), - baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), - baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), - baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))), - baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), - baseapp.SetInterBlockCache(cache), - baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), - baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), - baseapp.SetSnapshot(snapshotStore, snapshotOptions), - baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))), - baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))), - baseapp.SetChainID(chainID), - } + baseappOptions := server.DefaultBaseappOptions(appOpts) app, err := app.New( logger, db, traceStore, true, From a12e78a903e5ad10695ffb4d88cb7c504eb8db5e Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Thu, 29 Aug 2024 11:41:28 +0700 Subject: [PATCH 15/26] minor --- .../files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush index d9f4695bf8..5388a9d8d7 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush @@ -3,16 +3,10 @@ package cmd import ( "errors" "io" - "path/filepath" "cosmossdk.io/log" - "cosmossdk.io/store" - "cosmossdk.io/store/snapshots" - snapshottypes "cosmossdk.io/store/snapshots/types" - storetypes "cosmossdk.io/store/types" confixcmd "cosmossdk.io/tools/confix/cmd" dbm "github.com/cosmos/cosmos-db" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/debug" "github.com/cosmos/cosmos-sdk/client/flags" @@ -28,8 +22,6 @@ import ( authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" - "github.com/spf13/cast" "github.com/spf13/cobra" "github.com/spf13/viper" From 6e27849176523464525c1451ac0d1944a11c7e9f Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Thu, 29 Aug 2024 12:02:50 +0700 Subject: [PATCH 16/26] display the logging --- ignite/pkg/chaincmd/runner/chain.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ignite/pkg/chaincmd/runner/chain.go b/ignite/pkg/chaincmd/runner/chain.go index 5102e2319e..cd71015f30 100644 --- a/ignite/pkg/chaincmd/runner/chain.go +++ b/ignite/pkg/chaincmd/runner/chain.go @@ -47,9 +47,13 @@ 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.") + runOptions := runOptions{ + stdout: os.Stdout, + stderr: os.Stderr, + } return r.run( ctx, - runOptions{}, + runOptions, r.chainCmd.TestnetInPlaceCommand(newChainID, newOperatorAddress, options...), ) } From 751aa8de913d1a1276daaef399688e960b9d5b1c Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Thu, 29 Aug 2024 12:05:55 +0700 Subject: [PATCH 17/26] minor --- ignite/pkg/chaincmd/runner/chain.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ignite/pkg/chaincmd/runner/chain.go b/ignite/pkg/chaincmd/runner/chain.go index cd71015f30..0b133a47d2 100644 --- a/ignite/pkg/chaincmd/runner/chain.go +++ b/ignite/pkg/chaincmd/runner/chain.go @@ -46,7 +46,6 @@ 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.") runOptions := runOptions{ stdout: os.Stdout, stderr: os.Stderr, From 81e1e7cf445a06bac62ed201cb3cd62deff72359 Mon Sep 17 00:00:00 2001 From: Duong NV | Decentrio Date: Fri, 30 Aug 2024 08:55:10 +0700 Subject: [PATCH 18/26] Update ignite/cmd/testnet_inplace.go Co-authored-by: Danilo Pantani --- ignite/cmd/testnet_inplace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index 02fec3d71d..d19d9ef732 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -70,7 +70,7 @@ func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { if err != nil { return err } - keyringbankend, err := c.KeyringBackend() + keyringBackend, err := c.KeyringBackend() if err != nil { return err } From cd06599ac2b4751dd9497ae1eb39c4b67a4ca94e Mon Sep 17 00:00:00 2001 From: Duong NV | Decentrio Date: Fri, 30 Aug 2024 08:55:51 +0700 Subject: [PATCH 19/26] Update ignite/services/chain/testnet.go Co-authored-by: Danilo Pantani --- ignite/services/chain/testnet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ignite/services/chain/testnet.go b/ignite/services/chain/testnet.go index 0415fc493a..eff8221311 100644 --- a/ignite/services/chain/testnet.go +++ b/ignite/services/chain/testnet.go @@ -6,7 +6,7 @@ import ( "os" ) -type InplaceArgs struct { +type InPlaceArgs struct { NewChainID string NewOperatorAddress string PrvKeyValidator string From b98ff334ec3af788be4f7bbc55b2e3abda438c15 Mon Sep 17 00:00:00 2001 From: Duong NV | Decentrio Date: Fri, 30 Aug 2024 08:56:08 +0700 Subject: [PATCH 20/26] Update ignite/services/chain/testnet.go Co-authored-by: Danilo Pantani --- ignite/services/chain/testnet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ignite/services/chain/testnet.go b/ignite/services/chain/testnet.go index eff8221311..7acf083f06 100644 --- a/ignite/services/chain/testnet.go +++ b/ignite/services/chain/testnet.go @@ -10,7 +10,7 @@ type InPlaceArgs struct { NewChainID string NewOperatorAddress string PrvKeyValidator string - AcountsToFund string + AccountsToFund string } func (c Chain) TestnetInPlace(ctx context.Context, args InplaceArgs) error { From 4cfa9e0346dbcd042fbda5673047e6874ff79ae1 Mon Sep 17 00:00:00 2001 From: Duong NV | Decentrio Date: Fri, 30 Aug 2024 08:58:50 +0700 Subject: [PATCH 21/26] Update ignite/cmd/testnet_inplace.go Co-authored-by: Danilo Pantani --- ignite/cmd/testnet_inplace.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index d19d9ef732..d54c524c2d 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -82,20 +82,27 @@ func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { return err } - var operatorAddress sdk.ValAddress - var accounts string + var ( + operatorAddress sdk.ValAddress + accounts string + accErr *cosmosaccount.AccountDoesNotExistError + ) for _, acc := range cfg.Accounts { - var sdkAcc cosmosaccount.Account - if sdkAcc, err = ca.GetByName(acc.Name); err != nil { + sdkAcc, err := ca.GetByName(acc.Name) + if !errors.As(err, &accErr) { sdkAcc, _, err = ca.Create(acc.Name) - if err != nil { - return err - } } + 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 { From 5d09ef52e35d9f0a5e34400346f4b2534a21db11 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 30 Aug 2024 09:25:12 +0700 Subject: [PATCH 22/26] updates --- ignite/cmd/testnet_inplace.go | 9 +++++---- ignite/services/chain/runtime.go | 4 ++-- ignite/services/chain/testnet.go | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index d54c524c2d..7e98e51cc9 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -5,6 +5,7 @@ import ( "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" "github.com/spf13/cobra" ) @@ -75,7 +76,7 @@ func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { return err } ca, err := cosmosaccount.New( - cosmosaccount.WithKeyringBackend(cosmosaccount.KeyringBackend(keyringbankend)), + cosmosaccount.WithKeyringBackend(cosmosaccount.KeyringBackend(keyringBackend)), cosmosaccount.WithHome(home), ) if err != nil { @@ -89,7 +90,7 @@ func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { ) for _, acc := range cfg.Accounts { sdkAcc, err := ca.GetByName(acc.Name) - if !errors.As(err, &accErr) { + if errors.As(err, &accErr) { sdkAcc, _, err = ca.Create(acc.Name) } if err != nil { @@ -118,10 +119,10 @@ func testnetInplace(cmd *cobra.Command, session *cliui.Session) error { return err } - args := chain.InplaceArgs{ + args := chain.InPlaceArgs{ NewChainID: chainID, NewOperatorAddress: operatorAddress.String(), - AcountsToFund: accounts, + AccountsToFund: accounts, } return c.TestnetInPlace(cmd.Context(), args) } diff --git a/ignite/services/chain/runtime.go b/ignite/services/chain/runtime.go index 5c7f94d5ef..a0eb21e1df 100644 --- a/ignite/services/chain/runtime.go +++ b/ignite/services/chain/runtime.go @@ -37,12 +37,12 @@ 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 { +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.InPlaceWithAccountToFund(args.AccountsToFund), chaincmd.InPlaceWithSkipConfirmation(), ) return err diff --git a/ignite/services/chain/testnet.go b/ignite/services/chain/testnet.go index 7acf083f06..d759486a4b 100644 --- a/ignite/services/chain/testnet.go +++ b/ignite/services/chain/testnet.go @@ -10,10 +10,10 @@ type InPlaceArgs struct { NewChainID string NewOperatorAddress string PrvKeyValidator string - AccountsToFund string + AccountsToFund string } -func (c Chain) TestnetInPlace(ctx context.Context, args InplaceArgs) error { +func (c Chain) TestnetInPlace(ctx context.Context, args InPlaceArgs) error { commands, err := c.Commands(ctx) if err != nil { return err From b86f129eaa6d76c6fdb1eb2b5b94fff3743288aa Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 30 Aug 2024 09:37:34 +0700 Subject: [PATCH 23/26] moves method TestnetInPlaceCommand to testnet file --- ignite/pkg/chaincmd/chaincmd.go | 16 ---------------- ignite/pkg/chaincmd/in-place-testnet.go | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/ignite/pkg/chaincmd/chaincmd.go b/ignite/pkg/chaincmd/chaincmd.go index 304064f67e..c45baf53fc 100644 --- a/ignite/pkg/chaincmd/chaincmd.go +++ b/ignite/pkg/chaincmd/chaincmd.go @@ -190,22 +190,6 @@ 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{ diff --git a/ignite/pkg/chaincmd/in-place-testnet.go b/ignite/pkg/chaincmd/in-place-testnet.go index 1085321db6..84a3b38465 100644 --- a/ignite/pkg/chaincmd/in-place-testnet.go +++ b/ignite/pkg/chaincmd/in-place-testnet.go @@ -1,5 +1,9 @@ package chaincmd +import ( + "github.com/ignite/cli/v29/ignite/pkg/cmdrunner/step" +) + type InPlaceOption func([]string) []string func InPlaceWithPrvKey(prvKey string) InPlaceOption { @@ -25,3 +29,19 @@ func InPlaceWithSkipConfirmation() InPlaceOption { 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) +} From f6180814b820ce526ba61358f65d34e1cbb7aa4d Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Fri, 30 Aug 2024 23:08:39 +0700 Subject: [PATCH 24/26] make format --- ignite/cmd/testnet_inplace.go | 3 ++- ignite/services/chain/testnet.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ignite/cmd/testnet_inplace.go b/ignite/cmd/testnet_inplace.go index 7e98e51cc9..17afb21f2a 100644 --- a/ignite/cmd/testnet_inplace.go +++ b/ignite/cmd/testnet_inplace.go @@ -3,11 +3,12 @@ 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" - "github.com/spf13/cobra" ) func NewTestnetInPlace() *cobra.Command { diff --git a/ignite/services/chain/testnet.go b/ignite/services/chain/testnet.go index d759486a4b..5a3b85d77b 100644 --- a/ignite/services/chain/testnet.go +++ b/ignite/services/chain/testnet.go @@ -2,8 +2,9 @@ package chain import ( "context" - chainconfig "github.com/ignite/cli/v29/ignite/config/chain" "os" + + chainconfig "github.com/ignite/cli/v29/ignite/config/chain" ) type InPlaceArgs struct { From b0759a15e00df05f8edbe36cef31c0225b53f86c Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Sat, 31 Aug 2024 00:01:14 +0700 Subject: [PATCH 25/26] remove setting slashing in testnet --- .../cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush index 6bfddd5d66..57f7077da3 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush @@ -21,7 +21,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/spf13/cast" "github.com/spf13/cobra" @@ -176,18 +175,7 @@ func initAppForTestnet(app *app.App, args valArgs) *app.App { app.DistrKeeper.SetValidatorCurrentRewards(ctx, validator, distrtypes.NewValidatorCurrentRewards(sdk.DecCoins{}, 1)) app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, validator, distrtypes.InitialValidatorAccumulatedCommission()) app.DistrKeeper.SetValidatorOutstandingRewards(ctx, validator, distrtypes.ValidatorOutstandingRewards{Rewards: sdk.DecCoins{}}) - - // SLASHING - // - - // Set validator signing info for our new validator. - newConsAddr := sdk.ConsAddress(args.newValAddr.Bytes()) - newValidatorSigningInfo := slashingtypes.ValidatorSigningInfo{ - Address: newConsAddr.String(), - StartHeight: app.LastBlockHeight() - 1, - Tombstoned: false, - } - app.SlashingKeeper.SetValidatorSigningInfo(ctx, newConsAddr, newValidatorSigningInfo) + // BANK // From 2579a64fd7c665f79f2c808cf343ce5eff9c64a2 Mon Sep 17 00:00:00 2001 From: Likes To Eat Fish Date: Sat, 31 Aug 2024 07:43:59 +0700 Subject: [PATCH 26/26] setting slashing --- .../cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush index 57f7077da3..0a02a3bdd7 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/testnet.go.plush @@ -21,6 +21,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/spf13/cast" "github.com/spf13/cobra" @@ -176,6 +177,19 @@ func initAppForTestnet(app *app.App, args valArgs) *app.App { app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, validator, distrtypes.InitialValidatorAccumulatedCommission()) app.DistrKeeper.SetValidatorOutstandingRewards(ctx, validator, distrtypes.ValidatorOutstandingRewards{Rewards: sdk.DecCoins{}}) +<%= if (!IsChainMinimal) { %> + // SLASHING + // + + // Set validator signing info for our new validator. + newConsAddr := sdk.ConsAddress(args.newValAddr.Bytes()) + newValidatorSigningInfo := slashingtypes.ValidatorSigningInfo{ + Address: newConsAddr.String(), + StartHeight: app.LastBlockHeight() - 1, + Tombstoned: false, + } + app.SlashingKeeper.SetValidatorSigningInfo(ctx, newConsAddr, newValidatorSigningInfo) +<% } %> // BANK //