Some checks are pending
Docs Deploy / build_and_deploy (push) Waiting to run
Generate Docs / cli (push) Waiting to run
Generate Config Doc / cli (push) Waiting to run
Go formatting / go-formatting (push) Waiting to run
Check links / markdown-link-check (push) Waiting to run
Integration / pre-test (push) Waiting to run
Integration / test on (push) Blocked by required conditions
Integration / status (push) Blocked by required conditions
Lint / Lint Go code (push) Waiting to run
Test / test (ubuntu-latest) (push) Waiting to run
1187 lines
34 KiB
Markdown
1187 lines
34 KiB
Markdown
---
|
|
sidebar_position: 994
|
|
title: v0.25.0
|
|
description: For chains that were scaffolded with Ignite CLI versions lower than v0.25.0. changes are required to use Ignite CLI v0.25.0.
|
|
---
|
|
|
|
## Protobuf directory migration
|
|
|
|
`v0.25.0` changes the location of scaffolded `.proto` files. Previously, `.proto` files were located in `./proto/{moduleName}/`,
|
|
where `moduleName` is the same name of the Cosmos SDK module found in `./x/{moduleName}/`. This new version of `ignite`
|
|
modifies the scaffolded protobuf files so that they are now generated in `./proto/{appName}/{moduleName}`.
|
|
|
|
The only change that is needed to be made is to create an `{appName}` folder in the `proto` directory, and then place the
|
|
sub-directories within it. An example below demonstrates this change:
|
|
|
|
### Previous Directory Structure
|
|
|
|
This example shows a chain that was generated using `ignite` with `v0.24.0` using the following command:
|
|
|
|
```bash
|
|
ignite s chain github.com/cosmos/planet --no-module
|
|
ignite s module mars
|
|
```
|
|
|
|
```bash
|
|
├── app
|
|
├── cmd
|
|
├── docs
|
|
├── proto
|
|
│ ├── mars
|
|
├── x
|
|
│ ├── mars
|
|
├── README.md
|
|
├── config.yml
|
|
├── go.mod
|
|
├── go.sum
|
|
└── .gitignore
|
|
```
|
|
|
|
### `v0.25.0` Directory Structure
|
|
|
|
This example shows a chain that was generated using `ignite` with `v0.25.0` using the following command:
|
|
|
|
```bash
|
|
ignite s chain github.com/cosmos/planet --no-module
|
|
ignite s module mars
|
|
```
|
|
|
|
```bash
|
|
├── app
|
|
├── cmd
|
|
├── docs
|
|
├── proto
|
|
│ ├── planet
|
|
│ │ ├── mars
|
|
├── x
|
|
│ ├── mars
|
|
├── README.md
|
|
├── config.yml
|
|
├── go.mod
|
|
├── go.sum
|
|
└── .gitignore
|
|
```
|
|
|
|
The only difference is the additional directory `planet` which is the name of the application. The name of the app can
|
|
be verified by checking the package in the `go.mod` file. In this example, the package is `github.com/cosmos/planet`
|
|
where `planet` is the app name.
|
|
|
|
---
|
|
|
|
## Removing `cosmoscmd`
|
|
|
|
`v0.25.0` removes the `cosmoscmd` package from scaffolded chains. This package provided utility for creating
|
|
commands and starting up their application. The `cosmoscmd` package is now deprecated, and it is suggested that chains
|
|
implement this functionality in their codebase so they can be more easily upgraded and customized.
|
|
|
|
The main functionality of `cosmoscmd` will be moved to the `app` package of your chain. Some imports in these
|
|
examples contain the sample string, `{ModulePath}`. Replace this string with the Go module path of your blockchain.
|
|
For example, if your blockchain module path is `github.com/planet/mars`, `{ModulePath}/app/params` would be become
|
|
`github.com/planet/mars/app/params`.
|
|
|
|
#### Migration in `app` package
|
|
|
|
To begin, create a new file, `./app/params/encoding.go`, containing the following code:
|
|
|
|
```go
|
|
package params
|
|
|
|
import (
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
"github.com/cosmos/cosmos-sdk/codec/types"
|
|
)
|
|
|
|
// EncodingConfig specifies the concrete encoding types to use for a given app.
|
|
// This is provided for compatibility between protobuf and amino implementations.
|
|
type EncodingConfig struct {
|
|
InterfaceRegistry types.InterfaceRegistry
|
|
Marshaler codec.Codec
|
|
TxConfig client.TxConfig
|
|
Amino *codec.LegacyAmino
|
|
}
|
|
```
|
|
|
|
Next, create a new file, `./app/encoding.go`, containing the following code:
|
|
|
|
```go
|
|
package app
|
|
|
|
import (
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
"github.com/cosmos/cosmos-sdk/codec/types"
|
|
"github.com/cosmos/cosmos-sdk/std"
|
|
"github.com/cosmos/cosmos-sdk/x/auth/tx"
|
|
|
|
"{ModulePath}/app/params"
|
|
)
|
|
|
|
// makeEncodingConfig creates an EncodingConfig for an amino based test configuration.
|
|
func makeEncodingConfig() params.EncodingConfig {
|
|
amino := codec.NewLegacyAmino()
|
|
interfaceRegistry := types.NewInterfaceRegistry()
|
|
marshaler := codec.NewProtoCodec(interfaceRegistry)
|
|
txCfg := tx.NewTxConfig(marshaler, tx.DefaultSignModes)
|
|
|
|
return params.EncodingConfig{
|
|
InterfaceRegistry: interfaceRegistry,
|
|
Marshaler: marshaler,
|
|
TxConfig: txCfg,
|
|
Amino: amino,
|
|
}
|
|
}
|
|
|
|
// MakeEncodingConfig creates an EncodingConfig for testing
|
|
func MakeEncodingConfig() params.EncodingConfig {
|
|
encodingConfig := makeEncodingConfig()
|
|
std.RegisterLegacyAminoCodec(encodingConfig.Amino)
|
|
std.RegisterInterfaces(encodingConfig.InterfaceRegistry)
|
|
ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino)
|
|
ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry)
|
|
return encodingConfig
|
|
}
|
|
```
|
|
|
|
Next, modify `./app/simulation_test.go` so that it looks like the following:
|
|
|
|
```go
|
|
package app_test
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/cosmos/cosmos-sdk/simapp"
|
|
simulationtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
|
"github.com/stretchr/testify/require"
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
|
// remove-next-line
|
|
"github.com/ignite/cli/ignite/pkg/cosmoscmd"
|
|
|
|
// highlight-next-line
|
|
"{ModulePath}/app"
|
|
)
|
|
|
|
// remove-start
|
|
type SimApp interface {
|
|
cosmoscmd.App
|
|
GetBaseApp() *baseapp.BaseApp
|
|
AppCodec() codec.Codec
|
|
SimulationManager() *module.SimulationManager
|
|
ModuleAccountAddrs() map[string]bool
|
|
Name() string
|
|
LegacyAmino() *codec.LegacyAmino
|
|
BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock)
|
|
abci.ResponseBeginBlock
|
|
EndBlocker(ctx sdk.Context, req abci.RequestEndBlock)
|
|
abci.ResponseEndBlock
|
|
InitChainer(ctx sdk.Context, req abci.RequestInitChain)
|
|
abci.ResponseInitChain
|
|
}
|
|
|
|
// remove-end
|
|
|
|
// ...
|
|
|
|
// BenchmarkSimulation run the chain simulation
|
|
// Running using starport command:
|
|
// `starport chain simulate -v --numBlocks 200 --blockSize 50`
|
|
// Running as go benchmark test:
|
|
// `go test -benchmem -run=^$ -bench ^BenchmarkSimulation ./app -NumBlocks=200 -BlockSize 50 -Commit=true -Verbose=true -Enabled=true`
|
|
func BenchmarkSimulation(b *testing.B) {
|
|
|
|
// ...
|
|
|
|
// remove-next-line
|
|
encoding := cosmoscmd.MakeEncodingConfig(app.ModuleBasics)
|
|
// highlight-next-line
|
|
encoding := app.MakeEncodingConfig()
|
|
|
|
app := app.New(
|
|
logger,
|
|
db,
|
|
nil,
|
|
true,
|
|
map[int64]bool{},
|
|
app.DefaultNodeHome,
|
|
0,
|
|
encoding,
|
|
simapp.EmptyAppOptions{},
|
|
)
|
|
|
|
// remove-start
|
|
simApp, ok := app.(SimApp)
|
|
require.True(b, ok, "can't use simapp")
|
|
// remove-end
|
|
|
|
// Run randomized simulations
|
|
_, simParams, simErr := simulation.SimulateFromSeed(
|
|
b,
|
|
os.Stdout,
|
|
// highlight-next-line
|
|
app.BaseApp,
|
|
// highlight-next-line
|
|
simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
|
simulationtypes.RandomAccounts,
|
|
// highlight-next-line
|
|
simapp.SimulationOperations(app, app.AppCodec(), config),
|
|
// highlight-next-line
|
|
app.ModuleAccountAddrs(),
|
|
config,
|
|
// highlight-next-line
|
|
app.AppCodec(),
|
|
)
|
|
|
|
// export state and simParams before the simulation error is checked
|
|
// highlight-next-line
|
|
err = simapp.CheckExportSimulation(app, config, simParams)
|
|
require.NoError(b, err)
|
|
require.NoError(b, simErr)
|
|
|
|
// ...
|
|
}
|
|
```
|
|
|
|
The main changes here are that the `SimApp` interface has been removed and is being replaced with `app`.
|
|
|
|
The final modification in the `app` package is in `app/app.go`:
|
|
|
|
```go
|
|
package app
|
|
|
|
import (
|
|
// ...
|
|
|
|
// this line is used by starport scaffolding # stargate/app/moduleImport
|
|
|
|
// remove-next-line
|
|
"github.com/ignite/cli/ignite/pkg/cosmoscmd"
|
|
|
|
// highlight-start
|
|
appparams "{ModulePath}/app/params"
|
|
"{ModulePath}/docs"
|
|
// highlight-end
|
|
)
|
|
|
|
// ...
|
|
|
|
var (
|
|
// remove-next-line
|
|
_ cosmoscmd.App = (*App)(nil)
|
|
_ servertypes.Application = (*App)(nil)
|
|
_ simapp.App = (*App)(nil)
|
|
)
|
|
|
|
// ...
|
|
|
|
// New returns a reference to an initialized blockchain app
|
|
func New(
|
|
logger log.Logger,
|
|
db dbm.DB,
|
|
traceStore io.Writer,
|
|
loadLatest bool,
|
|
skipUpgradeHeights map[int64]bool,
|
|
homePath string,
|
|
invCheckPeriod uint,
|
|
// highlight-next-line
|
|
encodingConfig appparams.EncodingConfig,
|
|
appOpts servertypes.AppOptions,
|
|
baseAppOptions ...func(*baseapp.BaseApp),
|
|
// highlight-next-line
|
|
) *App {
|
|
appCodec := encodingConfig.Marshaler
|
|
cdc := encodingConfig.Amino
|
|
interfaceRegistry := encodingConfig.InterfaceRegistry
|
|
|
|
bApp := baseapp.NewBaseApp(
|
|
Name,
|
|
logger,
|
|
db,
|
|
encodingConfig.TxConfig.TxDecoder(),
|
|
baseAppOptions...,
|
|
)
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
// ...
|
|
|
|
// Name returns the name of the App
|
|
func (app *App) Name() string { return app.BaseApp.Name() }
|
|
|
|
// remove-start
|
|
// GetBaseApp returns the base app of the application
|
|
func (app App) GetBaseApp() *baseapp.BaseApp { return app.BaseApp }
|
|
|
|
// remove-end
|
|
|
|
// BeginBlocker application updates every begin block
|
|
func (app *App) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
|
return app.mm.BeginBlock(ctx, req)
|
|
}
|
|
|
|
// ...
|
|
```
|
|
|
|
Again, here we are removing the use of `cosmoscmd` and replacing it with `app`.
|
|
|
|
#### Migration in `cmd` package
|
|
|
|
Some imports in these
|
|
examples contain the sample string, `{binaryNamePrefix}d`. Replace this string with the binary name of your blockchain.
|
|
For example, if your blockchain module path is `github.com/planet/mars`, `./cmd/{binaryNamePrefix}d/cmd/` would be
|
|
become `./cmd/marsd/cmd/`.
|
|
|
|
First, create the new file `./cmd/{binaryNamePrefix}d/cmd/config.go` with the following code:
|
|
|
|
```go
|
|
package cmd
|
|
|
|
import (
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
"{ModulePath}/app"
|
|
)
|
|
|
|
func initSDKConfig() {
|
|
// Set prefixes
|
|
accountPubKeyPrefix := app.AccountAddressPrefix + "pub"
|
|
validatorAddressPrefix := app.AccountAddressPrefix + "valoper"
|
|
validatorPubKeyPrefix := app.AccountAddressPrefix + "valoperpub"
|
|
consNodeAddressPrefix := app.AccountAddressPrefix + "valcons"
|
|
consNodePubKeyPrefix := app.AccountAddressPrefix + "valconspub"
|
|
|
|
// Set and seal config
|
|
config := sdk.GetConfig()
|
|
config.SetBech32PrefixForAccount(app.AccountAddressPrefix, accountPubKeyPrefix)
|
|
config.SetBech32PrefixForValidator(validatorAddressPrefix, validatorPubKeyPrefix)
|
|
config.SetBech32PrefixForConsensusNode(consNodeAddressPrefix, consNodePubKeyPrefix)
|
|
config.Seal()
|
|
}
|
|
```
|
|
|
|
Next, create the new file `./cmd/{binaryNamePrefix}d/cmd/genaccounts.go` with the following code:
|
|
|
|
```go
|
|
package cmd
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
|
"github.com/cosmos/cosmos-sdk/server"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
|
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
"github.com/cosmos/cosmos-sdk/x/genutil"
|
|
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
const (
|
|
flagVestingStart = "vesting-start-time"
|
|
flagVestingEnd = "vesting-end-time"
|
|
flagVestingAmt = "vesting-amount"
|
|
)
|
|
|
|
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
|
|
func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]",
|
|
Short: "Add a genesis account to genesis.json",
|
|
Long: `Add a genesis account to genesis.json. The provided account must specify
|
|
the account address or key name and a list of initial coins. If a key name is given,
|
|
the address will be looked up in the local Keybase. The list of initial tokens must
|
|
contain valid denominations. Accounts may optionally be supplied with vesting parameters.
|
|
`,
|
|
Args: cobra.ExactArgs(2),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
clientCtx := client.GetClientContextFromCmd(cmd)
|
|
cdc := clientCtx.Codec
|
|
|
|
serverCtx := server.GetServerContextFromCmd(cmd)
|
|
config := serverCtx.Config
|
|
|
|
config.SetRoot(clientCtx.HomeDir)
|
|
|
|
coins, err := sdk.ParseCoinsNormalized(args[1])
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse coins: %w", err)
|
|
}
|
|
|
|
addr, err := sdk.AccAddressFromBech32(args[0])
|
|
if err != nil {
|
|
inBuf := bufio.NewReader(cmd.InOrStdin())
|
|
keyringBackend, err := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// attempt to lookup address from Keybase if no address was provided
|
|
kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf, cdc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
info, err := kb.Key(args[0])
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get address from Keybase: %w", err)
|
|
}
|
|
|
|
addr, err = info.GetAddress()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get address from Keybase: %w", err)
|
|
}
|
|
}
|
|
|
|
vestingStart, err := cmd.Flags().GetInt64(flagVestingStart)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
vestingEnd, err := cmd.Flags().GetInt64(flagVestingEnd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
vestingAmtStr, err := cmd.Flags().GetString(flagVestingAmt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse vesting amount: %w", err)
|
|
}
|
|
|
|
// create concrete account type based on input parameters
|
|
var genAccount authtypes.GenesisAccount
|
|
|
|
balances := banktypes.Balance{Address: addr.String(), Coins: coins.Sort()}
|
|
baseAccount := authtypes.NewBaseAccount(addr, nil, 0, 0)
|
|
|
|
if !vestingAmt.IsZero() {
|
|
baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd)
|
|
|
|
if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) ||
|
|
baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) {
|
|
return errors.New("vesting amount cannot be greater than total amount")
|
|
}
|
|
|
|
switch {
|
|
case vestingStart != 0 && vestingEnd != 0:
|
|
genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart)
|
|
|
|
case vestingEnd != 0:
|
|
genAccount = authvesting.NewDelayedVestingAccountRaw(baseVestingAccount)
|
|
|
|
default:
|
|
return errors.New("invalid vesting parameters; must supply start and end time or end time")
|
|
}
|
|
} else {
|
|
genAccount = baseAccount
|
|
}
|
|
|
|
if err := genAccount.Validate(); err != nil {
|
|
return fmt.Errorf("failed to validate new genesis account: %w", err)
|
|
}
|
|
|
|
genFile := config.GenesisFile()
|
|
appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to unmarshal genesis state: %w", err)
|
|
}
|
|
|
|
authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState)
|
|
|
|
accs, err := authtypes.UnpackAccounts(authGenState.Accounts)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get accounts from any: %w", err)
|
|
}
|
|
|
|
if accs.Contains(addr) {
|
|
return fmt.Errorf("cannot add account at existing address %s", addr)
|
|
}
|
|
|
|
// Add the new account to the set of genesis accounts and sanitize the
|
|
// accounts afterwards.
|
|
accs = append(accs, genAccount)
|
|
accs = authtypes.SanitizeGenesisAccounts(accs)
|
|
|
|
genAccs, err := authtypes.PackAccounts(accs)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to convert accounts into any's: %w", err)
|
|
}
|
|
authGenState.Accounts = genAccs
|
|
|
|
authGenStateBz, err := cdc.MarshalJSON(&authGenState)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal auth genesis state: %w", err)
|
|
}
|
|
|
|
appState[authtypes.ModuleName] = authGenStateBz
|
|
|
|
bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState)
|
|
bankGenState.Balances = append(bankGenState.Balances, balances)
|
|
bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances)
|
|
|
|
bankGenStateBz, err := cdc.MarshalJSON(bankGenState)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal bank genesis state: %w", err)
|
|
}
|
|
|
|
appState[banktypes.ModuleName] = bankGenStateBz
|
|
|
|
appStateJSON, err := json.Marshal(appState)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal application genesis state: %w", err)
|
|
}
|
|
|
|
genDoc.AppState = appStateJSON
|
|
return genutil.ExportGenesisFile(genDoc, genFile)
|
|
},
|
|
}
|
|
|
|
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)")
|
|
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
|
|
cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts")
|
|
cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts")
|
|
cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts")
|
|
flags.AddQueryFlagsToCmd(cmd)
|
|
|
|
return cmd
|
|
}
|
|
```
|
|
|
|
This command allows one to generate new accounts: `appd add-genesis-account`.
|
|
|
|
Next, create the new file `./cmd/{binaryNamePrefix}d/cmd/root.go` with the following code:
|
|
|
|
```go
|
|
package cmd
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/cosmos/cosmos-sdk/client/config"
|
|
"github.com/cosmos/cosmos-sdk/client/debug"
|
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
|
"github.com/cosmos/cosmos-sdk/client/rpc"
|
|
"github.com/cosmos/cosmos-sdk/server"
|
|
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
|
|
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
|
"github.com/cosmos/cosmos-sdk/snapshots"
|
|
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
|
|
"github.com/cosmos/cosmos-sdk/store"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
|
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
"github.com/cosmos/cosmos-sdk/x/crisis"
|
|
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
|
"github.com/ignite/cli/ignite/services/network"
|
|
"github.com/spf13/cast"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/pflag"
|
|
tmcfg "github.com/tendermint/tendermint/config"
|
|
tmcli "github.com/tendermint/tendermint/libs/cli"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
dbm "github.com/tendermint/tm-db"
|
|
// this line is used by starport scaffolding # root/moduleImport
|
|
|
|
"{ModulePath}/app"
|
|
appparams "{ModulePath}/app/params"
|
|
)
|
|
|
|
// NewRootCmd creates a new root command for a Cosmos SDK application
|
|
func NewRootCmd() (*cobra.Command, appparams.EncodingConfig) {
|
|
encodingConfig := app.MakeEncodingConfig()
|
|
initClientCtx := client.Context{}.
|
|
WithCodec(encodingConfig.Marshaler).
|
|
WithInterfaceRegistry(encodingConfig.InterfaceRegistry).
|
|
WithTxConfig(encodingConfig.TxConfig).
|
|
WithLegacyAmino(encodingConfig.Amino).
|
|
WithInput(os.Stdin).
|
|
WithAccountRetriever(types.AccountRetriever{}).
|
|
WithHomeDir(app.DefaultNodeHome).
|
|
WithViper("")
|
|
|
|
rootCmd := &cobra.Command{
|
|
Use: app.Name + "d",
|
|
Short: "Stargate CosmosHub App",
|
|
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
|
|
// set the default command outputs
|
|
cmd.SetOut(cmd.OutOrStdout())
|
|
cmd.SetErr(cmd.ErrOrStderr())
|
|
initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
initClientCtx, err = config.ReadFromClientConfig(initClientCtx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil {
|
|
return err
|
|
}
|
|
|
|
customAppTemplate, customAppConfig := initAppConfig()
|
|
customTMConfig := initTendermintConfig()
|
|
return server.InterceptConfigsPreRunHandler(
|
|
cmd, customAppTemplate, customAppConfig, customTMConfig,
|
|
)
|
|
},
|
|
}
|
|
|
|
initRootCmd(rootCmd, encodingConfig)
|
|
overwriteFlagDefaults(rootCmd, map[string]string{
|
|
flags.FlagChainID: strings.ReplaceAll(app.Name, "-", ""),
|
|
flags.FlagKeyringBackend: "test",
|
|
})
|
|
|
|
return rootCmd, encodingConfig
|
|
}
|
|
|
|
// initTendermintConfig helps to override default Tendermint Config values.
|
|
// return tmcfg.DefaultConfig if no custom configuration is required for the application.
|
|
func initTendermintConfig() *tmcfg.Config {
|
|
cfg := tmcfg.DefaultConfig()
|
|
return cfg
|
|
}
|
|
|
|
func initRootCmd(
|
|
rootCmd *cobra.Command,
|
|
encodingConfig appparams.EncodingConfig,
|
|
) {
|
|
// Set config
|
|
initSDKConfig()
|
|
|
|
rootCmd.AddCommand(
|
|
genutilcli.InitCmd(app.ModuleBasics, app.DefaultNodeHome),
|
|
genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome),
|
|
genutilcli.MigrateGenesisCmd(),
|
|
genutilcli.GenTxCmd(
|
|
app.ModuleBasics,
|
|
encodingConfig.TxConfig,
|
|
banktypes.GenesisBalancesIterator{},
|
|
app.DefaultNodeHome,
|
|
),
|
|
genutilcli.ValidateGenesisCmd(app.ModuleBasics),
|
|
AddGenesisAccountCmd(app.DefaultNodeHome),
|
|
tmcli.NewCompletionCmd(rootCmd, true),
|
|
debug.Cmd(),
|
|
config.Cmd(),
|
|
// this line is used by starport scaffolding # root/commands
|
|
)
|
|
|
|
a := appCreator{
|
|
encodingConfig,
|
|
}
|
|
|
|
// add server commands
|
|
server.AddCommands(
|
|
rootCmd,
|
|
app.DefaultNodeHome,
|
|
a.newApp,
|
|
a.appExport,
|
|
addModuleInitFlags,
|
|
)
|
|
|
|
// add keybase, auxiliary RPC, query, and tx child commands
|
|
rootCmd.AddCommand(
|
|
rpc.StatusCommand(),
|
|
queryCommand(),
|
|
txCommand(),
|
|
keys.Commands(app.DefaultNodeHome),
|
|
)
|
|
}
|
|
|
|
// queryCommand returns the sub-command to send queries to the app
|
|
func queryCommand() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "query",
|
|
Aliases: []string{"q"},
|
|
Short: "Querying subcommands",
|
|
DisableFlagParsing: true,
|
|
SuggestionsMinimumDistance: 2,
|
|
RunE: client.ValidateCmd,
|
|
}
|
|
|
|
cmd.AddCommand(
|
|
authcmd.GetAccountCmd(),
|
|
rpc.ValidatorCommand(),
|
|
rpc.BlockCommand(),
|
|
authcmd.QueryTxsByEventsCmd(),
|
|
authcmd.QueryTxCmd(),
|
|
)
|
|
|
|
app.ModuleBasics.AddQueryCommands(cmd)
|
|
cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID")
|
|
|
|
return cmd
|
|
}
|
|
|
|
// txCommand returns the sub-command to send transactions to the app
|
|
func txCommand() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "tx",
|
|
Short: "Transactions subcommands",
|
|
DisableFlagParsing: true,
|
|
SuggestionsMinimumDistance: 2,
|
|
RunE: client.ValidateCmd,
|
|
}
|
|
|
|
cmd.AddCommand(
|
|
authcmd.GetSignCommand(),
|
|
authcmd.GetSignBatchCommand(),
|
|
authcmd.GetMultiSignCommand(),
|
|
authcmd.GetValidateSignaturesCommand(),
|
|
flags.LineBreak,
|
|
authcmd.GetBroadcastCommand(),
|
|
authcmd.GetEncodeCommand(),
|
|
authcmd.GetDecodeCommand(),
|
|
)
|
|
|
|
app.ModuleBasics.AddTxCommands(cmd)
|
|
cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func addModuleInitFlags(startCmd *cobra.Command) {
|
|
crisis.AddModuleInitFlags(startCmd)
|
|
// this line is used by starport scaffolding # root/arguments
|
|
}
|
|
|
|
func overwriteFlagDefaults(c *cobra.Command, defaults map[string]string) {
|
|
set := func(s *pflag.FlagSet, key, val string) {
|
|
if f := s.Lookup(key); f != nil {
|
|
f.DefValue = val
|
|
f.Value.Set(val)
|
|
}
|
|
}
|
|
for key, val := range defaults {
|
|
set(c.Flags(), key, val)
|
|
set(c.PersistentFlags(), key, val)
|
|
}
|
|
for _, c := range c.Commands() {
|
|
overwriteFlagDefaults(c, defaults)
|
|
}
|
|
}
|
|
|
|
type appCreator struct {
|
|
encodingConfig appparams.EncodingConfig
|
|
}
|
|
|
|
// newApp creates a new Cosmos SDK app
|
|
func (a appCreator) newApp(
|
|
logger log.Logger,
|
|
db dbm.DB,
|
|
traceStore io.Writer,
|
|
appOpts servertypes.AppOptions,
|
|
) servertypes.Application {
|
|
var cache sdk.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", dbm.GoLevelDBBackend, 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)),
|
|
)
|
|
|
|
return app.New(
|
|
logger,
|
|
db,
|
|
traceStore,
|
|
true,
|
|
skipUpgradeHeights,
|
|
cast.ToString(appOpts.Get(flags.FlagHome)),
|
|
cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)),
|
|
a.encodingConfig,
|
|
appOpts,
|
|
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.SetInterBlockCache(cache),
|
|
baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))),
|
|
baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))),
|
|
baseapp.SetSnapshot(snapshotStore, snapshotOptions),
|
|
)
|
|
}
|
|
|
|
// appExport creates a new simapp (optionally at a given height)
|
|
func (a appCreator) appExport(
|
|
logger log.Logger,
|
|
db dbm.DB,
|
|
traceStore io.Writer,
|
|
height int64,
|
|
forZeroHeight bool,
|
|
jailAllowedAddrs []string,
|
|
appOpts servertypes.AppOptions,
|
|
) (servertypes.ExportedApp, error) {
|
|
homePath, ok := appOpts.Get(flags.FlagHome).(string)
|
|
if !ok || homePath == "" {
|
|
return servertypes.ExportedApp{}, errors.New("application home not set")
|
|
}
|
|
|
|
app := app.New(
|
|
logger,
|
|
db,
|
|
traceStore,
|
|
height == -1, // -1: no height provided
|
|
map[int64]bool{},
|
|
homePath,
|
|
uint(1),
|
|
a.encodingConfig,
|
|
appOpts,
|
|
)
|
|
|
|
if height != -1 {
|
|
if err := app.LoadHeight(height); err != nil {
|
|
return servertypes.ExportedApp{}, err
|
|
}
|
|
}
|
|
|
|
return app.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs)
|
|
}
|
|
|
|
// initAppConfig helps to override default appConfig template and configs.
|
|
// return "", nil if no custom configuration is required for the application.
|
|
func initAppConfig() (string, interface{}) {
|
|
// The following code snippet is just for reference.
|
|
|
|
// WASMConfig defines configuration for the wasm module.
|
|
type WASMConfig struct {
|
|
// This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
|
|
QueryGasLimit uint64 `mapstructure:"query_gas_limit"`
|
|
|
|
// Address defines the gRPC-web server to listen on
|
|
LruSize uint64 `mapstructure:"lru_size"`
|
|
}
|
|
|
|
type CustomAppConfig struct {
|
|
serverconfig.Config
|
|
|
|
WASM WASMConfig `mapstructure:"wasm"`
|
|
}
|
|
|
|
// Optionally allow the chain developer to overwrite the SDK's default
|
|
// server config.
|
|
srvCfg := serverconfig.DefaultConfig()
|
|
// The SDK's default minimum gas price is set to "" (empty value) inside
|
|
// app.toml. If left empty by validators, the node will halt on startup.
|
|
// However, the chain developer can set a default app.toml value for their
|
|
// validators here.
|
|
//
|
|
// In summary:
|
|
// - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their
|
|
// own app.toml config,
|
|
// - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their
|
|
// own app.toml to override, or use this default value.
|
|
//
|
|
// In simapp, we set the min gas prices to 0.
|
|
srvCfg.MinGasPrices = "0stake"
|
|
|
|
customAppConfig := CustomAppConfig{
|
|
Config: *srvCfg,
|
|
WASM: WASMConfig{
|
|
LruSize: 1,
|
|
QueryGasLimit: 300000,
|
|
},
|
|
}
|
|
|
|
customAppTemplate := serverconfig.DefaultConfigTemplate + `
|
|
[wasm]
|
|
# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
|
|
query_gas_limit = 300000
|
|
# This is the number of wasm vm instances we keep cached in memory for speed-up
|
|
# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally
|
|
lru_size = 0`
|
|
|
|
return customAppTemplate, customAppConfig
|
|
}
|
|
```
|
|
|
|
Finally, modify `./cmd/{binaryNamePrefix}d/main.go` to include the new changes:
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
|
|
"github.com/cosmos/cosmos-sdk/server"
|
|
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
|
|
// remove-next-line
|
|
"github.com/ignite/cli/ignite/pkg/cosmoscmd"
|
|
|
|
"{ModulePath}/app"
|
|
"{ModulePath}/cmd/{BinaryNamePrefix}d/cmd"
|
|
)
|
|
|
|
func main() {
|
|
// highlight-start
|
|
rootCmd, _ := cmd.NewRootCmd()
|
|
if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil {
|
|
switch e := err.(type) {
|
|
case server.ErrorCode:
|
|
os.Exit(e.Code)
|
|
|
|
default:
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
// highlight-end
|
|
}
|
|
```
|
|
|
|
#### Migration in `testutil` package
|
|
|
|
Modify `./testutil/network/network.go` to include the new changes:
|
|
|
|
|
|
```go
|
|
package network
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
|
pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types"
|
|
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
|
"github.com/cosmos/cosmos-sdk/simapp"
|
|
"github.com/cosmos/cosmos-sdk/testutil/network"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
|
"github.com/stretchr/testify/require"
|
|
tmrand "github.com/tendermint/tendermint/libs/rand"
|
|
tmdb "github.com/tendermint/tm-db"
|
|
|
|
// highlight-next-line
|
|
"{ModulePath}/app"
|
|
|
|
// remove-next-line
|
|
"github.com/ignite/cli/ignite/pkg/cosmoscmd"
|
|
)
|
|
|
|
// ...
|
|
|
|
// DefaultConfig will initialize config for the network with custom application,
|
|
// genesis and single validator. All other parameters are inherited from cosmos-sdk/testutil/network.DefaultConfig
|
|
func DefaultConfig() network.Config {
|
|
// highlight-next-line
|
|
encoding := app.MakeEncodingConfig()
|
|
// remove-next-line
|
|
encoding := cosmoscmd.MakeEncodingConfig(app.ModuleBasics)
|
|
return network.Config{
|
|
Codec: encoding.Marshaler,
|
|
TxConfig: encoding.TxConfig,
|
|
LegacyAmino: encoding.Amino,
|
|
InterfaceRegistry: encoding.InterfaceRegistry,
|
|
AccountRetriever: authtypes.AccountRetriever{},
|
|
AppConstructor: func(val network.Validator) servertypes.Application {
|
|
return app.New(
|
|
val.Ctx.Logger, tmdb.NewMemDB(), nil, true, map[int64]bool{}, val.Ctx.Config.RootDir, 0,
|
|
encoding,
|
|
simapp.EmptyAppOptions{},
|
|
baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.AppConfig.Pruning)),
|
|
baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices),
|
|
)
|
|
},
|
|
GenesisState: app.ModuleBasics.DefaultGenesis(encoding.Marshaler),
|
|
TimeoutCommit: 2 * time.Second,
|
|
ChainID: "chain-" + tmrand.NewRand().Str(6),
|
|
NumValidators: 1,
|
|
BondDenom: sdk.DefaultBondDenom,
|
|
MinGasPrices: fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom),
|
|
AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction),
|
|
StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction),
|
|
BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction),
|
|
PruningStrategy: pruningtypes.PruningOptionNothing,
|
|
CleanupDir: true,
|
|
SigningAlgo: string(hd.Secp256k1Type),
|
|
KeyringOptions: []keyring.Option{},
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Fix ICA controller keeper wiring
|
|
|
|
Related issue: https://github.com/ignite/cli/issues/2867
|
|
|
|
Apply the following changes to `app/app.go` file :
|
|
|
|
```go
|
|
package app
|
|
|
|
import (
|
|
|
|
// highlight-start
|
|
icacontrollerkeeper "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/controller/keeper"
|
|
icacontrollertypes "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/controller/types"
|
|
// highlight-end
|
|
// ...
|
|
)
|
|
|
|
// New returns a reference to an initialized blockchain app
|
|
func New(
|
|
logger log.Logger,
|
|
db dbm.DB,
|
|
traceStore io.Writer,
|
|
loadLatest bool,
|
|
skipUpgradeHeights map[int64]bool,
|
|
homePath string,
|
|
invCheckPeriod uint,
|
|
encodingConfig appparams.EncodingConfig,
|
|
appOpts servertypes.AppOptions,
|
|
baseAppOptions ...func(*baseapp.BaseApp),
|
|
) *App {
|
|
|
|
// ...
|
|
|
|
keys := sdk.NewKVStoreKeys(
|
|
authtypes.StoreKey, authz.ModuleName, banktypes.StoreKey,
|
|
stakingtypes.StoreKey,
|
|
minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey,
|
|
govtypes.StoreKey,
|
|
paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey,
|
|
feegrant.StoreKey, evidencetypes.StoreKey,
|
|
ibctransfertypes.StoreKey, icahosttypes.StoreKey,
|
|
capabilitytypes.StoreKey, group.StoreKey,
|
|
// highlight-next-line
|
|
icacontrollertypes.StoreKey,
|
|
yourchainmoduletypes.StoreKey,
|
|
// this line is used by starport scaffolding # stargate/app/storeKey
|
|
)
|
|
|
|
// ...
|
|
|
|
// remove-next-line
|
|
icaModule := ica.NewAppModule(nil, &app.ICAHostKeeper)
|
|
// highlight-start
|
|
icaControllerKeeper := icacontrollerkeeper.NewKeeper(
|
|
appCodec, keys[icacontrollertypes.StoreKey],
|
|
app.GetSubspace(icacontrollertypes.SubModuleName),
|
|
app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee
|
|
app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper,
|
|
scopedICAControllerKeeper, app.MsgServiceRouter(),
|
|
)
|
|
icaModule := ica.NewAppModule(&icaControllerKeeper, &app.ICAHostKeeper)
|
|
// highlight-end
|
|
icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper)
|
|
|
|
// ...
|
|
}
|
|
|
|
// ...
|
|
|
|
// initParamsKeeper init params keeper and its subspaces
|
|
func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper {
|
|
paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey)
|
|
|
|
paramsKeeper.Subspace(authtypes.ModuleName)
|
|
paramsKeeper.Subspace(banktypes.ModuleName)
|
|
paramsKeeper.Subspace(stakingtypes.ModuleName)
|
|
paramsKeeper.Subspace(minttypes.ModuleName)
|
|
paramsKeeper.Subspace(distrtypes.ModuleName)
|
|
paramsKeeper.Subspace(slashingtypes.ModuleName)
|
|
paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1.ParamKeyTable())
|
|
paramsKeeper.Subspace(crisistypes.ModuleName)
|
|
paramsKeeper.Subspace(ibctransfertypes.ModuleName)
|
|
paramsKeeper.Subspace(ibchost.ModuleName)
|
|
// highlight-next-line
|
|
paramsKeeper.Subspace(icacontrollertypes.SubModuleName)
|
|
paramsKeeper.Subspace(icahosttypes.SubModuleName)
|
|
paramsKeeper.Subspace(mychainmoduletypes.ModuleName)
|
|
// this line is used by starport scaffolding # stargate/app/paramSubspace
|
|
|
|
return paramsKeeper
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Fix capability keeper not sealed
|
|
|
|
Related issue: https://github.com/ignite/cli/issues/1921
|
|
|
|
Apply the following change to `app/app.go` file :
|
|
|
|
```go
|
|
package app
|
|
|
|
// New returns a reference to an initialized blockchain app
|
|
func New(
|
|
logger log.Logger,
|
|
db dbm.DB,
|
|
traceStore io.Writer,
|
|
loadLatest bool,
|
|
skipUpgradeHeights map[int64]bool,
|
|
homePath string,
|
|
invCheckPeriod uint,
|
|
encodingConfig appparams.EncodingConfig,
|
|
appOpts servertypes.AppOptions,
|
|
baseAppOptions ...func(*baseapp.BaseApp),
|
|
) *App {
|
|
|
|
// ...
|
|
|
|
// this line is used by starport scaffolding # stargate/app/keeperDefinition
|
|
|
|
// highlight-start
|
|
// Sealing prevents other modules from creating scoped sub-keepers
|
|
app.CapabilityKeeper.Seal()
|
|
// highlight-end
|
|
|
|
// Create static IBC router, add transfer route, then set and seal it
|
|
|
|
// ...
|
|
}
|
|
```
|