-
Notifications
You must be signed in to change notification settings - Fork 258
feat(cmd/testnetify): backport testnetify from live blockchain state #1995
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,257 @@ | ||||||||||||
| package app | ||||||||||||
|
|
||||||||||||
| import ( | ||||||||||||
| "fmt" | ||||||||||||
| "strings" | ||||||||||||
| "time" | ||||||||||||
|
|
||||||||||||
| "github.com/cosmos/cosmos-sdk/codec/types" | ||||||||||||
| storetypes "github.com/cosmos/cosmos-sdk/store/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" | ||||||||||||
| upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" | ||||||||||||
| tmos "github.com/tendermint/tendermint/libs/os" | ||||||||||||
| tmproto "github.com/tendermint/tendermint/proto/tendermint/types" | ||||||||||||
|
|
||||||||||||
| utypes "github.com/akash-network/node/upgrades/types" | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| type TestnetValidator struct { | ||||||||||||
| OperatorAddress sdk.ValAddress | ||||||||||||
| ConsensusAddress sdk.ConsAddress | ||||||||||||
| ConsensusPubKey *types.Any | ||||||||||||
| Moniker string | ||||||||||||
| Commission stakingtypes.Commission | ||||||||||||
| MinSelfDelegation sdk.Int | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| type TestnetUpgrade struct { | ||||||||||||
| Name string | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| type TestnetVotingPeriod struct { | ||||||||||||
| time.Duration | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| type TestnetGovConfig struct { | ||||||||||||
| VotingParams *struct { | ||||||||||||
| VotingPeriod TestnetVotingPeriod `json:"voting_period,omitempty"` | ||||||||||||
| } `json:"voting_params,omitempty"` | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| type TestnetConfig struct { | ||||||||||||
| Accounts []sdk.AccAddress | ||||||||||||
| Validators []TestnetValidator | ||||||||||||
| Gov TestnetGovConfig | ||||||||||||
| Upgrade TestnetUpgrade | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| func TrimQuotes(data string) string { | ||||||||||||
| data = strings.TrimPrefix(data, "\"") | ||||||||||||
| return strings.TrimSuffix(data, "\"") | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| func (t *TestnetVotingPeriod) UnmarshalJSON(data []byte) error { | ||||||||||||
| val := TrimQuotes(string(data)) | ||||||||||||
|
|
||||||||||||
| if !strings.HasSuffix(val, "s") { | ||||||||||||
| return fmt.Errorf("invalid format of voting period. must contain time unit. Valid time units are ns|us(µs)|ms|s|m|h") // nolint: goerr113 | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| var err error | ||||||||||||
| t.Duration, err = time.ParseDuration(val) | ||||||||||||
| if err != nil { | ||||||||||||
| return err | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| return nil | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // InitAkashAppForTestnet 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 InitAkashAppForTestnet( | ||||||||||||
| app *AkashApp, | ||||||||||||
| tcfg *TestnetConfig, | ||||||||||||
| ) *AkashApp { | ||||||||||||
| // | ||||||||||||
| // Required Changes: | ||||||||||||
| // | ||||||||||||
|
|
||||||||||||
| var err error | ||||||||||||
|
|
||||||||||||
| defer func() { | ||||||||||||
| if err != nil { | ||||||||||||
| tmos.Exit(err.Error()) | ||||||||||||
| } | ||||||||||||
| }() | ||||||||||||
|
Comment on lines
+86
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using os.Exit in library functions. Using - defer func() {
- if err != nil {
- tmos.Exit(err.Error())
- }
- }()Instead, return the error and let the caller decide how to handle it.
🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| ctx := app.BaseApp.NewUncachedContext(true, tmproto.Header{}) | ||||||||||||
|
|
||||||||||||
| // Remove all validators from power store | ||||||||||||
| stakingKey := app.GetKey(stakingtypes.ModuleName) | ||||||||||||
| stakingStore := ctx.KVStore(stakingKey) | ||||||||||||
| iterator := app.Keepers.Cosmos.Staking.ValidatorsPowerStoreIterator(ctx) | ||||||||||||
|
|
||||||||||||
| for ; iterator.Valid(); iterator.Next() { | ||||||||||||
| stakingStore.Delete(iterator.Key()) | ||||||||||||
| } | ||||||||||||
| if err := iterator.Close(); err != nil { | ||||||||||||
| panic(err) | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // Remove all validators from last validators store | ||||||||||||
| iterator = app.Keepers.Cosmos.Staking.LastValidatorsIterator(ctx) | ||||||||||||
|
|
||||||||||||
| for ; iterator.Valid(); iterator.Next() { | ||||||||||||
| stakingStore.Delete(iterator.Key()) | ||||||||||||
| } | ||||||||||||
| if err := iterator.Close(); err != nil { | ||||||||||||
| panic(err) | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // Remove all validators from validator store | ||||||||||||
| iterator = storetypes.KVStorePrefixIterator(stakingStore, stakingtypes.ValidatorsKey) | ||||||||||||
| for ; iterator.Valid(); iterator.Next() { | ||||||||||||
| stakingStore.Delete(iterator.Key()) | ||||||||||||
| } | ||||||||||||
| if err := iterator.Close(); err != nil { | ||||||||||||
| panic(err) | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // Remove all validators from unbonding queue | ||||||||||||
| iterator = storetypes.KVStorePrefixIterator(stakingStore, stakingtypes.ValidatorQueueKey) | ||||||||||||
| for ; iterator.Valid(); iterator.Next() { | ||||||||||||
| stakingStore.Delete(iterator.Key()) | ||||||||||||
| } | ||||||||||||
| if err := iterator.Close(); err != nil { | ||||||||||||
| panic(err) | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| for _, val := range tcfg.Validators { | ||||||||||||
| // Create Validator struct for our new validator. | ||||||||||||
| newVal := stakingtypes.Validator{ | ||||||||||||
| OperatorAddress: val.OperatorAddress.String(), | ||||||||||||
| ConsensusPubkey: val.ConsensusPubKey, | ||||||||||||
| 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(), | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // Add our validator to power and last validators store | ||||||||||||
| app.Keepers.Cosmos.Staking.SetValidator(ctx, newVal) | ||||||||||||
| err = app.Keepers.Cosmos.Staking.SetValidatorByConsAddr(ctx, newVal) | ||||||||||||
| if err != nil { | ||||||||||||
| return nil | ||||||||||||
| } | ||||||||||||
troian marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||
|
|
||||||||||||
| app.Keepers.Cosmos.Staking.SetValidatorByPowerIndex(ctx, newVal) | ||||||||||||
|
|
||||||||||||
| valAddr := newVal.GetOperator() | ||||||||||||
| app.Keepers.Cosmos.Staking.SetLastValidatorPower(ctx, valAddr, 0) | ||||||||||||
|
|
||||||||||||
| app.Keepers.Cosmos.Distr.Hooks().AfterValidatorCreated(ctx, valAddr) | ||||||||||||
| app.Keepers.Cosmos.Slashing.Hooks().AfterValidatorCreated(ctx, valAddr) | ||||||||||||
|
|
||||||||||||
| // DISTRIBUTION | ||||||||||||
| // | ||||||||||||
|
|
||||||||||||
| // Initialize records for this validator across all distribution stores | ||||||||||||
| app.Keepers.Cosmos.Distr.SetValidatorHistoricalRewards(ctx, valAddr, 0, distrtypes.NewValidatorHistoricalRewards(sdk.DecCoins{}, 1)) | ||||||||||||
| app.Keepers.Cosmos.Distr.SetValidatorCurrentRewards(ctx, valAddr, distrtypes.NewValidatorCurrentRewards(sdk.DecCoins{}, 1)) | ||||||||||||
| app.Keepers.Cosmos.Distr.SetValidatorAccumulatedCommission(ctx, valAddr, distrtypes.InitialValidatorAccumulatedCommission()) | ||||||||||||
| app.Keepers.Cosmos.Distr.SetValidatorOutstandingRewards(ctx, valAddr, distrtypes.ValidatorOutstandingRewards{Rewards: sdk.DecCoins{}}) | ||||||||||||
|
|
||||||||||||
| // SLASHING | ||||||||||||
| // | ||||||||||||
|
|
||||||||||||
| newConsAddr := val.ConsensusAddress | ||||||||||||
|
|
||||||||||||
| // Set validator signing info for our new validator. | ||||||||||||
| newValidatorSigningInfo := slashingtypes.ValidatorSigningInfo{ | ||||||||||||
| Address: newConsAddr.String(), | ||||||||||||
| StartHeight: app.LastBlockHeight() - 1, | ||||||||||||
| Tombstoned: false, | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| _, _ = app.Keepers.Cosmos.Staking.ApplyAndReturnValidatorSetUpdates(ctx) | ||||||||||||
|
|
||||||||||||
| app.Keepers.Cosmos.Slashing.SetValidatorSigningInfo(ctx, newConsAddr, newValidatorSigningInfo) | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // | ||||||||||||
| // Optional Changes: | ||||||||||||
| // | ||||||||||||
|
|
||||||||||||
| // GOV | ||||||||||||
| // | ||||||||||||
|
|
||||||||||||
| voteParams := app.Keepers.Cosmos.Gov.GetVotingParams(ctx) | ||||||||||||
| voteParams.VotingPeriod = tcfg.Gov.VotingParams.VotingPeriod.Duration | ||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add nil check for VotingParams. Accessing + if tcfg.Gov.VotingParams != nil {
voteParams.VotingPeriod = tcfg.Gov.VotingParams.VotingPeriod.Duration
app.Keepers.Cosmos.Gov.SetVotingParams(ctx, voteParams)
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||
| app.Keepers.Cosmos.Gov.SetVotingParams(ctx, voteParams) | ||||||||||||
|
|
||||||||||||
| // BANK | ||||||||||||
| // | ||||||||||||
|
|
||||||||||||
| defaultCoins := sdk.NewCoins( | ||||||||||||
| sdk.NewInt64Coin("uakt", 1000000000000), | ||||||||||||
| sdk.NewInt64Coin("ibc/12C6A0C374171B595A0A9E18B83FA09D295FB1F2D8C6DAA3AC28683471752D84", 1000000000000), // axlUSDC | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| for _, account := range tcfg.Accounts { | ||||||||||||
| err := app.Keepers.Cosmos.Bank.MintCoins(ctx, minttypes.ModuleName, defaultCoins) | ||||||||||||
| if err != nil { | ||||||||||||
| return nil | ||||||||||||
| } | ||||||||||||
| err = app.Keepers.Cosmos.Bank.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, account, defaultCoins) | ||||||||||||
| if err != nil { | ||||||||||||
| return nil | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // UPGRADE | ||||||||||||
| // | ||||||||||||
| if tcfg.Upgrade.Name != "" { | ||||||||||||
| upgradePlan := upgradetypes.Plan{ | ||||||||||||
| Name: tcfg.Upgrade.Name, | ||||||||||||
| Height: app.LastBlockHeight() + 10, | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| err = app.Keepers.Cosmos.Upgrade.ScheduleUpgrade(ctx, upgradePlan) | ||||||||||||
| if err != nil { | ||||||||||||
| panic(err) | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| for name, fn := range utypes.GetUpgradesList() { | ||||||||||||
| upgrade, err := fn(app.Logger(), &app.App) | ||||||||||||
| if err != nil { | ||||||||||||
| panic(err) | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if tcfg.Upgrade.Name == name { | ||||||||||||
| app.Logger().Info(fmt.Sprintf("configuring upgrade `%s`", name)) | ||||||||||||
| if storeUpgrades := upgrade.StoreLoader(); storeUpgrades != nil && tcfg.Upgrade.Name == name { | ||||||||||||
| app.Logger().Info(fmt.Sprintf("setting up store upgrades for `%s`", name)) | ||||||||||||
| app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(app.LastBlockHeight(), storeUpgrades)) | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| return app | ||||||||||||
| } | ||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "io" | ||
|
|
||
| "github.com/tendermint/tendermint/libs/log" | ||
| dbm "github.com/tendermint/tm-db" | ||
|
|
||
| servertypes "github.com/cosmos/cosmos-sdk/server/types" | ||
|
|
||
| akash "github.com/akash-network/node/app" | ||
| "github.com/akash-network/node/cmd/akash/cmd/testnetify" | ||
| ) | ||
|
|
||
| // 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 AkashApp | ||
| app := newApp(logger, db, traceStore, appOpts) | ||
| akashApp, ok := app.(*akash.AkashApp) | ||
| if !ok { | ||
| panic("app created from newApp is not of type AkashApp") | ||
| } | ||
|
|
||
| tcfg, valid := appOpts.Get(testnetify.KeyTestnetConfig).(*akash.TestnetConfig) | ||
| if !valid { | ||
| panic("cflags.KeyTestnetConfig is not of type akash.TestnetConfig") | ||
| } | ||
|
|
||
| // Make modifications to the normal AkashApp required to run the network locally | ||
| return akash.InitAkashAppForTestnet(akashApp, tcfg) | ||
| } |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove overly restrictive time unit validation.
The validation only allows durations ending with 's', but Go's
time.ParseDurationsupports multiple units (ns, us, µs, ms, s, m, h). The error message mentions these units but the code rejects them.📝 Committable suggestion
🤖 Prompt for AI Agents