refactor for sdk update

- register crypto types

- fix app codec

eager config and cli init

[wip] fix app cli

[wip] new msg handler registration (bonds)

clean up module autocli: use <> for required positional args

system tests

- registry

[wip] system tests fix, refactor

registry tests

TransferCoinsToModuleAccount: clarify function
This commit is contained in:
Roy Crihfield 2024-10-27 19:54:43 +08:00
parent 8ccf602c63
commit 72a93dec2f
31 changed files with 1201 additions and 666 deletions

View File

@ -7,6 +7,8 @@ LACONIC_BINARY = laconicd
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
COMMIT := $(shell git log -1 --format='%H')
COSMOS_BUILD_OPTIONS := v2
# don't override user values
ifeq (,$(VERSION))
VERSION := $(shell git describe --exact-match 2>/dev/null)
@ -106,3 +108,7 @@ test-e2e:
test-unit:
go test ./utils/... ./cmd/... -mod=readonly -test.v
test-system: build
test -d ./tests/system/binaries || ln -sf $(BUILDDIR) ./tests/system/binaries
go test ./tests/system -test.v -timeout 10m

View File

@ -2,22 +2,16 @@ package app
import (
_ "embed"
"os"
"path/filepath"
"github.com/spf13/viper"
"fmt"
coreserver "cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/depinject/appconfig"
"cosmossdk.io/log"
"cosmossdk.io/runtime/v2"
server "cosmossdk.io/server/v2"
serverstore "cosmossdk.io/server/v2/store"
"cosmossdk.io/store/v2"
"cosmossdk.io/store/v2/root"
// crypto/keys/ed25519/keys.pb.go:123
coreserver "cosmossdk.io/core/server"
bankkeeper "cosmossdk.io/x/bank/keeper"
consensuskeeper "cosmossdk.io/x/consensus/keeper"
distrkeeper "cosmossdk.io/x/distribution/keeper"
@ -32,12 +26,15 @@ import (
"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/types/module"
"github.com/cosmos/cosmos-sdk/std"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
_ "cosmossdk.io/api/cosmos/tx/config/v1" // import for side-effects
_ "cosmossdk.io/x/accounts" // import for side-effects
_ "cosmossdk.io/x/bank" // import for side-effects
_ "cosmossdk.io/api/cosmos/tx/config/v1" // import for side-effects
_ "cosmossdk.io/x/accounts" // import for side-effects
_ "cosmossdk.io/x/bank" // import for side-effects
// _ "cosmossdk.io/x/bank/v2" // import for side-effects
_ "cosmossdk.io/runtime/v2/services" // import for side-effects
_ "cosmossdk.io/x/consensus" // import for side-effects
_ "cosmossdk.io/x/distribution" // import for side-effects
_ "cosmossdk.io/x/gov" // import for side-effects
@ -54,21 +51,21 @@ import (
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import for side-effects
)
// DefaultNodeHome default home directories for the application daemon
var DefaultNodeHome string
//go:embed app.yaml
var AppConfigYAML []byte
var (
_ server.AppI[transaction.Tx] = (*LaconicApp)(nil)
//go:embed app.yaml
AppConfigYAML []byte
)
type (
Tx = transaction.Tx
AppBuilder = runtime.AppBuilder[Tx]
)
// LaconicApp extends an ABCI application, but with most of its parameters exported.
// They are exported for convenience in creating helper functions, as object
// capabilities aren't needed for testing.
type LaconicApp struct {
*runtime.App[transaction.Tx]
type LaconicApp[T Tx] struct {
*runtime.App[T]
// legacyAmino *codec.LegacyAmino
appCodec codec.Codec
txConfig client.TxConfig
@ -89,23 +86,6 @@ type LaconicApp struct {
BondKeeper *bondkeeper.Keeper
RegistryKeeper registrykeeper.Keeper
OnboardingKeeper *onboardingkeeper.Keeper
// simulation manager
sm *module.SimulationManager
}
type (
AppTx = transaction.Tx
AppBuilder = runtime.AppBuilder[AppTx]
)
func init() {
userHomeDir, err := os.UserHomeDir()
if err != nil {
panic(err)
}
DefaultNodeHome = filepath.Join(userHomeDir, ".laconicd")
}
// AppConfig returns the default app config.
@ -122,50 +102,46 @@ func AppConfig() depinject.Config {
codec.ProvideInterfaceRegistry,
codec.ProvideAddressCodec,
codec.ProvideProtoCodec,
codec.ProvideLegacyAmino,
codec.ProvideLegacyAmino, // note: needed by ProvideAppBuilder (runtime/v2)
ProvideRootStoreConfig,
// // inject desired account types:
// basedepinject.ProvideAccount,
// multisigdepinject.ProvideAccount,
// lockupdepinject.ProvideAllLockupAccounts,
// // provide base account options
// basedepinject.ProvideSecp256K1PubKey,
),
depinject.Invoke(
std.RegisterInterfaces,
// std.RegisterLegacyAminoCodec,
),
)
}
// NewLaconicApp returns a reference to an initialized LaconicApp.
func NewLaconicApp(
logger log.Logger,
// db corestore.KVStoreWithBatch,
// traceStore io.Writer,
viper *viper.Viper,
loadLatest bool,
// appOpts server.AppOptions, // TODO migrate?
appBuilderOpts ...runtime.AppBuilderOption[AppTx],
) (*LaconicApp, error) {
func NewLaconicApp[T Tx](
config depinject.Config,
outputs ...any,
) (*LaconicApp[T], error) {
var (
app LaconicApp
appBuilder *AppBuilder
app LaconicApp[T]
appBuilder *runtime.AppBuilder[T]
storeBuilder root.Builder
err error
)
logfile := "/Users/roy/vulcanize/dump/laconic-debug/app_depinject.log"
if err := depinject.InjectDebug(
// depinject.Debug(),
depinject.DebugOptions(
depinject.FileLogger(logfile),
),
depinject.Configs(
AppConfig(),
depinject.Supply(
logger,
// appOpts,
),
),
&appBuilder,
outputs = append(outputs,
&storeBuilder,
&appBuilder,
&app.appCodec,
// &app.legacyAmino,
&app.txConfig,
&app.interfaceRegistry,
&app.StakingKeeper,
&app.AccountKeeper,
&app.BankKeeper,
&app.StakingKeeper,
&app.SlashingKeeper,
&app.DistrKeeper,
&app.GovKeeper,
@ -174,76 +150,46 @@ func NewLaconicApp(
&app.BondKeeper,
&app.RegistryKeeper,
&app.OnboardingKeeper,
)
if err = depinject.Inject(
depinject.Configs(AppConfig(), config),
outputs...,
); err != nil {
return nil, err
}
// store/v2 follows a slightly more eager config life cycle than server components
storeConfig, err := serverstore.UnmarshalConfig(viper.AllSettings())
// // TODO: db config correct?
// // TODO: store tracer injection?
app.App, err = appBuilder.Build()
if err != nil {
panic(err)
}
app.store, err = storeBuilder.Build(logger, storeConfig)
if err != nil {
panic(err)
}
// TODO: db config correct?
// TODO: store tracer injection?
if app.App, err = appBuilder.Build(appBuilderOpts...); err != nil {
return nil, err
}
// TODO
// // register streaming services
// if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil {
// return nil, err
// }
app.store = storeBuilder.Get()
if app.store == nil {
return nil, fmt.Errorf("store builder did not return a db")
}
/**** Module Options ****/
// TODO: review streaming services
// create the simulation manager and define the order of the modules for deterministic simulations
// NOTE: this is not required for apps that don't use the simulator for fuzz testing transactions
app.sm = module.NewSimulationManagerFromAppModules(
app.ModuleManager().Modules(),
make(map[string]module.AppModuleSimulation, 0))
app.sm.RegisterStoreDecoders()
// Note: upgrade handlers are registered here in simapp
// TODO: remove
if loadLatest {
if err = app.LoadLatest(); err != nil {
return nil, err
}
if err = app.LoadLatest(); err != nil {
return nil, err
}
return &app, nil
}
// // LegacyAmino returns LaconicApp's amino codec.
// func (app *LaconicApp) LegacyAmino() *codec.LegacyAmino {
// return app.legacyAmino
// }
func (app *LaconicApp) InterfaceRegistry() coreserver.InterfaceRegistry {
func (app *LaconicApp[T]) InterfaceRegistry() coreserver.InterfaceRegistry {
return app.interfaceRegistry
}
// GetKey returns the KVStoreKey for the provided store key.
func (app *LaconicApp) Store() store.RootStore {
func (app *LaconicApp[T]) Store() store.RootStore {
return app.store
}
// func (app *LaconicApp) kvStoreKeys() map[string]*store.KVStoreKey {
// keys := make(map[string]*store.KVStoreKey)
// for _, k := range app.GetStoreKeys() {
// if kv, ok := k.(*storetypes.KVStoreKey); ok {
// keys[kv.Name()] = kv
// }
// }
// return keys
// }
// SimulationManager implements the SimulationApp interface
func (app *LaconicApp) SimulationManager() *module.SimulationManager {
return app.sm
func ProvideRootStoreConfig(config runtime.GlobalConfig) (*root.Config, error) {
return serverstore.UnmarshalConfig(config)
}

View File

@ -13,7 +13,7 @@ import (
// file.
// This is a demonstation of how to export a genesis file. Export may need extended at
// the user discretion for cleaning the genesis state at the end provided with jailAllowedAddrs
func (app *LaconicApp) ExportAppStateAndValidators(
func (app *LaconicApp[T]) ExportAppStateAndValidators(
jailAllowedAddrs []string,
) (v2.ExportedApp, error) {
ctx := context.Background()

View File

@ -1,14 +1,15 @@
package cmd
import (
"context"
"fmt"
"io"
"github.com/spf13/cobra"
"github.com/spf13/viper"
corectx "cosmossdk.io/core/context"
"cosmossdk.io/client/v2/offchain"
coreserver "cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
runtimev2 "cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/server/v2/api/grpc"
"cosmossdk.io/server/v2/api/rest"
@ -18,78 +19,142 @@ import (
confixcmd "cosmossdk.io/tools/confix/cmd"
"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/keys"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"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"
genutilv2 "github.com/cosmos/cosmos-sdk/x/genutil/v2"
genutilv2cli "github.com/cosmos/cosmos-sdk/x/genutil/v2/cli"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/utils"
)
func initRootCmd(rootCmd *cobra.Command, txConfig client.TxConfig, moduleManager moduleManager) {
// CommandDependencies is a struct that contains all the dependencies needed to initialize the root command.
// an alternative design could fetch these even later from the command context
type CommandDependencies[T app.Tx] struct {
GlobalConfig coreserver.ConfigMap
TxConfig client.TxConfig
ModuleManager *runtimev2.MM[T]
LaconicApp *app.LaconicApp[T]
Consensus serverv2.ServerComponent[T]
}
func InitRootCmd[T app.Tx](
rootCmd *cobra.Command,
logger log.Logger,
deps CommandDependencies[T],
) (serverv2.ConfigWriter, error) {
cfg := sdk.GetConfig()
cfg.Seal()
rootCmd.AddCommand(
genutilcli.InitCmd(moduleManager),
genutilcli.InitCmd(deps.ModuleManager),
genesisCommand(deps.ModuleManager, deps.LaconicApp),
NewTestnetCmd(deps.ModuleManager),
debug.Cmd(),
confixcmd.ConfigCommand(),
NewTestnetCmd(moduleManager),
// TODO
// pruning.Cmd(newApp),
// snapshot.Cmd(newApp),
)
if err := serverv2.AddCommands(
rootCmd,
newApp,
initServerConfig(),
cometbft.New(
utils.GenericTxDecoder[app.AppTx]{txConfig},
initCometOptions[app.AppTx](),
initCometConfig(),
),
grpc.New[app.AppTx](),
serverstore.New[app.AppTx](),
telemetry.New[app.AppTx](),
rest.New[app.AppTx](),
// serverv2.StartCmdOptions[*app.LaconicApp]{
// PostSetup: func(
// _ *app.LaconicApp,
// svrCtx *server.Context,
// clientCtx client.Context,
// ctx context.Context,
// g *errgroup.Group,
// ) error {
// g.Go(func() error {
// return gql.Server(ctx, clientCtx, svrCtx.Logger.With("module", "gql-server"))
// })
// return nil
// },
// },
); err != nil {
panic(err)
}
// add keybase, auxiliary RPC, query, genesis, and tx child commands
rootCmd.AddCommand(
server.StatusCommand(),
genutilv2cli.Commands(
moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule),
moduleManager,
appExport),
// add keybase, auxiliary RPC, query, genesis, and tx child commands
queryCommand(),
txCommand(),
keys.Commands(),
offchain.OffChain(),
)
// TODO
// pruning.Cmd(newApp),
// snapshot.Cmd(newApp),
// build CLI skeleton for initial config parsing or a client application invocation
if deps.LaconicApp == nil {
if deps.Consensus == nil {
deps.Consensus = cometbft.NewWithConfigOptions[T](initCometConfig())
}
return serverv2.AddCommands[T](
rootCmd,
logger,
io.NopCloser(nil),
deps.GlobalConfig,
initServerConfig(),
deps.Consensus,
&grpc.Server[T]{},
&serverstore.Server[T]{},
&telemetry.Server[T]{},
&rest.Server[T]{},
)
}
// build full app!
app := deps.LaconicApp
grpcServer, err := grpc.New[T](logger, app.InterfaceRegistry(), app.QueryHandlers(), app.Query, deps.GlobalConfig)
if err != nil {
return nil, err
}
// store component (not a server)
storeComponent, err := serverstore.New[T](app.Store(), deps.GlobalConfig)
if err != nil {
return nil, err
}
restServer, err := rest.New(logger, app.App.AppManager, deps.GlobalConfig)
if err != nil {
return nil, err
}
// consensus component
if deps.Consensus == nil {
deps.Consensus, err = cometbft.New(
logger,
app.Name(),
app.Store(),
app.App.AppManager,
app.App.QueryHandlers(),
app.App.SchemaDecoderResolver(),
&utils.GenericTxDecoder[T]{deps.TxConfig},
deps.GlobalConfig,
initCometOptions[T](),
)
if err != nil {
return nil, err
}
}
telemetryServer, err := telemetry.New[T](deps.GlobalConfig, logger)
if err != nil {
return nil, err
}
// wire server commands
return serverv2.AddCommands[T](
rootCmd,
logger,
app,
deps.GlobalConfig,
initServerConfig(),
deps.Consensus,
grpcServer,
storeComponent,
telemetryServer,
restServer,
)
}
// genesisCommand builds genesis-related `simd genesis` command.
func genesisCommand[T app.Tx](
moduleManager *runtimev2.MM[T],
app *app.LaconicApp[T],
) *cobra.Command {
var genTxValidator func([]transaction.Msg) error
if moduleManager != nil {
genTxValidator = moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule).GenTxValidator()
}
cmd := genutilv2cli.Commands(
genTxValidator,
moduleManager,
app,
)
return cmd
}
func queryCommand() *cobra.Command {
@ -103,11 +168,11 @@ func queryCommand() *cobra.Command {
}
cmd.AddCommand(
server.QueryBlockCmd(),
cometbft.QueryBlockCmd(),
cometbft.QueryBlocksCmd(),
cometbft.QueryBlockResultsCmd(),
authcmd.QueryTxsByEventsCmd(),
server.QueryBlocksCmd(),
authcmd.QueryTxCmd(),
server.QueryBlockResultsCmd(),
)
return cmd
@ -137,102 +202,29 @@ func txCommand() *cobra.Command {
return cmd
}
func newApp(logger log.Logger, viper *viper.Viper) serverv2.AppI[app.AppTx] {
// viper.Set(serverv2.FlagHome, app.DefaultNodeHome)
lacapp, err := app.NewLaconicApp(logger, viper, true)
if err != nil {
panic(err)
func RootCommandPersistentPreRun(clientCtx client.Context) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
// set the default command outputs
cmd.SetOut(cmd.OutOrStdout())
cmd.SetErr(cmd.ErrOrStderr())
clientCtx = clientCtx.WithCmdContext(cmd.Context())
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
customClientTemplate, customClientConfig := initClientConfig()
clientCtx, err = config.CreateClientConfig(
clientCtx, customClientTemplate, customClientConfig)
if err != nil {
return err
}
if err = client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
return err
}
return nil
}
return serverv2.AppI[app.AppTx](lacapp)
}
// appExport creates a new simapp (optionally at a given height) and exports state.
func appExport(
ctx context.Context,
height int64,
jailAllowedAddrs []string,
) (genutilv2.ExportedApp, error) {
value := ctx.Value(corectx.ViperContextKey)
viper, ok := value.(*viper.Viper)
if !ok {
return genutilv2.ExportedApp{},
fmt.Errorf("incorrect viper type %T: expected *viper.Viper in context", value)
}
value = ctx.Value(corectx.LoggerContextKey)
logger, ok := value.(log.Logger)
if !ok {
return genutilv2.ExportedApp{},
fmt.Errorf("incorrect logger type %T: expected log.Logger in context", value)
}
// overwrite the FlagInvCheckPeriod
viper.Set(server.FlagInvCheckPeriod, 1)
viper.Set(serverv2.FlagHome, app.DefaultNodeHome)
lacapp, err := app.NewLaconicApp(logger, viper, false)
if err != nil {
return genutilv2.ExportedApp{}, err
}
if height != -1 {
err = lacapp.LoadHeight(uint64(height))
} else {
err = lacapp.LoadLatest()
}
if err != nil {
return genutilv2.ExportedApp{}, err
}
return lacapp.ExportAppStateAndValidators(jailAllowedAddrs)
}
// // appExport creates a new app (optionally at a given height) and exports state.
// func appExport(
// logger log.Logger,
// db corestore.KVStoreWithBatch,
// traceStore io.Writer,
// height int64,
// forZeroHeight bool,
// jailAllowedAddrs []string,
// appOpts servertypes.AppOptions,
// modulesToExport []string,
// ) (genutilv2.ExportedApp, error) {
// var (
// laconicApp *app.LaconicApp
// err error
// )
// // this check is necessary as we use the flag in x/upgrade.
// // we can exit more gracefully by checking the flag here.
// homePath, ok := appOpts.Get(flags.FlagHome).(string)
// if !ok || homePath == "" {
// return servertypes.ExportedApp{}, errors.New("application home not set")
// }
// viperAppOpts, ok := appOpts.(*viper.Viper)
// if !ok {
// return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper")
// }
// // overwrite the FlagInvCheckPeriod
// viperAppOpts.Set(server.FlagInvCheckPeriod, 1)
// appOpts = viperAppOpts
// if height != -1 {
// laconicApp, err = app.NewLaconicApp(logger, db, false)
// if err != nil {
// return servertypes.ExportedApp{}, err
// }
// if err := laconicApp.LoadHeight(uint64(height)); err != nil {
// return servertypes.ExportedApp{}, err
// }
// } else {
// panic("height cannot be < 0")
// laconicApp, err = app.NewLaconicApp(logger, db, true)
// if err != nil {
// return servertypes.ExportedApp{}, err
// }
// }
// return laconicApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
// }

View File

@ -1,65 +1,28 @@
package cmd
import (
"strings"
"time"
cmtcfg "github.com/cometbft/cometbft/config"
"cosmossdk.io/core/transaction"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/server/v2/cometbft"
sdk "github.com/cosmos/cosmos-sdk/types"
clientconfig "github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"cosmossdk.io/core/transaction"
)
// initAppConfig helps to override default client config template and configs.
// return "", nil if no custom configuration is required for the application.
func initClientConfig() (string, interface{}) {
type GasConfig struct {
GasAdjustment float64 `mapstructure:"gas-adjustment"`
}
type CustomClientConfig struct {
clientconfig.Config `mapstructure:",squash"`
GasConfig GasConfig `mapstructure:"gas"`
}
// Optionally allow the chain developer to overwrite the SDK's default client config.
clientCfg := clientconfig.DefaultConfig()
// The SDK's default keyring backend is set to "os".
// This is more secure than "test" and is the recommended value.
//
// In simapp, we set the default keyring backend to test, as SimApp is meant
// to be an example and testing application.
clientCfg.KeyringBackend = keyring.BackendTest
// Now we set the custom config default values.
customClientConfig := CustomClientConfig{
Config: *clientCfg,
GasConfig: GasConfig{
GasAdjustment: 1.5,
},
}
// The default SDK app template is defined in serverconfig.DefaultConfigTemplate.
// We append the custom config template to the default one.
// And we set the default config to the custom app template.
customClientConfigTemplate := clientconfig.DefaultClientConfigTemplate + strings.TrimSpace(`
# This is default the gas adjustment factor used in tx commands.
# It can be overwritten by the --gas-adjustment flag in each tx command.
gas-adjustment = {{ .GasConfig.GasAdjustment }}
`)
return customClientConfigTemplate, customClientConfig
// customClientConfigTemplate, customClientConfig
return "", nil
}
// Allow the chain developer to overwrite the server default app toml config.
func initServerConfig() serverv2.ServerConfig {
serverCfg := serverv2.DefaultServerConfig()
serverCfg.MinGasPrices = "0" + sdk.DefaultBondDenom
// The server's default minimum gas price is set to "0stake" inside
// app.toml. However, the chain developer can set a default app.toml value for their
// validators here. Please update value based on chain denom.
@ -79,9 +42,11 @@ func initCometConfig() cometbft.CfgOption {
cfg := cmtcfg.DefaultConfig()
// display only warn logs by default except for p2p and state
// better default logging
cfg.LogLevel = "*:warn,server:info,p2p:info,state:info"
cfg.LogLevel += ",auction:info,bond:info,registry:info,gql-server:info"
// increase block timeout
cfg.Consensus.TimeoutCommit = 5 * time.Second
cfg.Consensus.TimeoutCommit = 3 * time.Second
// overwrite default pprof listen address
cfg.RPC.PprofListenAddress = "localhost:6060"

View File

@ -0,0 +1,71 @@
package cmd
import (
"os"
clientv2keyring "cosmossdk.io/client/v2/autocli/keyring"
"cosmossdk.io/core/address"
runtime "cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
func ProvideClientContext(
configMap runtime.GlobalConfig,
appCodec codec.Codec,
interfaceRegistry codectypes.InterfaceRegistry,
txConfig client.TxConfig,
// legacyAmino registry.AminoRegistrar,
addressCodec address.Codec,
validatorAddressCodec address.ValidatorAddressCodec,
consensusAddressCodec address.ConsensusAddressCodec,
) client.Context {
var err error
homeDir, ok := configMap[serverv2.FlagHome].(string)
if !ok {
panic("server.ConfigMap must contain a string value for serverv2.FlagHome")
}
clientCtx := client.Context{}.
WithCodec(appCodec).
WithInterfaceRegistry(interfaceRegistry).
WithTxConfig(txConfig).
// WithLegacyAmino(amino).
WithInput(os.Stdin).
WithAccountRetriever(types.AccountRetriever{}).
WithAddressCodec(addressCodec).
WithValidatorAddressCodec(validatorAddressCodec).
WithConsensusAddressCodec(consensusAddressCodec).
WithHomeDir(homeDir).
WithViper(EnvPrefix) // env variable prefix
// Read the config to overwrite the default values with the values from the config file
customClientTemplate, customClientConfig := initClientConfig()
clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig)
if err != nil {
panic(err)
}
// // Workaround: Unset clientCtx.HomeDir and clientCtx.KeyringDir from depinject clientCtx as they
// // are given precedence over the CLI args (--home flag) in some commands
// // TODO: Implement proper fix
// clientCtx.HomeDir = ""
// clientCtx.KeyringDir = ""
return clientCtx
}
func ProvideKeyring(clientCtx client.Context, addressCodec address.Codec) (clientv2keyring.Keyring, error) {
kb, err := client.NewKeyringFromBackend(clientCtx, clientCtx.Keyring.Backend())
if err != nil {
return nil, err
}
return keyring.NewAutoCLIKeyring(kb, addressCodec)
}

View File

@ -1,181 +1,123 @@
package cmd
import (
"fmt"
"os"
"time"
"errors"
cmtcfg "github.com/cometbft/cometbft/config"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"cosmossdk.io/client/v2/autocli"
clientv2keyring "cosmossdk.io/client/v2/autocli/keyring"
"cosmossdk.io/core/address"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
runtime "cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/server"
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
"github.com/cosmos/cosmos-sdk/x/auth/types"
nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/gql"
)
const EnvPrefix = "LACONIC"
const (
// EnvPrefix is the environment variable prefix for the application
EnvPrefix = "LACONIC"
type moduleManager = *runtime.MM[transaction.Tx]
// DefaultNodeHome is the default data directory name for the application
DefaultNodeHome = ".laconicd"
)
// NewRootCmd creates a new root command for laconicd. It is called once in the
// main function.
func NewRootCmd() *cobra.Command {
var (
txConfigOpts tx.ConfigOptions
autoCliOpts autocli.AppOptions
moduleManager moduleManager
clientCtx client.Context
)
if err := depinject.InjectDebug(
depinject.Debug(),
depinject.Configs(
app.AppConfig(),
depinject.Supply(
log.NewNopLogger(),
),
depinject.Provide(
ProvideClientContext,
ProvideKeyring,
),
),
&txConfigOpts,
&autoCliOpts,
&moduleManager,
&clientCtx,
); err != nil {
panic(err)
func NewRootCmd[T app.Tx](
args ...string,
) (*cobra.Command, error) {
rootCommand := &cobra.Command{
Use: "laconicd",
SilenceErrors: true,
}
rootCmd := &cobra.Command{
Use: "laconicd",
Short: "Laconic Daemon",
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
// set the default command outputs
cmd.SetOut(cmd.OutOrStdout())
cmd.SetErr(cmd.ErrOrStderr())
clientCtx = clientCtx.WithCmdContext(cmd.Context()).WithViper(EnvPrefix)
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
clientCtx, err = config.CreateClientConfig(clientCtx, "", nil)
if err != nil {
return err
}
// sign mode textual is only available in online mode
if !clientCtx.Offline {
// This needs to happen after initializing the client context so the RPC client is set
txConfigOpts.EnabledSignModes = append(txConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL)
txConfigOpts.TextualCoinMetadataQueryFn = txmodule.NewGRPCCoinMetadataQueryFn(clientCtx)
txConfigWithTextual, err := tx.NewTxConfigWithOptions(
codec.NewProtoCodec(clientCtx.InterfaceRegistry),
txConfigOpts,
)
if err != nil {
return err
}
clientCtx = clientCtx.WithTxConfig(txConfigWithTextual)
}
if err := client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
return err
}
// overwrite the minimum gas price from the app configuration
srvCfg := serverconfig.DefaultConfig()
srvCfg.MinGasPrices = fmt.Sprintf("0%s", sdk.DefaultBondDenom)
// overwrite the block timeout
cmtCfg := cmtcfg.DefaultConfig()
// TODO use FinalizeBlockResponse.next_block_delay
cmtCfg.Consensus.TimeoutCommit = 3 * time.Second
cmtCfg.LogLevel = "*:error,p2p:info,state:info,auction:info,bond:info,registry:info,gql-server:info" // better default logging
return server.InterceptConfigsPreRunHandler(cmd, serverconfig.DefaultConfigTemplate, srvCfg, cmtCfg)
},
}
initRootCmd(rootCmd, clientCtx.TxConfig, moduleManager)
if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {
panic(err)
}
// Add flags for GQL server.
rootCmd = gql.AddGQLFlags(rootCmd)
return rootCmd
}
func ProvideClientContext(
appCodec codec.Codec,
interfaceRegistry codectypes.InterfaceRegistry,
txConfig client.TxConfig,
// legacyAmino registry.AminoRegistrar,
addressCodec address.Codec,
validatorAddressCodec address.ValidatorAddressCodec,
consensusAddressCodec address.ConsensusAddressCodec,
) client.Context {
var err error
clientCtx := client.Context{}.
WithCodec(appCodec).
WithInterfaceRegistry(interfaceRegistry).
WithTxConfig(txConfig).
// WithLegacyAmino(amino).
WithInput(os.Stdin).
WithAccountRetriever(types.AccountRetriever{}).
WithAddressCodec(addressCodec).
WithValidatorAddressCodec(validatorAddressCodec).
WithConsensusAddressCodec(consensusAddressCodec).
WithHomeDir(app.DefaultNodeHome).
WithViper(EnvPrefix) // env variable prefix
// Read the config to overwrite the default values with the values from the config file
clientCtx, err = config.CreateClientConfig(clientCtx, "", nil)
configWriter, err := InitRootCmd(rootCommand, log.NewNopLogger(), CommandDependencies[T]{})
if err != nil {
panic(err)
return nil, err
}
// Workaround: Unset clientCtx.HomeDir and clientCtx.KeyringDir from depinject clientCtx as they
// are given precedence over the CLI args (--home flag) in some commands
// TODO: Implement proper fix
clientCtx.HomeDir = ""
clientCtx.KeyringDir = ""
return clientCtx
}
func ProvideKeyring(clientCtx client.Context, addressCodec address.Codec) (clientv2keyring.Keyring, error) {
kb, err := client.NewKeyringFromBackend(clientCtx, clientCtx.Keyring.Backend())
factory, err := serverv2.NewCommandFactory(
serverv2.WithConfigWriter(configWriter),
serverv2.WithStdDefaultHomeDir(DefaultNodeHome),
serverv2.WithLoggerFactory(serverv2.NewLogger),
)
if err != nil {
return nil, err
}
return keyring.NewAutoCLIKeyring(kb, addressCodec)
nodeCmds := nodeservice.NewNodeCommands()
autoCLIModuleOpts := make(map[string]*autocliv1.ModuleOptions)
autoCLIModuleOpts[nodeCmds.Name()] = nodeCmds.AutoCLIOptions()
autoCliOpts, err := autocli.NewAppOptionsFromConfig(
depinject.Configs(app.AppConfig(), depinject.Supply(runtime.GlobalConfig{})),
autoCLIModuleOpts,
)
if err != nil {
return nil, err
}
if err = autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
}
subCommand, configMap, logger, err := factory.ParseCommand(rootCommand, args)
if err != nil {
if errors.Is(err, pflag.ErrHelp) {
return rootCommand, nil
}
return nil, err
}
var (
moduleManager *runtime.MM[T]
clientCtx client.Context
laconic *app.LaconicApp[T]
depinjectConfig = depinject.Configs(
depinject.Supply(logger, runtime.GlobalConfig(configMap)),
depinject.Provide(ProvideClientContext),
)
)
if serverv2.IsAppRequired(subCommand) {
// server construction
laconic, err = app.NewLaconicApp[T](depinjectConfig, &autoCliOpts, &moduleManager, &clientCtx)
if err != nil {
return nil, err
}
} else {
// client construction
if err = depinject.Inject(
depinject.Configs(
app.AppConfig(),
depinjectConfig,
),
&autoCliOpts, &moduleManager, &clientCtx,
); err != nil {
return nil, err
}
}
commandDeps := CommandDependencies[T]{
GlobalConfig: configMap,
TxConfig: clientCtx.TxConfig,
ModuleManager: moduleManager,
LaconicApp: laconic,
}
rootCommand = &cobra.Command{
Use: "laconicd",
Short: "Laconic Daemon",
SilenceErrors: true,
PersistentPreRunE: RootCommandPersistentPreRun(clientCtx),
}
factory.EnhanceRootCommand(rootCommand)
_, err = InitRootCmd(rootCommand, logger, commandDeps)
if err != nil {
return nil, err
}
autoCliOpts.ModuleOptions = autoCLIModuleOpts
if err := autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
}
return rootCommand, nil
}

View File

@ -0,0 +1,67 @@
package cmd_test
import (
"bytes"
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
)
func TestInitCmd(t *testing.T) {
args := []string{
"init", // Test the init cmd
"laconicd-test", // Moniker
fmt.Sprintf("--%s=%s", cli.FlagOverwrite, "true"), // Overwrite genesis.json, in case it already exists
}
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
require.NoError(t, err)
rootCmd.SetArgs(args)
require.NoError(t, rootCmd.Execute())
}
func TestHomeFlagRegistration(t *testing.T) {
homeDir := "/tmp/foo"
args := []string{
"query",
fmt.Sprintf("--%s", flags.FlagHome),
homeDir,
}
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
require.NoError(t, err)
rootCmd.SetArgs(args)
require.NoError(t, rootCmd.Execute())
result, err := rootCmd.Flags().GetString(flags.FlagHome)
require.NoError(t, err)
require.Equal(t, result, homeDir)
}
func TestHelpRequested(t *testing.T) {
argz := [][]string{
{"query", "--help"},
{"query", "tx", "-h"},
{"--help"},
{"start", "-h"},
}
for _, args := range argz {
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
require.NoError(t, err)
var out bytes.Buffer
rootCmd.SetArgs(args)
rootCmd.SetOut(&out)
require.NoError(t, rootCmd.Execute())
require.Contains(t, out.String(), args[0])
require.Contains(t, out.String(), "--help")
require.Contains(t, out.String(), "Usage:")
}
}

View File

@ -37,8 +37,6 @@ import (
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"git.vdb.to/cerc-io/laconicd/utils"
)
var (
@ -74,6 +72,14 @@ func addTestnetFlagsToCmd(cmd *cobra.Command) {
cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
cmd.Flags().String(serverv2.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
cmd.Flags().String(flags.FlagKeyType, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for")
cmd.Flags().String(flagNodeDirPrefix, "node", "Prefix for the name of per-validator subdirectories (to be number-suffixed like node0, node1, ...)")
cmd.Flags().String(flagNodeDaemonHome, "laconicd", "Home directory of the node's daemon configuration")
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
cmd.Flags().String(flagListenIPAddress, "127.0.0.1", "TCP or UNIX socket IP address for the RPC server to listen on")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
cmd.Flags().Duration(flagCommitTimeout, 5*time.Second, "Time to wait after a block commit before starting on the new height")
cmd.Flags().Bool(flagSingleHost, false, "Cluster runs on a single host machine with different ports")
cmd.Flags().String(flagStakingDenom, sdk.DefaultBondDenom, "Default staking token denominator")
}
// NewTestnetCmd creates a root testnet command with subcommands to run an in-process testnet or initialize
@ -139,15 +145,6 @@ Example:
}
addTestnetFlagsToCmd(cmd)
cmd.Flags().String(flagNodeDirPrefix, "node", "Prefix for the name of per-validator subdirectories (to be number-suffixed like node0, node1, ...)")
cmd.Flags().String(flagNodeDaemonHome, "laconicd", "Home directory of the node's daemon configuration")
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
cmd.Flags().String(flagListenIPAddress, "127.0.0.1", "TCP or UNIX socket IP address for the RPC server to listen on")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
cmd.Flags().Duration(flagCommitTimeout, 5*time.Second, "Time to wait after a block commit before starting on the new height")
cmd.Flags().Bool(flagSingleHost, false, "Cluster runs on a single host machine with different ports")
cmd.Flags().String(flagStakingDenom, sdk.DefaultBondDenom, "Default staking token denominator")
return cmd
}
@ -327,15 +324,10 @@ func initTestnetFiles[T transaction.Tx](
serverCfg := serverv2.DefaultServerConfig()
serverCfg.MinGasPrices = args.minGasPrices
// Write server config
cometServer := cometbft.New[T](
utils.GenericTxDecoder[T]{clientCtx.TxConfig},
cometbft.ServerOptions[T]{},
cometbft.OverwriteDefaultConfigTomlConfig(nodeConfig),
)
storeServer := store.New[T]()
grpcServer := grpc.New[T](grpc.OverwriteDefaultConfig(grpcConfig))
server := serverv2.NewServer[T](serverCfg, cometServer, grpcServer, storeServer)
cometServer := cometbft.NewWithConfigOptions[T](cometbft.OverwriteDefaultConfigTomlConfig(nodeConfig))
storeServer := &store.Server[T]{}
grpcServer := grpc.NewWithConfigOptions[T](grpc.OverwriteDefaultConfig(grpcConfig))
server := serverv2.NewServer[T](serverCfg, cometServer, storeServer, grpcServer)
err = server.WriteConfig(filepath.Join(nodeDir, "config"))
if err != nil {
return err

View File

@ -6,7 +6,6 @@ import (
"github.com/stretchr/testify/require"
svrcmd "cosmossdk.io/server/v2"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
@ -15,12 +14,13 @@ import (
)
func TestInitTestFilesCmd(t *testing.T) {
rootCmd := cmd.NewRootCmd()
rootCmd.SetArgs([]string{
args := []string{
"testnet", // Test the testnet init-files command
"init-files",
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), // Set keyring-backend to test
})
require.NoError(t, svrcmd.Execute(rootCmd, "", app.DefaultNodeHome))
}
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
require.NoError(t, err)
rootCmd.SetArgs(args)
require.NoError(t, rootCmd.Execute())
}

View File

@ -1,28 +0,0 @@
package main_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
svrcmd "cosmossdk.io/server/v2"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
)
func TestInitCmd(t *testing.T) {
rootCmd := cmd.NewRootCmd()
rootCmd.SetArgs([]string{
"init", // Test the init cmd
"localtestnet", // Moniker
fmt.Sprintf("--%s=%s", cli.FlagOverwrite, "true"), // Overwrite genesis.json, in case it already exists
fmt.Sprintf("--%s=%s", flags.FlagChainID, "laconic_9000-1"),
})
err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome)
require.NoError(t, err)
}

View File

@ -1,22 +1,31 @@
package main
import (
"errors"
"fmt"
"os"
"git.vdb.to/cerc-io/laconicd/app"
"git.vdb.to/cerc-io/laconicd/cmd/laconicd/cmd"
clientv2helpers "cosmossdk.io/client/v2/helpers"
serverv2 "cosmossdk.io/server/v2"
_ "git.vdb.to/cerc-io/laconicd/app/params" // import for side-effects
)
func main() {
rootCmd := cmd.NewRootCmd()
if err := serverv2.Execute(rootCmd, clientv2helpers.EnvPrefix, app.DefaultNodeHome); err != nil {
fmt.Fprintln(rootCmd.OutOrStderr(), err)
// reproduce default cobra behavior so that eager parsing of flags is possible.
// see: https://github.com/spf13/cobra/blob/e94f6d0dd9a5e5738dca6bce03c4b1207ffbc0ec/command.go#L1082
args := os.Args[1:]
rootCmd, err := cmd.NewRootCmd[app.Tx](args...)
if err != nil {
if _, pErr := fmt.Fprintln(os.Stderr, err); pErr != nil {
panic(errors.Join(err, pErr))
}
os.Exit(1)
}
if err = rootCmd.Execute(); err != nil {
if _, pErr := fmt.Fprintln(rootCmd.OutOrStderr(), err); pErr != nil {
panic(errors.Join(err, pErr))
}
os.Exit(1)
}
}

47
go.mod
View File

@ -15,9 +15,9 @@ replace (
require (
cosmossdk.io/api v0.7.6
cosmossdk.io/client/v2 v2.0.0-beta.1
cosmossdk.io/collections v0.4.0
cosmossdk.io/core v1.0.0-alpha.5
cosmossdk.io/depinject v1.0.0
cosmossdk.io/collections v0.4.1-0.20241104084251-838f1557af0a
cosmossdk.io/core v1.0.0-alpha.5.0.20241108140525-43e28b43ad7a
cosmossdk.io/depinject v1.1.0
cosmossdk.io/errors v1.0.1
cosmossdk.io/log v1.4.1
cosmossdk.io/math v1.3.0
@ -46,13 +46,17 @@ require (
github.com/ipld/go-ipld-prime v0.21.0
github.com/rs/cors v1.11.1
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.19.0
github.com/statechannels/go-nitro v0.1.2
github.com/stretchr/testify v1.9.0
github.com/tidwall/gjson v1.14.4
github.com/tidwall/sjson v1.2.5
github.com/vektah/gqlparser/v2 v2.5.11
golang.org/x/sync v0.8.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142
google.golang.org/grpc v1.67.1
go.uber.org/mock v0.5.0
golang.org/x/sync v0.9.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1
google.golang.org/grpc v1.68.0
google.golang.org/protobuf v1.35.1
gopkg.in/yaml.v3 v3.0.1
)
@ -61,6 +65,9 @@ require (
cosmossdk.io/server/v2/appmanager v0.0.0-20240802110823-cffeedff643d
cosmossdk.io/server/v2/stf v0.0.0-20240708142107-25e99c54bac1
cosmossdk.io/x/accounts v1.0.0-alpha.4
cosmossdk.io/x/accounts/defaults/base v0.0.0-00010101000000-000000000000
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-00010101000000-000000000000
cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000
cosmossdk.io/x/bank v1.0.0-alpha.4
cosmossdk.io/x/consensus v0.0.0-20241007000829-38662ecb209f
cosmossdk.io/x/distribution v0.0.0-20241007000829-38662ecb209f
@ -69,15 +76,12 @@ require (
cosmossdk.io/x/protocolpool v1.0.0-alpha.4
cosmossdk.io/x/slashing v0.0.0-20241007000829-38662ecb209f
cosmossdk.io/x/staking v1.0.0-alpha.4
github.com/tidwall/gjson v1.14.4
github.com/tidwall/sjson v1.2.5
go.uber.org/mock v0.5.0
)
require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.35.1-20240701160653-fedbb9acfd2f.1 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1 // indirect
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 // indirect
cosmossdk.io/core/testing v0.0.0 // indirect
cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 // indirect
cosmossdk.io/schema v0.3.1-0.20241010135032-192601639cac // indirect
cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 // indirect
@ -107,7 +111,7 @@ require (
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/crypto v0.1.2 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/iavl v1.3.0 // indirect
github.com/cosmos/iavl v1.3.1 // indirect
github.com/cosmos/ics23/go v0.11.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect
github.com/creachadair/atomicfile v0.3.5 // indirect
@ -122,7 +126,7 @@ require (
github.com/emicklei/dot v1.6.2 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/getsentry/sentry-go v0.27.0 // indirect
github.com/go-kit/kit v0.13.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
@ -204,7 +208,6 @@ require (
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/supranational/blst v0.3.13 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
@ -219,14 +222,14 @@ require (
go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/term v0.25.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/term v0.26.0 // indirect
golang.org/x/text v0.20.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gotest.tools/v3 v3.5.1 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
@ -256,6 +259,8 @@ replace (
// cosmossdk.io/core => ../cosmos-sdk/core
cosmossdk.io/api => ../cosmos-sdk/api
cosmossdk.io/client/v2 => ../cosmos-sdk/client/v2
cosmossdk.io/core/testing => ../cosmos-sdk/core/testing
cosmossdk.io/depinject => ../cosmos-sdk/depinject
cosmossdk.io/runtime/v2 => ../cosmos-sdk/runtime/v2
cosmossdk.io/server/v2 => ../cosmos-sdk/server/v2
cosmossdk.io/server/v2/appmanager => ../cosmos-sdk/server/v2/appmanager
@ -265,6 +270,9 @@ replace (
cosmossdk.io/store/v2 => ../cosmos-sdk/store/v2
cosmossdk.io/tests/systemtests => ../cosmos-sdk/tests/systemtests
cosmossdk.io/x/accounts => ../cosmos-sdk/x/accounts
cosmossdk.io/x/accounts/defaults/base => ../cosmos-sdk/x/accounts/defaults/base
cosmossdk.io/x/accounts/defaults/lockup => ../cosmos-sdk/x/accounts/defaults/lockup
cosmossdk.io/x/accounts/defaults/multisig => ../cosmos-sdk/x/accounts/defaults/multisig
cosmossdk.io/x/bank => ../cosmos-sdk/x/bank
cosmossdk.io/x/consensus => ../cosmos-sdk/x/consensus
cosmossdk.io/x/distribution => ../cosmos-sdk/x/distribution
@ -276,7 +284,10 @@ replace (
cosmossdk.io/x/slashing => ../cosmos-sdk/x/slashing
cosmossdk.io/x/staking => ../cosmos-sdk/x/staking
cosmossdk.io/x/tx => ../cosmos-sdk/x/tx
github.com/cometbft/cometbft => ../cometbft
github.com/cosmos/cosmos-sdk => ../cosmos-sdk
github.com/cosmos/cosmos-sdk/tests => ../cosmos-sdk/tests
)
replace google.golang.org/protobuf => /Users/roy/clone/protobuf-go

74
go.sum
View File

@ -4,14 +4,10 @@ buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88e
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1/go.mod h1:zqi/LZjZhyvjCMTEVIwAf5VRlkLduuCfqmZxgoormq0=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v1.0.0-alpha.5 h1:McjYXAQ6XcT20v2uHyH7PhoWH8V+mebzfVFqT3GinsI=
cosmossdk.io/core v1.0.0-alpha.5/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 h1:NxxUo0GMJUbIuVg0R70e3cbn9eFTEuMr7ev1AFvypdY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29/go.mod h1:8s2tPeJtSiQuoyPmr2Ag7meikonISO4Fv4MoO8+ORrs=
cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050=
cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8=
cosmossdk.io/collections v0.4.1-0.20241104084251-838f1557af0a h1:9DxUD+82dO3c+R3XqwW+a7i4nVLiN6I0g2rp2rLOh7E=
cosmossdk.io/collections v0.4.1-0.20241104084251-838f1557af0a/go.mod h1:DcD++Yfcq0OFtM3CJNYLIBjfZ+4DEyeJ/AUk6gkwlOE=
cosmossdk.io/core v1.0.0-alpha.5.0.20241108140525-43e28b43ad7a h1:iN3KJqxjdsIxHDKOFjQ6GQpQNYwcqnhVR9jkuwU7bDA=
cosmossdk.io/core v1.0.0-alpha.5.0.20241108140525-43e28b43ad7a/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY=
cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=
cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U=
cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA=
@ -144,8 +140,8 @@ github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ
github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU=
github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro=
github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0=
github.com/cosmos/iavl v1.3.0 h1:Ezaxt8aPA3kbkhsfyqwenChGLQwHDAIif3tG9x1FMV8=
github.com/cosmos/iavl v1.3.0/go.mod h1:T6SfBcyhulVIY2G/ZtAtQm/QiJvsuhIos52V4dWYk88=
github.com/cosmos/iavl v1.3.1 h1:+W1G2uSUtJMqMGpwz/fKiwZxY2DDT/9/0hyNLm6Geu0=
github.com/cosmos/iavl v1.3.1/go.mod h1:T6SfBcyhulVIY2G/ZtAtQm/QiJvsuhIos52V4dWYk88=
github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU=
github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0=
github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM=
@ -210,8 +206,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@ -257,11 +253,6 @@ github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
@ -277,7 +268,6 @@ github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl76
github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@ -628,8 +618,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
@ -675,8 +665,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -716,12 +706,12 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -729,8 +719,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -759,10 +749,10 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
@ -773,24 +763,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -81,7 +81,7 @@ func NewTestNetworkFixture() network.TestFixture {
}
abci, err := setUpConsensus(
val.GetLogger(), 100_000, mempool.NoOpMempool[laconicApp.AppTx]{},
val.GetLogger(), 100_000, mempool.NoOpMempool[laconicApp.Tx]{},
dir, val.GetClientCtx().TxConfig)
if err != nil {
panic(fmt.Errorf("failed to build ABCI app: %w", err))

27
tests/system/cli.go Normal file
View File

@ -0,0 +1,27 @@
package system
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"cosmossdk.io/tests/systemtests"
)
func NewCLIWrapper(t *testing.T, sut *SystemUnderTest, verbose bool, fees string) *systemtests.CLIWrapper {
t.Helper()
return systemtests.NewCLIWrapperX(
t,
sut.execBinary,
sut.rpcAddr,
sut.chainID,
sut.AwaitNextBlock,
sut.nodesCount,
filepath.Join(WorkDir, sut.outputDir),
fees,
verbose,
assert.NoError,
true,
)
}

151
tests/system/events.go Normal file
View File

@ -0,0 +1,151 @@
package system
import (
"context"
"testing"
"time"
"github.com/cometbft/cometbft/libs/sync"
client "github.com/cometbft/cometbft/rpc/client/http"
ctypes "github.com/cometbft/cometbft/rpc/core/types"
"github.com/stretchr/testify/require"
)
// EventListener watches for events on the chain
type EventListener struct {
t *testing.T
client *client.HTTP
}
var DefaultWaitTime = 30 * time.Second
type (
CleanupFn func()
EventConsumer func(e ctypes.ResultEvent) (more bool)
)
// NewEventListener event listener
func NewEventListener(t *testing.T, rpcAddr string) *EventListener {
t.Helper()
httpClient, err := client.New(rpcAddr)
require.NoError(t, err)
require.NoError(t, httpClient.Start())
return &EventListener{client: httpClient, t: t}
}
// Subscribe to receive events for a topic. Does not block.
// For query syntax See https://docs.cosmos.network/master/core/events.html#subscribing-to-events
func (l *EventListener) Subscribe(query string, cb EventConsumer) func() {
ctx, done := context.WithCancel(context.Background())
l.t.Cleanup(done)
eventsChan, err := l.client.WSEvents.Subscribe(ctx, "testing", query)
require.NoError(l.t, err)
cleanup := func() {
ctx, _ := context.WithTimeout(ctx, DefaultWaitTime) //nolint:govet // used in cleanup only
go l.client.WSEvents.Unsubscribe(ctx, "testing", query) //nolint:errcheck // used by tests only
done()
}
go func() {
for e := range eventsChan {
if !cb(e) {
return
}
}
}()
return cleanup
}
// AwaitQuery blocks and waits for a single result or timeout. This can be used with `broadcast-mode=async`.
// For query syntax See https://docs.cosmos.network/master/core/events.html#subscribing-to-events
func (l *EventListener) AwaitQuery(query string, optMaxWaitTime ...time.Duration) *ctypes.ResultEvent {
c, result := CaptureSingleEventConsumer()
maxWaitTime := DefaultWaitTime
if len(optMaxWaitTime) != 0 {
maxWaitTime = optMaxWaitTime[0]
}
cleanupFn := l.Subscribe(query, TimeoutConsumer(l.t, maxWaitTime, c))
l.t.Cleanup(cleanupFn)
return result
}
// TimeoutConsumer is an event consumer decorator with a max wait time. Panics when wait time exceeded without
// a result returned
func TimeoutConsumer(t *testing.T, maxWaitTime time.Duration, next EventConsumer) EventConsumer {
t.Helper()
ctx, done := context.WithCancel(context.Background())
t.Cleanup(done)
timeout := time.NewTimer(maxWaitTime)
timedOut := make(chan struct{}, 1)
go func() {
select {
case <-ctx.Done():
case <-timeout.C:
timedOut <- struct{}{}
close(timedOut)
}
}()
return func(e ctypes.ResultEvent) (more bool) {
select {
case <-timedOut:
t.Fatalf("Timeout waiting for new events %s", maxWaitTime)
return false
default:
timeout.Reset(maxWaitTime)
result := next(e)
if !result {
done()
}
return result
}
}
}
// CaptureSingleEventConsumer consumes one event. No timeout
func CaptureSingleEventConsumer() (EventConsumer, *ctypes.ResultEvent) {
var result ctypes.ResultEvent
return func(e ctypes.ResultEvent) (more bool) {
return false
}, &result
}
// CaptureAllEventsConsumer is an `EventConsumer` that captures all events until `done()` is called to stop or timeout happens.
// The consumer works async in the background and returns all the captured events when `done()` is called.
// This can be used to verify that certain events have happened.
// Example usage:
//
// c, done := CaptureAllEventsConsumer(t)
// query := `tm.event='Tx'`
// cleanupFn := l.Subscribe(query, c)
// t.Cleanup(cleanupFn)
//
// // do something in your test that create events
//
// assert.Len(t, done(), 1) // then verify your assumption
func CaptureAllEventsConsumer(t *testing.T, optMaxWaitTime ...time.Duration) (c EventConsumer, done func() []ctypes.ResultEvent) {
t.Helper()
maxWaitTime := DefaultWaitTime
if len(optMaxWaitTime) != 0 {
maxWaitTime = optMaxWaitTime[0]
}
var (
mu sync.Mutex
capturedEvents []ctypes.ResultEvent
exit bool
)
collectEventsConsumer := func(e ctypes.ResultEvent) (more bool) {
mu.Lock()
defer mu.Unlock()
if exit {
return false
}
capturedEvents = append(capturedEvents, e)
return true
}
return TimeoutConsumer(t, maxWaitTime, collectEventsConsumer), func() []ctypes.ResultEvent {
mu.Lock()
defer mu.Unlock()
exit = true
return capturedEvents
}
}

View File

@ -0,0 +1,7 @@
package system
import "testing"
func TestMain(m *testing.M) {
RunTests(m)
}

View File

@ -0,0 +1,234 @@
package system
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
"cosmossdk.io/math"
"cosmossdk.io/tests/systemtests"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
registrytypes "git.vdb.to/cerc-io/laconicd/x/registry"
)
var recordFilePath = "../data/examples/service_provider_example.yml"
func init() {
var err error
if recordFilePath, err = filepath.Abs(recordFilePath); err != nil {
panic(err)
}
if _, err = os.Stat(recordFilePath); err != nil {
panic(err)
}
}
type systemTestSuite struct {
t *testing.T
fees string
}
type registryTestSuite struct {
*systemTestSuite
accountName string
accountAddress string
bondDenom string
bondId string
}
func newSystemTestSuite(t *testing.T, fees string) *systemTestSuite {
return &systemTestSuite{
t: t,
fees: fees,
}
}
func (s *systemTestSuite) cli() *systemtests.CLIWrapper {
return NewCLIWrapper(s.t, sut, verbose, s.fees)
}
func (s *systemTestSuite) SubTest(name string, f func(t *systemTestSuite)) {
s.t.Run(name, func(t *testing.T) {
subsuite := newSystemTestSuite(t, s.fees)
f(subsuite)
})
}
// run manually:
// go test ./tests/system -test.v -timeout 10m --verbose --nodes-count 1 -run TestRegistrySetRecord
func TestRegistrySetRecord(t *testing.T) {
s := setupSuite(t)
testCases := []struct {
name string
args []string
err bool
}{
{
"request with invalid payload file arg",
[]string{"bad-file", s.bondId},
true,
},
{
"success",
append([]string{recordFilePath, s.bondId}, s.commonTxFlags()...),
false,
},
}
for _, tc := range testCases {
s.SubTest(fmt.Sprintf("Case %s", tc.name), func(s *systemTestSuite) {
cli := s.cli()
cmd := append([]string{"tx", "registry", "set"}, tc.args...)
if tc.err {
cli := cli.WithRunErrorMatcher(assert.Error)
_ = cli.RunCommandWithArgs(cmd...)
} else {
txhash := cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
}
})
}
}
func setupSuite(t *testing.T) *registryTestSuite {
sut.ResetChain(t)
accountName := "node0"
bondDenom := sdk.DefaultBondDenom
var accountAddress string
s := newSystemTestSuite(t, "3"+bondDenom)
registry := codectypes.NewInterfaceRegistry()
// codec.RegisterInterfaces(registry)
cdc := codec.NewProtoCodec(registry)
sut.ModifyGenesisJSON(t, func(genesis []byte) []byte {
accountAddress = s.cli().GetKeyAddr(accountName)
// update registry genesis params
var regState registrytypes.GenesisState
rawSupply := gjson.Get(string(genesis), "app_state.registry").String()
require.NoError(t, cdc.UnmarshalJSON([]byte(rawSupply), &regState))
updateParams(&regState.Params, bondDenom)
regStateBz, err := cdc.MarshalJSON(&regState)
require.NoError(t, err)
genesis, err = sjson.SetRawBytes(genesis, "app_state.registry", regStateBz)
require.NoError(t, err)
return genesis
})
sut.StartChain(t)
rts := registryTestSuite{
systemTestSuite: s,
accountName: accountName,
accountAddress: accountAddress,
bondDenom: bondDenom,
}
rts.bondId = createBond(&rts)
return &rts
}
func createBond(s *registryTestSuite) string {
cli := s.cli()
cmd := []string{
"tx", "bond", "create",
fmt.Sprintf("1000000%s", s.bondDenom),
"--from", s.accountName,
}
txhash := cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
raw := cli.CustomQuery("q", "bond", "list")
var queryResponse bondtypes.QueryBondsResponse
require.NoError(s.t, json.Unmarshal([]byte(raw), &queryResponse))
bonds := queryResponse.GetBonds()
require.NotEmpty(s.t, bonds)
return bonds[0].GetId()
}
func reserveName(s *registryTestSuite, authorityName string) {
cli := s.cli()
cmd := []string{
"tx", "registry", "reserve-authority",
authorityName,
s.accountAddress,
}
txhash := cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
}
func createNameRecord(s *registryTestSuite, authorityName string) {
cli := s.cli()
// reserve name authority
cmd := []string{
"tx", "registry", "reserve-authority",
authorityName,
s.accountAddress,
}
txhash := cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
// add bond-id to name authority
cmd = []string{
"tx", "registry", "authority-bond",
authorityName, s.bondId,
}
txhash = cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
cmd = []string{
"tx", "registry", "set-name",
fmt.Sprintf("lrn://%s/", authorityName),
"test_hello_cid",
}
txhash = cli.Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
}
func createRecord(s *registryTestSuite, bondId string) {
cmd := []string{
"tx", "registry", "set",
recordFilePath, bondId,
}
txhash := s.cli().Run(cmd...)
systemtests.RequireTxSuccess(s.t, txhash)
}
func updateParams(params *registrytypes.Params, bondDenom string) {
params.RecordRent = sdk.NewCoin(bondDenom, math.NewInt(1000))
params.RecordRentDuration = 10 * time.Second
params.AuthorityRent = sdk.NewCoin(bondDenom, math.NewInt(1000))
params.AuthorityGracePeriod = 10 * time.Second
params.AuthorityAuctionCommitFee = sdk.NewCoin(bondDenom, math.NewInt(100))
params.AuthorityAuctionRevealFee = sdk.NewCoin(bondDenom, math.NewInt(100))
params.AuthorityAuctionMinimumBid = sdk.NewCoin(bondDenom, math.NewInt(500))
}
func (s registryTestSuite) commonTxFlags() []string {
return []string{
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.accountName),
// fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
// fmt.Sprintf("--%s=json", flags.FlagOutput),
// fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
// fmt.Sprintf("--%s=%s", flags.FlagFees, fmt.Sprintf("3%s", s.bondDenom)),
}
}

133
tests/system/test_runner.go Normal file
View File

@ -0,0 +1,133 @@
package system
import (
"flag"
"fmt"
"os"
"os/exec"
"strconv"
"strings"
"testing"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var (
sut *SystemUnderTest
verbose bool
execBinaryName = "laconicd"
// block time (commit timeout) should match what the testnet command generates
blockTime = time.Second
)
func RunTests(m *testing.M) {
waitTime := flag.Duration("wait-time", DefaultWaitTime, "time to wait for chain events")
nodesCount := flag.Int("nodes-count", 4, "number of nodes in the cluster")
// blockTime := flag.Duration("block-time", 1000*time.Millisecond, "block creation time")
// execBinary := flag.String("binary", "simd", "executable binary for server/ client side")
// bech32Prefix := flag.String("bech32", "cosmos", "bech32 prefix to be used with addresses")
flag.BoolVar(&verbose, "verbose", false, "verbose output")
flag.Parse()
// fail fast on most common setup issue
requireEnoughFileHandlers(*nodesCount + 1) // +1 as tests may start another node
dir, err := os.Getwd()
if err != nil {
panic(err)
}
WorkDir = dir
if verbose {
println("Work dir: ", WorkDir)
}
initSDKConfig("laconic")
DefaultWaitTime = *waitTime
// if *execBinary == "" {
// panic("executable binary name must not be empty")
// }
// sdk systemtests expects this to be set for v2 server/runtime
os.Setenv("COSMOS_BUILD_OPTIONS", "v2")
sut = NewSystemUnderTest(execBinaryName, verbose, *nodesCount, blockTime)
sut.SetupChain() // setup chain and keyring
// run tests
exitCode := m.Run()
// postprocess
sut.StopChain()
if verbose || exitCode != 0 {
sut.PrintBuffer()
printResultFlag(exitCode == 0)
}
os.Exit(exitCode)
}
func GetSystemUnderTest() *SystemUnderTest {
return sut
}
func IsVerbose() bool {
return verbose
}
func GetExecutableName() string {
return execBinaryName
}
// requireEnoughFileHandlers uses `ulimit`
func requireEnoughFileHandlers(nodesCount int) {
ulimit, err := exec.LookPath("ulimit")
if err != nil || ulimit == "" { // skip when not available
return
}
cmd := exec.Command(ulimit, "-n")
cmd.Dir = WorkDir
out, err := cmd.CombinedOutput()
if err != nil {
panic(fmt.Sprintf("unexpected error :%#+v, output: %s", err, string(out)))
}
fileDescrCount, err := strconv.Atoi(strings.Trim(string(out), " \t\n"))
if err != nil {
panic(fmt.Sprintf("unexpected error :%#+v, output: %s", err, string(out)))
}
expFH := nodesCount * 260 // random number that worked on my box
if fileDescrCount < expFH {
panic(fmt.Sprintf("Fail fast. Insufficient setup. Run 'ulimit -n %d'", expFH))
}
}
func initSDKConfig(bech32Prefix string) {
config := sdk.GetConfig()
config.SetBech32PrefixForAccount(bech32Prefix, bech32Prefix+sdk.PrefixPublic)
config.SetBech32PrefixForValidator(bech32Prefix+sdk.PrefixValidator+sdk.PrefixOperator, bech32Prefix+sdk.PrefixValidator+sdk.PrefixOperator+sdk.PrefixPublic)
config.SetBech32PrefixForConsensusNode(bech32Prefix+sdk.PrefixValidator+sdk.PrefixConsensus, bech32Prefix+sdk.PrefixValidator+sdk.PrefixConsensus+sdk.PrefixPublic)
}
const (
successFlag = `
___ _ _ ___ ___ ___ ___ ___
/ __| | | |/ __/ __/ _ \/ __/ __|
\__ \ |_| | (_| (_| __/\__ \__ \
|___/\__,_|\___\___\___||___/___/`
failureFlag = `
__ _ _ _
/ _| (_) | | |
| |_ __ _ _| | ___ __| |
| _/ _| | | |/ _ \/ _| |
| || (_| | | | __/ (_| |
|_| \__,_|_|_|\___|\__,_|`
)
func printResultFlag(ok bool) {
if ok {
fmt.Println(successFlag)
} else {
fmt.Println(failureFlag)
}
}

View File

@ -29,7 +29,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "GetAuction",
Use: "get [auction-id]",
Use: "get <auction-id>",
Short: "Get auction info by auction id",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "id"},
@ -37,7 +37,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "AuctionsByOwner",
Use: "by-owner [owner-address]",
Use: "by-owner <owner-address>",
Short: "Get auctions list by owner / creator address",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "owner_address"},
@ -45,7 +45,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "GetBid",
Use: "get-bid [auction-id] [bidder]",
Use: "get-bid <auction-id> <bidder>",
Short: "Get auction bid by auction id and bidder",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "auction_id"},
@ -54,7 +54,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "GetBids",
Use: "get-bids [auction-id]",
Use: "get-bids <auction-id>",
Short: "Get all auction bids",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "auction_id"},
@ -62,7 +62,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "AuctionsByBidder",
Use: "by-bidder [bidder]",
Use: "by-bidder <bidder>",
Short: "Get auctions list by bidder",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "bidder_address"},
@ -81,7 +81,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "CreateAuction",
Use: "create [commits-duration] [reveals-duration] [commit-fee] [reveal-fee]",
Use: "create <commits-duration> <reveals-duration> <commit-fee> <reveal-fee>",
Short: "Create an auction",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "commits_duration"},

View File

@ -14,7 +14,7 @@ import (
// Used in e2e tests
func NewCreateBondCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create [amount]",
Use: "create <amount>",
Short: "Create bond.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {

View File

@ -172,7 +172,7 @@ func (k Keeper) GetBondById(ctx context.Context, id string) (bondtypes.Bond, err
bond, err := k.Bonds.Get(ctx, id)
if err != nil {
if errors.Is(err, collections.ErrNotFound) {
return bondtypes.Bond{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found.")
err = errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Bond not found")
}
return bondtypes.Bond{}, err
}
@ -397,8 +397,8 @@ func (k Keeper) getMaxBondAmount(ctx context.Context) (sdk.Coins, error) {
return sdk.NewCoins(maxBondAmount), nil
}
// TransferCoinsToModuleAccount moves funds from the bonds module account to another module account.
func (k Keeper) TransferCoinsToModuleAccount(ctx context.Context, id, moduleAccount string, coins sdk.Coins) error {
// TransferRentToModuleAccount sends rent from a bond to a module account.
func (k Keeper) TransferRentToModuleAccount(ctx context.Context, id, moduleAccount string, rent sdk.Coins) error {
if has, err := k.HasBond(ctx, id); !has {
if err != nil {
return err
@ -412,15 +412,14 @@ func (k Keeper) TransferCoinsToModuleAccount(ctx context.Context, id, moduleAcco
}
// Deduct rent from bond.
updatedBalance, isNeg := bond.Balance.SafeSub(coins...)
updatedBalance, isNeg := bond.Balance.SafeSub(rent...)
if isNeg {
// Check if bond has sufficient funds.
return errorsmod.Wrap(sdkerrors.ErrInsufficientFunds, "Insufficient funds.")
}
// Move funds from bond module to record rent module.
err = k.bankKeeper.SendCoinsFromModuleToModule(ctx, bondtypes.ModuleName, moduleAccount, coins)
err = k.bankKeeper.SendCoinsFromModuleToModule(ctx, bondtypes.ModuleName, moduleAccount, rent)
if err != nil {
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Error transferring funds.")
}

View File

@ -11,18 +11,17 @@ import (
"git.vdb.to/cerc-io/laconicd/x/bond"
)
var _ bond.MsgServer = msgServer{}
type msgServer struct {
type msgHandlers struct {
k *Keeper
}
// NewMsgServerImpl returns an implementation of the module MsgServer interface.
func NewMsgServerImpl(keeper *Keeper) bond.MsgServer {
return &msgServer{k: keeper}
// NewHandlers returns an implementation of the module MsgServer interface.
func NewHandlers(keeper *Keeper) msgHandlers {
return msgHandlers{k: keeper}
}
func (ms msgServer) CreateBond(c context.Context, msg *bond.MsgCreateBond) (*bond.MsgCreateBondResponse, error) {
func (ms msgHandlers) CreateBond(c context.Context, msg *bond.MsgCreateBond) (*bond.MsgCreateBondResponse, error) {
panic("handlers.CreateBond is definitely called")
if err := msg.ValidateBasic(); err != nil {
return nil, err
}
@ -60,7 +59,7 @@ func (ms msgServer) CreateBond(c context.Context, msg *bond.MsgCreateBond) (*bon
}
// RefillBond implements bond.MsgServer.
func (ms msgServer) RefillBond(c context.Context, msg *bond.MsgRefillBond) (*bond.MsgRefillBondResponse, error) {
func (ms msgHandlers) RefillBond(c context.Context, msg *bond.MsgRefillBond) (*bond.MsgRefillBondResponse, error) {
if err := msg.ValidateBasic(); err != nil {
return nil, err
}
@ -99,7 +98,7 @@ func (ms msgServer) RefillBond(c context.Context, msg *bond.MsgRefillBond) (*bon
}
// WithdrawBond implements bond.MsgServer.
func (ms msgServer) WithdrawBond(c context.Context, msg *bond.MsgWithdrawBond) (*bond.MsgWithdrawBondResponse, error) {
func (ms msgHandlers) WithdrawBond(c context.Context, msg *bond.MsgWithdrawBond) (*bond.MsgWithdrawBondResponse, error) {
if err := msg.ValidateBasic(); err != nil {
return nil, err
}
@ -138,7 +137,7 @@ func (ms msgServer) WithdrawBond(c context.Context, msg *bond.MsgWithdrawBond) (
}
// CancelBond implements bond.MsgServer.
func (ms msgServer) CancelBond(c context.Context, msg *bond.MsgCancelBond) (*bond.MsgCancelBondResponse, error) {
func (ms msgHandlers) CancelBond(c context.Context, msg *bond.MsgCancelBond) (*bond.MsgCancelBondResponse, error) {
if err := msg.ValidateBasic(); err != nil {
return nil, err
}
@ -176,7 +175,7 @@ func (ms msgServer) CancelBond(c context.Context, msg *bond.MsgCancelBond) (*bon
}
// UpdateParams defines a method to perform updation of module params.
func (ms msgServer) UpdateParams(c context.Context, msg *bond.MsgUpdateParams) (*bond.MsgUpdateParamsResponse, error) {
func (ms msgHandlers) UpdateParams(c context.Context, msg *bond.MsgUpdateParams) (*bond.MsgUpdateParamsResponse, error) {
if ms.k.authority != msg.Authority {
return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", ms.k.authority, msg.Authority)
}

View File

@ -9,19 +9,17 @@ import (
bondtypes "git.vdb.to/cerc-io/laconicd/x/bond"
)
var _ bondtypes.QueryServer = queryServer{}
type queryServer struct {
type queryHandlers struct {
k *Keeper
}
// NewQueryServerImpl returns an implementation of the module QueryServer.
func NewQueryServerImpl(k *Keeper) bondtypes.QueryServer {
return queryServer{k}
// NewQueryHandlers returns an implementation of the module QueryServer.
func NewQueryHandlers(k *Keeper) bondtypes.QueryServer {
return queryHandlers{k}
}
// Params implements bond.QueryServer.
func (qs queryServer) Params(ctx context.Context, _ *bondtypes.QueryParamsRequest) (*bondtypes.QueryParamsResponse, error) {
func (qs queryHandlers) Params(ctx context.Context, _ *bondtypes.QueryParamsRequest) (*bondtypes.QueryParamsResponse, error) {
params, err := qs.k.GetParams(ctx)
if err != nil {
return nil, err
@ -31,7 +29,7 @@ func (qs queryServer) Params(ctx context.Context, _ *bondtypes.QueryParamsReques
}
// Bonds implements bond.QueryServer.
func (qs queryServer) Bonds(ctx context.Context, _ *bondtypes.QueryBondsRequest) (*bondtypes.QueryBondsResponse, error) {
func (qs queryHandlers) Bonds(ctx context.Context, _ *bondtypes.QueryBondsRequest) (*bondtypes.QueryBondsResponse, error) {
resp, err := qs.k.ListBonds(ctx)
if err != nil {
return nil, err
@ -41,7 +39,7 @@ func (qs queryServer) Bonds(ctx context.Context, _ *bondtypes.QueryBondsRequest)
}
// GetBondById implements bond.QueryServer.
func (qs queryServer) GetBondById(ctx context.Context, req *bondtypes.QueryGetBondByIdRequest) (*bondtypes.QueryGetBondByIdResponse, error) {
func (qs queryHandlers) GetBondById(ctx context.Context, req *bondtypes.QueryGetBondByIdRequest) (*bondtypes.QueryGetBondByIdResponse, error) {
bondId := req.GetId()
if len(bondId) == 0 {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "bond id required")
@ -56,7 +54,7 @@ func (qs queryServer) GetBondById(ctx context.Context, req *bondtypes.QueryGetBo
}
// GetBondsByOwner implements bond.QueryServer.
func (qs queryServer) GetBondsByOwner(
func (qs queryHandlers) GetBondsByOwner(
ctx context.Context,
req *bondtypes.QueryGetBondsByOwnerRequest,
) (*bondtypes.QueryGetBondsByOwnerResponse, error) {
@ -76,7 +74,7 @@ func (qs queryServer) GetBondsByOwner(
}
// GetBondModuleBalance implements bond.QueryServer.
func (qs queryServer) GetBondModuleBalance(
func (qs queryHandlers) GetBondModuleBalance(
ctx context.Context,
_ *bondtypes.QueryGetBondModuleBalanceRequest,
) (*bondtypes.QueryGetBondModuleBalanceResponse, error) {

View File

@ -29,7 +29,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "GetBondById",
Use: "get [bond-id]",
Use: "get <bond-id>",
Short: "Get bond info by bond id",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "id"},
@ -37,7 +37,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "GetBondsByOwner",
Use: "by-owner [owner-address]",
Use: "by-owner <owner-address>",
Short: "Get bonds list by owner address",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "owner"},
@ -56,7 +56,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "CreateBond",
Use: "create [amount]",
Use: "create <amount>",
Short: "Create bond",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "coins"},
@ -64,7 +64,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "RefillBond",
Use: "refill [bond-id] [amount]",
Use: "refill <bond-id> <amount>",
Short: "Refill bond",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "id"},
@ -73,7 +73,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "WithdrawBond",
Use: "withdraw [bond-id] [amount]",
Use: "withdraw <bond-id> <amount>",
Short: "Withdraw amount from bond",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "id"},
@ -82,7 +82,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "CancelBond",
Use: "cancel [bond-id]",
Use: "cancel <bond-id>",
Short: "Cancel bond",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "id"},

View File

@ -5,15 +5,19 @@ import (
"encoding/json"
"fmt"
gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
// "google.golang.org/grpc"
appmodule "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/registry"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime"
"git.vdb.to/cerc-io/laconicd/x/bond"
"git.vdb.to/cerc-io/laconicd/x/bond/client/cli"
"git.vdb.to/cerc-io/laconicd/x/bond/keeper"
)
@ -22,10 +26,12 @@ var (
_ appmodule.HasGenesis = AppModule{}
_ appmodule.HasConsensusVersion = AppModule{}
_ appmodule.HasRegisterInterfaces = AppModule{}
// _ appmodule.HasMsgHandlers = AppModule{}
_ appmodule.HasQueryHandlers = AppModule{}
_ module.HasGRPCGateway = AppModule{}
_ module.HasServices = AppModule{}
_ module.HasInvariants = AppModule{}
// _ module.HasServices = AppModule{}
_ module.HasInvariants = AppModule{}
// _ module.HasAminoCodec = AppModule{} // TODO
)
@ -111,16 +117,50 @@ func (am AppModule) ExportGenesis(ctx context.Context) (json.RawMessage, error)
return am.cdc.MustMarshalJSON(gs), nil
}
// module.HasServices
// // module.HasServices
func (am AppModule) RegisterServices(cfg module.Configurator) {
// Register servers
bond.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
bond.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServerImpl(am.keeper))
}
// func (am AppModule) RegisterServices(registrar grpc.ServiceRegistrar) error {
// bond.RegisterMsgServer(registrar, keeper.NewHandlers(am.keeper))
// bond.RegisterQueryServer(registrar, keeper.NewQueryHandlers(am.keeper))
// return nil
// }
// module.HasInvariants
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
keeper.RegisterInvariants(ir, am.keeper)
}
// RegisterMsgHandlers registers the message handlers for the bond module.
func (am AppModule) RegisterMsgHandlers(router appmodule.MsgRouter) {
handlers := keeper.NewHandlers(am.keeper)
appmodule.RegisterMsgHandler(router, handlers.CreateBond)
appmodule.RegisterMsgHandler(router, handlers.RefillBond)
appmodule.RegisterMsgHandler(router, handlers.WithdrawBond)
appmodule.RegisterMsgHandler(router, handlers.CancelBond)
appmodule.RegisterMsgHandler(router, handlers.UpdateParams)
}
// RegisterQueryHandlers registers the query handlers for the bond module.
func (am AppModule) RegisterQueryHandlers(router appmodule.QueryRouter) {
handlers := keeper.NewQueryHandlers(am.keeper)
appmodule.RegisterMsgHandler(router, handlers.Params)
appmodule.RegisterMsgHandler(router, handlers.Bonds)
appmodule.RegisterMsgHandler(router, handlers.GetBondById)
appmodule.RegisterMsgHandler(router, handlers.GetBondsByOwner)
appmodule.RegisterMsgHandler(router, handlers.GetBondModuleBalance)
}
// GetTxCmd returns the root tx command for the bank/v2 module.
// TODO: Remove & use autocli
func (AppModule) GetTxCmd() *cobra.Command {
return cli.NewTxCmd()
}
// GetQueryCmd returns the root query command for the bank/v2 module.
// TODO: Remove & use autocli
func (AppModule) GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd()
}

View File

@ -20,7 +20,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "GetParticipantByAddress",
Use: "get-by-address [address]",
Use: "get-by-address <address>",
Short: "Get participant by address",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "address"},
@ -28,7 +28,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "GetParticipantByNitroAddress",
Use: "get-by-nitro-address [nitro_address]",
Use: "get-by-nitro-address <nitro-address>",
Short: "Get participant by nitro address",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "nitro_address"},
@ -42,7 +42,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "OnboardParticipant",
Use: "enroll [eth_payload] [eth_signature] [role] [kyc_id]",
Use: "enroll <eth-payload> <eth-signature> <role> <kyc-id>",
Short: "Enroll a testnet validator",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "eth_payload"},

View File

@ -440,7 +440,7 @@ func (k Keeper) processRecord(ctx context.Context, record *registrytypes.Readabl
}
rent := params.RecordRent
if err = k.bondKeeper.TransferCoinsToModuleAccount(
if err = k.bondKeeper.TransferRentToModuleAccount(
ctx, record.BondId, registrytypes.RecordRentModuleAccountName, sdk.NewCoins(rent),
); err != nil {
return err
@ -721,7 +721,7 @@ func (k Keeper) tryTakeRecordRent(ctx context.Context, record registrytypes.Reco
}
rent := params.RecordRent
sdkErr := k.bondKeeper.TransferCoinsToModuleAccount(ctx, record.BondId, registrytypes.RecordRentModuleAccountName, sdk.NewCoins(rent))
sdkErr := k.bondKeeper.TransferRentToModuleAccount(ctx, record.BondId, registrytypes.RecordRentModuleAccountName, sdk.NewCoins(rent))
if sdkErr != nil {
// Insufficient funds, mark record as deleted.
record.Deleted = true

View File

@ -622,7 +622,7 @@ func (k Keeper) tryTakeAuthorityRent(ctx context.Context, name string, authority
}
rent := params.AuthorityRent
sdkErr := k.bondKeeper.TransferCoinsToModuleAccount(ctx, authority.BondId, registrytypes.AuthorityRentModuleAccountName, sdk.NewCoins(rent))
sdkErr := k.bondKeeper.TransferRentToModuleAccount(ctx, authority.BondId, registrytypes.AuthorityRentModuleAccountName, sdk.NewCoins(rent))
if sdkErr != nil {
// Insufficient funds, mark authority as expired.
authority.Status = registrytypes.AuthorityExpired

View File

@ -29,7 +29,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "GetRecord",
Use: "get [record-id]",
Use: "get <record-id>",
Short: "Get record info by record id",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "id"},
@ -37,7 +37,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "GetRecordsByBondId",
Use: "get-records-by-bond-id [bond-id]",
Use: "get-records-by-bond-id <bond-id>",
Short: "Get records by bond id",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "id"},
@ -45,7 +45,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "Whois",
Use: "whois [name]",
Use: "whois <name>",
Short: "Get name authority info",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "name"},
@ -71,7 +71,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "LookupLrn",
Use: "lookup [lrn]",
Use: "lookup <lrn>",
Short: "Get naming info for LRN",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "lrn"},
@ -79,7 +79,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "ResolveLrn",
Use: "resolve [lrn]",
Use: "resolve <lrn>",
Short: "Resolve LRN to record",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "lrn"},
@ -98,7 +98,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "RenewRecord",
Use: "renew-record [record-id]",
Use: "renew-record <record-id>",
Short: "Renew (expired) record",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "record_id"},
@ -106,7 +106,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "ReserveAuthority",
Use: "reserve-authority [name] [owner]",
Use: "reserve-authority <name> <owner>",
Short: "Reserve authority name",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "name"},
@ -115,7 +115,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "SetAuthorityBond",
Use: "authority-bond [name] [bond-id]",
Use: "authority-bond <name> <bond-id>",
Short: "Associate authority with bond",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "name"},
@ -124,7 +124,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "SetName",
Use: "set-name [lrn] [cid]",
Use: "set-name <lrn> <cid>",
Short: "Set LRN to CID mapping",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "lrn"},
@ -133,7 +133,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "DeleteName",
Use: "delete-name [lrn]",
Use: "delete-name <lrn>",
Short: "Delete LRN",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "lrn"},
@ -141,7 +141,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "AssociateBond",
Use: "associate-bond [record-id] [bond-id]",
Use: "associate-bond <record-id> <bond-id>",
Short: "Associate record with a bond",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "record_id"},
@ -150,7 +150,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "DissociateBond",
Use: "dissociate-bond [record-id]",
Use: "dissociate-bond <record-id>",
Short: "Dissociate record from (existing) bond",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "record_id"},
@ -158,7 +158,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "DissociateRecords",
Use: "dissociate-records [bond-id]",
Use: "dissociate-records <bond-id>",
Short: "Dissociate all records from a bond",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "bond_id"},
@ -166,7 +166,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
{
RpcMethod: "ReassociateRecords",
Use: "reassociate-records [old-bond-id] [new-bond-id]",
Use: "reassociate-records <old-bond-id> <new-bond-id>",
Short: "Re-associate all records from an old to a new bond",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "old_bond_id"},