Skip to content

Commit

Permalink
feat: in-place testnet creator (#7374)
Browse files Browse the repository at this point in the history
* plug in testnetify

* fix import

* utilize appOpts

* add upgrade trigger

* update sdk fork tag

* add changelog
  • Loading branch information
czarcas7ic authored Feb 6, 2024
1 parent c5313af commit 0b32654
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Misc Improvements

* [#7360](https://github.com/osmosis-labs/osmosis/pull/7360) Bump cometbft-db from 0.8.0 to 0.10.0
* [#7374](https://github.com/osmosis-labs/osmosis/pull/7374) In place testnet creation CLI
* [#7385](https://github.com/osmosis-labs/osmosis/pull/7385) Add missing protobuf interface

### Config
Expand Down
231 changes: 231 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"reflect"
"time"

wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"

Expand Down Expand Up @@ -41,12 +42,15 @@ import (

autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"

runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services"

"github.com/CosmWasm/wasmd/x/wasm"
dbm "github.com/cometbft/cometbft-db"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cometbft/cometbft/crypto"
"github.com/cometbft/cometbft/libs/bytes"
tmjson "github.com/cometbft/cometbft/libs/json"
"github.com/cometbft/cometbft/libs/log"
tmos "github.com/cometbft/cometbft/libs/os"
Expand All @@ -66,12 +70,14 @@ import (
"github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/bech32"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/cosmos/cosmos-sdk/x/crisis"

minttypes "github.com/osmosis-labs/osmosis/v22/x/mint/types"
protorevtypes "github.com/osmosis-labs/osmosis/v22/x/protorev/types"

"github.com/osmosis-labs/osmosis/v22/app/keepers"
Expand Down Expand Up @@ -404,6 +410,231 @@ func NewOsmosisApp(
return app
}

// InitOsmosisAppForTestnet 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 InitOsmosisAppForTestnet(app *OsmosisApp, newValAddr bytes.HexBytes, newValPubKey crypto.PubKey, newOperatorAddress, upgradeToTrigger string) *OsmosisApp {
//
// Required Changes:
//

ctx := app.BaseApp.NewUncachedContext(true, tmproto.Header{})
pubkey := &ed25519.PubKey{Key: newValPubKey.Bytes()}
pubkeyAny, err := types.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("osmovaloper", bz)
if err != nil {
tmos.Exit(err.Error())
}
newVal := stakingtypes.Validator{
OperatorAddress: bech32Addr,
ConsensusPubkey: pubkeyAny,
Jailed: false,
Status: stakingtypes.Bonded,
Tokens: sdk.NewInt(900000000000000),
DelegatorShares: sdk.MustNewDecFromStr("10000000"),
Description: stakingtypes.Description{
Moniker: "Testnet Validator",
},
Commission: stakingtypes.Commission{
CommissionRates: stakingtypes.CommissionRates{
Rate: sdk.MustNewDecFromStr("0.05"),
MaxRate: sdk.MustNewDecFromStr("0.1"),
MaxChangeRate: sdk.MustNewDecFromStr("0.05"),
},
},
MinSelfDelegation: sdk.OneInt(),
}

// Remove all validators from power store
stakingKey := app.GetKey(stakingtypes.ModuleName)
stakingStore := ctx.KVStore(stakingKey)
iterator := app.StakingKeeper.ValidatorsPowerStoreIterator(ctx)
for ; iterator.Valid(); iterator.Next() {
stakingStore.Delete(iterator.Key())
}
iterator.Close()

// Remove all valdiators from last validators store
iterator = app.StakingKeeper.LastValidatorsIterator(ctx)
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, newVal.GetOperator(), 0)
if err := app.StakingKeeper.Hooks().AfterValidatorCreated(ctx, newVal.GetOperator()); err != nil {
panic(err)
}

// DISTRIBUTION
//

// Initialize records for this validator across all distribution stores
app.DistrKeeper.SetValidatorHistoricalRewards(ctx, newVal.GetOperator(), 0, distrtypes.NewValidatorHistoricalRewards(sdk.DecCoins{}, 1))
app.DistrKeeper.SetValidatorCurrentRewards(ctx, newVal.GetOperator(), distrtypes.NewValidatorCurrentRewards(sdk.DecCoins{}, 1))
app.DistrKeeper.SetValidatorAccumulatedCommission(ctx, newVal.GetOperator(), distrtypes.InitialValidatorAccumulatedCommission())
app.DistrKeeper.SetValidatorOutstandingRewards(ctx, newVal.GetOperator(), 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:
//

// GOV
//

newExpeditedVotingPeriod := time.Minute
newVotingPeriod := time.Minute * 2

govParams := app.GovKeeper.GetParams(ctx)
govParams.ExpeditedVotingPeriod = &newExpeditedVotingPeriod
govParams.VotingPeriod = &newVotingPeriod
govParams.MinDeposit = sdk.NewCoins(sdk.NewInt64Coin("uosmo", 100000000))
govParams.ExpeditedMinDeposit = sdk.NewCoins(sdk.NewInt64Coin("uosmo", 150000000))

err = app.GovKeeper.SetParams(ctx, govParams)
if err != nil {
tmos.Exit(err.Error())
}

// EPOCHS
//

dayEpochInfo := app.EpochsKeeper.GetEpochInfo(ctx, "day")
dayEpochInfo.Duration = time.Hour * 6
// Prevents epochs from running back to back
dayEpochInfo.CurrentEpochStartTime = time.Now().UTC()
dayEpochInfo.CurrentEpochStartHeight = app.LastBlockHeight()
app.EpochsKeeper.DeleteEpochInfo(ctx, "day")
err = app.EpochsKeeper.AddEpochInfo(ctx, dayEpochInfo)
if err != nil {
tmos.Exit(err.Error())
}

weekEpochInfo := app.EpochsKeeper.GetEpochInfo(ctx, "week")
weekEpochInfo.Duration = time.Hour * 12
// Prevents epochs from running back to back
weekEpochInfo.CurrentEpochStartTime = time.Now().UTC()
weekEpochInfo.CurrentEpochStartHeight = app.LastBlockHeight()
app.EpochsKeeper.DeleteEpochInfo(ctx, "week")
err = app.EpochsKeeper.AddEpochInfo(ctx, weekEpochInfo)
if err != nil {
tmos.Exit(err.Error())
}

// BANK
//

defaultCoins := sdk.NewCoins(
sdk.NewInt64Coin("ibc/0CD3A0285E1341859B5E86B6AB7682F023D03E97607CCC1DC95706411D866DF7", 1000000000000), // DAI
sdk.NewInt64Coin("uosmo", 1000000000000),
sdk.NewInt64Coin("uion", 1000000000))

localOsmosisAccounts := []sdk.AccAddress{
sdk.MustAccAddressFromBech32("osmo12smx2wdlyttvyzvzg54y2vnqwq2qjateuf7thj"),
sdk.MustAccAddressFromBech32("osmo1cyyzpxplxdzkeea7kwsydadg87357qnahakaks"),
sdk.MustAccAddressFromBech32("osmo18s5lynnmx37hq4wlrw9gdn68sg2uxp5rgk26vv"),
sdk.MustAccAddressFromBech32("osmo1qwexv7c6sm95lwhzn9027vyu2ccneaqad4w8ka"),
sdk.MustAccAddressFromBech32("osmo14hcxlnwlqtq75ttaxf674vk6mafspg8xwgnn53"),
sdk.MustAccAddressFromBech32("osmo12rr534cer5c0vj53eq4y32lcwguyy7nndt0u2t"),
sdk.MustAccAddressFromBech32("osmo1nt33cjd5auzh36syym6azgc8tve0jlvklnq7jq"),
sdk.MustAccAddressFromBech32("osmo10qfrpash5g2vk3hppvu45x0g860czur8ff5yx0"),
sdk.MustAccAddressFromBech32("osmo1f4tvsdukfwh6s9swrc24gkuz23tp8pd3e9r5fa"),
sdk.MustAccAddressFromBech32("osmo1myv43sqgnj5sm4zl98ftl45af9cfzk7nhjxjqh"),
sdk.MustAccAddressFromBech32("osmo14gs9zqh8m49yy9kscjqu9h72exyf295afg6kgk"),
sdk.MustAccAddressFromBech32("osmo1jllfytsz4dryxhz5tl7u73v29exsf80vz52ucc")}

// Fund localosmosis accounts
for _, account := range localOsmosisAccounts {
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("ibc/0CD3A0285E1341859B5E86B6AB7682F023D03E97607CCC1DC95706411D866DF7", 1000000000000000), // DAI
sdk.NewInt64Coin("uosmo", 1000000000000000),
sdk.NewInt64Coin("uion", 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("osmo1rqgf207csps822qwmd3k2n6k6k4e99w502e79t"), faucetCoins)
if err != nil {
tmos.Exit(err.Error())
}

// Mars bank account
marsCoins := sdk.NewCoins(
sdk.NewInt64Coin("uosmo", 10000000000000),
sdk.NewInt64Coin("ibc/903A61A498756EA560B85A85132D3AEE21B5DEDD41213725D22ABF276EA6945E", 400000000000),
sdk.NewInt64Coin("ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858", 3000000000000),
sdk.NewInt64Coin("ibc/C140AFD542AE77BD7DCC83F13FDD8C5E5BB8C4929785E6EC2F4C636F98F17901", 200000000000),
sdk.NewInt64Coin("ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2", 700000000000),
sdk.NewInt64Coin("ibc/D1542AA8762DB13087D8364F3EA6509FD6F009A34F00426AF9E4F9FA85CBBF1F", 2000000000),
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("osmo1ev02crc36675xd8s029qh7wg3wjtfk37jr004z"), marsCoins)
if err != nil {
tmos.Exit(err.Error())
}

// UPGRADE
//

if upgradeToTrigger != "" {
upgradePlan := upgradetypes.Plan{
Name: upgradeToTrigger,
Height: app.LastBlockHeight(),
}
err = app.UpgradeKeeper.ScheduleUpgrade(ctx, upgradePlan)
if err != nil {
panic(err)
}
}

return app
}

// MakeCodecs returns the application codec and a legacy Amino codec.
func MakeCodecs() (codec.Codec, *codec.LegacyAmino) {
config := MakeEncodingConfig()
Expand Down
59 changes: 53 additions & 6 deletions cmd/osmosisd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ import (

"github.com/osmosis-labs/osmosis/osmomath"
"github.com/osmosis-labs/osmosis/v22/app/params"
v23 "github.com/osmosis-labs/osmosis/v22/app/upgrades/v23" // should be automated to be updated to current version every upgrade
"github.com/osmosis-labs/osmosis/v22/ingest/sqs"

tmcfg "github.com/cometbft/cometbft/config"
"github.com/cometbft/cometbft/crypto"
"github.com/cometbft/cometbft/libs/bytes"
tmcli "github.com/cometbft/cometbft/libs/cli"
"github.com/cometbft/cometbft/libs/log"
tmtypes "github.com/cometbft/cometbft/types"
Expand Down Expand Up @@ -55,6 +58,7 @@ import (
genutil "github.com/cosmos/cosmos-sdk/x/genutil"
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

"github.com/CosmWasm/wasmd/x/wasm"
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
Expand Down Expand Up @@ -682,6 +686,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
)

server.AddCommands(rootCmd, osmosis.DefaultNodeHome, newApp, createOsmosisAppAndExport, addModuleInitFlags)
server.AddTestnetCreatorCommand(rootCmd, osmosis.DefaultNodeHome, newTestnetApp, addModuleInitFlags)

for i, cmd := range rootCmd.Commands() {
if cmd.Name() == "start" {
Expand Down Expand Up @@ -828,12 +833,7 @@ func newApp(logger log.Logger, db cometbftdb.DB, traceStore io.Writer, appOpts s
wasmOpts = append(wasmOpts, wasmkeeper.WithVMCacheMetrics(prometheus.DefaultRegisterer))
}

return osmosis.NewOsmosisApp(
logger, db, traceStore, true, skipUpgradeHeights,
cast.ToString(appOpts.Get(flags.FlagHome)),
cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)),
appOpts,
wasmOpts,
baseAppOptions := []func(*baseapp.BaseApp){
baseapp.SetPruning(pruningOpts),
baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))),
baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))),
Expand All @@ -847,9 +847,56 @@ func newApp(logger log.Logger, db cometbftdb.DB, traceStore io.Writer, appOpts s
baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))),
baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))),
baseapp.SetChainID(chainID),
}

