Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: int in-place testnet creation #4297

Merged
merged 40 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
490cb6f
int in-place testnet creation
likesToEatFish Aug 9, 2024
7867c87
merge main
likesToEatFish Aug 9, 2024
6e51b12
takes many arguments for command and move dependencies to testnet file
likesToEatFish Aug 12, 2024
01b6af7
Merge branch 'main' into duong/in-place-testnet
likesToEatFish Aug 12, 2024
21bc6c2
changelog
likesToEatFish Aug 12, 2024
6e3c919
add command testnet inplace
likesToEatFish Aug 13, 2024
8ccfebc
Merge pull request #1 from likesToEatFish/dong/cmdignitetestnet
likesToEatFish Aug 13, 2024
9a1bd7f
Merge branch 'main' into duong/in-place-testnet
likesToEatFish Aug 13, 2024
376beb4
updates
likesToEatFish Aug 13, 2024
6976bc3
minor
likesToEatFish Aug 16, 2024
27d7fdd
split InPlaceOption to another file
likesToEatFish Aug 16, 2024
2a19044
remove OperatorAddress and use normal accounts
likesToEatFish Aug 16, 2024
6ad2f1f
Merge pull request #2 from likesToEatFish/duong/3000
likesToEatFish Aug 16, 2024
6faece1
minor
likesToEatFish Aug 16, 2024
48ae91a
updates
likesToEatFish Aug 16, 2024
75c5016
minor
likesToEatFish Aug 16, 2024
99dcc09
Merge pull request #3 from likesToEatFish/duong/3000
likesToEatFish Aug 16, 2024
52bc3d1
Merge branch 'main' into duong/in-place-testnet
likesToEatFish Aug 16, 2024
88aca11
Merge branch 'main' into duong/in-place-testnet
likesToEatFish Aug 19, 2024
7bd3490
updates docs
likesToEatFish Aug 28, 2024
882780d
Merge branch 'main' into duong/in-place-testnet
likesToEatFish Aug 28, 2024
0f4b8c6
minor typo
likesToEatFish Aug 29, 2024
7b93ce1
revert baseappOptions
likesToEatFish Aug 29, 2024
a12e78a
minor
likesToEatFish Aug 29, 2024
6e27849
display the logging
likesToEatFish Aug 29, 2024
751aa8d
minor
likesToEatFish Aug 29, 2024
fc295c9
Merge branch 'main' into duong/in-place-testnet
likesToEatFish Aug 29, 2024
5130a8c
Merge branch 'main' into duong/in-place-testnet
Pantani Aug 29, 2024
81e1e7c
Update ignite/cmd/testnet_inplace.go
likesToEatFish Aug 30, 2024
cd06599
Update ignite/services/chain/testnet.go
likesToEatFish Aug 30, 2024
b98ff33
Update ignite/services/chain/testnet.go
likesToEatFish Aug 30, 2024
4cfa9e0
Update ignite/cmd/testnet_inplace.go
likesToEatFish Aug 30, 2024
5d09ef5
updates
likesToEatFish Aug 30, 2024
b86f129
moves method TestnetInPlaceCommand to testnet file
likesToEatFish Aug 30, 2024
2a4a60d
Merge branch 'main' into duong/in-place-testnet
Pantani Aug 30, 2024
f618081
make format
likesToEatFish Aug 30, 2024
b0759a1
remove setting slashing in testnet
likesToEatFish Aug 30, 2024
2579a64
setting slashing
likesToEatFish Aug 31, 2024
67dd7f1
Merge branch 'main' into duong/in-place-testnet
likesToEatFish Aug 31, 2024
66e4032
Merge branch 'main' into duong/in-place-testnet
julienrbrt Sep 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 203 additions & 0 deletions ignite/templates/app/files/app/app.go.plush
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -403,3 +413,196 @@ func BlockedAddresses() map[string]bool {
}
return result
}

// InitAppForTestnet is broken down into two sections:
likesToEatFish marked this conversation as resolved.
Show resolved Hide resolved
// 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)
likesToEatFish marked this conversation as resolved.
Show resolved Hide resolved
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:
likesToEatFish marked this conversation as resolved.
Show resolved Hide resolved
// ==============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{
likesToEatFish marked this conversation as resolved.
Show resolved Hide resolved
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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"

Expand All @@ -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(),
Expand Down Expand Up @@ -124,7 +136,66 @@ func newApp(
traceStore io.Writer,
appOpts servertypes.AppOptions,
) servertypes.Application {
baseappOptions := server.DefaultBaseappOptions(appOpts)
var cache storetypes.MultiStorePersistentCache
likesToEatFish marked this conversation as resolved.
Show resolved Hide resolved

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,
Expand Down Expand Up @@ -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)
}
Loading
Loading