// If this is an in place testnet, set any new stores that may exist
if cast.ToBool(appOpts.Get(server.KeyIsTestnet)) {
version := store.NewCommitMultiStore(db).LatestVersion() + 1
fmt.Println("version", version)
baseAppOptions = append(baseAppOptions, baseapp.SetStoreLoader(upgradetypes.UpgradeStoreLoader(version, &v23.Upgrade.StoreUpgrades)))
}

return osmosis.NewOsmosisApp(
logger, db, traceStore, true, skipUpgradeHeights,
cast.ToString(appOpts.Get(flags.FlagHome)),
cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)),
appOpts,
wasmOpts,
baseAppOptions...,
)
}

// 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 cometbftdb.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application {
// Create an app and type cast to an OsmosisApp
app := newApp(logger, db, traceStore, appOpts)
osmosisApp, ok := app.(*osmosis.OsmosisApp)
if !ok {
panic("app created from newApp is not of type osmosisApp")
}

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

// Make modifications to the normal OsmosisApp required to run the network locally
return osmosis.InitOsmosisAppForTestnet(osmosisApp, newValAddr, newValPubKey, newOperatorAddress, upgradeToTrigger)
}

// createOsmosisAppAndExport creates and exports the new Osmosis app, returns the state of the new Osmosis app for a genesis file.
func createOsmosisAppAndExport(
logger log.Logger, db cometbftdb.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string,
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,9 @@ replace (
// v1.0.0-beta.3 is incompatible, so we use v1.0.0-beta.2
github.com/cosmos/cosmos-proto => github.com/cosmos/cosmos-proto v1.0.0-beta.2

// Our cosmos-sdk branch is: https://github.com/osmosis-labs/cosmos-sdk/tree/osmo-v22/v0.47.5, current branch: osmo-v22/v0.47.5. Direct commit link: https://github.com/osmosis-labs/cosmos-sdk/commit/cf358f6fc20cabfb5cb8ce75fc10b2623150869e
// Our cosmos-sdk branch is: https://github.com/osmosis-labs/cosmos-sdk/tree/osmo-v22/v0.47.5, current branch: osmo-v22/v0.47.5. Direct commit link: https://github.com/osmosis-labs/cosmos-sdk/commit/97b06aa49e4c814f9ec4e64be2d5eaf7be42a259
// https://github.com/osmosis-labs/cosmos-sdk/releases/tag/v0.47.5-v22-osmo-2
github.com/cosmos/cosmos-sdk => github.com/osmosis-labs/cosmos-sdk v0.47.5-v22-osmo-2
github.com/cosmos/cosmos-sdk => github.com/osmosis-labs/cosmos-sdk v0.47.5-v22-osmo-3
github.com/cosmos/gogoproto => github.com/cosmos/gogoproto v1.4.10
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1

Expand Down
Loading

0 comments on commit 0b32654

Please sign in to comment.