diff --git a/Makefile b/Makefile index 57a99094..bb936ed0 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,18 @@ # Project variables. PROJECT_NAME = 'ignite apps' +## mocks: generate mocks +mocks: + @echo Generating mocks + @go install github.com/vektra/mockery/v2@latest + @for dir in $$(find $$(pwd -P) -mindepth 1 -maxdepth 4 -type d); do \ + if [ -e "$$dir/go.mod" ]; then \ + echo "Running go generate in $$dir"; \ + cd "$$dir" && mockery; \ + fi \ + done + + ## goget: Run go get for all apps. goget: @echo Running go get $(REPO)... diff --git a/app.ignite.yml b/app.ignite.yml index f0df8536..eed851c3 100644 --- a/app.ignite.yml +++ b/app.ignite.yml @@ -1,5 +1,8 @@ version: 1 apps: + network: + description: Launch new Cosmos blockchains by interacting with the Ignite Chain to coordinate with validators + path: ./spaceship spaceship: description: Deploy your chain into a remote server in minutes path: ./spaceship diff --git a/go.work.example b/go.work.example index f07f6bad..895de8ac 100644 --- a/go.work.example +++ b/go.work.example @@ -6,9 +6,10 @@ use ( ./examples/health-monitor ./examples/hello-world ./examples/hooks + ./appregistry ./explorer ./hermes - ./appregistry + ./network ./rollkit ./spaceship ./wasm diff --git a/hermes/main.go b/hermes/main.go index 550ffb21..011f4e9f 100644 --- a/hermes/main.go +++ b/hermes/main.go @@ -20,7 +20,7 @@ func (app) Manifest(context.Context) (*plugin.Manifest, error) { } func (app) Execute(ctx context.Context, c *plugin.ExecutedCommand, _ plugin.ClientAPI) error { - // Remove the three two elements "ignite", "relayer" and "hermes" from OsArgs. + // Remove the three elements "ignite", "relayer" and "hermes" from OsArgs. args := c.OsArgs[3:] switch args[0] { case "configure": diff --git a/network/.mockery.yml b/network/.mockery.yml new file mode 100644 index 00000000..fde65344 --- /dev/null +++ b/network/.mockery.yml @@ -0,0 +1,25 @@ +all: False +quiet: False +log-level: debug +recursive: True +with-expecter: True +outpkg: "mocks" +dir: "network/mocks" +mockname: "{{.InterfaceName}}" +filename: "{{.InterfaceNameSnake}}.go" +packages: + github.com/ignite/apps/network/network: + interfaces: + Chain: + CosmosClient: + github.com/ignite/apps/network/network/testutil: + interfaces: + ProjectClient: + ProfileClient: + LaunchClient: + BankClient: + RewardClient: + StakingClient: + MonitoringcClient: + MonitoringpClient: + AccountInfo: diff --git a/network/CHANGELOG.md b/network/CHANGELOG.md new file mode 100644 index 00000000..c8d60358 --- /dev/null +++ b/network/CHANGELOG.md @@ -0,0 +1,5 @@ +# Spaceship App Changelog + +## [`v0.1.0`](https://github.com/ignite/apps/releases/tag/spaceship/v0.1.0) + +* First release of the Ignite Network app compatible with Ignite >= v28.x.y diff --git a/network/README.md b/network/README.md new file mode 100644 index 00000000..57fb585a --- /dev/null +++ b/network/README.md @@ -0,0 +1,20 @@ +# Network App + +`network` is a app developed for [Ignite CLI](https://github.com/ignite/cli). + +The plugin adds `ignite network` commands that allow launching new Cosmos blockchains by interacting with the Ignite Chain to coordinate with validators. + +The plugin is integrated into Ignite CLI by default. + +[**Check out our documentation for launching chains with the commands**](https://docs.ignite.com/nightly/network/introduction) + +## Developer instruction + +- clone this repo locally +- Run `ignite plugin add -g /absolute/path/to/apps/network` to add the plugin to global config +- `ignite network` command is now available with the local version of the plugin. + +Then repeat the following loop: + +- Hack on the plugin code +- Rerun `ignite network` to recompile the plugin and test diff --git a/network/cmd/debug/main.go b/network/cmd/debug/main.go new file mode 100644 index 00000000..0f47a88d --- /dev/null +++ b/network/cmd/debug/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "os" + + "github.com/ignite/apps/network/cmd" +) + +func main() { + if err := cmd.NewNetwork().Execute(); err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/network/cmd/network.go b/network/cmd/network.go new file mode 100644 index 00000000..8b55c924 --- /dev/null +++ b/network/cmd/network.go @@ -0,0 +1,395 @@ +package cmd + +import ( + "path/filepath" + + "github.com/ignite/cli/v28/ignite/config" + "github.com/ignite/cli/v28/ignite/pkg/cache" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" + "github.com/ignite/cli/v28/ignite/pkg/cosmosclient" + "github.com/ignite/cli/v28/ignite/pkg/events" + "github.com/ignite/cli/v28/ignite/pkg/gitpod" + "github.com/pkg/errors" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networkchain" + "github.com/ignite/apps/network/network/networktypes" +) + +var ( + nightly bool + local bool +) + +const ( + flagNightly = "nightly" + flagLocal = "local" + + flagHome = "home" + flagFrom = "from" + flagAddressPrefix = "prefix" + flagKeyringBackend = "keyring-backend" + flagKeyringDir = "keyring-dir" + flagYes = "yes" + flagClearCache = "clear-cache" + flagCheckDependencies = "check-dependencies" + flagAdvanced = "advanced" + + flagPage = "page" + flagLimit = "limit" + flagPageKey = "page-key" + flagOffset = "offset" + flagCountTotal = "count-total" + flagReverse = "reverse" + + flagSPNNodeAddress = "spn-node-address" + flagSPNFaucetAddress = "spn-faucet-address" + + spnNodeAddressNightly = "https://rpc.devnet.ignite.com:443" + spnFaucetAddressNightly = "https://faucet.devnet.ignite.com:443" + + spnNodeAddressLocal = "http://0.0.0.0:26661" + spnFaucetAddressLocal = "http://0.0.0.0:4502" +) + +// NewNetwork creates a new network command that holds some other sub commands +// related to creating a new network collaboratively. +func NewNetwork() *cobra.Command { + c := &cobra.Command{ + Use: "network [command]", + Aliases: []string{"n"}, + Short: "Launch a blockchain in production", + Long: ` +Ignite Network commands allow to coordinate the launch of sovereign Cosmos blockchains. + +To launch a Cosmos blockchain you need someone to be a coordinator and others to +be validators. These are just roles, anyone can be a coordinator or a validator. +A coordinator publishes information about a chain to be launched on the Ignite +blockchain, approves validator requests and coordinates the launch. Validators +send requests to join a chain and start their nodes when a blockchain is ready +for launch. + +To publish the information about your chain as a coordinator run the following +command (the URL should point to a repository with a Cosmos SDK chain): + + ignite network chain publish github.com/ignite/example + +This command will return a launch identifier you will be using in the following +commands. Let's say this identifier is 42. + +Next, ask validators to initialize their nodes and request to join the network +as validators. For a testnet you can use the default values suggested by the +CLI. + + ignite network chain init 42 + + ignite network chain join 42 --amount 95000000stake + +As a coordinator list all validator requests: + + ignite network request list 42 + +Approve validator requests: + + ignite network request approve 42 1,2 + +Once you've approved all validators you need in the validator set, announce that +the chain is ready for launch: + + ignite network chain launch 42 + +Validators can now prepare their nodes for launch: + + ignite network chain prepare 42 + +The output of this command will show a command that a validator would use to +launch their node, for example “exampled --home ~/.example”. After enough +validators launch their nodes, a blockchain will be live. +`, + SilenceUsage: true, + SilenceErrors: true, + } + + // configure flags. + c.PersistentFlags().BoolVar(&local, flagLocal, false, "Use local SPN network") + c.PersistentFlags().BoolVar(&nightly, flagNightly, false, "Use nightly SPN network") + // Includes Flags for Node and Faucet Address + c.PersistentFlags().AddFlagSet(flagSetSpnAddresses()) + + // add sub commands. + c.AddCommand( + NewNetworkChain(), + NewNetworkProject(), + NewNetworkRequest(), + NewNetworkReward(), + NewNetworkValidator(), + NewNetworkProfile(), + NewNetworkCoordinator(), + NewNetworkTool(), + NewNetworkVersion(), + ) + + return c +} + +var cosmos *cosmosclient.Client + +type ( + NetworkBuilderOption func(builder *NetworkBuilder) + + NetworkBuilder struct { + AccountRegistry cosmosaccount.Registry + + ev events.Bus + cmd *cobra.Command + cc cosmosclient.Client + } + + NetworkAddresses struct { + NodeAddress string + FaucetAddress string + } +) + +func CollectEvents(ev events.Bus) NetworkBuilderOption { + return func(builder *NetworkBuilder) { + builder.ev = ev + } +} + +func flagSetSPNAccountPrefixes() *flag.FlagSet { + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.String(flagAddressPrefix, networktypes.SPN, "account address prefix") + return fs +} + +func newNetworkBuilder(cmd *cobra.Command, options ...NetworkBuilderOption) (NetworkBuilder, error) { + var ( + err error + n = NetworkBuilder{cmd: cmd} + ) + + if n.cc, err = getNetworkCosmosClient(cmd); err != nil { + return NetworkBuilder{}, err + } + + n.AccountRegistry = n.cc.AccountRegistry + + for _, apply := range options { + apply(&n) + } + return n, nil +} + +func (n NetworkBuilder) Chain(source networkchain.SourceOption, options ...networkchain.Option) (*networkchain.Chain, error) { + if home := getHome(n.cmd); home != "" { + options = append(options, networkchain.WithHome(home)) + } + + options = append(options, networkchain.CollectEvents(n.ev)) + + return networkchain.New(n.cmd.Context(), n.AccountRegistry, source, options...) +} + +func (n NetworkBuilder) Network(options ...network.Option) (network.Network, error) { + var ( + err error + from = getFrom(n.cmd) + account = cosmosaccount.Account{} + ) + if from != "" { + account, err = cosmos.AccountRegistry.GetByName(getFrom(n.cmd)) + if err != nil { + return network.Network{}, errors.Wrap(err, "make sure that this account exists, use 'ignite account -h' to manage accounts") + } + } + + options = append(options, network.CollectEvents(n.ev)) + + return network.New(*cosmos, account, options...), nil +} + +func getNetworkCosmosClient(cmd *cobra.Command) (cosmosclient.Client, error) { + spn, err := getSpnAddresses(cmd) + if err != nil { + return cosmosclient.Client{}, err + } + + cosmosOptions := []cosmosclient.Option{ + cosmosclient.WithHome(cosmosaccount.KeyringHome), + cosmosclient.WithNodeAddress(spn.NodeAddress), + cosmosclient.WithAddressPrefix(networktypes.SPN), + cosmosclient.WithUseFaucet(spn.FaucetAddress, networktypes.SPNDenom, 5), + cosmosclient.WithKeyringServiceName(cosmosaccount.KeyringServiceName), + cosmosclient.WithKeyringDir(getKeyringDir(cmd)), + cosmosclient.WithGas(cosmosclient.GasAuto), + } + + keyringBackend := getKeyringBackend(cmd) + // use test keyring backend on Gitpod in order to prevent prompting for keyring + // password. This happens because Gitpod uses containers. + // + // when not on Gitpod, OS keyring backend is used which only asks password once. + if gitpod.IsOnGitpod() { + keyringBackend = cosmosaccount.KeyringTest + } + if keyringBackend != "" { + cosmosOptions = append(cosmosOptions, cosmosclient.WithKeyringBackend(keyringBackend)) + } + + // init cosmos client only once on start in order to spnclient to + // reuse unlocked keyring in the following steps. + if cosmos == nil { + client, err := cosmosclient.New(cmd.Context(), cosmosOptions...) + if err != nil { + return cosmosclient.Client{}, err + } + cosmos = &client + } + + if err := cosmos.AccountRegistry.EnsureDefaultAccount(); err != nil { + return cosmosclient.Client{}, err + } + + return *cosmos, nil +} + +func newCache(cmd *cobra.Command) (cache.Storage, error) { + cacheRootDir, err := config.DirPath() + if err != nil { + return cache.Storage{}, err + } + + const cacheFileName = "ignite_network_cache.db" + storage, err := cache.NewStorage(filepath.Join(cacheRootDir, cacheFileName)) + if err != nil { + return cache.Storage{}, err + } + + if flagGetClearCache(cmd) { + if err := storage.Clear(); err != nil { + return cache.Storage{}, err + } + } + + return storage, nil +} + +func flagSetHome() *flag.FlagSet { + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.String(flagHome, "", "home directory used for blockchains") + return fs +} + +func getHome(cmd *cobra.Command) (home string) { + home, _ = cmd.Flags().GetString(flagHome) + return +} + +func flagNetworkFrom() *flag.FlagSet { + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.String(flagFrom, cosmosaccount.DefaultAccount, "account name to use for sending transactions to SPN") + return fs +} + +func getFrom(cmd *cobra.Command) string { + prefix, _ := cmd.Flags().GetString(flagFrom) + return prefix +} + +func flagSetKeyringBackend() *flag.FlagSet { + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.String(flagKeyringBackend, string(cosmosaccount.KeyringTest), "keyring backend to store your account keys") + return fs +} + +func getKeyringBackend(cmd *cobra.Command) cosmosaccount.KeyringBackend { + backend, _ := cmd.Flags().GetString(flagKeyringBackend) + return cosmosaccount.KeyringBackend(backend) +} + +func flagSetKeyringDir() *flag.FlagSet { + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.String(flagKeyringDir, cosmosaccount.KeyringHome, "accounts keyring directory") + return fs +} + +func getKeyringDir(cmd *cobra.Command) string { + keyringDir, _ := cmd.Flags().GetString(flagKeyringDir) + return keyringDir +} + +func getAddressPrefix(cmd *cobra.Command) string { + prefix, _ := cmd.Flags().GetString(flagAddressPrefix) + return prefix +} + +func flagSetClearCache(cmd *cobra.Command) { + cmd.PersistentFlags().Bool(flagClearCache, false, "clear the build cache (advanced)") +} + +func flagGetClearCache(cmd *cobra.Command) bool { + clearCache, _ := cmd.Flags().GetBool(flagClearCache) + return clearCache +} + +func flagSetYes() *flag.FlagSet { + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.BoolP(flagYes, "y", false, "answers interactive yes/no questions with yes") + return fs +} + +func getYes(cmd *cobra.Command) (ok bool) { + ok, _ = cmd.Flags().GetBool(flagYes) + return +} + +func flagSetCheckDependencies() *flag.FlagSet { + usage := "verify that cached dependencies have not been modified since they were downloaded" + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.Bool(flagCheckDependencies, false, usage) + return fs +} + +func flagGetCheckDependencies(cmd *cobra.Command) (check bool) { + check, _ = cmd.Flags().GetBool(flagCheckDependencies) + return +} + +func printSection(session *cliui.Session, title string) error { + return session.Printf("------\n%s\n------\n\n", title) +} + +func flagSetSpnAddresses() *flag.FlagSet { + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.String(flagSPNNodeAddress, spnNodeAddressNightly, "SPN node address") + fs.String(flagSPNFaucetAddress, spnFaucetAddressNightly, "SPN faucet address") + return fs +} + +func getSpnAddresses(cmd *cobra.Command) (NetworkAddresses, error) { + // check preconfigured networks + if nightly && local { + return NetworkAddresses{}, errors.New("local and nightly networks can't both be specified in the same command, specify local or nightly") + } + if nightly { + return NetworkAddresses{spnNodeAddressNightly, spnFaucetAddressNightly}, nil + } + if local { + return NetworkAddresses{spnNodeAddressLocal, spnFaucetAddressLocal}, nil + } + + spnNodeAddress, err := cmd.Flags().GetString(flagSPNNodeAddress) + if err != nil { + return NetworkAddresses{}, err + } + + spnFaucetAddress, err := cmd.Flags().GetString(flagSPNFaucetAddress) + if err != nil { + return NetworkAddresses{}, err + } + return NetworkAddresses{spnNodeAddress, spnFaucetAddress}, nil +} diff --git a/network/cmd/network_chain.go b/network/cmd/network_chain.go new file mode 100644 index 00000000..695a628b --- /dev/null +++ b/network/cmd/network_chain.go @@ -0,0 +1,49 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// NewNetworkChain creates a new chain command that holds some other +// sub commands related to launching a network for a chain. +func NewNetworkChain() *cobra.Command { + c := &cobra.Command{ + Use: "chain", + Short: "Publish a chain, join as a validator and prepare node for launch", + Long: `The "chain" namespace features the most commonly used commands for launching +blockchains with Ignite. + +As a coordinator you "publish" your blockchain to Ignite. When enough validators +are approved for the genesis and no changes are excepted to be made to the +genesis, a coordinator announces that the chain is ready for launch with the +"launch" command. In the case of an unsuccessful launch, the coordinator can revert it +using the "revert-launch" command. + +As a validator, you "init" your node and apply to become a validator for a +blockchain with the "join" command. After the launch of the chain is announced, +validators can generate the finalized genesis and download the list of peers with the +"prepare" command. + +The "install" command can be used to download, compile the source code and +install the chain's binary locally. The binary can be used, for example, to +initialize a validator node or to interact with the chain after it has been +launched. + +All chains published to Ignite can be listed by using the "list" command. +`, + } + + c.AddCommand( + NewNetworkChainList(), + NewNetworkChainPublish(), + NewNetworkChainInit(), + NewNetworkChainInstall(), + NewNetworkChainJoin(), + NewNetworkChainPrepare(), + NewNetworkChainShow(), + NewNetworkChainLaunch(), + NewNetworkChainRevertLaunch(), + ) + + return c +} diff --git a/network/cmd/network_chain_init.go b/network/cmd/network_chain_init.go new file mode 100644 index 00000000..ee4db896 --- /dev/null +++ b/network/cmd/network_chain_init.go @@ -0,0 +1,249 @@ +package cmd + +import ( + "errors" + "fmt" + + "github.com/ignite/cli/v28/ignite/pkg/chaincmd" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/cliquiz" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" + cosmosgenesis "github.com/ignite/cli/v28/ignite/pkg/cosmosutil/genesis" + "github.com/ignite/cli/v28/ignite/services/chain" + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networkchain" +) + +const ( + flagValidatorAccount = "validator-account" + flagValidatorWebsite = "validator-website" + flagValidatorDetails = "validator-details" + flagValidatorSecurityContact = "validator-security-contact" + flagValidatorMoniker = "validator-moniker" + flagValidatorIdentity = "validator-identity" + flagValidatorSelfDelegation = "validator-self-delegation" + flagValidatorGasPrice = "validator-gas-price" + + defaultSelfDelegation = "95000000stake" + defaultCommissionMax = "0.10" + defaultCommissionMaxRate = "0.20" + defaultCommissionMaxChangeRate = "0.01" +) + +// NewNetworkChainInit returns a new command to initialize a chain from a published chain ID. +func NewNetworkChainInit() *cobra.Command { + c := &cobra.Command{ + Use: "init [launch-id]", + Short: "Initialize a chain from a published chain ID", + Long: `Ignite network chain init is a command used by validators to initialize a +validator node for a blockchain from the information stored on the Ignite chain. + + ignite network chain init 42 + +This command fetches the information about a chain with launch ID 42. The source +code of the chain is cloned in a temporary directory, and the node's binary is +compiled from the source. The binary is then used to initialize the node. By +default, Ignite uses "~/spn/[launch-id]/" as the home directory for the blockchain. + +An important part of initializing a validator node is creation of the gentx (a +transaction that adds a validator at the genesis of the chain). + +The "init" command will prompt for values like self-delegation and commission. +These values will be used in the validator's gentx. You can use flags to provide +the values in non-interactive mode. + +Use the "--home" flag to choose a different path for the home directory of the +blockchain: + + ignite network chain init 42 --home ~/mychain + +The end result of the "init" command is a validator home directory with a +genesis validator transaction (gentx) file.`, + Args: cobra.ExactArgs(1), + RunE: networkChainInitHandler, + } + + flagSetClearCache(c) + c.Flags().String(flagValidatorAccount, cosmosaccount.DefaultAccount, "account for the chain validator") + c.Flags().String(flagValidatorWebsite, "", "associate a website with the validator") + c.Flags().String(flagValidatorDetails, "", "details about the validator") + c.Flags().String(flagValidatorSecurityContact, "", "validator security contact email") + c.Flags().String(flagValidatorMoniker, "", "custom validator moniker") + c.Flags().String(flagValidatorIdentity, "", "validator identity signature (ex. UPort or Keybase)") + c.Flags().String(flagValidatorSelfDelegation, "", "validator minimum self delegation") + c.Flags().String(flagValidatorGasPrice, "", "validator gas price") + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + c.Flags().AddFlagSet(flagSetYes()) + c.Flags().AddFlagSet(flagSetCheckDependencies()) + return c +} + +func networkChainInitHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // check if the provided account for the validator exists. + validatorAccount, _ := cmd.Flags().GetString(flagValidatorAccount) + if _, err = nb.AccountRegistry.GetByName(validatorAccount); err != nil { + return err + } + + // if a chain has already been initialized with this launch ID, we ask for confirmation + // before erasing the directory. + chainHome, exist, err := networkchain.IsChainHomeExist(launchID) + if err != nil { + return err + } + + if !getYes(cmd) && exist { + question := fmt.Sprintf( + "The chain has already been initialized under: %s. Would you like to overwrite the home directory", + chainHome, + ) + if err := session.AskConfirm(question); err != nil { + if errors.Is(err, promptui.ErrAbort) { + return nil + } + + return err + } + } + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + chainLaunch, err := n.ChainLaunch(cmd.Context(), launchID) + if err != nil { + return err + } + + networkOptions := []networkchain.Option{ + networkchain.WithKeyringBackend(chaincmd.KeyringBackendTest), + } + + if flagGetCheckDependencies(cmd) { + networkOptions = append(networkOptions, networkchain.CheckDependencies()) + } + + c, err := nb.Chain(networkchain.SourceLaunch(chainLaunch), networkOptions...) + if err != nil { + return err + } + + if err := c.Init(cmd.Context(), cacheStorage); err != nil { + return err + } + + genesisPath, err := c.GenesisPath() + if err != nil { + return err + } + + genesis, err := cosmosgenesis.FromPath(genesisPath) + if err != nil { + return err + } + stakeDenom, err := genesis.StakeDenom() + if err != nil { + return err + } + + // ask validator information. + defaultSelfDel := chainLaunch.AccountBalance.String() + if defaultSelfDel == "" { + defaultSelfDel = defaultSelfDelegation + } + v, err := askValidatorInfo(cmd, session, stakeDenom, defaultSelfDel) + if err != nil { + return err + } + session.StartSpinner("Generating your Gentx") + + gentxPath, err := c.InitAccount(cmd.Context(), v, validatorAccount) + if err != nil { + return err + } + + return session.Printf("%s Gentx generated: %s\n", icons.Bullet, gentxPath) +} + +// askValidatorInfo prompts to the user questions to query validator information. +func askValidatorInfo( + cmd *cobra.Command, + session *cliui.Session, + stakeDenom, + defaultSelfDel string, +) (chain.Validator, error) { + var ( + account, _ = cmd.Flags().GetString(flagValidatorAccount) + website, _ = cmd.Flags().GetString(flagValidatorWebsite) + details, _ = cmd.Flags().GetString(flagValidatorDetails) + securityContact, _ = cmd.Flags().GetString(flagValidatorSecurityContact) + moniker, _ = cmd.Flags().GetString(flagValidatorMoniker) + identity, _ = cmd.Flags().GetString(flagValidatorIdentity) + selfDelegation, _ = cmd.Flags().GetString(flagValidatorSelfDelegation) + gasPrice, _ = cmd.Flags().GetString(flagValidatorGasPrice) + ) + if gasPrice == "" { + gasPrice = "0" + stakeDenom + } + v := chain.Validator{ + Name: account, + Website: website, + Details: details, + Moniker: moniker, + Identity: identity, + SecurityContact: securityContact, + MinSelfDelegation: selfDelegation, + GasPrices: gasPrice, + } + + questions := append([]cliquiz.Question{}, + cliquiz.NewQuestion("Staking amount", + &v.StakingAmount, + cliquiz.DefaultAnswer(defaultSelfDel), + cliquiz.Required(), + ), + cliquiz.NewQuestion("Commission rate", + &v.CommissionRate, + cliquiz.DefaultAnswer(defaultCommissionMax), + cliquiz.Required(), + ), + cliquiz.NewQuestion("Commission max rate", + &v.CommissionMaxRate, + cliquiz.DefaultAnswer(defaultCommissionMaxRate), + cliquiz.Required(), + ), + cliquiz.NewQuestion("Commission max change rate", + &v.CommissionMaxChangeRate, + cliquiz.DefaultAnswer(defaultCommissionMaxChangeRate), + cliquiz.Required(), + ), + ) + return v, session.Ask(questions...) +} diff --git a/network/cmd/network_chain_install.go b/network/cmd/network_chain_install.go new file mode 100644 index 00000000..87fa8efe --- /dev/null +++ b/network/cmd/network_chain_install.go @@ -0,0 +1,83 @@ +package cmd + +import ( + "path/filepath" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/colors" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/goenv" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networkchain" +) + +// NewNetworkChainInstall returns a new command to install a chain's binary by the launch id. +func NewNetworkChainInstall() *cobra.Command { + c := &cobra.Command{ + Use: "install [launch-id]", + Short: "Install chain binary for a launch", + Args: cobra.ExactArgs(1), + RunE: networkChainInstallHandler, + } + + flagSetClearCache(c) + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetCheckDependencies()) + return c +} + +func networkChainInstallHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + chainLaunch, err := n.ChainLaunch(cmd.Context(), launchID) + if err != nil { + return err + } + + var networkOptions []networkchain.Option + + if flagGetCheckDependencies(cmd) { + networkOptions = append(networkOptions, networkchain.CheckDependencies()) + } + + c, err := nb.Chain(networkchain.SourceLaunch(chainLaunch), networkOptions...) + if err != nil { + return err + } + + binaryName, err := c.Build(cmd.Context(), cacheStorage) + if err != nil { + return err + } + binaryPath := filepath.Join(goenv.Bin(), binaryName) + + session.Printf("%s Binary installed\n", icons.OK) + session.Printf("%s Binary's name: %s\n", icons.Info, colors.Info(binaryName)) + session.Printf("%s Binary's path: %s\n", icons.Info, colors.Info(binaryPath)) + + return nil +} diff --git a/network/cmd/network_chain_join.go b/network/cmd/network_chain_join.go new file mode 100644 index 00000000..504416be --- /dev/null +++ b/network/cmd/network_chain_join.go @@ -0,0 +1,253 @@ +package cmd + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/cliquiz" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/gitpod" + "github.com/ignite/cli/v28/ignite/pkg/xchisel" + "github.com/manifoldco/promptui" + "github.com/pkg/errors" + "github.com/rdegges/go-ipify" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networkchain" +) + +const ( + flagGentx = "gentx" + flagAmount = "amount" + flagNoAccount = "no-account" + flagPeerAddress = "peer-address" +) + +// NewNetworkChainJoin creates a new chain join command to join +// to a network as a validator. +func NewNetworkChainJoin() *cobra.Command { + c := &cobra.Command{ + Use: "join [launch-id]", + Short: "Request to join a network as a validator", + Long: `The "join" command is used by validators to send a request to join a blockchain. +The required argument is a launch ID of a blockchain. The "join" command expects +that the validator has already setup a home directory for the blockchain and has +a gentx either by running "ignite network chain init" or initializing the data +directory manually with the chain's binary. + +By default the "join" command just sends the request to join as a validator. +However, often a validator also needs to request an genesis account with a token +balance to afford self-delegation. + +The following command will send a request to join blockchain with launch ID 42 +as a validator and request to be added as an account with a token balance of +95000000 STAKE. + + ignite network chain join 42 --amount 95000000stake + +A request to join as a validator contains a gentx file. Ignite looks for gentx +in a home directory used by "ignite network chain init" by default. To use a +different directory, use the "--home" flag or pass a gentx file directly with +the "--gentx" flag. + +To join a chain as a validator, you must provide the IP address of your node so +that other validators can connect to it. The join command will ask you for the +IP address and will attempt to automatically detect and fill in the value. If +you want to manually specify the IP address, you can use the "--peer-address" +flag: + + ignite network chain join 42 --peer-address 0.0.0.0 + +Since "join" broadcasts a transaction to the Ignite blockchain, you will need an +account on the Ignite blockchain. During the testnet phase, however, Ignite +automatically requests tokens from a faucet. +`, + Args: cobra.ExactArgs(1), + RunE: networkChainJoinHandler, + } + + c.Flags().String(flagGentx, "", "path to a gentx json file") + c.Flags().String(flagAmount, "", "amount of coins for account request (ignored if coordinator has fixed the account balances or if --no-acount flag is set)") + c.Flags().String(flagPeerAddress, "", "peer's address") + c.Flags().Bool(flagNoAccount, false, "prevent sending a request for a genesis account") + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + c.Flags().AddFlagSet(flagSetYes()) + c.Flags().AddFlagSet(flagSetCheckDependencies()) + + return c +} + +func networkChainJoinHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + var ( + joinOptions []network.JoinOption + gentxPath, _ = cmd.Flags().GetString(flagGentx) + amount, _ = cmd.Flags().GetString(flagAmount) + noAccount, _ = cmd.Flags().GetBool(flagNoAccount) + ) + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID. + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // if there is no custom gentx, we need to detect the public address. + if gentxPath == "" { + // get the peer public address for the validator. + publicAddr, err := askPublicAddress(cmd, session) + if err != nil { + return err + } + + joinOptions = append(joinOptions, network.WithPublicAddress(publicAddr)) + } + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + chainLaunch, err := n.ChainLaunch(cmd.Context(), launchID) + if err != nil { + return err + } + + var networkOptions []networkchain.Option + + if flagGetCheckDependencies(cmd) { + networkOptions = append(networkOptions, networkchain.CheckDependencies()) + } + + c, err := nb.Chain(networkchain.SourceLaunch(chainLaunch), networkOptions...) + if err != nil { + return err + } + + // use the default gentx path from chain home if not provided + if gentxPath == "" { + gentxPath, err = c.DefaultGentxPath() + if err != nil { + return err + } + } else { + // if a custom gentx is provided, we initialize the chain home in order to check accounts + if err := c.Init(cmd.Context(), cacheStorage); err != nil { + return err + } + } + + // genesis account request + if !noAccount { + switch { + case c.IsAccountBalanceFixed(): + // fixed account balance + joinOptions = append(joinOptions, network.WithAccountRequest(c.AccountBalance())) + case amount != "": + // account balance set by user + amountCoins, err := sdk.ParseCoinsNormalized(amount) + if err != nil { + return errors.Wrap(err, "error parsing amount") + } + joinOptions = append(joinOptions, network.WithAccountRequest(amountCoins)) + default: + // fixed balance and no amount entered by the user, we ask if they want to skip account request + if !getYes(cmd) { + question := fmt.Sprintf( + "You haven't set the --%s flag and therefore an account request won't be submitted. Do you confirm", + flagAmount, + ) + if err := session.AskConfirm(question); err != nil { + if errors.Is(err, promptui.ErrAbort) { + return nil + } + + return err + } + } + + session.Printf("%s %s\n", icons.Info, "Account request won't be submitted") + } + } + + // create requests to join as a validator + joinRequests, err := n.GetJoinRequestContents(cmd.Context(), c, launchID, gentxPath, joinOptions...) + if err != nil { + return err + } + + // simulate the join requests + if err := verifyRequestsFromRequestContents( + cmd.Context(), + cacheStorage, + nb, + launchID, + joinRequests..., + ); err != nil { + return err + } + + // send join requests + return n.SendRequests(cmd.Context(), launchID, joinRequests) +} + +// askPublicAddress prepare questions to interactively ask for a publicAddress +// when peer isn't provided and not running through chisel proxy. +func askPublicAddress(cmd *cobra.Command, session *cliui.Session) (publicAddress string, err error) { + ctx := cmd.Context() + + if gitpod.IsOnGitpod() { + publicAddress, err = gitpod.URLForPort(ctx, xchisel.DefaultServerPort) + if err != nil { + return "", errors.Wrap(err, "cannot read public Gitpod address of the node") + } + return publicAddress, nil + } + + peerAddress, _ := cmd.Flags().GetString(flagPeerAddress) + + // The `--peer-address` flag is required when "--yes" is present + if getYes(cmd) && peerAddress == "" { + return "", errors.New("a peer address is required") + } + + // Don't prompt for an address when it is available as a flag value + if peerAddress != "" { + return peerAddress, nil + } + + // Try to guess the current peer address. This address is used + // as default when prompting user for the right peer address. + if ip, err := ipify.GetIp(); err == nil { + peerAddress = fmt.Sprintf("%s:26656", ip) + } + + options := []cliquiz.Option{cliquiz.Required()} + if peerAddress != "" { + options = append(options, cliquiz.DefaultAnswer(peerAddress)) + } + + questions := []cliquiz.Question{cliquiz.NewQuestion( + "Peer's address", + &publicAddress, + options..., + )} + return publicAddress, session.Ask(questions...) +} diff --git a/network/cmd/network_chain_launch.go b/network/cmd/network_chain_launch.go new file mode 100644 index 00000000..6edbb15c --- /dev/null +++ b/network/cmd/network_chain_launch.go @@ -0,0 +1,97 @@ +package cmd + +import ( + "time" + + timeparser "github.com/aws/smithy-go/time" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +const ( + flagLauchTime = "launch-time" +) + +// NewNetworkChainLaunch creates a new chain launch command to launch +// the network as a coordinator. +func NewNetworkChainLaunch() *cobra.Command { + c := &cobra.Command{ + Use: "launch [launch-id]", + Short: "Trigger the launch of a chain", + Long: `The launch command communicates to the world that the chain is ready to be +launched. + +Only the coordinator of the chain can execute the launch command. + + ignite network chain launch 42 + +After the launch command is executed no changes to the genesis are accepted. For +example, validators will no longer be able to successfully execute the "ignite +network chain join" command to apply as a validator. + +The launch command sets the date and time after which the chain will start. By +default, the current time is set. To give validators more time to prepare for +the launch, set the time with the "--launch-time" flag: + + ignite network chain launch 42 --launch-time 2023-01-01T00:00:00Z + +After the launch command is executed, validators can generate the finalized +genesis and prepare their nodes for the launch. For example, validators can run +"ignite network chain prepare" to generate the genesis and populate the peer +list. + +If you want to change the launch time or open up the genesis file for changes +you can use "ignite network chain revert-launch" to make it possible, for +example, to accept new validators and add accounts. +`, + Args: cobra.ExactArgs(1), + RunE: networkChainLaunchHandler, + } + + c.Flags().String( + flagLauchTime, + "", + "timestamp the chain is effectively launched (example \"2022-01-01T00:00:00Z\")", + ) + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + + return c +} + +func networkChainLaunchHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // parse launch time + var launchTime time.Time + launchTimeStr, _ := cmd.Flags().GetString(flagLauchTime) + + if launchTimeStr != "" { + launchTime, err = timeparser.ParseDateTime(launchTimeStr) + if err != nil { + return err + } + } + + n, err := nb.Network() + if err != nil { + return err + } + + return n.TriggerLaunch(cmd.Context(), launchID, launchTime) +} diff --git a/network/cmd/network_chain_list.go b/network/cmd/network_chain_list.go new file mode 100644 index 00000000..478eb748 --- /dev/null +++ b/network/cmd/network_chain_list.go @@ -0,0 +1,132 @@ +package cmd + +import ( + "errors" + "fmt" + "time" + + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/entrywriter" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networktypes" +) + +var LaunchSummaryHeader = []string{ + "launch ID", + "chain ID", + "source", + "phase", +} + +var LaunchSummaryAdvancedHeader = []string{ + "project ID", + "network", + "reward", +} + +// NewNetworkChainList returns a new command to list all published chains on Ignite. +func NewNetworkChainList() *cobra.Command { + c := &cobra.Command{ + Use: "list", + Short: "List published chains", + Args: cobra.NoArgs, + RunE: networkChainListHandler, + } + c.Flags().Bool(flagAdvanced, false, "show advanced information about the chains") + c.Flags().Uint64(flagLimit, 100, "limit of results per page") + c.Flags().Uint64(flagPage, 1, "page for chain list result") + + return c +} + +func networkChainListHandler(cmd *cobra.Command, _ []string) error { + var ( + advanced, _ = cmd.Flags().GetBool(flagAdvanced) + limit, _ = cmd.Flags().GetUint64(flagLimit) + page, _ = cmd.Flags().GetUint64(flagPage) + ) + + session := cliui.New(cliui.StartSpinner()) + + defer session.End() + + if page == 0 { + return errors.New("invalid page value") + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + n, err := nb.Network(network.CollectEvents(session.EventBus())) + if err != nil { + return err + } + chainLaunches, err := n.ChainLaunchesWithReward(cmd.Context(), &query.PageRequest{ + Offset: limit * (page - 1), + Limit: limit, + }) + if err != nil { + return err + } + + return renderLaunchSummaries(chainLaunches, session, advanced) +} + +// renderLaunchSummaries writes into the provided out, the list of summarized launches. +func renderLaunchSummaries(chainLaunches []networktypes.ChainLaunch, session *cliui.Session, advanced bool) error { + header := LaunchSummaryHeader + if advanced { + // advanced information show the project ID, type of network and rewards for incentivized testnet + header = append(header, LaunchSummaryAdvancedHeader...) + } + + var launchEntries [][]string + + // iterate and fetch summary for chains + for _, c := range chainLaunches { + + // get the current phase of the chain + var phase string + switch { + case !c.LaunchTriggered: + phase = "coordinating" + case time.Now().Before(c.LaunchTime): + phase = "launching" + default: + phase = "launched" + } + + entry := []string{ + fmt.Sprintf("%d", c.ID), + c.ChainID, + c.SourceURL, + phase, + } + + // add advanced information + if advanced { + project := "no project" + if c.ProjectID > 0 { + project = fmt.Sprintf("%d", c.ProjectID) + } + + reward := entrywriter.None + if len(c.Reward) > 0 { + reward = c.Reward + } + + entry = append(entry, + project, + c.Network.String(), + reward) + } + + launchEntries = append(launchEntries, entry) + } + + return session.PrintTable(header, launchEntries...) +} diff --git a/network/cmd/network_chain_prepare.go b/network/cmd/network_chain_prepare.go new file mode 100644 index 00000000..a645b3f8 --- /dev/null +++ b/network/cmd/network_chain_prepare.go @@ -0,0 +1,208 @@ +package cmd + +import ( + "fmt" + "path/filepath" + + "github.com/ignite/cli/v28/ignite/pkg/cache" + "github.com/ignite/cli/v28/ignite/pkg/chaincmd" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/colors" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/gitpod" + "github.com/ignite/cli/v28/ignite/pkg/goenv" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networkchain" + "github.com/ignite/apps/network/network/networktypes" +) + +const ( + flagForce = "force" +) + +// NewNetworkChainPrepare returns a new command to prepare the chain for launch. +func NewNetworkChainPrepare() *cobra.Command { + c := &cobra.Command{ + Use: "prepare [launch-id]", + Short: "Prepare the chain for launch", + Long: `The prepare command prepares a validator node for the chain launch by generating +the final genesis and adding IP addresses of peers to the validator's +configuration file. + + ignite network chain prepare 42 + +By default, Ignite uses "$HOME/spn/LAUNCH_ID" as the data directory. If you used +a different data directory when initializing the node, use the "--home" flag and +set the correct path to the data directory. + +Ignite generates the genesis file in "config/genesis.json" and adds peer IPs by +modifying "config/config.toml". + +The prepare command should be executed after the coordinator has triggered the +chain launch and finalized the genesis with "ignite network chain launch". You +can force Ignite to run the prepare command without checking if the launch has +been triggered with the "--force" flag (this is not recommended). + +After the prepare command is executed the node is ready to be started. +`, + Args: cobra.ExactArgs(1), + RunE: networkChainPrepareHandler, + } + + flagSetClearCache(c) + c.Flags().BoolP(flagForce, "f", false, "force the prepare command to run even if the chain is not launched") + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetCheckDependencies()) + + return c +} + +func networkChainPrepareHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + force, _ := cmd.Flags().GetBool(flagForce) + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + // fetch chain information + chainLaunch, err := n.ChainLaunch(cmd.Context(), launchID) + if err != nil { + return err + } + + if !force && chainLaunch.Metadata.Cli.Version != "" && !chainLaunch.Metadata.IsCurrentVersion() { + return fmt.Errorf(`chain %d has been published with a different version of the plugin (%s, current version is %s) +this may result in a genesis that is different from other validators' genesis +use --force to prepare anyway`, + launchID, + chainLaunch.Metadata.Cli.Version, + networktypes.Version, + ) + } + + if !force && !chainLaunch.LaunchTriggered { + return fmt.Errorf("chain %d launch has not been triggered yet. use --force to prepare anyway", launchID) + } + + networkOptions := []networkchain.Option{ + networkchain.WithKeyringBackend(chaincmd.KeyringBackendTest), + } + + if flagGetCheckDependencies(cmd) { + networkOptions = append(networkOptions, networkchain.CheckDependencies()) + } + + c, err := nb.Chain(networkchain.SourceLaunch(chainLaunch), networkOptions...) + if err != nil { + return err + } + + if err := prepareFromGenesisInformation( + cmd, + cacheStorage, + launchID, + n, + c, + chainLaunch, + ); err != nil { + return err + } + + chainHome, err := c.Home() + if err != nil { + return err + } + binaryName, err := c.BinaryName() + if err != nil { + return err + } + binaryDir := filepath.Dir(filepath.Join(goenv.Bin(), binaryName)) + + session.Printf("%s Chain is prepared for launch\n", icons.OK) + session.Println("\nYou can start your node by running the following command:") + commandStr := fmt.Sprintf("%s start --home %s", binaryName, chainHome) + if gitpod.IsOnGitpod() { + // Gitpod requires to enable proxy-tunnel tool + commandStr = fmt.Sprintf( + "ignite network tool proxy-tunnel %s/spn.yml & %s", + chainHome, commandStr, + ) + } + session.Printf("\t%s/%s\n", binaryDir, colors.Info(commandStr)) + + return nil +} + +// prepareFromGenesisInformation prepares the genesis of the chain from the queried genesis information from the launch ID of the chain. +func prepareFromGenesisInformation( + cmd *cobra.Command, + cacheStorage cache.Storage, + launchID uint64, + n network.Network, + c *networkchain.Chain, + chainLaunch networktypes.ChainLaunch, +) error { + var ( + rewardsInfo networktypes.Reward + lastBlockHeight int64 + consumerUnbondingTime int64 + ) + + // fetch the information to construct genesis + genesisInformation, err := n.GenesisInformation(cmd.Context(), launchID) + if err != nil { + return err + } + + // fetch the info for rewards if the consumer revision height is defined + if chainLaunch.ConsumerRevisionHeight > 0 { + rewardsInfo, lastBlockHeight, consumerUnbondingTime, err = n.RewardsInfo( + cmd.Context(), + launchID, + chainLaunch.ConsumerRevisionHeight, + ) + if err != nil { + return err + } + } + + spnChainID, err := n.ChainID(cmd.Context()) + if err != nil { + return err + } + + return c.Prepare( + cmd.Context(), + cacheStorage, + genesisInformation, + rewardsInfo, + spnChainID, + lastBlockHeight, + consumerUnbondingTime, + ) +} diff --git a/network/cmd/network_chain_publish.go b/network/cmd/network_chain_publish.go new file mode 100644 index 00000000..66eeb383 --- /dev/null +++ b/network/cmd/network_chain_publish.go @@ -0,0 +1,366 @@ +package cmd + +import ( + "fmt" + "os" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/xurl" + "github.com/ignite/network/pkg/chainid" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networkchain" +) + +const ( + flagTag = "tag" + flagBranch = "branch" + flagHash = "hash" + flagGenesisURL = "genesis-url" + flagGenesisConfig = "genesis-config" + flagProject = "project" + flagShares = "shares" + flagNoCheck = "no-check" + flagChainID = "chain-id" + flagMainnet = "mainnet" + flagAccountBalance = "account-balance" + flagRewardCoins = "reward.coins" + flagRewardHeight = "reward.height" +) + +// NewNetworkChainPublish returns a new command to publish a new chain to start a new network. +func NewNetworkChainPublish() *cobra.Command { + c := &cobra.Command{ + Use: "publish [source-url]", + Short: "Publish a new chain to start a new network", + Long: `To begin the process of launching a blockchain with Ignite, a coordinator needs +to publish the information about a blockchain. The only required bit of +information is the URL of the source code of the blockchain. + +The following command publishes the information about an example blockchain: + + ignite network chain publish github.com/ignite/example + +This command fetches the source code of the blockchain, compiles the binary, +verifies that a blockchain can be started with the binary, and publishes the +information about the blockchain to Ignite. Currently, only public repositories +are supported. The command returns an integer number that acts as an identifier +of the chain on Ignite. + +By publishing a blockchain on Ignite you become the "coordinator" of this +blockchain. A coordinator is an account that has the authority to approve and +reject validator requests, set parameters of the blockchain and trigger the +launch of the chain. + +The default Git branch is used when publishing a chain. If you want to use a +specific branch, tag or a commit hash, use "--branch", "--tag", or "--hash" +flags respectively. + +The repository name is used as the default chain ID. Ignite does not ensure that +chain IDs are unique, but they have to have a valid format: [string]-[integer]. +To set a custom chain ID use the "--chain-id" flag. + + ignite network chain publish github.com/ignite/example --chain-id foo-1 + +Once the chain is published users can request accounts with coin balances to be +added to the chain's genesis. By default, users are free to request any number +of tokens. If you want all users requesting tokens to get the same amount, use +the "--account-balance" flag with a list of coins. + + ignite network chain publish github.com/ignite/example --account-balance 2000foocoin +`, + Args: cobra.ExactArgs(1), + RunE: networkChainPublishHandler, + } + + flagSetClearCache(c) + c.Flags().String(flagBranch, "", "Git branch to use for the repo") + c.Flags().String(flagTag, "", "Git tag to use for the repo") + c.Flags().String(flagHash, "", "Git hash to use for the repo") + c.Flags().String(flagGenesisURL, "", "URL to a custom Genesis") + c.Flags().String(flagGenesisConfig, "", "name of an Ignite config file in the repo for custom Genesis") + c.Flags().String(flagChainID, "", "chain ID to use for this network") + c.Flags().Int64(flagProject, -1, "project ID to use for this network") + c.Flags().Bool(flagNoCheck, false, "skip verifying chain's integrity") + c.Flags().String(flagMetadata, "", "add chain metadata") + c.Flags().String(flagProjectTotalSupply, "", "add a total of the mainnet of a project") + c.Flags().String(flagShares, "", "add shares for the project") + c.Flags().Bool(flagMainnet, false, "initialize a mainnet project") + c.Flags().String(flagAccountBalance, "", "balance for each approved genesis account for the chain") + c.Flags().String(flagRewardCoins, "", "reward coins") + c.Flags().Int64(flagRewardHeight, 0, "last reward height") + c.Flags().String(flagAmount, "", "amount of coins for account request") + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetYes()) + c.Flags().AddFlagSet(flagSetCheckDependencies()) + + return c +} + +func networkChainPublishHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + var ( + tag, _ = cmd.Flags().GetString(flagTag) + branch, _ = cmd.Flags().GetString(flagBranch) + hash, _ = cmd.Flags().GetString(flagHash) + genesisURL, _ = cmd.Flags().GetString(flagGenesisURL) + genesisConfig, _ = cmd.Flags().GetString(flagGenesisConfig) + chainID, _ = cmd.Flags().GetString(flagChainID) + project, _ = cmd.Flags().GetInt64(flagProject) + noCheck, _ = cmd.Flags().GetBool(flagNoCheck) + metadata, _ = cmd.Flags().GetString(flagMetadata) + projectTotalSupplyStr, _ = cmd.Flags().GetString(flagProjectTotalSupply) + sharesStr, _ = cmd.Flags().GetString(flagShares) + isMainnet, _ = cmd.Flags().GetBool(flagMainnet) + accountBalance, _ = cmd.Flags().GetString(flagAccountBalance) + rewardCoinsStr, _ = cmd.Flags().GetString(flagRewardCoins) + rewardDuration, _ = cmd.Flags().GetInt64(flagRewardHeight) + amount, _ = cmd.Flags().GetString(flagAmount) + ) + + // parse the amount. + amountCoins, err := sdk.ParseCoinsNormalized(amount) + if err != nil { + return errors.Wrap(err, "error parsing amount") + } + + accountBalanceCoins, err := sdk.ParseCoinsNormalized(accountBalance) + if err != nil { + return errors.Wrap(err, "error parsing account balance") + } + + source, err := xurl.MightHTTPS(args[0]) + if err != nil { + return fmt.Errorf("invalid source url format: %w", err) + } + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + if project > -1 && projectTotalSupplyStr != "" { + return fmt.Errorf("%s and %s flags cannot be set together", flagProject, flagProjectTotalSupply) + } + if isMainnet { + if project < 0 && projectTotalSupplyStr == "" { + return fmt.Errorf( + "%s flag requires one of the %s or %s flags to be set", + flagMainnet, + flagProject, + flagProjectTotalSupply, + ) + } + if chainID == "" { + return fmt.Errorf("%s flag requires the %s flag", flagMainnet, flagChainID) + } + } + + if chainID != "" { + chainName, _, err := chainid.ParseGenesisChainID(chainID) + if err != nil { + return errors.Wrapf(err, "invalid chain id: %s", chainID) + } + if err := chainid.CheckChainName(chainName); err != nil { + return errors.Wrapf(err, "invalid chain id name: %s", chainName) + } + } + + totalSupply, err := sdk.ParseCoinsNormalized(projectTotalSupplyStr) + if err != nil { + return err + } + + rewardCoins, err := sdk.ParseCoinsNormalized(rewardCoinsStr) + if err != nil { + return err + } + + if (!rewardCoins.Empty() && rewardDuration == 0) || + (rewardCoins.Empty() && rewardDuration > 0) { + return fmt.Errorf("%s and %s flags must be provided together", flagRewardCoins, flagRewardHeight) + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // use source from chosen target. + var sourceOption networkchain.SourceOption + + switch { + case tag != "": + sourceOption = networkchain.SourceRemoteTag(source, tag) + case branch != "": + sourceOption = networkchain.SourceRemoteBranch(source, branch) + case hash != "": + sourceOption = networkchain.SourceRemoteHash(source, hash) + default: + sourceOption = networkchain.SourceRemote(source) + } + + var initOptions []networkchain.Option + + // cannot use both genesisURL and genesisConfig + if genesisURL != "" && genesisConfig != "" { + return errors.New("cannot use both genesis-url and genesis-config for initial genesis." + + "Please use only one of the options.") + } + + // use custom genesis from url if given. + if genesisURL != "" { + initOptions = append(initOptions, networkchain.WithGenesisFromURL(genesisURL)) + } + + // use custom genesis config if given + if genesisConfig != "" { + initOptions = append(initOptions, networkchain.WithGenesisFromConfig(genesisConfig)) + } + + // init in a temp dir. + homeDir, err := os.MkdirTemp("", "") + if err != nil { + return err + } + defer os.RemoveAll(homeDir) + + initOptions = append(initOptions, networkchain.WithHome(homeDir)) + + // prepare publish options + publishOptions := []network.PublishOption{network.WithMetadata(metadata)} + + switch { + case genesisURL != "": + publishOptions = append(publishOptions, network.WithCustomGenesisURL(genesisURL)) + case genesisConfig != "": + publishOptions = append(publishOptions, network.WithCustomGenesisConfig(genesisConfig)) + + } + + if project > -1 { + publishOptions = append(publishOptions, network.WithProject(project)) + } else if projectTotalSupplyStr != "" { + totalSupply, err := sdk.ParseCoinsNormalized(projectTotalSupplyStr) + if err != nil { + return err + } + if !totalSupply.Empty() { + publishOptions = append(publishOptions, network.WithTotalSupply(totalSupply)) + } + } + + // use custom chain id if given. + if chainID != "" { + publishOptions = append(publishOptions, network.WithChainID(chainID)) + } + + if !accountBalanceCoins.IsZero() { + publishOptions = append(publishOptions, network.WithAccountBalance(accountBalanceCoins)) + } + + if isMainnet { + publishOptions = append(publishOptions, network.Mainnet()) + } + + if !totalSupply.Empty() { + publishOptions = append(publishOptions, network.WithTotalSupply(totalSupply)) + } + + if sharesStr != "" { + sharePercentages, err := network.ParseSharePercents(sharesStr) + if err != nil { + return err + } + + publishOptions = append(publishOptions, network.WithPercentageShares(sharePercentages)) + } + + // TODO: Issue an error or warning when this flag is used with "no-check"? + // The "check-dependencies" flag is ignored when the "no-check" one is present. + if flagGetCheckDependencies(cmd) { + initOptions = append(initOptions, networkchain.CheckDependencies()) + } + + // init the chain. + c, err := nb.Chain(sourceOption, initOptions...) + if err != nil { + return err + } + + if !noCheck { + if err := c.Init(cmd.Context(), cacheStorage); err != nil { + // initialize the chain for checking. + return fmt.Errorf("blockchain init failed: %w", err) + } + } + + session.StartSpinner("Publishing...") + + n, err := nb.Network() + if err != nil { + return err + } + + launchID, projectID, err := n.Publish(cmd.Context(), c, publishOptions...) + if err != nil { + return err + } + + if !rewardCoins.IsZero() && rewardDuration > 0 { + if err := n.SetReward(cmd.Context(), launchID, rewardDuration, rewardCoins); err != nil { + return err + } + } + + if !amountCoins.IsZero() { + // create a request to add an account to the genesis + addr, err := n.AccountAddress() + if err != nil { + return err + } + addAccountRequest := launchtypes.NewGenesisAccount( + launchID, + addr, + amountCoins, + ) + + // simulate the add account request + if err := verifyRequestsFromRequestContents( + cmd.Context(), + cacheStorage, + nb, + launchID, + addAccountRequest, + ); err != nil { + return err + } + + // send the request + if err := n.SendRequest(cmd.Context(), launchID, addAccountRequest); err != nil { + return err + } + } + + session.Printf("%s Network published \n", icons.OK) + if isMainnet { + session.Printf("%s Mainnet ID: %d \n", icons.Bullet, launchID) + } else { + session.Printf("%s Launch ID: %d \n", icons.Bullet, launchID) + } + if projectID > -1 { + session.Printf("%s Project ID: %d \n", icons.Bullet, projectID) + } + + return nil +} diff --git a/network/cmd/network_chain_revert_launch.go b/network/cmd/network_chain_revert_launch.go new file mode 100644 index 00000000..0f5c2787 --- /dev/null +++ b/network/cmd/network_chain_revert_launch.go @@ -0,0 +1,58 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +// NewNetworkChainRevertLaunch creates a new chain revert launch command +// to revert a launched chain. +func NewNetworkChainRevertLaunch() *cobra.Command { + c := &cobra.Command{ + Use: "revert-launch [launch-id]", + Short: "Revert launch of a network as a coordinator", + Long: `The revert launch command reverts the previously scheduled launch of a chain. + +Only the coordinator of the chain can execute the launch command. + + ignite network chain revert-launch 42 + +After the revert launch command is executed, changes to the genesis of the chain +are allowed again. For example, validators will be able to request to join the +chain. Revert launch also resets the launch time. +`, + Args: cobra.ExactArgs(1), + RunE: networkChainRevertLaunchHandler, + } + + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + + return c +} + +func networkChainRevertLaunchHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + return n.RevertLaunch(cmd.Context(), launchID) +} diff --git a/network/cmd/network_chain_show.go b/network/cmd/network_chain_show.go new file mode 100644 index 00000000..d88235de --- /dev/null +++ b/network/cmd/network_chain_show.go @@ -0,0 +1,40 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +const flagOut = "out" + +// NewNetworkChainShow creates a new chain show +// command to show a chain details on SPN. +func NewNetworkChainShow() *cobra.Command { + c := &cobra.Command{ + Use: "show", + Short: "Show details of a chain", + } + c.AddCommand( + newNetworkChainShowInfo(), + newNetworkChainShowGenesis(), + newNetworkChainShowAccounts(), + newNetworkChainShowValidators(), + newNetworkChainShowPeers(), + ) + return c +} + +func networkChainLaunch(cmd *cobra.Command, args []string, session *cliui.Session) (NetworkBuilder, uint64, error) { + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return nb, 0, err + } + // parse launch ID. + launchID, err := network.ParseID(args[0]) + if err != nil { + return nb, launchID, err + } + return nb, launchID, err +} diff --git a/network/cmd/network_chain_show_accounts.go b/network/cmd/network_chain_show_accounts.go new file mode 100644 index 00000000..43ffba15 --- /dev/null +++ b/network/cmd/network_chain_show_accounts.go @@ -0,0 +1,94 @@ +package cmd + +import ( + "strconv" + + "github.com/spf13/cobra" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/cosmosutil" +) + +var ( + chainGenesisAccSummaryHeader = []string{"Genesis Account", "Coins"} + chainVestingAccSummaryHeader = []string{"Vesting Account", "Total Balance", "Vesting", "EndTime"} +) + +func newNetworkChainShowAccounts() *cobra.Command { + c := &cobra.Command{ + Use: "accounts [launch-id]", + Short: "Show all vesting and genesis accounts of the chain", + Args: cobra.ExactArgs(1), + RunE: networkChainShowAccountsHandler, + } + + c.Flags().AddFlagSet(flagSetSPNAccountPrefixes()) + + return c +} + +func networkChainShowAccountsHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + addressPrefix := getAddressPrefix(cmd) + + nb, launchID, err := networkChainLaunch(cmd, args, session) + if err != nil { + return err + } + n, err := nb.Network() + if err != nil { + return err + } + + genesisAccs, err := n.GenesisAccounts(cmd.Context(), launchID) + if err != nil { + return err + } + vestingAccs, err := n.VestingAccounts(cmd.Context(), launchID) + if err != nil { + return err + } + if len(genesisAccs)+len(vestingAccs) == 0 { + return session.Printf("%s %s\n", icons.Info, "empty chain account list") + } + + genesisAccEntries := make([][]string, 0) + for _, acc := range genesisAccs { + address, err := cosmosutil.ChangeAddressPrefix(acc.Address, addressPrefix) + if err != nil { + return err + } + + genesisAccEntries = append(genesisAccEntries, []string{address, acc.Coins.String()}) + } + genesisVestingAccEntries := make([][]string, 0) + for _, acc := range vestingAccs { + address, err := cosmosutil.ChangeAddressPrefix(acc.Address, addressPrefix) + if err != nil { + return err + } + + genesisVestingAccEntries = append(genesisVestingAccEntries, []string{ + address, + acc.TotalBalance.String(), + acc.Vesting.String(), + strconv.FormatInt(acc.EndTime, 10), + }) + } + + if len(genesisAccEntries) > 0 { + if err = session.PrintTable(chainGenesisAccSummaryHeader, genesisAccEntries...); err != nil { + return err + } + } + if len(genesisVestingAccEntries) > 0 { + if err = session.PrintTable(chainVestingAccSummaryHeader, genesisVestingAccEntries...); err != nil { + return err + } + } + + return nil +} diff --git a/network/cmd/network_chain_show_genesis.go b/network/cmd/network_chain_show_genesis.go new file mode 100644 index 00000000..16463974 --- /dev/null +++ b/network/cmd/network_chain_show_genesis.go @@ -0,0 +1,110 @@ +package cmd + +import ( + "os" + "path/filepath" + + "github.com/ignite/cli/v28/ignite/pkg/chaincmd" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/xos" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network/networkchain" + "github.com/ignite/apps/network/network/networktypes" +) + +func newNetworkChainShowGenesis() *cobra.Command { + c := &cobra.Command{ + Use: "genesis [launch-id]", + Short: "Show the chain genesis file", + Args: cobra.ExactArgs(1), + RunE: networkChainShowGenesisHandler, + } + + flagSetClearCache(c) + c.Flags().String(flagOut, "./genesis.json", "path to output Genesis file") + + return c +} + +func networkChainShowGenesisHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + out, _ := cmd.Flags().GetString(flagOut) + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + nb, launchID, err := networkChainLaunch(cmd, args, session) + if err != nil { + return err + } + n, err := nb.Network() + if err != nil { + return err + } + + chainLaunch, err := n.ChainLaunch(cmd.Context(), launchID) + if err != nil { + return err + } + + networkOptions := []networkchain.Option{ + networkchain.WithKeyringBackend(chaincmd.KeyringBackendTest), + } + + c, err := nb.Chain(networkchain.SourceLaunch(chainLaunch), networkOptions...) + if err != nil { + return err + } + + // generate the genesis in a temp dir + tmpHome, err := os.MkdirTemp("", "*-spn") + if err != nil { + return err + } + defer os.RemoveAll(tmpHome) + + c.SetHome(tmpHome) + + if err := prepareFromGenesisInformation( + cmd, + cacheStorage, + launchID, + n, + c, + chainLaunch, + ); err != nil { + return err + } + + // get the new genesis path + genesisPath, err := c.GenesisPath() + if err != nil { + return err + } + + if err := os.MkdirAll(filepath.Dir(out), 0o744); err != nil { + return err + } + + if err := xos.Rename(genesisPath, out); err != nil { + return err + } + + if chainLaunch.Metadata.Cli.Version != "" && !chainLaunch.Metadata.IsCurrentVersion() { + session.Printf(`⚠️ chain %d has been published with a different version of the plugin (%s, current version is %s) +this may result in a genesis that is different from other validators' genesis +for chain launch, please update the plugin to the same version\n`, + launchID, + chainLaunch.Metadata.Cli.Version, + networktypes.Version, + ) + } + + return session.Printf("%s Genesis generated: %s\n", icons.Bullet, out) +} diff --git a/network/cmd/network_chain_show_info.go b/network/cmd/network_chain_show_info.go new file mode 100644 index 00000000..59b14b9f --- /dev/null +++ b/network/cmd/network_chain_show_info.go @@ -0,0 +1,53 @@ +package cmd + +import ( + "errors" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/yaml" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +func newNetworkChainShowInfo() *cobra.Command { + c := &cobra.Command{ + Use: "info [launch-id]", + Short: "Show info details of the chain", + Args: cobra.ExactArgs(1), + RunE: networkChainShowInfoHandler, + } + return c +} + +func networkChainShowInfoHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, launchID, err := networkChainLaunch(cmd, args, session) + if err != nil { + return err + } + n, err := nb.Network() + if err != nil { + return err + } + + chainLaunch, err := n.ChainLaunch(cmd.Context(), launchID) + if err != nil { + return err + } + + reward, err := n.ChainReward(cmd.Context(), launchID) + if err != nil && !errors.Is(err, network.ErrObjectNotFound) { + return err + } + chainLaunch.Reward = reward.RemainingCoins.String() + + info, err := yaml.Marshal(cmd.Context(), chainLaunch) + if err != nil { + return err + } + + return session.Print(info) +} diff --git a/network/cmd/network_chain_show_peers.go b/network/cmd/network_chain_show_peers.go new file mode 100644 index 00000000..5bdc27b8 --- /dev/null +++ b/network/cmd/network_chain_show_peers.go @@ -0,0 +1,77 @@ +package cmd + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +func newNetworkChainShowPeers() *cobra.Command { + c := &cobra.Command{ + Use: "peers [launch-id]", + Short: "Show peers list of the chain", + Args: cobra.ExactArgs(1), + RunE: networkChainShowPeersHandler, + } + + c.Flags().String(flagOut, "./peers.txt", "path to output peers list") + + return c +} + +func networkChainShowPeersHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + out, _ := cmd.Flags().GetString(flagOut) + + nb, launchID, err := networkChainLaunch(cmd, args, session) + if err != nil { + return err + } + n, err := nb.Network() + if err != nil { + return err + } + + genVals, err := n.GenesisValidators(cmd.Context(), launchID) + if err != nil { + return err + } + + peers := make([]string, 0) + for _, acc := range genVals { + peer, err := network.PeerAddress(acc.Peer) + if err != nil { + return err + } + peers = append(peers, peer) + } + + if len(peers) == 0 { + session.Printf("%s %s\n", icons.Info, "no peers found") + return nil + + } + + if err := os.MkdirAll(filepath.Dir(out), 0o744); err != nil { + return err + } + + b := &bytes.Buffer{} + peerList := strings.Join(peers, ",") + fmt.Fprintln(b, peerList) + if err := os.WriteFile(out, b.Bytes(), 0o644); err != nil { + return err + } + + return session.Printf("%s Peer list generated: %s\n", icons.Bullet, out) +} diff --git a/network/cmd/network_chain_show_validators.go b/network/cmd/network_chain_show_validators.go new file mode 100644 index 00000000..213197f2 --- /dev/null +++ b/network/cmd/network_chain_show_validators.go @@ -0,0 +1,69 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/cosmosutil" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +var chainGenesisValSummaryHeader = []string{"Genesis Validator", "Self Delegation", "Peer"} + +func newNetworkChainShowValidators() *cobra.Command { + c := &cobra.Command{ + Use: "validators [launch-id]", + Short: "Show all validators of the chain", + Args: cobra.ExactArgs(1), + RunE: networkChainShowValidatorsHandler, + } + + c.Flags().AddFlagSet(flagSetSPNAccountPrefixes()) + + return c +} + +func networkChainShowValidatorsHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + addressPrefix := getAddressPrefix(cmd) + + nb, launchID, err := networkChainLaunch(cmd, args, session) + if err != nil { + return err + } + n, err := nb.Network() + if err != nil { + return err + } + + validators, err := n.GenesisValidators(cmd.Context(), launchID) + if err != nil { + return err + } + validatorEntries := make([][]string, 0) + for _, acc := range validators { + peer, err := network.PeerAddress(acc.Peer) + if err != nil { + return err + } + + address, err := cosmosutil.ChangeAddressPrefix(acc.Address, addressPrefix) + if err != nil { + return err + } + + validatorEntries = append(validatorEntries, []string{ + address, + acc.SelfDelegation.String(), + peer, + }) + } + if len(validatorEntries) == 0 { + return session.Printf("%s %s\n", icons.Info, "no account found") + } + + return session.PrintTable(chainGenesisValSummaryHeader, validatorEntries...) +} diff --git a/network/cmd/network_coordinator.go b/network/cmd/network_coordinator.go new file mode 100644 index 00000000..df781d2f --- /dev/null +++ b/network/cmd/network_coordinator.go @@ -0,0 +1,17 @@ +package cmd + +import "github.com/spf13/cobra" + +// NewNetworkCoordinator creates a new coordinator command +// it contains sub commands to manage coordinator profile. +func NewNetworkCoordinator() *cobra.Command { + c := &cobra.Command{ + Use: "coordinator", + Short: "Show and update a coordinator profile", + } + c.AddCommand( + NewNetworkCoordinatorShow(), + NewNetworkCoordinatorSet(), + ) + return c +} diff --git a/network/cmd/network_coordinator_set.go b/network/cmd/network_coordinator_set.go new file mode 100644 index 00000000..4face804 --- /dev/null +++ b/network/cmd/network_coordinator_set.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "errors" + + profiletypes "github.com/ignite/network/x/profile/types" + "github.com/spf13/cobra" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" +) + +// NewNetworkCoordinatorSet creates a command to set an information in a coordinator profile. +func NewNetworkCoordinatorSet() *cobra.Command { + c := &cobra.Command{ + Use: "set details|identity|website [value]", + Short: "Set an information in a coordinator profile", + Long: `Coordinators on Ignite can set a profile containing a description for the coordinator. +The coordinator set command allows to set information for the coordinator. +The following information can be set: +- details: general information about the coordinator. +- identity: a piece of information to verify the identity of the coordinator with a system like Keybase or Veramo. +- website: website of the coordinator. +`, + RunE: networkCoordinatorSetHandler, + Args: cobra.ExactArgs(2), + } + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkCoordinatorSetHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + var description profiletypes.CoordinatorDescription + switch args[0] { + case "details": + description.Details = args[1] + case "identity": + description.Identity = args[1] + case "website": + description.Website = args[1] + default: + return errors.New("invalid attribute, must provide details, identity, website or security") + } + + if err := n.SetCoordinatorDescription(cmd.Context(), description); err != nil { + return err + } + + return session.Printf("%s Coordinator updated \n", icons.OK) +} diff --git a/network/cmd/network_coordinator_show.go b/network/cmd/network_coordinator_show.go new file mode 100644 index 00000000..bd7a19e1 --- /dev/null +++ b/network/cmd/network_coordinator_show.go @@ -0,0 +1,56 @@ +package cmd + +import ( + "github.com/spf13/cobra" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/yaml" +) + +// NewNetworkCoordinatorShow creates a command to show coordinator information. +func NewNetworkCoordinatorShow() *cobra.Command { + c := &cobra.Command{ + Use: "show [address]", + Short: "Show a coordinator profile", + RunE: networkCoordinatorShowHandler, + Args: cobra.ExactArgs(1), + } + return c +} + +func networkCoordinatorShowHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + coordinator, err := n.Coordinator(cmd.Context(), args[0]) + if err != nil { + return err + } + + // convert the request object to YAML to be more readable + // and convert the byte array fields to string. + coordinatorYaml, err := yaml.Marshal(cmd.Context(), struct { + Identity string + Details string + Website string + }{ + coordinator.Identity, + coordinator.Details, + coordinator.Website, + }) + if err != nil { + return err + } + + return session.Println(coordinatorYaml) +} diff --git a/network/cmd/network_profile.go b/network/cmd/network_profile.go new file mode 100644 index 00000000..0d620b21 --- /dev/null +++ b/network/cmd/network_profile.go @@ -0,0 +1,58 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/yaml" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +// NewNetworkProfile returns a new command to show the address profile info on Starport Network. +func NewNetworkProfile() *cobra.Command { + c := &cobra.Command{ + Use: "profile [project-id]", + Short: "Show the address profile info", + Args: cobra.RangeArgs(0, 1), + RunE: networkProfileHandler, + Hidden: true, + } + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetHome()) + return c +} + +func networkProfileHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + var projectID uint64 + if len(args) > 0 { + projectID, err = network.ParseID(args[0]) + if err != nil { + return err + } + } + + profile, err := n.Profile(cmd.Context(), projectID) + if err != nil { + return err + } + + profileInfo, err := yaml.Marshal(cmd.Context(), profile) + if err != nil { + return err + } + return session.Println(profileInfo) +} diff --git a/network/cmd/network_project.go b/network/cmd/network_project.go new file mode 100644 index 00000000..7916b680 --- /dev/null +++ b/network/cmd/network_project.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// NewNetworkProject creates a new project command that holds other +// subcommands related to launching a network for a project. +func NewNetworkProject() *cobra.Command { + c := &cobra.Command{ + Use: "project", + Short: "Handle projects", + Hidden: true, + } + c.AddCommand( + NewNetworkProjectPublish(), + NewNetworkProjectList(), + NewNetworkProjectShow(), + NewNetworkProjectUpdate(), + NewNetworkProjectAccount(), + ) + return c +} diff --git a/network/cmd/network_project_account.go b/network/cmd/network_project_account.go new file mode 100644 index 00000000..a9a84b30 --- /dev/null +++ b/network/cmd/network_project_account.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "github.com/spf13/cobra" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" +) + +var projectMainnetsAccSummaryHeader = []string{"Mainnet Account", "Shares"} + +// NewNetworkProjectAccount creates a new project account command that holds some other +// sub commands related to account for a project. +func NewNetworkProjectAccount() *cobra.Command { + c := &cobra.Command{ + Use: "account", + Short: "Handle project accounts", + } + c.AddCommand( + newNetworkProjectAccountList(), + ) + return c +} + +func newNetworkProjectAccountList() *cobra.Command { + c := &cobra.Command{ + Use: "list [project-id]", + Short: "Show all mainnet and mainnet vesting of the project", + Args: cobra.ExactArgs(1), + RunE: newNetworkProjectAccountListHandler, + } + return c +} + +func newNetworkProjectAccountListHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, projectID, err := networkChainLaunch(cmd, args, session) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + // get all project accounts + mainnetAccs, err := n.MainnetAccounts(cmd.Context(), projectID) + if err != nil { + return err + } + + if len(mainnetAccs) == 0 { + return session.Printf("%s no project account found\n", icons.Info) + } + + mainnetAccEntries := make([][]string, 0) + for _, acc := range mainnetAccs { + mainnetAccEntries = append(mainnetAccEntries, []string{acc.Address, acc.Shares.String()}) + } + + if len(mainnetAccEntries) > 0 { + if err = session.PrintTable(projectMainnetsAccSummaryHeader, mainnetAccEntries...); err != nil { + return err + } + } + + return nil +} diff --git a/network/cmd/network_project_list.go b/network/cmd/network_project_list.go new file mode 100644 index 00000000..e66f476d --- /dev/null +++ b/network/cmd/network_project_list.go @@ -0,0 +1,72 @@ +package cmd + +import ( + "fmt" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/entrywriter" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network/networktypes" +) + +var ProjectSummaryHeader = []string{ + "id", + "name", + "coordinator id", + "mainnet id", +} + +// NewNetworkProjectList returns a new command to list all published Projects on Ignite. +func NewNetworkProjectList() *cobra.Command { + c := &cobra.Command{ + Use: "list", + Short: "List published projects", + Args: cobra.NoArgs, + RunE: networkProjectListHandler, + } + return c +} + +func networkProjectListHandler(cmd *cobra.Command, _ []string) error { + session := cliui.New(cliui.StartSpinner()) + + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + projects, err := n.Projects(cmd.Context()) + if err != nil { + return err + } + + return renderProjectSummaries(projects, session) +} + +// renderProjectSummaries writes into the provided out, the list of summarized projects. +func renderProjectSummaries(projects []networktypes.Project, session *cliui.Session) error { + var projectEntries [][]string + + for _, c := range projects { + mainnetID := entrywriter.None + if c.MainnetInitialized { + mainnetID = fmt.Sprintf("%d", c.MainnetID) + } + + projectEntries = append(projectEntries, []string{ + fmt.Sprintf("%d", c.ID), + c.Name, + fmt.Sprintf("%d", c.CoordinatorID), + mainnetID, + }) + } + + return session.PrintTable(ProjectSummaryHeader, projectEntries...) +} diff --git a/network/cmd/network_project_publish.go b/network/cmd/network_project_publish.go new file mode 100644 index 00000000..03fbadc9 --- /dev/null +++ b/network/cmd/network_project_publish.go @@ -0,0 +1,57 @@ +package cmd + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/spf13/cobra" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" +) + +const ( + flagMetadata = "metadata" +) + +// NewNetworkProjectPublish returns a new command to publish a new projects on Ignite. +func NewNetworkProjectPublish() *cobra.Command { + c := &cobra.Command{ + Use: "create [name] [total-supply]", + Short: "Create a project", + Args: cobra.ExactArgs(2), + RunE: networkProjectPublishHandler, + } + c.Flags().String(flagMetadata, "", "Add a metadata to the chain") + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + c.Flags().AddFlagSet(flagSetHome()) + return c +} + +func networkProjectPublishHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + totalSupply, err := sdk.ParseCoinsNormalized(args[1]) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + metadata, _ := cmd.Flags().GetString(flagMetadata) + projectID, err := n.CreateProject(cmd.Context(), args[0], metadata, totalSupply) + if err != nil { + return err + } + + return session.Printf("%s Project ID: %d \n", icons.Bullet, projectID) +} diff --git a/network/cmd/network_project_show.go b/network/cmd/network_project_show.go new file mode 100644 index 00000000..6241400f --- /dev/null +++ b/network/cmd/network_project_show.go @@ -0,0 +1,53 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/yaml" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +// NewNetworkProjectShow returns a new command to show published project on Ignite. +func NewNetworkProjectShow() *cobra.Command { + c := &cobra.Command{ + Use: "show [project-id]", + Short: "Show published project", + Args: cobra.ExactArgs(1), + RunE: networkProjectShowHandler, + } + return c +} + +func networkProjectShowHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + // parse project ID + projectID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + project, err := n.Project(cmd.Context(), projectID) + if err != nil { + return err + } + + info, err := yaml.Marshal(cmd.Context(), project) + if err != nil { + return err + } + + return session.Println(info) +} diff --git a/network/cmd/network_project_update.go b/network/cmd/network_project_update.go new file mode 100644 index 00000000..e9e2f070 --- /dev/null +++ b/network/cmd/network_project_update.go @@ -0,0 +1,106 @@ +package cmd + +import ( + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/yaml" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +const ( + flagProjectName = "name" + flagProjectMetadata = "metadata" + flagProjectTotalSupply = "total-supply" +) + +func NewNetworkProjectUpdate() *cobra.Command { + c := &cobra.Command{ + Use: "update [project-id]", + Short: "Update details fo the project of the project", + Args: cobra.ExactArgs(1), + RunE: networkProjectUpdateHandler, + } + c.Flags().String(flagProjectName, "", "update the project name") + c.Flags().String(flagProjectMetadata, "", "update the project metadata") + c.Flags().String(flagProjectTotalSupply, "", "update the total of the mainnet of a project") + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkProjectUpdateHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + var ( + projectName, _ = cmd.Flags().GetString(flagProjectName) + metadata, _ = cmd.Flags().GetString(flagProjectMetadata) + projectTotalSupply, _ = cmd.Flags().GetString(flagProjectTotalSupply) + ) + + totalSupply, err := sdk.ParseCoinsNormalized(projectTotalSupply) + if err != nil { + return err + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse project ID + projectID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + if projectName == "" && metadata == "" && totalSupply.Empty() { + return fmt.Errorf("at least one of the flags %s must be provided", + strings.Join([]string{ + flagProjectName, + flagProjectMetadata, + flagProjectTotalSupply, + }, ", "), + ) + } + + n, err := nb.Network() + if err != nil { + return err + } + + var proposals []network.Prop + + if projectName != "" { + proposals = append(proposals, network.WithProjectName(projectName)) + } + if metadata != "" { + proposals = append(proposals, network.WithProjectMetadata(metadata)) + } + if !totalSupply.Empty() { + proposals = append(proposals, network.WithProjectTotalSupply(totalSupply)) + } + + if err = n.UpdateProject(cmd.Context(), projectID, proposals...); err != nil { + return err + } + + project, err := n.Project(cmd.Context(), projectID) + if err != nil { + return err + } + session.Println() + + info, err := yaml.Marshal(cmd.Context(), project) + if err != nil { + return err + } + + return session.Print(info) +} diff --git a/network/cmd/network_request.go b/network/cmd/network_request.go new file mode 100644 index 00000000..3461d92c --- /dev/null +++ b/network/cmd/network_request.go @@ -0,0 +1,40 @@ +package cmd + +import "github.com/spf13/cobra" + +// NewNetworkRequest creates a new approval request command that holds some other +// sub commands related to handle request for a chain. +func NewNetworkRequest() *cobra.Command { + c := &cobra.Command{ + Use: "request", + Short: "Create, show, reject and approve requests", + Long: `The "request" namespace contains commands for creating, showing, approving, and +rejecting requests. + +A request is mechanism in Ignite that allows changes to be made to the genesis +file like adding accounts with token balances and validators. Anyone can submit +a request, but only the coordinator of a chain can approve or reject a request. + +Each request has a status: + +* Pending: waiting for the approval of the coordinator +* Approved: approved by the coordinator, its content has been applied to the + launch information +* Rejected: rejected by the coordinator or the request creator +`, + } + + c.AddCommand( + NewNetworkRequestShow(), + NewNetworkRequestList(), + NewNetworkRequestApprove(), + NewNetworkRequestReject(), + NewNetworkRequestVerify(), + NewNetworkRequestAddAccount(), + NewNetworkRequestRemoveAccount(), + NewNetworkRequestRemoveValidator(), + NewNetworkRequestChangeParam(), + ) + + return c +} diff --git a/network/cmd/network_request_add_account.go b/network/cmd/network_request_add_account.go new file mode 100644 index 00000000..1f1f0ce7 --- /dev/null +++ b/network/cmd/network_request_add_account.go @@ -0,0 +1,128 @@ +package cmd + +import ( + "errors" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cosmosutil" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networkchain" + "github.com/ignite/apps/network/network/networktypes" +) + +// NewNetworkRequestAddAccount creates a new command to send add account request. +func NewNetworkRequestAddAccount() *cobra.Command { + c := &cobra.Command{ + Use: "add-account [launch-id] [address] [coins]", + Short: "Send request to add account", + Long: `The "add account" command creates a new request to add an account with a given +address and a specified coin balance to the genesis of the chain. + +The request automatically fails to be applied if a genesis account or a vesting +account with an identical address is already specified in the launch +information. + +If a coordinator has specified that all genesis accounts on a chain should have +the same balance (useful for testnets, for example), the "add account" expects +only an address as an argument. Attempt to provide a token balance will result +in an error. +`, + RunE: networkRequestAddAccountHandler, + Args: cobra.RangeArgs(2, 3), + } + + flagSetClearCache(c) + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkRequestAddAccountHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // get the address for the account and change the prefix for Ignite Chain + address, err := cosmosutil.ChangeAddressPrefix(args[1], networktypes.SPN) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + chainLaunch, err := n.ChainLaunch(cmd.Context(), launchID) + if err != nil { + return err + } + + c, err := nb.Chain(networkchain.SourceLaunch(chainLaunch)) + if err != nil { + return err + } + + var balance sdk.Coins + if c.IsAccountBalanceFixed() { + balance = c.AccountBalance() + if len(args) == 3 { + return fmt.Errorf( + "balance can't be provided, balance has been set by coordinator to %s", + balance.String(), + ) + } + } else { + if len(args) < 3 { + return errors.New("account balance expected") + } + balanceStr := args[2] + balance, err = sdk.ParseCoinsNormalized(balanceStr) + if err != nil { + return err + } + } + + // create the add account request + addAccountRequest := launchtypes.NewGenesisAccount( + launchID, + address, + balance, + ) + + // simulate the add account request + if err := verifyRequestsFromRequestContents( + cmd.Context(), + cacheStorage, + nb, + launchID, + addAccountRequest, + ); err != nil { + return err + } + + // send the request + return n.SendRequest(cmd.Context(), launchID, addAccountRequest) +} diff --git a/network/cmd/network_request_approve.go b/network/cmd/network_request_approve.go new file mode 100644 index 00000000..69730f9d --- /dev/null +++ b/network/cmd/network_request_approve.go @@ -0,0 +1,110 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/numbers" + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +const ( + flagNoVerification = "no-verification" +) + +// NewNetworkRequestApprove creates a new request approve +// command to approve requests for a chain. +func NewNetworkRequestApprove() *cobra.Command { + c := &cobra.Command{ + Use: "approve [launch-id] [number<,...>]", + Aliases: []string{"accept"}, + Short: "Approve requests", + Long: `The "approve" command is used by a chain's coordinator to approve requests. +Multiple requests can be approved using a comma-separated list and/or using a +dash syntax. + + ignite network request approve 42 1,2,3-6,7,8 + +The command above approves requests with IDs from 1 to 8 included on a chain +with a launch ID 42. + +When requests are approved Ignite applies the requested changes and simulates +initializing and launching the chain locally. If the chain starts successfully, +requests are considered to be "verified" and are approved. If one or more +requested changes stop the chain from launching locally, the verification +process fails and the approval of all requests is canceled. To skip the +verification process use the "--no-verification" flag. + +Note that Ignite will try to approve requests in the same order as request IDs +are submitted to the "approve" command.`, + RunE: networkRequestApproveHandler, + Args: cobra.ExactArgs(2), + } + + flagSetClearCache(c) + c.Flags().Bool(flagNoVerification, false, "approve the requests without verifying them") + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkRequestApproveHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // Get the list of request ids + ids, err := numbers.ParseList(args[1]) + if err != nil { + return err + } + + // Verify the requests are valid + noVerification, err := cmd.Flags().GetBool(flagNoVerification) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + // if requests must be verified, we simulate the chain in a temporary directory with the requests + if !noVerification { + if err := verifyRequests(cmd.Context(), cacheStorage, nb, launchID, ids...); err != nil { + return errors.Wrap(err, "request(s) not valid") + } + session.Printf("%s Request(s) %s verified\n", icons.OK, numbers.List(ids, "#")) + } + + // Submit the approved requests + reviewals := make([]network.Reviewal, 0) + for _, id := range ids { + reviewals = append(reviewals, network.ApproveRequest(id)) + } + if err := n.SubmitRequestReviewals(cmd.Context(), launchID, reviewals...); err != nil { + return err + } + + return session.Printf("%s Request(s) %s approved\n", icons.OK, numbers.List(ids, "#")) +} diff --git a/network/cmd/network_request_change_param.go b/network/cmd/network_request_change_param.go new file mode 100644 index 00000000..dc7c3b4a --- /dev/null +++ b/network/cmd/network_request_change_param.go @@ -0,0 +1,101 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networkchain" +) + +// NewNetworkRequestChangeParam creates a new command to send param change request. +func NewNetworkRequestChangeParam() *cobra.Command { + c := &cobra.Command{ + Use: "change-param [launch-id] [module-name] [param-name] [value (json, string, number)]", + Short: "Send request to change a module param", + RunE: networkRequestChangeParamHandler, + Args: cobra.ExactArgs(4), + } + + flagSetClearCache(c) + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkRequestChangeParamHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + module := args[1] + param := args[2] + value := []byte(args[3]) + + n, err := nb.Network() + if err != nil { + return err + } + + // fetch chain information + chainLaunch, err := n.ChainLaunch(cmd.Context(), launchID) + if err != nil { + return err + } + + c, err := nb.Chain(networkchain.SourceLaunch(chainLaunch)) + if err != nil { + return err + } + + // check validity of request + err = c.CheckRequestChangeParam( + cmd.Context(), + module, + param, + value, + ) + if err != nil { + return err + } + + // create the param change request + paramChangeRequest := launchtypes.NewParamChange( + launchID, + module, + param, + value, + ) + + // simulate the param change request + if err := verifyRequestsFromRequestContents( + cmd.Context(), + cacheStorage, + nb, + launchID, + paramChangeRequest, + ); err != nil { + return err + } + + // send the request + return n.SendRequest(cmd.Context(), launchID, paramChangeRequest) +} diff --git a/network/cmd/network_request_list.go b/network/cmd/network_request_list.go new file mode 100644 index 00000000..d9bdcee9 --- /dev/null +++ b/network/cmd/network_request_list.go @@ -0,0 +1,176 @@ +package cmd + +import ( + "fmt" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cosmosutil" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networktypes" +) + +var requestSummaryHeader = []string{"ID", "Status", "Type", "Content"} + +// NewNetworkRequestList creates a new request list command to list +// requests for a chain. +func NewNetworkRequestList() *cobra.Command { + c := &cobra.Command{ + Use: "list [launch-id]", + Short: "List all requests for a chain", + RunE: networkRequestListHandler, + Args: cobra.ExactArgs(1), + } + + c.Flags().AddFlagSet(flagSetSPNAccountPrefixes()) + + return c +} + +func networkRequestListHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + addressPrefix := getAddressPrefix(cmd) + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + requests, err := n.Requests(cmd.Context(), launchID) + if err != nil { + return err + } + + return renderRequestSummaries(requests, session, addressPrefix) +} + +// renderRequestSummaries writes into the provided out, the list of summarized requests. +func renderRequestSummaries( + requests []networktypes.Request, + session *cliui.Session, + addressPrefix string, +) error { + requestEntries := make([][]string, 0) + for _, request := range requests { + var ( + id = fmt.Sprintf("%d", request.RequestID) + requestType = "Unknown" + content = "" + ) + switch req := request.Content.Content.(type) { + case *launchtypes.RequestContent_GenesisAccount: + requestType = "Add Genesis Account" + + address, err := cosmosutil.ChangeAddressPrefix( + req.GenesisAccount.Address, + addressPrefix, + ) + if err != nil { + return err + } + + content = fmt.Sprintf("%s, %s", + address, + req.GenesisAccount.Coins.String()) + case *launchtypes.RequestContent_GenesisValidator: + requestType = "Add Genesis Validator" + peer, err := network.PeerAddress(req.GenesisValidator.Peer) + if err != nil { + return err + } + + address, err := cosmosutil.ChangeAddressPrefix( + req.GenesisValidator.Address, + addressPrefix, + ) + if err != nil { + return err + } + + content = fmt.Sprintf("%s, %s, %s", + peer, + address, + req.GenesisValidator.SelfDelegation.String()) + case *launchtypes.RequestContent_VestingAccount: + requestType = "Add Vesting Account" + + // parse vesting options + var vestingCoins string + dv := req.VestingAccount.VestingOptions.GetDelayedVesting() + if dv == nil { + vestingCoins = "unrecognized vesting option" + } else { + vestingCoins = fmt.Sprintf("%s (vesting: %s)", dv.TotalBalance, dv.Vesting) + } + + address, err := cosmosutil.ChangeAddressPrefix( + req.VestingAccount.Address, + addressPrefix, + ) + if err != nil { + return err + } + + content = fmt.Sprintf("%s, %s", + address, + vestingCoins, + ) + case *launchtypes.RequestContent_ValidatorRemoval: + requestType = "Remove Validator" + + address, err := cosmosutil.ChangeAddressPrefix( + req.ValidatorRemoval.ValAddress, + addressPrefix, + ) + if err != nil { + return err + } + + content = address + case *launchtypes.RequestContent_AccountRemoval: + requestType = "Remove Account" + + address, err := cosmosutil.ChangeAddressPrefix( + req.AccountRemoval.Address, + addressPrefix, + ) + if err != nil { + return err + } + + content = address + + case *launchtypes.RequestContent_ParamChange: + requestType = "Change Param" + content = fmt.Sprintf( + "module: %s param: %s, value: %s", + req.ParamChange.Module, + req.ParamChange.Param, + string(req.ParamChange.Value), + ) + } + + requestEntries = append(requestEntries, []string{ + id, + request.Status, + requestType, + content, + }) + } + return session.PrintTable(requestSummaryHeader, requestEntries...) +} diff --git a/network/cmd/network_request_reject.go b/network/cmd/network_request_reject.go new file mode 100644 index 00000000..845910d1 --- /dev/null +++ b/network/cmd/network_request_reject.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/numbers" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +// NewNetworkRequestReject creates a new request reject +// command to reject requests for a chain. +func NewNetworkRequestReject() *cobra.Command { + c := &cobra.Command{ + Use: "reject [launch-id] [number<,...>]", + Aliases: []string{"accept"}, + Short: "Reject requests", + Long: `The "reject" command is used by a chain's coordinator to reject requests. + + ignite network request reject 42 1,2,3-6,7,8 + +The syntax of the "reject" command is similar to that of the "approve" command. +`, + RunE: networkRequestRejectHandler, + Args: cobra.ExactArgs(2), + } + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkRequestRejectHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // Get the list of request ids + ids, err := numbers.ParseList(args[1]) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + // Submit the rejected requests + reviewals := make([]network.Reviewal, 0) + for _, id := range ids { + reviewals = append(reviewals, network.RejectRequest(id)) + } + if err := n.SubmitRequestReviewals(cmd.Context(), launchID, reviewals...); err != nil { + return err + } + + return session.Printf("%s Request(s) %s rejected\n", icons.OK, numbers.List(ids, "#")) +} diff --git a/network/cmd/network_request_remove_account.go b/network/cmd/network_request_remove_account.go new file mode 100644 index 00000000..b04bea9e --- /dev/null +++ b/network/cmd/network_request_remove_account.go @@ -0,0 +1,79 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cosmosutil" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networktypes" +) + +// NewNetworkRequestRemoveAccount creates a new command to send remove account request. +func NewNetworkRequestRemoveAccount() *cobra.Command { + c := &cobra.Command{ + Use: "remove-account [launch-id] [address]", + Short: "Send request to remove a genesis account", + RunE: networkRequestRemoveAccountHandler, + Args: cobra.ExactArgs(2), + } + + flagSetClearCache(c) + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkRequestRemoveAccountHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // get the address for the account and change the prefix for Ignite Chain + address, err := cosmosutil.ChangeAddressPrefix(args[1], networktypes.SPN) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + // create the remove account request + removeAccountRequest := launchtypes.NewAccountRemoval( + address, + ) + + // simulate the remove account request + if err := verifyRequestsFromRequestContents( + cmd.Context(), + cacheStorage, + nb, + launchID, + removeAccountRequest, + ); err != nil { + return err + } + + // send the request + return n.SendRequest(cmd.Context(), launchID, removeAccountRequest) +} diff --git a/network/cmd/network_request_remove_validator.go b/network/cmd/network_request_remove_validator.go new file mode 100644 index 00000000..4a1916d6 --- /dev/null +++ b/network/cmd/network_request_remove_validator.go @@ -0,0 +1,79 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cosmosutil" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networktypes" +) + +// NewNetworkRequestRemoveValidator creates a new command to send remove validator request. +func NewNetworkRequestRemoveValidator() *cobra.Command { + c := &cobra.Command{ + Use: "remove-validator [launch-id] [address]", + Short: "Send request to remove a validator", + RunE: networkRequestRemoveValidatorHandler, + Args: cobra.ExactArgs(2), + } + + flagSetClearCache(c) + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkRequestRemoveValidatorHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // get the address for the account and change the prefix for Ignite Chain + address, err := cosmosutil.ChangeAddressPrefix(args[1], networktypes.SPN) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + // create the remove validator request + removeValidatorRequest := launchtypes.NewValidatorRemoval( + address, + ) + + // simulate the remove validator request + if err := verifyRequestsFromRequestContents( + cmd.Context(), + cacheStorage, + nb, + launchID, + removeValidatorRequest, + ); err != nil { + return err + } + + // send the request + return n.SendRequest(cmd.Context(), launchID, removeValidatorRequest) +} diff --git a/network/cmd/network_request_show.go b/network/cmd/network_request_show.go new file mode 100644 index 00000000..cd4a9dd1 --- /dev/null +++ b/network/cmd/network_request_show.go @@ -0,0 +1,69 @@ +package cmd + +import ( + "strconv" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/yaml" + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +// NewNetworkRequestShow creates a new request show command to show +// requests details for a chain. +func NewNetworkRequestShow() *cobra.Command { + c := &cobra.Command{ + Use: "show [launch-id] [request-id]", + Short: "Show detailed information about a request", + RunE: networkRequestShowHandler, + Args: cobra.ExactArgs(2), + } + return c +} + +func networkRequestShowHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // parse request ID + requestID, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return errors.Wrap(err, "error parsing requestID") + } + + n, err := nb.Network() + if err != nil { + return err + } + + request, err := n.Request(cmd.Context(), launchID, requestID) + if err != nil { + return err + } + + // convert the request object to YAML to be more readable + // and convert the byte array fields to string. + requestYaml, err := yaml.Marshal(cmd.Context(), request, + "$.Content.content.genesisValidator.genTx", + "$.Content.content.genesisValidator.consPubKey", + "$.Content.content.paramChange.value", + ) + if err != nil { + return err + } + + return session.Println(requestYaml) +} diff --git a/network/cmd/network_request_verify.go b/network/cmd/network_request_verify.go new file mode 100644 index 00000000..088d347d --- /dev/null +++ b/network/cmd/network_request_verify.go @@ -0,0 +1,177 @@ +package cmd + +import ( + "context" + "os" + + "github.com/ignite/cli/v28/ignite/pkg/cache" + "github.com/ignite/cli/v28/ignite/pkg/chaincmd" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/numbers" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" + "github.com/ignite/apps/network/network/networkchain" + "github.com/ignite/apps/network/network/networktypes" +) + +// NewNetworkRequestVerify verify the request and simulate the chain. +func NewNetworkRequestVerify() *cobra.Command { + c := &cobra.Command{ + Use: "verify [launch-id] [number<,...>]", + Short: "Verify the request and simulate the chain genesis from them", + Long: `The "verify" command applies selected requests to the genesis of a chain locally +to verify that approving these requests will result in a valid genesis that +allows a chain to launch without issues. This command does not approve requests, +only checks them. +`, + RunE: networkRequestVerifyHandler, + Args: cobra.ExactArgs(2), + } + + flagSetClearCache(c) + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkRequestVerifyHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // get the list of request ids + ids, err := numbers.ParseList(args[1]) + if err != nil { + return err + } + + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + // verify the requests + if err := verifyRequests(cmd.Context(), cacheStorage, nb, launchID, ids...); err != nil { + session.Printf("%s Request(s) %s not valid\n", icons.NotOK, numbers.List(ids, "#")) + return err + } + + return session.Printf("%s Request(s) %s verified\n", icons.OK, numbers.List(ids, "#")) +} + +// verifyRequests initializes the chain from the launch ID in a temporary directory +// and simulate the launch of the chain from genesis with the request IDs. +func verifyRequests( + ctx context.Context, + cacheStorage cache.Storage, + nb NetworkBuilder, + launchID uint64, + requestIDs ...uint64, +) error { + // initialize the chain for simulation + c, n, genesisInformation, cleanup, err := initializeSimulationEnvironment(ctx, nb, launchID) + if err != nil { + return err + } + defer cleanup() + + // fetch the requests from the network + requests, err := n.RequestFromIDs(ctx, launchID, requestIDs...) + if err != nil { + return err + } + + return c.SimulateRequests( + ctx, + cacheStorage, + genesisInformation, + requests, + ) +} + +// verifyRequestsFromRequestContents initializes the chain from the launch ID in a temporary directory +// and simulate the launch of the chain from genesis with the request contents. +func verifyRequestsFromRequestContents( + ctx context.Context, + cacheStorage cache.Storage, + nb NetworkBuilder, + launchID uint64, + requestContents ...launchtypes.RequestContent, +) error { + // initialize the chain for simulation + c, _, genesisInformation, cleanup, err := initializeSimulationEnvironment(ctx, nb, launchID) + if err != nil { + return err + } + defer cleanup() + + return c.SimulateRequests( + ctx, + cacheStorage, + genesisInformation, + networktypes.RequestsFromRequestContents(launchID, requestContents), + ) +} + +// initializeSimulationEnvironment initializes the chain from the launch ID in a temporary directory for simulating requests. +func initializeSimulationEnvironment( + ctx context.Context, + nb NetworkBuilder, + launchID uint64, +) ( + c *networkchain.Chain, + n network.Network, + gi networktypes.GenesisInformation, + cleanup func(), + err error, +) { + n, err = nb.Network() + if err != nil { + return c, n, gi, cleanup, err + } + + // fetch the current genesis information and the requests for the chain for simulation + gi, err = n.GenesisInformation(ctx, launchID) + if err != nil { + return c, n, gi, cleanup, err + } + + // initialize the chain with a temporary dir + chainLaunch, err := n.ChainLaunch(ctx, launchID) + if err != nil { + return c, n, gi, cleanup, err + } + + homeDir, err := os.MkdirTemp("", "") + if err != nil { + return c, n, gi, cleanup, err + } + + // TODO avoid init chain two times with the prepare command + c, err = nb.Chain( + networkchain.SourceLaunch(chainLaunch), + networkchain.WithHome(homeDir), + networkchain.WithKeyringBackend(chaincmd.KeyringBackendTest), + ) + if err != nil { + os.RemoveAll(homeDir) + return c, n, gi, cleanup, err + } + + return c, n, gi, func() { os.RemoveAll(homeDir) }, nil +} diff --git a/network/cmd/network_reward.go b/network/cmd/network_reward.go new file mode 100644 index 00000000..ffada129 --- /dev/null +++ b/network/cmd/network_reward.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +// NewNetworkReward creates a new chain reward command. +func NewNetworkReward() *cobra.Command { + c := &cobra.Command{ + Use: "reward", + Short: "Manage network rewards", + Hidden: true, + } + c.AddCommand( + NewNetworkRewardSet(), + NewNetworkRewardRelease(), + ) + return c +} diff --git a/network/cmd/network_reward_release.go b/network/cmd/network_reward_release.go new file mode 100644 index 00000000..620abd52 --- /dev/null +++ b/network/cmd/network_reward_release.go @@ -0,0 +1,314 @@ +package cmd + +import ( + "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network/networktypes" +) + +const ( + flagTestnetFaucet = "testnet-faucet" + flagTestnetAddressPrefix = "testnet-prefix" + flagTestnetAccount = "testnet-account" + flagTestnetGasPrice = "testnet-gasprice" + flagTestnetGasLimit = "testnet-gaslimit" + flagSPNGasPrice = "spn-gasprice" + flagSPNGasLimit = "spn-gaslimit" + flagCreateClientOnly = "create-client-only" + + defaultTestnetGasPrice = "0.0000025stake" + defaultSPNGasPrice = "0.0000025" + networktypes.SPNDenom + defaultGasLimit = 400000 +) + +// NewNetworkRewardRelease connects the monitoring modules of launched +// chains with SPN and distribute rewards with chain Relayer. +func NewNetworkRewardRelease() *cobra.Command { + c := &cobra.Command{ + Use: "release [launch-id] [chain-rpc]", + Short: "Connect the monitoring modules of launched chains with SPN", + Args: cobra.ExactArgs(2), + RunE: networkRewardRelease, + } + + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().String(flagSPNGasPrice, defaultSPNGasPrice, "gas price used for transactions on SPN") + c.Flags().String(flagTestnetGasPrice, defaultTestnetGasPrice, "gas price used for transactions on testnet chain") + c.Flags().Int64(flagSPNGasLimit, defaultGasLimit, "gas limit used for transactions on SPN") + c.Flags().Int64(flagTestnetGasLimit, defaultGasLimit, "gas limit used for transactions on testnet chain") + c.Flags().String(flagTestnetAddressPrefix, cosmosaccount.AccountPrefixCosmos, "address prefix of the testnet chain") + c.Flags().String(flagTestnetAccount, cosmosaccount.DefaultAccount, "testnet chain account") + c.Flags().String(flagTestnetFaucet, "", "faucet address of the testnet chain") + c.Flags().Bool(flagCreateClientOnly, false, "only create the network client id") + + return c +} + +func networkRewardRelease(cmd *cobra.Command, args []string) (err error) { + return err +} + +/* +func networkRewardRelease(cmd *cobra.Command, args []string) (err error) { + defer func() { + var accountErr *cosmosaccount.AccountDoesNotExistError + if errors.As(err, &accountErr) { + err = errors.Wrap(accountErr, `make sure to create or import your account through "ignite account" commands`) + } + }() + + session := cliui.New(cliui.StartSpinnerWithText("Setting up chains...")) + defer session.End() + + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + chainRPC := xurl.HTTPEnsurePort(args[1]) + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + n, err := nb.Network() + if err != nil { + return err + } + spnChainID, err := n.ChainID(cmd.Context()) + if err != nil { + return err + } + + ca, err := cosmosaccount.New( + cosmosaccount.WithKeyringBackend(getKeyringBackend(cmd)), + ) + if err != nil { + return err + } + + if err := ca.EnsureDefaultAccount(); err != nil { + return err + } + + var ( + createClientOnly, _ = cmd.Flags().GetBool(flagCreateClientOnly) + spnGasPrice, _ = cmd.Flags().GetString(flagSPNGasPrice) + testnetGasPrice, _ = cmd.Flags().GetString(flagTestnetGasPrice) + spnGasLimit, _ = cmd.Flags().GetInt64(flagSPNGasLimit) + testnetGasLimit, _ = cmd.Flags().GetInt64(flagTestnetGasLimit) + // TODO fetch from genesis + testnetAddressPrefix, _ = cmd.Flags().GetString(flagTestnetAddressPrefix) + testnetAccount, _ = cmd.Flags().GetString(flagTestnetAccount) + testnetFaucet, _ = cmd.Flags().GetString(flagTestnetFaucet) + ) + + session.StartSpinner("Creating network relayer client ID...") + chain, spn, err := createClient(cmd, n, session, launchID, chainRPC, spnChainID) + if err != nil { + return err + } + if createClientOnly { + return nil + } + + session.StartSpinner("Fetching chain info...") + session.Println() + + spnAddresses, err := getSpnAddresses(cmd) + if err != nil { + return err + } + + r := relayer.New(ca) + // initialize the chains + spnChain, err := ignitecmd.InitChain( + cmd, + r, + session, + ignitecmd.RelayerSource, + getFrom(cmd), + spnAddresses.NodeAddress, + spnAddresses.FaucetAddress, + spnGasPrice, + spnGasLimit, + networktypes.SPN, + spn.ClientID, + ) + if err != nil { + return err + } + spnChain.ID = spn.ChainID + + testnetChain, err := ignitecmd.InitChain( + cmd, + r, + session, + ignitecmd.RelayerTarget, + testnetAccount, + chainRPC, + testnetFaucet, + testnetGasPrice, + testnetGasLimit, + testnetAddressPrefix, + chain.ClientID, + ) + if err != nil { + return err + } + testnetChain.ID = chain.ChainID + + session.StartSpinner("Creating links between chains...") + + pathID, cfg, err := spnRelayerConfig(*spnChain, *testnetChain, spn, chain) + if err != nil { + return err + } + if spn.ChannelID == "" { + cfg, err = r.Link(cmd.Context(), cfg, pathID) + if err != nil { + return err + } + } + + if err := printSection(session, "Paths"); err != nil { + return err + } + + session.StartSpinner("Loading...") + + path, err := cfg.PathByID(pathID) + if err != nil { + return err + } + + var buf bytes.Buffer + w := tabwriter.NewWriter(&buf, 0, 0, 1, ' ', tabwriter.TabIndent) + fmt.Fprintf(w, "%s:\n", path.ID) + fmt.Fprintf(w, " \t%s\t>\t(port: %s)\t(channel: %s)\n", path.Src.ChainID, path.Src.PortID, path.Src.ChannelID) + fmt.Fprintf(w, " \t%s\t>\t(port: %s)\t(channel: %s)\n", path.Dst.ChainID, path.Dst.PortID, path.Dst.ChannelID) + fmt.Fprintln(w) + w.Flush() + session.Print(buf.String()) + + if err := printSection(session, "Listening and relaying packets between chains..."); err != nil { + return err + } + + return r.Start(cmd.Context(), cfg, pathID, nil) +} + +func createClient( + cmd *cobra.Command, + n network.Network, + session *cliui.Session, + launchID uint64, + nodeAPI, + spnChainID string, +) (networktypes.RewardIBCInfo, networktypes.RewardIBCInfo, error) { + nodeClient, err := cosmosclient.New(cmd.Context(), cosmosclient.WithNodeAddress(nodeAPI)) + if err != nil { + return networktypes.RewardIBCInfo{}, networktypes.RewardIBCInfo{}, err + } + node := network.NewNode(nodeClient) + + chainRelayer, err := node.RewardIBCInfo(cmd.Context()) + if err != nil { + return networktypes.RewardIBCInfo{}, networktypes.RewardIBCInfo{}, err + } + + rewardsInfo, chainID, unboundingTime, err := node.RewardsInfo(cmd.Context()) + if err != nil { + return networktypes.RewardIBCInfo{}, networktypes.RewardIBCInfo{}, err + } + + spnRelayer, err := n.RewardIBCInfo(cmd.Context(), launchID) + if errors.Is(err, network.ErrObjectNotFound) { + spnRelayer.ClientID, err = n.CreateClient(cmd.Context(), launchID, unboundingTime, rewardsInfo) + } + if err != nil { + return networktypes.RewardIBCInfo{}, networktypes.RewardIBCInfo{}, err + } + + chainRelayer.ChainID = chainID + spnRelayer.ChainID = spnChainID + + session.Printf( + "%s Network client: %s\n", + icons.Info, + spnRelayer.ClientID, + ) + printRelayerOptions(session, spnRelayer.ConnectionID, spnRelayer.ChainID, "connection") + printRelayerOptions(session, spnRelayer.ChannelID, spnRelayer.ChainID, "channel") + + session.Printf( + "%s Testnet chain %s client: %s\n", + icons.Info, + chainRelayer.ChainID, + chainRelayer.ClientID, + ) + printRelayerOptions(session, chainRelayer.ConnectionID, chainRelayer.ChainID, "connection") + printRelayerOptions(session, chainRelayer.ChannelID, chainRelayer.ChainID, "channel") + return chainRelayer, spnRelayer, err +} + +func printRelayerOptions(session *cliui.Session, obj, chainID, option string) { + if obj != "" { + session.Printf("%s The chain %s already have a %s: %s\n", + icons.Bullet, + chainID, + option, + obj, + ) + } +} + +func spnRelayerConfig( + srcChain, + dstChain relayer.Chain, + srcChannel, + dstChannel networktypes.RewardIBCInfo, +) (string, relayerconf.Config, error) { + var ( + pathID = relayer.PathID(srcChain.ID, dstChain.ID) + conf = relayerconf.Config{ + Version: relayerconf.SupportVersion, + Chains: []relayerconf.Chain{srcChain.Config(), dstChain.Config()}, + Paths: []relayerconf.Path{ + { + ID: pathID, + Ordering: relayer.OrderingOrdered, + Src: relayerconf.PathEnd{ + ChainID: srcChain.ID, + PortID: networktypes.SPNPortID, + Version: networktypes.SPNVersion, + ConnectionID: srcChannel.ConnectionID, + ChannelID: srcChannel.ChannelID, + }, + Dst: relayerconf.PathEnd{ + ChainID: dstChain.ID, + PortID: networktypes.ChainPortID, + Version: networktypes.SPNVersion, + ConnectionID: dstChannel.ConnectionID, + ChannelID: dstChannel.ChannelID, + }, + }, + }, + } + ) + switch { + case srcChannel.ConnectionID != "" && + srcChannel.ChannelID != "" && + dstChannel.ConnectionID != "" && + dstChannel.ChannelID != "": + return pathID, conf, nil + case srcChannel.ConnectionID == "" && + srcChannel.ChannelID == "" && + dstChannel.ConnectionID == "" && + dstChannel.ChannelID == "": + return pathID, conf, nil + } + return pathID, conf, errors.New("connection was already established and is missing in one of the chains") +} +*/ diff --git a/network/cmd/network_reward_set.go b/network/cmd/network_reward_set.go new file mode 100644 index 00000000..0c476e85 --- /dev/null +++ b/network/cmd/network_reward_set.go @@ -0,0 +1,62 @@ +package cmd + +import ( + "fmt" + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/spf13/cobra" + + "github.com/ignite/apps/network/network" +) + +// NewNetworkRewardSet creates a new chain reward set command to +// add the chain reward to the network as a coordinator. +func NewNetworkRewardSet() *cobra.Command { + c := &cobra.Command{ + Use: "set [launch-id] [last-reward-height] [coins]", + Short: "set a network chain reward", + Args: cobra.ExactArgs(3), + RunE: networkChainRewardSetHandler, + } + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + return c +} + +func networkChainRewardSetHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + // parse launch ID + launchID, err := network.ParseID(args[0]) + if err != nil { + return err + } + + // parse the last reward height + lastRewardHeight, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + return err + } + + coins, err := sdk.ParseCoinsNormalized(args[2]) + if err != nil { + return fmt.Errorf("failed to parse coins: %w", err) + } + + n, err := nb.Network() + if err != nil { + return err + } + + return n.SetReward(cmd.Context(), launchID, lastRewardHeight, coins) +} diff --git a/network/cmd/network_tool.go b/network/cmd/network_tool.go new file mode 100644 index 00000000..6616ba64 --- /dev/null +++ b/network/cmd/network_tool.go @@ -0,0 +1,91 @@ +package cmd + +import ( + "fmt" + "time" + + "github.com/spf13/cobra" + "golang.org/x/sync/errgroup" + + "github.com/ignite/cli/v28/ignite/pkg/ctxticker" + "github.com/ignite/cli/v28/ignite/pkg/xchisel" + + "github.com/ignite/apps/network/network/networkchain" +) + +func NewNetworkTool() *cobra.Command { + c := &cobra.Command{ + Use: "tool [command]", + Short: "Commands to run subsidiary tools", + } + c.AddCommand(NewNetworkToolProxyTunnel()) + return c +} + +func NewNetworkToolProxyTunnel() *cobra.Command { + c := &cobra.Command{ + Use: "proxy-tunnel [config-file]", + Short: "Setup a proxy tunnel via HTTP", + Long: `Starts an HTTP proxy server and HTTP proxy clients for each node that +needs HTTP tunneling. + +HTTP tunneling is activated **ONLY** if SPN_CONFIG_FILE has "tunneled_peers" +field inside with a list of tunneled peers/nodes. + +If you're using SPN as coordinator and do not want to allow HTTP tunneling +feature at all, you can prevent "spn.yml" file to being generated by not +approving validator requests that has HTTP tunneling enabled instead of plain +TCP connections.`, + Args: cobra.ExactArgs(1), + RunE: networkToolProxyTunnelHandler, + } + return c +} + +const tunnelRerunDelay = 5 * time.Second + +func networkToolProxyTunnelHandler(cmd *cobra.Command, args []string) error { + spnConfig, err := networkchain.GetSPNConfig(args[0]) + if err != nil { + return fmt.Errorf("failed to open spn config file: %w", err) + } + // exit if there aren't tunneled validators in the network + if len(spnConfig.TunneledPeers) == 0 { + return nil + } + + g, ctx := errgroup.WithContext(cmd.Context()) + for _, peer := range spnConfig.TunneledPeers { + if peer.Name == networkchain.HTTPTunnelChisel { + peer := peer + g.Go(func() error { + return ctxticker.DoNow(ctx, tunnelRerunDelay, func() error { + fmt.Printf("Starting chisel client, tunnelAddress:%s, localPort:%s\n", peer.Address, peer.LocalPort) + err := xchisel.StartClient(ctx, peer.Address, peer.LocalPort, "26656") + if err != nil { + fmt.Printf( + "Failed to start chisel client, tunnelAddress:%s, localPort:%s, reason:%v\n", + peer.Address, peer.LocalPort, err, + ) + } + return nil + }) + }) + } + } + + g.Go(func() error { + return ctxticker.DoNow(ctx, tunnelRerunDelay, func() error { + fmt.Printf("Starting chisel server, port:%s\n", xchisel.DefaultServerPort) + err := xchisel.StartServer(ctx, xchisel.DefaultServerPort) + if err != nil { + fmt.Printf( + "Failed to start chisel server, port:%s, reason:%v\n", + xchisel.DefaultServerPort, err, + ) + } + return nil + }) + }) + return g.Wait() +} diff --git a/network/cmd/network_validator.go b/network/cmd/network_validator.go new file mode 100644 index 00000000..c02c8d0d --- /dev/null +++ b/network/cmd/network_validator.go @@ -0,0 +1,17 @@ +package cmd + +import "github.com/spf13/cobra" + +// NewNetworkValidator creates a new validator command +// it contains sub commands to manage validator profile. +func NewNetworkValidator() *cobra.Command { + c := &cobra.Command{ + Use: "validator", + Short: "Show and update a validator profile", + } + c.AddCommand( + NewNetworkValidatorShow(), + NewNetworkValidatorSet(), + ) + return c +} diff --git a/network/cmd/network_validator_set.go b/network/cmd/network_validator_set.go new file mode 100644 index 00000000..39e9413c --- /dev/null +++ b/network/cmd/network_validator_set.go @@ -0,0 +1,69 @@ +package cmd + +import ( + "errors" + + profiletypes "github.com/ignite/network/x/profile/types" + "github.com/spf13/cobra" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" +) + +// NewNetworkValidatorSet creates a command to set an information in a validator profile. +func NewNetworkValidatorSet() *cobra.Command { + c := &cobra.Command{ + Use: "set details|identity|website|security [value]", + Short: "Set an information in a validator profile", + Long: `Validators on Ignite can set a profile containing a description for the validator. +The validator set command allows to set information for the validator. +The following information can be set: +- details: general information about the validator. +- identity: piece of information to verify identity of the validator with a system like Keybase of Veramo. +- website: website of the validator. +- security: security contact for the validator. +`, + RunE: networkValidatorSetHandler, + Args: cobra.ExactArgs(2), + } + c.Flags().AddFlagSet(flagNetworkFrom()) + c.Flags().AddFlagSet(flagSetHome()) + c.Flags().AddFlagSet(flagSetKeyringBackend()) + c.Flags().AddFlagSet(flagSetKeyringDir()) + return c +} + +func networkValidatorSetHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + var validator profiletypes.Validator + switch args[0] { + case "details": + validator.Description.Details = args[1] + case "identity": + validator.Description.Identity = args[1] + case "website": + validator.Description.Website = args[1] + case "security": + validator.Description.SecurityContact = args[1] + default: + return errors.New("invalid attribute, must provide details, identity, website or security") + } + + if err := n.SetValidatorDescription(cmd.Context(), validator); err != nil { + return err + } + + return session.Printf("%s Validator updated \n", icons.OK) +} diff --git a/network/cmd/network_validator_show.go b/network/cmd/network_validator_show.go new file mode 100644 index 00000000..93d76705 --- /dev/null +++ b/network/cmd/network_validator_show.go @@ -0,0 +1,58 @@ +package cmd + +import ( + "github.com/spf13/cobra" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + "github.com/ignite/cli/v28/ignite/pkg/yaml" +) + +// NewNetworkValidatorShow creates a command to show validator information. +func NewNetworkValidatorShow() *cobra.Command { + c := &cobra.Command{ + Use: "show [address]", + Short: "Show a validator profile", + RunE: networkValidatorShowHandler, + Args: cobra.ExactArgs(1), + } + return c +} + +func networkValidatorShowHandler(cmd *cobra.Command, args []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) + if err != nil { + return err + } + + n, err := nb.Network() + if err != nil { + return err + } + + validator, err := n.Validator(cmd.Context(), args[0]) + if err != nil { + return err + } + + // convert the request object to YAML to be more readable + // and convert the byte array fields to string. + validatorYaml, err := yaml.Marshal(cmd.Context(), struct { + Identity string + Details string + Website string + Security string + }{ + validator.Identity, + validator.Details, + validator.Website, + validator.SecurityContact, + }) + if err != nil { + return err + } + + return session.Println(validatorYaml) +} diff --git a/network/cmd/network_version.go b/network/cmd/network_version.go new file mode 100644 index 00000000..1ab49549 --- /dev/null +++ b/network/cmd/network_version.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "github.com/spf13/cobra" + + "github.com/ignite/cli/v28/ignite/pkg/cliui" + + "github.com/ignite/apps/network/network/networktypes" +) + +// NewNetworkVersion creates a new version command to get the version of the plugin. +// The version of the plugin to use to interact with a chain might be specified by the coordinator. +func NewNetworkVersion() *cobra.Command { + c := &cobra.Command{ + Use: "version", + Short: "Version of the plugin", + Long: `The version of the plugin to use to interact with a chain might be specified by the coordinator. +`, + RunE: networkVersion, + Args: cobra.NoArgs, + } + return c +} + +func networkVersion(_ *cobra.Command, _ []string) error { + session := cliui.New(cliui.StartSpinner()) + defer session.End() + + return session.Printf("%s\n", networktypes.Version) +} diff --git a/network/go.mod b/network/go.mod new file mode 100644 index 00000000..cc212945 --- /dev/null +++ b/network/go.mod @@ -0,0 +1,263 @@ +module github.com/ignite/apps/network + +go 1.22.1 + +replace github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + +require ( + cosmossdk.io/math v1.3.0 + github.com/aws/smithy-go v1.22.0 + github.com/cenkalti/backoff v2.2.1+incompatible + github.com/cometbft/cometbft v0.38.12 + github.com/cosmos/cosmos-sdk v0.50.9 + github.com/cosmos/ibc-go/v8 v8.5.1 + github.com/go-git/go-git/v5 v5.12.0 + github.com/goccy/go-yaml v1.11.3 + github.com/hashicorp/go-plugin v1.6.2 + github.com/ignite/cli/v28 v28.5.3 + github.com/ignite/network v0.0.0-20241106044344-0a82c3e356fb + github.com/manifoldco/promptui v0.9.0 + github.com/pelletier/go-toml v1.9.5 + github.com/pkg/errors v0.9.1 + github.com/rdegges/go-ipify v0.0.0-20150526035502-2d94a6a86c40 + github.com/spf13/cobra v1.8.1 + github.com/spf13/pflag v1.0.5 + github.com/stretchr/testify v1.9.0 + golang.org/x/sync v0.8.0 + google.golang.org/grpc v1.66.0 + google.golang.org/protobuf v1.34.2 +) + +require ( + cosmossdk.io/api v0.7.5 // indirect + cosmossdk.io/collections v0.4.0 // indirect + cosmossdk.io/core v0.11.1 // indirect + cosmossdk.io/depinject v1.0.0 // indirect + cosmossdk.io/errors v1.0.1 // indirect + cosmossdk.io/log v1.4.1 // indirect + cosmossdk.io/store v1.1.1 // indirect + cosmossdk.io/x/evidence v0.1.1 // indirect + cosmossdk.io/x/feegrant v0.1.1 // indirect + cosmossdk.io/x/tx v0.13.4 // indirect + cosmossdk.io/x/upgrade v0.1.4 // indirect + dario.cat/mergo v1.0.0 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect + github.com/99designs/keyring v1.2.2 // indirect + github.com/AlecAivazis/survey/v2 v2.3.7 // indirect + github.com/DataDog/datadog-go v3.2.0+incompatible // indirect + github.com/DataDog/zstd v1.5.5 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v1.0.0 // indirect + github.com/andrew-d/go-termutil v0.0.0-20150726205930-009166a695a2 // indirect + github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/briandowns/spinner v1.23.0 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/buger/jsonparser v1.1.1 // indirect + github.com/bytedance/sonic v1.12.3 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/charmbracelet/lipgloss v0.6.0 // indirect + github.com/chzyer/readline v1.5.1 // indirect + github.com/cloudflare/circl v1.3.7 // indirect + github.com/cockroachdb/errors v1.11.3 // indirect + github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/pebble v1.1.1 // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect + github.com/cometbft/cometbft-db v0.11.0 // indirect + github.com/containerd/containerd v1.7.11 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/cosmos-db v1.0.2 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect + github.com/cosmos/go-bip39 v1.0.0 // indirect + github.com/cosmos/gogogateway v1.2.0 // indirect + github.com/cosmos/gogoproto v1.7.0 // indirect + github.com/cosmos/iavl v1.2.0 // indirect + github.com/cosmos/ibc-go/modules/capability v1.0.1 // indirect + github.com/cosmos/ics23/go v0.11.0 // indirect + github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect + github.com/creack/pty v1.1.18 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/danieljoos/wincred v1.2.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect + github.com/dgraph-io/badger/v2 v2.2007.4 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/docker/docker v27.1.1+incompatible // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/emicklei/dot v1.6.1 // indirect + github.com/emicklei/proto v1.12.2 // indirect + github.com/emicklei/proto-contrib v0.15.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/fatih/color v1.17.0 // indirect + github.com/fatih/structs v1.1.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/go-openapi/analysis v0.23.0 // indirect + github.com/go-openapi/errors v0.22.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/gobuffalo/flect v0.3.0 // indirect + github.com/gobuffalo/genny/v2 v2.1.0 // indirect + github.com/gobuffalo/github_flavored_markdown v1.1.4 // indirect + github.com/gobuffalo/helpers v0.6.7 // indirect + github.com/gobuffalo/logger v1.0.7 // indirect + github.com/gobuffalo/packd v1.0.2 // indirect + github.com/gobuffalo/plush/v4 v4.1.19 // indirect + github.com/gobuffalo/tags/v3 v3.1.4 // indirect + github.com/gobuffalo/validate/v3 v3.3.3 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect + github.com/gogo/googleapis v1.4.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/glog v1.2.1 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-github/v48 v48.2.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/css v1.0.0 // indirect + github.com/gorilla/handlers v1.5.2 // indirect + github.com/gorilla/mux v1.8.1 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.3 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect + github.com/hdevalence/ed25519consensus v0.1.0 // indirect + github.com/huandu/skiplist v1.2.0 // indirect + github.com/iancoleman/strcase v0.3.0 // indirect + github.com/ignite/modules v0.0.3-0.20241106034624-8a3f18117729 // indirect + github.com/ignite/web v0.6.1 // indirect + github.com/imdario/mergo v0.3.15 // indirect + github.com/improbable-eng/grpc-web v0.15.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/jpillora/ansi v1.0.3 // indirect + github.com/jpillora/backoff v1.0.0 // indirect + github.com/jpillora/chisel v1.9.1 // indirect + github.com/jpillora/requestlog v1.0.0 // indirect + github.com/jpillora/sizestr v1.0.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/linxGnu/grocksdb v1.8.14 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/microcosm-cc/bluemonday v1.0.23 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/moby v24.0.9+incompatible // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/user v0.1.0 // indirect + github.com/mtibben/percent v0.2.1 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nqd/flat v0.2.0 // indirect + github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect + github.com/oklog/run v1.1.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/onsi/gomega v1.34.2 // indirect + github.com/otiai10/copy v1.14.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.20.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/radovskyb/watcher v1.0.7 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/rs/zerolog v1.33.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect + github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/viper v1.19.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect + github.com/tendermint/go-amino v0.16.0 // indirect + github.com/tidwall/btree v1.7.0 // indirect + github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/zondax/hid v0.9.2 // indirect + github.com/zondax/ledger-go v0.14.3 // indirect + go.etcd.io/bbolt v1.3.10 // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.24.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gotest.tools/v3 v3.5.1 // indirect + nhooyr.io/websocket v1.8.6 // indirect + pgregory.net/rapid v1.1.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/network/go.sum b/network/go.sum new file mode 100644 index 00000000..705f819b --- /dev/null +++ b/network/go.sum @@ -0,0 +1,1345 @@ +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= +cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= +cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= +cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U= +cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= +cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= +cloud.google.com/go/compute v1.28.0 h1:OPtBxMcheSS+DWfci803qvPly3d4w7Eu5ztKBcFfzwk= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/iam v1.2.0 h1:kZKMKVNk/IsSSc/udOb83K0hL/Yh/Gcqpz+oAkoIFN8= +cloud.google.com/go/iam v1.2.0/go.mod h1:zITGuWgsLZxd8OwAlX+eMFgZDXzBm7icj1PVTYG766Q= +cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= +cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= +cosmossdk.io/api v0.7.5 h1:eMPTReoNmGUm8DeiQL9DyM8sYDjEhWzL1+nLbI9DqtQ= +cosmossdk.io/api v0.7.5/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= +cosmossdk.io/client/v2 v2.0.0-beta.4 h1:LGIzWbVTOof/IHQZeoWwxPX0fq607ONXhsfA7eUrQIg= +cosmossdk.io/client/v2 v2.0.0-beta.4/go.mod h1:c753d0sBv3AQRx6X+BOKL1aGpKjZMTZAHGiLPbVi5TE= +cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= +cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= +cosmossdk.io/core v0.11.1 h1:h9WfBey7NAiFfIcUhDVNS503I2P2HdZLebJlUIs8LPA= +cosmossdk.io/core v0.11.1/go.mod h1:OJzxcdC+RPrgGF8NJZR2uoQr56tc7gfBKhiKeDO7hH0= +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/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= +cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= +cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= +cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= +cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= +cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= +cosmossdk.io/store v1.1.1 h1:NA3PioJtWDVU7cHHeyvdva5J/ggyLDkyH0hGHl2804Y= +cosmossdk.io/store v1.1.1/go.mod h1:8DwVTz83/2PSI366FERGbWSH7hL6sB7HbYp8bqksNwM= +cosmossdk.io/x/circuit v0.1.1 h1:KPJCnLChWrxD4jLwUiuQaf5mFD/1m7Omyo7oooefBVQ= +cosmossdk.io/x/circuit v0.1.1/go.mod h1:B6f/urRuQH8gjt4eLIXfZJucrbreuYrKh5CSjaOxr+Q= +cosmossdk.io/x/evidence v0.1.1 h1:Ks+BLTa3uftFpElLTDp9L76t2b58htjVbSZ86aoK/E4= +cosmossdk.io/x/evidence v0.1.1/go.mod h1:OoDsWlbtuyqS70LY51aX8FBTvguQqvFrt78qL7UzeNc= +cosmossdk.io/x/feegrant v0.1.1 h1:EKFWOeo/pup0yF0svDisWWKAA9Zags6Zd0P3nRvVvw8= +cosmossdk.io/x/feegrant v0.1.1/go.mod h1:2GjVVxX6G2fta8LWj7pC/ytHjryA6MHAJroBWHFNiEQ= +cosmossdk.io/x/tx v0.13.4 h1:Eg0PbJgeO0gM8p5wx6xa0fKR7hIV6+8lC56UrsvSo0Y= +cosmossdk.io/x/tx v0.13.4/go.mod h1:BkFqrnGGgW50Y6cwTy+JvgAhiffbGEKW6KF9ufcDpvk= +cosmossdk.io/x/upgrade v0.1.4 h1:/BWJim24QHoXde8Bc64/2BSEB6W4eTydq0X/2f8+g38= +cosmossdk.io/x/upgrade v0.1.4/go.mod h1:9v0Aj+fs97O+Ztw+tG3/tp5JSlrmT7IcFhAebQHmOPo= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= +github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= +github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= +github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andrew-d/go-termutil v0.0.0-20150726205930-009166a695a2 h1:axBiC50cNZOs7ygH5BgQp4N+aYrZ2DNpWZ1KG3VOSOM= +github.com/andrew-d/go-termutil v0.0.0-20150726205930-009166a695a2/go.mod h1:jnzFpU88PccN/tPPhCpnNU8mZphvKxYM9lLNkd8e+os= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= +github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= +github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= +github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c= +github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= +github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= +github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/bufbuild/protocompile v0.14.0 h1:z3DW4IvXE5G/uTOnSQn+qwQQxvhckkTWLS/0No/o7KU= +github.com/bufbuild/protocompile v0.14.0/go.mod h1:N6J1NYzkspJo3ZwyL4Xjvli86XOj1xq4qAasUFxGups= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU= +github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY= +github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= +github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= +github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/cometbft/cometbft v0.38.12 h1:OWsLZN2KcSSFe8bet9xCn07VwhBnavPea3VyPnNq1bg= +github.com/cometbft/cometbft v0.38.12/go.mod h1:GPHp3/pehPqgX1930HmK1BpBLZPxB75v/dZg8Viwy+o= +github.com/cometbft/cometbft-db v0.11.0 h1:M3Lscmpogx5NTbb1EGyGDaFRdsoLWrUWimFEyf7jej8= +github.com/cometbft/cometbft-db v0.11.0/go.mod h1:GDPJAC/iFHNjmZZPN8V8C1yr/eyityhi2W1hz2MGKSc= +github.com/containerd/containerd v1.7.11 h1:lfGKw3eU35sjV0aG2eYZTiwFEY1pCzxdzicHP3SZILw= +github.com/containerd/containerd v1.7.11/go.mod h1:5UluHxHTX2rdvYuZ5OJTC5m/KJNs0Zs9wVoJm9zf5ZE= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= +github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= +github.com/cosmos/cosmos-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAKs= +github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= +github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= +github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= +github.com/cosmos/cosmos-sdk v0.50.9 h1:gt2usjz0H0qW6KwAxWw7ZJ3XU8uDwmhN+hYG3nTLeSg= +github.com/cosmos/cosmos-sdk v0.50.9/go.mod h1:TMH6wpoYBcg7Cp5BEg8fneLr+8XloNQkf2MRNF9V6JE= +github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= +github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= +github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= +github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= +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.2.0 h1:kVxTmjTh4k0Dh1VNL046v6BXqKziqMDzxo93oh3kOfM= +github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= +github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= +github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= +github.com/cosmos/ibc-go/v8 v8.5.1 h1:3JleEMKBjRKa3FeTKt4fjg22za/qygLBo7mDkoYTNBs= +github.com/cosmos/ibc-go/v8 v8.5.1/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo= +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= +github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= +github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= +github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/emicklei/dot v1.6.1 h1:ujpDlBkkwgWUY+qPId5IwapRW/xEoligRSYjioR6DFI= +github.com/emicklei/dot v1.6.1/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/emicklei/proto v1.12.2 h1:ZDyDzrfMt7ncmyor/j07uoOCGLKtU5F87vTPwIzLe/o= +github.com/emicklei/proto v1.12.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emicklei/proto-contrib v0.15.0 h1:5D8JKpV1qekMDFwEJp8NVJGY1We6t14dn9D4G05fpyo= +github.com/emicklei/proto-contrib v0.15.0/go.mod h1:p6zmoy14hFYiwUb35X7nJ4u4l1vfvjc1mWrIt8QB3kw= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +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/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= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI= +github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk= +github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE= +github.com/gobuffalo/genny/v2 v2.1.0 h1:cCRBbqzo3GfNvj3UetD16zRgUvWFEyyl0qTqquuIqOM= +github.com/gobuffalo/genny/v2 v2.1.0/go.mod h1:4yoTNk4bYuP3BMM6uQKYPvtP6WsXFGm2w2EFYZdRls8= +github.com/gobuffalo/github_flavored_markdown v1.1.3/go.mod h1:IzgO5xS6hqkDmUh91BW/+Qxo/qYnvfzoz3A7uLkg77I= +github.com/gobuffalo/github_flavored_markdown v1.1.4 h1:WacrEGPXUDX+BpU1GM/Y0ADgMzESKNWls9hOTG1MHVs= +github.com/gobuffalo/github_flavored_markdown v1.1.4/go.mod h1:Vl9686qrVVQou4GrHRK/KOG3jCZOKLUqV8MMOAYtlso= +github.com/gobuffalo/helpers v0.6.7 h1:C9CedoRSfgWg2ZoIkVXgjI5kgmSpL34Z3qdnzpfNVd8= +github.com/gobuffalo/helpers v0.6.7/go.mod h1:j0u1iC1VqlCaJEEVkZN8Ia3TEzfj/zoXANqyJExTMTA= +github.com/gobuffalo/logger v1.0.7 h1:LTLwWelETXDYyqF/ASf0nxaIcdEOIJNxRokPcfI/xbU= +github.com/gobuffalo/logger v1.0.7/go.mod h1:u40u6Bq3VVvaMcy5sRBclD8SXhBYPS0Qk95ubt+1xJM= +github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= +github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= +github.com/gobuffalo/plush/v4 v4.1.16/go.mod h1:6t7swVsarJ8qSLw1qyAH/KbrcSTwdun2ASEQkOznakg= +github.com/gobuffalo/plush/v4 v4.1.19 h1:o0E5gEJw+ozkAwQoCeiaWC6VOU2lEmX+GhtGkwpqZ8o= +github.com/gobuffalo/plush/v4 v4.1.19/go.mod h1:WiKHJx3qBvfaDVlrv8zT7NCd3dEMaVR/fVxW4wqV17M= +github.com/gobuffalo/tags/v3 v3.1.4 h1:X/ydLLPhgXV4h04Hp2xlbI2oc5MDaa7eub6zw8oHjsM= +github.com/gobuffalo/tags/v3 v3.1.4/go.mod h1:ArRNo3ErlHO8BtdA0REaZxijuWnWzF6PUXngmMXd2I0= +github.com/gobuffalo/validate/v3 v3.3.3 h1:o7wkIGSvZBYBd6ChQoLxkz2y1pfmhbI4jNJYh6PuNJ4= +github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= +github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +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.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +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= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +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= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github/v48 v48.2.0 h1:68puzySE6WqUY9KWmpOsDEQfDZsso98rT6pZcz9HqcE= +github.com/google/go-github/v48 v48.2.0/go.mod h1:dDlehKBDo850ZPvCTK0sEqTCVWcrGl2LcDiajkYi89Y= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= +github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.3 h1:QRje2j5GZimBzlbhGA2V2QlGNgL8G6e+wGo/+/2bWI0= +github.com/googleapis/enterprise-certificate-proxy v0.3.3/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4= +github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-metrics v0.5.3 h1:M5uADWMOGCTUNU1YuC4hfknOeHNaX54LDm4oYSucoNE= +github.com/hashicorp/go-metrics v0.5.3/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= +github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= +github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= +github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= +github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw= +github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ignite/cli/v28 v28.5.3 h1:UHB/Ds9Yw5Oqrh+WdS92z2PEoQuMDTid+M86cVpy6uQ= +github.com/ignite/cli/v28 v28.5.3/go.mod h1:TXv/JEkao4H0wrM8r3VHasIndPV9+yJLdDo4IYRbPis= +github.com/ignite/modules v0.0.3-0.20241106034624-8a3f18117729 h1:T3e1/0qilW8g8xIQYlhWdegT3txToTCcWNjnghrfma8= +github.com/ignite/modules v0.0.3-0.20241106034624-8a3f18117729/go.mod h1:Rmv2KTn5jfXL/qkKdaHD4ExJ1eaH1iVQDs+YD4eTV+o= +github.com/ignite/network v0.0.0-20241106044344-0a82c3e356fb h1:BVMdDc3z1ZNQVYNzvre1eCPlL54184rf85caEM1ZDZI= +github.com/ignite/network v0.0.0-20241106044344-0a82c3e356fb/go.mod h1:brUUj6kxI2xg5D5IWowRGCLtkHMqPPx+937wnoeqTDk= +github.com/ignite/web v0.6.1 h1:kHG+T7NnR8cCPjAGxEFQD+njVYM08toeG57iYRXzpwo= +github.com/ignite/web v0.6.1/go.mod h1:WZWBaBYF8RazN7dE462BLpvXDY8ScacxcJ07BKwX/jY= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= +github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= +github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jhump/protoreflect v1.15.3 h1:6SFRuqU45u9hIZPJAoZ8c28T3nK64BNdp9w6jFonzls= +github.com/jhump/protoreflect v1.15.3/go.mod h1:4ORHmSBmlCW8fh3xHmJMGyul1zNqZK4Elxc8qKP+p1k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/ansi v1.0.3 h1:nn4Jzti0EmRfDxm7JtEs5LzCbNwd5sv+0aE+LdS9/ZQ= +github.com/jpillora/ansi v1.0.3/go.mod h1:D2tT+6uzJvN1nBVQILYWkIdq7zG+b5gcFN5WI/VyjMY= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jpillora/chisel v1.9.1 h1:nGOF58+45WHlvDcq6AZu7En8nWOBCZHqj9boo5rB4qU= +github.com/jpillora/chisel v1.9.1/go.mod h1:qvgGfFR9ZhiDoYJM4IM1omX1HLbQSkZag8miP9u4SsQ= +github.com/jpillora/requestlog v1.0.0 h1:bg++eJ74T7DYL3DlIpiwknrtfdUA9oP/M4fL+PpqnyA= +github.com/jpillora/requestlog v1.0.0/go.mod h1:HTWQb7QfDc2jtHnWe2XEIEeJB7gJPnVdpNn52HXPvy8= +github.com/jpillora/sizestr v1.0.0 h1:4tr0FLxs1Mtq3TnsLDV+GYUWG7Q26a6s+tV5Zfw2ygw= +github.com/jpillora/sizestr v1.0.0/go.mod h1:bUhLv4ctkknatr6gR42qPxirmd5+ds1u7mzD+MZ33f0= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA= +github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/linxGnu/grocksdb v1.8.14 h1:HTgyYalNwBSG/1qCQUIott44wU5b2Y9Kr3z7SK5OfGQ= +github.com/linxGnu/grocksdb v1.8.14/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= +github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= +github.com/microcosm-cc/bluemonday v1.0.22/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/microcosm-cc/bluemonday v1.0.23 h1:SMZe2IGa0NuHvnVNAZ+6B38gsTbi5e4sViiWJyDDqFY= +github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/moby v24.0.9+incompatible h1:Z/hFbZJqC5Fmuf6jesMLdHU71CMAgdiSJ1ZYey+bFmg= +github.com/moby/moby v24.0.9+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs= +github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nqd/flat v0.2.0 h1:g6lXtMxsxrz6PZOO+rNnAJUn/GGRrK4FgVEhy/v+cHI= +github.com/nqd/flat v0.2.0/go.mod h1:FOuslZmNY082wVfVUUb7qAGWKl8z8Nor9FMg+Xj2Nss= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dlRvE5fWabOchtH7znfiFCcOvmIYgOeAS5ifBXBlh9Q= +github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= +github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= +github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= +github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= +github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 h1:jik8PHtAIsPlCRJjJzl4udgEf7hawInF9texMeO2jrU= +github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8= +github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE= +github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rdegges/go-ipify v0.0.0-20150526035502-2d94a6a86c40 h1:31Y7UZ1yTYBU4E79CE52I/1IRi3TqiuwquXGNtZDXWs= +github.com/rdegges/go-ipify v0.0.0-20150526035502-2d94a6a86c40/go.mod h1:j4c6zEU0eMG1oiZPUy+zD4ykX0NIpjZAEOEAviTWC18= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= +github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= +github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= +github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc= +github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= +github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= +github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= +golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +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.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk= +golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +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= +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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.196.0 h1:k/RafYqebaIJBO3+SMnfEGtFVlvp5vSgqTUF54UN/zg= +google.golang.org/api v0.196.0/go.mod h1:g9IL21uGkYgvQ5BZg6BAtoGJQIm8r6EgaAbpNey5wBE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU= +google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4= +google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0= +google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +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.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +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.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +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= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= +pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/network/main.go b/network/main.go new file mode 100644 index 00000000..4b3ff0a4 --- /dev/null +++ b/network/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "context" + "os" + + hplugin "github.com/hashicorp/go-plugin" + "github.com/ignite/cli/v28/ignite/services/plugin" + + "github.com/ignite/apps/network/cmd" +) + +type app struct{} + +func (app) Manifest(_ context.Context) (*plugin.Manifest, error) { + m := &plugin.Manifest{ + Name: "network", + } + m.ImportCobraCommand(cmd.NewNetwork(), "ignite") + return m, nil +} + +func (app) Execute(ctx context.Context, c *plugin.ExecutedCommand, api plugin.ClientAPI) error { + // Instead of a switch on c.Use, we run the root command like if + // we were in a command line context. This implies to set os.Args + // correctly. + // Remove the first arg "ignite" and "network" from OSArgs because our network + // command root is "network" not "ignite". + os.Args = c.OsArgs[1:] + return cmd.NewNetwork().Execute() +} + +func (app) ExecuteHookPre(_ context.Context, _ *plugin.ExecutedHook, _ plugin.ClientAPI) error { + return nil +} + +func (app) ExecuteHookPost(_ context.Context, _ *plugin.ExecutedHook, _ plugin.ClientAPI) error { + return nil +} + +func (app) ExecuteHookCleanUp(_ context.Context, _ *plugin.ExecutedHook, _ plugin.ClientAPI) error { + return nil +} + +func main() { + hplugin.Serve(&hplugin.ServeConfig{ + HandshakeConfig: plugin.HandshakeConfig(), + Plugins: map[string]hplugin.Plugin{ + "network": plugin.NewGRPC(&app{}), + }, + GRPCServer: hplugin.DefaultGRPCServer, + }) +} diff --git a/network/network/address/address.go b/network/network/address/address.go new file mode 100644 index 00000000..e1af83c8 --- /dev/null +++ b/network/network/address/address.go @@ -0,0 +1,28 @@ +package address + +import ( + "github.com/cosmos/cosmos-sdk/codec/address" + "github.com/cosmos/cosmos-sdk/types/bech32" + "github.com/ignite/cli/v28/ignite/pkg/errors" +) + +// ChangeValidatorAddressPrefix returns the address with another prefix from the validator address. +func ChangeValidatorAddressPrefix(addr, newPrefix string) (string, error) { + return ChangeAddressPrefix(addr, "cosmosvaloper", newPrefix) +} + +// ChangeAddressPrefix returns the address with another prefix. +func ChangeAddressPrefix(addr, prefix, newPrefix string) (string, error) { + if newPrefix == "" { + return "", errors.New("empty new prefix") + } + if prefix == "" { + return "", errors.New("empty prefix") + } + cdc := address.NewBech32Codec(prefix) + bAddr, err := cdc.StringToBytes(addr) + if err != nil { + return "", err + } + return bech32.ConvertAndEncode(newPrefix, bAddr) +} diff --git a/network/network/client.go b/network/network/client.go new file mode 100644 index 00000000..c8a7d252 --- /dev/null +++ b/network/network/client.go @@ -0,0 +1,98 @@ +package network + +import ( + "context" + "errors" + + monitoringctypes "github.com/ignite/network/x/monitoringc/types" + + "github.com/ignite/apps/network/network/networktypes" +) + +// CreateClient send create client message to SPN. +func (n Network) CreateClient( + ctx context.Context, + launchID uint64, + unbondingTime int64, + rewardsInfo networktypes.Reward, +) (string, error) { + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return "", err + } + + msgCreateClient := monitoringctypes.NewMsgCreateClient( + addr, + launchID, + rewardsInfo.ConsensusState, + rewardsInfo.ValidatorSet, + unbondingTime, + rewardsInfo.RevisionHeight, + ) + + res, err := n.cosmos.BroadcastTx(ctx, n.account, msgCreateClient) + if err != nil { + return "", err + } + + var createClientRes monitoringctypes.MsgCreateClientResponse + if err := res.Decode(&createClientRes); err != nil { + return "", err + } + return createClientRes.ClientId, nil +} + +// verifiedClientIDs fetches the verified client ids from SPN by launch id. +func (n Network) verifiedClientIDs(ctx context.Context, launchID uint64) ([]string, error) { + res, err := n.monitoringConsumerQuery.GetVerifiedClientID(ctx, + &monitoringctypes.QueryGetVerifiedClientIDRequest{ + LaunchId: launchID, + }, + ) + + if isNotFoundErr(err) { + return nil, ErrObjectNotFound + } else if err != nil { + return nil, err + } + return res.VerifiedClientId.ClientIdList, nil +} + +// RewardIBCInfo returns IBC info to relay packets for a chain to claim rewards. +func (n Network) RewardIBCInfo(ctx context.Context, launchID uint64) (networktypes.RewardIBCInfo, error) { + clientStates, err := n.verifiedClientIDs(ctx, launchID) + if err != nil { + return networktypes.RewardIBCInfo{}, err + } + if len(clientStates) == 0 { + return networktypes.RewardIBCInfo{}, ErrObjectNotFound + } + + clientID := clientStates[0] + + connections, err := n.node.clientConnections(ctx, clientID) + if err != nil && !errors.Is(err, ErrObjectNotFound) { + return networktypes.RewardIBCInfo{}, err + } + if errors.Is(err, ErrObjectNotFound) || len(connections) == 0 { + return networktypes.RewardIBCInfo{}, nil + } + + connectionID := connections[0] + + channels, err := n.node.connectionChannels(ctx, connectionID) + if err != nil && !errors.Is(err, ErrObjectNotFound) { + return networktypes.RewardIBCInfo{}, err + } + if errors.Is(err, ErrObjectNotFound) || len(connections) == 0 { + return networktypes.RewardIBCInfo{}, nil + } + + info := networktypes.RewardIBCInfo{ + ClientID: clientID, + ConnectionID: connectionID, + ChannelID: channels[0], + } + + return info, nil +} diff --git a/network/network/errors.go b/network/network/errors.go new file mode 100644 index 00000000..bce9dd60 --- /dev/null +++ b/network/network/errors.go @@ -0,0 +1,24 @@ +package network + +import ( + "strings" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func isNotFoundErr(err error) bool { + s, ok := status.FromError(err) + if ok { + switch s.Code() { + case codes.NotFound: + return true + case codes.Unknown: + if strings.Contains(s.Message(), "not found") { + return true + } + return false + } + } + return false +} diff --git a/network/network/gentx/gentx.go b/network/network/gentx/gentx.go new file mode 100644 index 00000000..a29144a5 --- /dev/null +++ b/network/network/gentx/gentx.go @@ -0,0 +1,92 @@ +package gentx + +import ( + "encoding/base64" + "encoding/json" + "os" + + sdkmath "cosmossdk.io/math" + "github.com/cometbft/cometbft/crypto/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/errors" +) + +type ( + // GentxInfo represents the basic info about gentx file. + GentxInfo struct { + ValidatorAddress string + PubKey ed25519.PubKey + SelfDelegation sdk.Coin + Memo string + } + + // Gentx represents the gentx file. + Gentx struct { + Body struct { + Messages []struct { + ValidatorAddress string `json:"validator_address"` + PubKey struct { + Type string `json:"@type"` + Key string `json:"key"` + } `json:"pubkey"` + Value struct { + Denom string `json:"denom"` + Amount string `json:"amount"` + } `json:"value"` + } `json:"messages"` + Memo string `json:"memo"` + } `json:"body"` + } +) + +// GentxFromPath returns GentxInfo from the json file. +func GentxFromPath(path string) (info GentxInfo, gentx []byte, err error) { + if _, err := os.Stat(path); os.IsNotExist(err) { + return info, gentx, errors.New("chain home folder is not initialized yet: " + path) + } + + gentx, err = os.ReadFile(path) + if err != nil { + return info, gentx, err + } + + info, err = ParseGentx(gentx) + return info, gentx, err +} + +// ParseGentx returns GentxInfo and the gentx file in bytes. +func ParseGentx(gentxBz []byte) (info GentxInfo, err error) { + // Try parsing gentx + var gentx Gentx + if err := json.Unmarshal(gentxBz, &gentx); err != nil { + return info, errors.Errorf("unmarshal gentx: %w", err) + } + if gentx.Body.Messages == nil { + return info, errors.New("the gentx cannot be parsed") + } + + if len(gentx.Body.Messages) != 1 { + return info, errors.New("add validator gentx must contain 1 message") + } + + info.Memo = gentx.Body.Memo + info.ValidatorAddress = gentx.Body.Messages[0].ValidatorAddress + + pb := gentx.Body.Messages[0].PubKey.Key + info.PubKey, err = base64.StdEncoding.DecodeString(pb) + if err != nil { + return info, errors.Errorf("invalid validator public key %w", err) + } + + amount, ok := sdkmath.NewIntFromString(gentx.Body.Messages[0].Value.Amount) + if !ok { + return info, errors.New("the self-delegation inside the gentx is invalid") + } + + info.SelfDelegation = sdk.NewCoin( + gentx.Body.Messages[0].Value.Denom, + amount, + ) + + return info, nil +} diff --git a/network/network/gentx/gentx_test.go b/network/network/gentx/gentx_test.go new file mode 100644 index 00000000..41595b6d --- /dev/null +++ b/network/network/gentx/gentx_test.go @@ -0,0 +1,70 @@ +package gentx + +import ( + "encoding/base64" + "testing" + + sdkmath "cosmossdk.io/math" + "github.com/cometbft/cometbft/crypto/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestParseGentx(t *testing.T) { + pk1, err := base64.StdEncoding.DecodeString("aeQLCJOjXUyB7evOodI4mbrshIt3vhHGlycJDbUkaMs=") + require.NoError(t, err) + pk2, err := base64.StdEncoding.DecodeString("OL+EIoo7DwyaBFDbPbgAhwS5rvgIqoUa0x8qWqzfQVQ=") + require.NoError(t, err) + + tests := []struct { + name string + gentxPath string + wantInfo GentxInfo + wantErr bool + }{ + { + name: "parse gentx file 1", + gentxPath: "testdata/gentx1.json", + wantInfo: GentxInfo{ + ValidatorAddress: "cosmosvaloper1dd246yq6z5vzjz9gh8cff46pll75yyl8pu8cup", + PubKey: ed25519.PubKey(pk1), + SelfDelegation: sdk.Coin{ + Denom: "stake", + Amount: sdkmath.NewInt(95000000), + }, + Memo: "9b1f4adbfb0c0b513040d914bfb717303c0eaa71@192.168.0.148:26656", + }, + }, { + name: "parse gentx file 2", + gentxPath: "testdata/gentx2.json", + wantInfo: GentxInfo{ + ValidatorAddress: "cosmosvaloper1mmlqwyqk7neqegffp99q86eckpm4pjah5sl2dw", + PubKey: ed25519.PubKey(pk2), + SelfDelegation: sdk.Coin{ + Denom: "stake", + Amount: sdkmath.NewInt(95000000), + }, + Memo: "a412c917cb29f73cc3ad0592bbd0152fe0e690bd@192.168.0.148:26656", + }, + }, { + name: "parse invalid file", + gentxPath: "testdata/gentx_invalid.json", + wantErr: true, + }, { + name: "not found file", + gentxPath: "testdata/gentx_not_found.json", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotInfo, _, err := GentxFromPath(tt.gentxPath) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.Equal(t, tt.wantInfo, gotInfo) + }) + } +} diff --git a/network/network/gentx/testdata/gentx1.json b/network/network/gentx/testdata/gentx1.json new file mode 100644 index 00000000..3b4aecde --- /dev/null +++ b/network/network/gentx/testdata/gentx1.json @@ -0,0 +1,61 @@ +{ + "auth_info": { + "fee": { + "amount": [], + "gas_limit": "200000", + "granter": "", + "payer": "" + }, + "signer_infos": [ + { + "mode_info": { + "single": { + "mode": "SIGN_MODE_DIRECT" + } + }, + "public_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "AhLlX8QQEymFlvdKrb0xfYGHt7GTK8KiExAThDHQKSe4" + }, + "sequence": "0" + } + ] + }, + "body": { + "extension_options": [], + "memo": "9b1f4adbfb0c0b513040d914bfb717303c0eaa71@192.168.0.148:26656", + "messages": [ + { + "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", + "commission": { + "max_change_rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "rate": "0.100000000000000000" + }, + "delegator_address": "cosmos1dd246yq6z5vzjz9gh8cff46pll75yyl8ygndsj", + "description": { + "details": "", + "identity": "", + "moniker": "default", + "security_contact": "", + "website": "" + }, + "min_self_delegation": "1", + "pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "aeQLCJOjXUyB7evOodI4mbrshIt3vhHGlycJDbUkaMs=" + }, + "validator_address": "cosmosvaloper1dd246yq6z5vzjz9gh8cff46pll75yyl8pu8cup", + "value": { + "amount": "95000000", + "denom": "stake" + } + } + ], + "non_critical_extension_options": [], + "timeout_height": "0" + }, + "signatures": [ + "sz0uixBOHJoZbvVrz670vLBRQ5Z2wnhHeNRxKJPz5dADKfz34/sg7FQv6nCeEomODMrgjUD70YBeguKIqxjcLw==" + ] +} \ No newline at end of file diff --git a/network/network/gentx/testdata/gentx2.json b/network/network/gentx/testdata/gentx2.json new file mode 100644 index 00000000..24357d5a --- /dev/null +++ b/network/network/gentx/testdata/gentx2.json @@ -0,0 +1,66 @@ +{ + "auth_info": { + "fee": { + "amount": [ + { + "amount": "5000", + "denom": "stake" + } + ], + "gas_limit": "200000", + "granter": "", + "payer": "" + }, + "signer_infos": [ + { + "mode_info": { + "single": { + "mode": "SIGN_MODE_DIRECT" + } + }, + "public_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "AslH/zmmjEHI/jWup3tC/TfG4eRiD959tyE9z98xt/oO" + }, + "sequence": "0" + } + ] + }, + "body": { + "extension_options": [], + "memo": "a412c917cb29f73cc3ad0592bbd0152fe0e690bd@192.168.0.148:26656", + "messages": [ + { + "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", + "commission": { + "max_change_rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "rate": "0.100000000000000000" + }, + "delegator_address": "", + "description": { + "details": "", + "identity": "", + "moniker": "alice", + "security_contact": "", + "website": "" + }, + "min_self_delegation": "1", + "pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "OL+EIoo7DwyaBFDbPbgAhwS5rvgIqoUa0x8qWqzfQVQ=" + }, + "validator_address": "cosmosvaloper1mmlqwyqk7neqegffp99q86eckpm4pjah5sl2dw", + "value": { + "amount": "95000000", + "denom": "stake" + } + } + ], + "non_critical_extension_options": [], + "timeout_height": "0" + }, + "signatures": [ + "XDwkcX6QNRDL7FYD/UCNXmwVZHR7tCVyTh+VKAC8KJESZyCEo4/Uo9HGRX2pWGX0nrn/v5h2HKzHxXc/41rDag==" + ] +} \ No newline at end of file diff --git a/network/network/gentx/testdata/gentx_invalid.json b/network/network/gentx/testdata/gentx_invalid.json new file mode 100644 index 00000000..e3153028 --- /dev/null +++ b/network/network/gentx/testdata/gentx_invalid.json @@ -0,0 +1,6 @@ +{ + "amount": [], + "gas_limit": "200000", + "granter": "", + "payer": "" +} \ No newline at end of file diff --git a/network/network/join.go b/network/network/join.go new file mode 100644 index 00000000..dac2d262 --- /dev/null +++ b/network/network/join.go @@ -0,0 +1,103 @@ +package network + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/xurl" + launchtypes "github.com/ignite/network/x/launch/types" + + "github.com/ignite/apps/network/network/address" + "github.com/ignite/apps/network/network/gentx" + "github.com/ignite/apps/network/network/networkchain" + "github.com/ignite/apps/network/network/networktypes" +) + +type joinOptions struct { + accountAmount sdk.Coins + publicAddress string +} + +type JoinOption func(*joinOptions) + +// WithAccountRequest allows to join the chain by requesting a genesis account with the specified amount of tokens. +func WithAccountRequest(amount sdk.Coins) JoinOption { + return func(o *joinOptions) { + o.accountAmount = amount + } +} + +// WithPublicAddress allows to specify a peer public address for the node. +func WithPublicAddress(addr string) JoinOption { + return func(o *joinOptions) { + o.publicAddress = addr + } +} + +// GetJoinRequestContents returns the request contents to join a chain as a validator. +func (n Network) GetJoinRequestContents( + ctx context.Context, + c Chain, + launchID uint64, + gentxPath string, + options ...JoinOption, +) (reqs []launchtypes.RequestContent, err error) { + o := joinOptions{} + for _, apply := range options { + apply(&o) + } + + var ( + nodeID string + peer launchtypes.Peer + ) + + // parse the gentx content + gentxInfo, gentx, err := gentx.GentxFromPath(gentxPath) + if err != nil { + return reqs, err + } + + // get the peer address + if o.publicAddress != "" { + if nodeID, err = c.NodeID(ctx); err != nil { + return reqs, err + } + + if xurl.IsHTTP(o.publicAddress) { + peer = launchtypes.NewPeerTunnel(nodeID, networkchain.HTTPTunnelChisel, o.publicAddress) + } else { + peer = launchtypes.NewPeerConn(nodeID, o.publicAddress) + } + } else { + // if the peer address is not specified, we parse it from the gentx memo + if peer, err = ParsePeerAddress(gentxInfo.Memo); err != nil { + return reqs, err + } + } + + // change the chain address prefix to spn + accountAddress, err := address.ChangeValidatorAddressPrefix(gentxInfo.ValidatorAddress, networktypes.SPN) + if err != nil { + return reqs, err + } + + if !o.accountAmount.IsZero() { + reqs = append(reqs, launchtypes.NewGenesisAccount( + launchID, + accountAddress, + o.accountAmount, + )) + } + + reqs = append(reqs, launchtypes.NewGenesisValidator( + launchID, + accountAddress, + gentx, + gentxInfo.PubKey, + gentxInfo.SelfDelegation, + peer, + )) + + return reqs, nil +} diff --git a/network/network/join_test.go b/network/network/join_test.go new file mode 100644 index 00000000..18b00e42 --- /dev/null +++ b/network/network/join_test.go @@ -0,0 +1,213 @@ +package network + +import ( + "context" + "errors" + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/address" + "github.com/ignite/apps/network/network/networktypes" + "github.com/ignite/apps/network/network/testutil" +) + +const ( + TestDenom = "stake" + TestAmountString = "95000000" + TestAmountInt = int64(95000000) + TestAccountRequestID = uint64(1) + TestGenesisValidatorRequestID = uint64(2) +) + +func TestJoin(t *testing.T) { + t.Run("successfully get join request with custom public address", func(t *testing.T) { + account := testutil.NewTestAccount(t, testutil.TestAccountName) + tmp := t.TempDir() + valAddr, err := account.Address("cosmosvaloper") + require.NoError(t, err) + gentx := testutil.NewGentx( + valAddr, + TestDenom, + TestAmountString, + "", + testutil.PeerAddress, + ) + gentxPath := gentx.SaveTo(t, tmp) + suite, network := newSuite(account) + + addr, err := address.ChangeValidatorAddressPrefix(valAddr, networktypes.SPN) + require.NoError(t, err) + + expectedReqs := []launchtypes.RequestContent{ + launchtypes.NewGenesisValidator( + testutil.LaunchID, + addr, + gentx.JSON(t), + []byte{}, + sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), + launchtypes.Peer{ + Id: testutil.NodeID, + Connection: &launchtypes.Peer_TcpAddress{ + TcpAddress: testutil.TCPAddress, + }, + }, + ), + } + + suite.ChainMock.On("NodeID", context.Background()).Return(testutil.NodeID, nil).Once() + reqs, err := network.GetJoinRequestContents( + context.Background(), + suite.ChainMock, + testutil.LaunchID, + gentxPath, + WithPublicAddress(testutil.TCPAddress), + ) + require.NoError(t, err) + require.ElementsMatch(t, expectedReqs, reqs) + }) + + t.Run("successfully get join request with public address read from the gentx", func(t *testing.T) { + account := testutil.NewTestAccount(t, testutil.TestAccountName) + tmp := t.TempDir() + valAddr, err := account.Address("cosmosvaloper") + require.NoError(t, err) + gentx := testutil.NewGentx( + valAddr, + TestDenom, + TestAmountString, + "", + testutil.PeerAddress, + ) + gentxPath := gentx.SaveTo(t, tmp) + suite, network := newSuite(account) + + addr, err := address.ChangeValidatorAddressPrefix(valAddr, networktypes.SPN) + require.NoError(t, err) + + expectedReqs := []launchtypes.RequestContent{ + launchtypes.NewGenesisValidator( + testutil.LaunchID, + addr, + gentx.JSON(t), + []byte{}, + sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), + launchtypes.Peer{ + Id: testutil.NodeID, + Connection: &launchtypes.Peer_TcpAddress{ + TcpAddress: testutil.TCPAddress, + }, + }, + ), + } + + reqs, err := network.GetJoinRequestContents( + context.Background(), + suite.ChainMock, + testutil.LaunchID, + gentxPath, + ) + require.NoError(t, err) + require.ElementsMatch(t, expectedReqs, reqs) + }) + + t.Run("successfully get join request with account request", func(t *testing.T) { + account := testutil.NewTestAccount(t, testutil.TestAccountName) + tmp := t.TempDir() + valAddr, err := account.Address("cosmosvaloper") + require.NoError(t, err) + gentx := testutil.NewGentx( + valAddr, + TestDenom, + TestAmountString, + "", + testutil.PeerAddress, + ) + gentxPath := gentx.SaveTo(t, tmp) + suite, network := newSuite(account) + + addr, err := address.ChangeValidatorAddressPrefix(valAddr, networktypes.SPN) + require.NoError(t, err) + + expectedReqs := []launchtypes.RequestContent{ + launchtypes.NewGenesisValidator( + testutil.LaunchID, + addr, + gentx.JSON(t), + []byte{}, + sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)), + launchtypes.Peer{ + Id: testutil.NodeID, + Connection: &launchtypes.Peer_TcpAddress{ + TcpAddress: testutil.TCPAddress, + }, + }, + ), + launchtypes.NewGenesisAccount( + testutil.LaunchID, + addr, + sdk.NewCoins(sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt))), + ), + } + + suite.ChainMock.On("NodeID", context.Background()).Return(testutil.NodeID, nil).Once() + reqs, err := network.GetJoinRequestContents( + context.Background(), + suite.ChainMock, + testutil.LaunchID, + gentxPath, + WithAccountRequest(sdk.NewCoins(sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt)))), + WithPublicAddress(testutil.TCPAddress), + ) + require.NoError(t, err) + require.ElementsMatch(t, expectedReqs, reqs) + }) + + t.Run("failed to get join request, failed to read node id", func(t *testing.T) { + account := testutil.NewTestAccount(t, testutil.TestAccountName) + tmp := t.TempDir() + valAddr, err := account.Address("cosmosvaloper") + require.NoError(t, err) + gentx := testutil.NewGentx( + valAddr, + TestDenom, + TestAmountString, + "", + testutil.PeerAddress, + ) + gentxPath := gentx.SaveTo(t, tmp) + suite, network := newSuite(account) + expectedError := errors.New("failed to get node id") + + suite.ChainMock. + On("NodeID", mock.Anything). + Return("", expectedError). + Once() + + _, err = network.GetJoinRequestContents( + context.Background(), + suite.ChainMock, + testutil.LaunchID, + gentxPath, + WithPublicAddress(testutil.TCPAddress), + ) + require.ErrorIs(t, err, expectedError) + suite.AssertAllMocks(t) + }) + + t.Run("failed to get join request, failed to read gentx", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + gentxPath = "invalid/path" + suite, network = newSuite(account) + ) + + _, err := network.GetJoinRequestContents(context.Background(), suite.ChainMock, testutil.LaunchID, gentxPath) + require.Error(t, err) + suite.AssertAllMocks(t) + }) +} diff --git a/network/network/launch.go b/network/network/launch.go new file mode 100644 index 00000000..c9477404 --- /dev/null +++ b/network/network/launch.go @@ -0,0 +1,101 @@ +package network + +import ( + "context" + "fmt" + "time" + + "github.com/ignite/cli/v28/ignite/pkg/events" + launchtypes "github.com/ignite/network/x/launch/types" + + "github.com/ignite/apps/network/network/networktypes" +) + +// MinLaunchTimeOffset represents an offset used when minimum launch time is used +// minimum launch time will be block time + minimum launch time duration param +// block time when tx is executed is not predicable, therefore we add few seconds +// to ensure the minimum duration is reached. +const MinLaunchTimeOffset = time.Second * 30 + +// LaunchParams fetches the chain launch module params from SPN. +func (n Network) LaunchParams(ctx context.Context) (launchtypes.Params, error) { + res, err := n.launchQuery.Params(ctx, &launchtypes.QueryParamsRequest{}) + if err != nil { + return launchtypes.Params{}, err + } + return res.GetParams(), nil +} + +// TriggerLaunch launches a chain as a coordinator. +func (n Network) TriggerLaunch(ctx context.Context, launchID uint64, launchTime time.Time) error { + n.ev.Send(fmt.Sprintf("Launching chain %d", launchID), events.ProgressStart()) + params, err := n.LaunchParams(ctx) + if err != nil { + return err + } + + var ( + minLaunchTime = n.clock.Now().Add(params.LaunchTimeRange.MinLaunchTime).Add(MinLaunchTimeOffset) + maxLaunchTime = n.clock.Now().Add(params.LaunchTimeRange.MaxLaunchTime) + ) + address, err := n.account.Address(networktypes.SPN) + if err != nil { + return err + } + + if launchTime.IsZero() { + // Use minimum launch time by default + launchTime = minLaunchTime + } else { + // check launch time is in range + switch { + case launchTime.Before(minLaunchTime): + return fmt.Errorf("launch time %s lower than minimum %s", launchTime, minLaunchTime) + case launchTime.After(maxLaunchTime): + return fmt.Errorf("launch time %s bigger than maximum %s", launchTime, maxLaunchTime) + } + } + + launchDuration := launchTime.Sub(n.clock.Now()) + msg := launchtypes.NewMsgTriggerLaunch(address, launchID, launchDuration) + n.ev.Send("Setting launch time", events.ProgressUpdate()) + res, err := n.cosmos.BroadcastTx(ctx, n.account, msg) + if err != nil { + return err + } + + var launchRes launchtypes.MsgTriggerLaunchResponse + if err := res.Decode(&launchRes); err != nil { + return err + } + + n.ev.Send( + fmt.Sprintf("Chain %d will be launched on %s", launchID, launchTime), + events.ProgressFinish(), + ) + return nil +} + +// RevertLaunch reverts a launched chain as a coordinator. +func (n Network) RevertLaunch(ctx context.Context, launchID uint64) error { + n.ev.Send(fmt.Sprintf("Reverting launched chain %d", launchID), events.ProgressStart()) + + address, err := n.account.Address(networktypes.SPN) + if err != nil { + return err + } + + msg := launchtypes.NewMsgRevertLaunch(address, launchID) + _, err = n.cosmos.BroadcastTx(ctx, n.account, msg) + if err != nil { + return err + } + + n.ev.Send( + fmt.Sprintf("Chain %d launch was reverted", launchID), + events.ProgressFinish(), + ) + + n.ev.Send("Genesis time was reset", events.ProgressFinish()) + return nil +} diff --git a/network/network/launch_test.go b/network/network/launch_test.go new file mode 100644 index 00000000..6a132118 --- /dev/null +++ b/network/network/launch_test.go @@ -0,0 +1,293 @@ +package network + +import ( + "context" + "errors" + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networktypes" + "github.com/ignite/apps/network/network/testutil" +) + +const ( + TestMinRemainingTime = time.Second * 3600 + TestMaxRemainingTime = time.Second * 86400 + TestRevertDelay = time.Second * 3600 + TestMaxMetadataLength uint64 = 2000 +) + +func TestTriggerLaunch(t *testing.T) { + t.Run("successfully launch a chain", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.LaunchQueryMock. + On("Params", context.Background(), &launchtypes.QueryParamsRequest{}). + Return(&launchtypes.QueryParamsResponse{ + Params: launchtypes.NewParams( + TestMinRemainingTime, + TestMaxRemainingTime, + TestRevertDelay, + sdk.Coins(nil), + sdk.Coins(nil), + TestMaxMetadataLength, + ), + }, nil). + Once() + suite.CosmosClientMock. + On("BroadcastTx", + context.Background(), + account, + &launchtypes.MsgTriggerLaunch{ + Coordinator: addr, + LaunchId: testutil.LaunchID, + LaunchTime: TestMaxRemainingTime, + }). + Return(testutil.NewResponse(&launchtypes.MsgTriggerLaunchResponse{}), nil). + Once() + + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, sampleTime.Add(TestMaxRemainingTime)) + require.NoError(t, launchError) + suite.AssertAllMocks(t) + }) + + t.Run("failed to launch a chain, remaining time is lower than allowed", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + remainingTimeLowerThanMinimum = sampleTime + ) + + suite.LaunchQueryMock. + On("Params", context.Background(), &launchtypes.QueryParamsRequest{}). + Return(&launchtypes.QueryParamsResponse{ + Params: launchtypes.NewParams( + TestMinRemainingTime, + TestMaxRemainingTime, + TestRevertDelay, + sdk.Coins(nil), + sdk.Coins(nil), + TestMaxMetadataLength, + ), + }, nil). + Once() + + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, remainingTimeLowerThanMinimum) + require.Errorf( + t, + launchError, + "remaining time %s lower than minimum %s", + remainingTimeLowerThanMinimum.String(), + sampleTime.Add(TestMinRemainingTime).Add(MinLaunchTimeOffset).String(), + ) + suite.AssertAllMocks(t) + }) + + t.Run("failed to launch a chain, remaining time is greater than allowed", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + remainingTimeGreaterThanMaximum = sampleTime.Add(TestMaxRemainingTime).Add(time.Second) + ) + + suite.LaunchQueryMock. + On("Params", context.Background(), &launchtypes.QueryParamsRequest{}). + Return(&launchtypes.QueryParamsResponse{ + Params: launchtypes.NewParams( + TestMinRemainingTime, + TestMaxRemainingTime, + TestRevertDelay, + sdk.Coins(nil), + sdk.Coins(nil), + TestMaxMetadataLength, + ), + }, nil). + Once() + + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, remainingTimeGreaterThanMaximum) + require.Errorf( + t, + launchError, + "remaining time %s greater than maximum %s", + remainingTimeGreaterThanMaximum.String(), + sampleTime.Add(TestMaxRemainingTime).String(), + ) + suite.AssertAllMocks(t) + }) + + t.Run("failed to launch a chain, failed to broadcast the launch tx", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + expectedError = errors.New("Failed to fetch") + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.LaunchQueryMock. + On("Params", context.Background(), &launchtypes.QueryParamsRequest{}). + Return(&launchtypes.QueryParamsResponse{ + Params: launchtypes.NewParams( + TestMinRemainingTime, + TestMaxRemainingTime, + TestRevertDelay, + sdk.Coins(nil), + sdk.Coins(nil), + TestMaxMetadataLength, + ), + }, nil). + Once() + suite.CosmosClientMock. + On("BroadcastTx", + context.Background(), + account, + &launchtypes.MsgTriggerLaunch{ + Coordinator: addr, + LaunchId: testutil.LaunchID, + LaunchTime: TestMaxRemainingTime, + }). + Return(testutil.NewResponse(&launchtypes.MsgTriggerLaunch{}), expectedError). + Once() + + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, sampleTime.Add(TestMaxRemainingTime)) + require.Error(t, launchError) + require.Equal(t, expectedError, launchError) + suite.AssertAllMocks(t) + }) + + t.Run("failed to launch a chain, invalid response from chain", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + expectedError = errors.New("failed to fetch") + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.LaunchQueryMock. + On("Params", context.Background(), &launchtypes.QueryParamsRequest{}). + Return(&launchtypes.QueryParamsResponse{ + Params: launchtypes.NewParams( + TestMinRemainingTime, + TestMaxRemainingTime, + TestRevertDelay, + sdk.Coins(nil), + sdk.Coins(nil), + TestMaxMetadataLength, + ), + }, nil). + Once() + suite.CosmosClientMock. + On("BroadcastTx", + context.Background(), + account, + &launchtypes.MsgTriggerLaunch{ + Coordinator: addr, + LaunchId: testutil.LaunchID, + LaunchTime: TestMaxRemainingTime, + }). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{}), expectedError). + Once() + + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, sampleTime.Add(TestMaxRemainingTime)) + require.Error(t, launchError) + require.Equal(t, expectedError, launchError) + suite.AssertAllMocks(t) + }) + + t.Run("failed to launch a chain, failed to fetch chain params", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + expectedError = errors.New("failed to fetch") + ) + + suite.LaunchQueryMock. + On("Params", context.Background(), &launchtypes.QueryParamsRequest{}). + Return(&launchtypes.QueryParamsResponse{ + Params: launchtypes.NewParams( + TestMinRemainingTime, + TestMaxRemainingTime, + TestRevertDelay, + sdk.Coins(nil), + sdk.Coins(nil), + TestMaxMetadataLength, + ), + }, expectedError). + Once() + + launchError := network.TriggerLaunch(context.Background(), testutil.LaunchID, sampleTime.Add(TestMaxRemainingTime)) + require.Error(t, launchError) + require.Equal(t, expectedError, launchError) + suite.AssertAllMocks(t) + }) +} + +func TestRevertLaunch(t *testing.T) { + t.Run("successfully revert launch", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.CosmosClientMock. + On("BroadcastTx", + context.Background(), + account, + &launchtypes.MsgRevertLaunch{ + Coordinator: addr, + LaunchId: testutil.LaunchID, + }). + Return(testutil.NewResponse(&launchtypes.MsgRevertLaunchResponse{}), nil). + Once() + + revertError := network.RevertLaunch(context.Background(), testutil.LaunchID) + require.NoError(t, revertError) + suite.AssertAllMocks(t) + }) + + t.Run("failed to revert launch, failed to broadcast revert launch tx", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + expectedError = errors.New("failed to revert launch") + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.CosmosClientMock. + On("BroadcastTx", + context.Background(), + account, + &launchtypes.MsgRevertLaunch{ + Coordinator: addr, + LaunchId: testutil.LaunchID, + }). + Return( + testutil.NewResponse(&launchtypes.MsgRevertLaunchResponse{}), + expectedError, + ). + Once() + + revertError := network.RevertLaunch(context.Background(), testutil.LaunchID) + require.Error(t, revertError) + require.Equal(t, expectedError, revertError) + suite.AssertAllMocks(t) + }) +} diff --git a/network/network/mocks/account_info.go b/network/network/mocks/account_info.go new file mode 100644 index 00000000..a6c5cfb1 --- /dev/null +++ b/network/network/mocks/account_info.go @@ -0,0 +1,32 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import "github.com/stretchr/testify/mock" + +// AccountInfo is an autogenerated mock type for the AccountInfo type +type AccountInfo struct { + mock.Mock +} + +type AccountInfo_Expecter struct { + mock *mock.Mock +} + +func (_m *AccountInfo) EXPECT() *AccountInfo_Expecter { + return &AccountInfo_Expecter{mock: &_m.Mock} +} + +// NewAccountInfo creates a new instance of AccountInfo. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewAccountInfo(t interface { + mock.TestingT + Cleanup(func()) +}) *AccountInfo { + mock := &AccountInfo{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/bank_client.go b/network/network/mocks/bank_client.go new file mode 100644 index 00000000..46800fd3 --- /dev/null +++ b/network/network/mocks/bank_client.go @@ -0,0 +1,1000 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +// BankClient is an autogenerated mock type for the BankClient type +type BankClient struct { + mock.Mock +} + +type BankClient_Expecter struct { + mock *mock.Mock +} + +func (_m *BankClient) EXPECT() *BankClient_Expecter { + return &BankClient_Expecter{mock: &_m.Mock} +} + +// AllBalances provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) AllBalances(ctx context.Context, in *types.QueryAllBalancesRequest, opts ...grpc.CallOption) (*types.QueryAllBalancesResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AllBalances") + } + + var r0 *types.QueryAllBalancesResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllBalancesRequest, ...grpc.CallOption) (*types.QueryAllBalancesResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllBalancesRequest, ...grpc.CallOption) *types.QueryAllBalancesResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllBalancesResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllBalancesRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_AllBalances_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AllBalances' +type BankClient_AllBalances_Call struct { + *mock.Call +} + +// AllBalances is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllBalancesRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) AllBalances(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_AllBalances_Call { + return &BankClient_AllBalances_Call{Call: _e.mock.On("AllBalances", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_AllBalances_Call) Run(run func(ctx context.Context, in *types.QueryAllBalancesRequest, opts ...grpc.CallOption)) *BankClient_AllBalances_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllBalancesRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_AllBalances_Call) Return(_a0 *types.QueryAllBalancesResponse, _a1 error) *BankClient_AllBalances_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_AllBalances_Call) RunAndReturn(run func(context.Context, *types.QueryAllBalancesRequest, ...grpc.CallOption) (*types.QueryAllBalancesResponse, error)) *BankClient_AllBalances_Call { + _c.Call.Return(run) + return _c +} + +// Balance provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) Balance(ctx context.Context, in *types.QueryBalanceRequest, opts ...grpc.CallOption) (*types.QueryBalanceResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Balance") + } + + var r0 *types.QueryBalanceResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryBalanceRequest, ...grpc.CallOption) (*types.QueryBalanceResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryBalanceRequest, ...grpc.CallOption) *types.QueryBalanceResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryBalanceResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryBalanceRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_Balance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Balance' +type BankClient_Balance_Call struct { + *mock.Call +} + +// Balance is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryBalanceRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) Balance(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_Balance_Call { + return &BankClient_Balance_Call{Call: _e.mock.On("Balance", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_Balance_Call) Run(run func(ctx context.Context, in *types.QueryBalanceRequest, opts ...grpc.CallOption)) *BankClient_Balance_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryBalanceRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_Balance_Call) Return(_a0 *types.QueryBalanceResponse, _a1 error) *BankClient_Balance_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_Balance_Call) RunAndReturn(run func(context.Context, *types.QueryBalanceRequest, ...grpc.CallOption) (*types.QueryBalanceResponse, error)) *BankClient_Balance_Call { + _c.Call.Return(run) + return _c +} + +// DenomMetadata provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) DenomMetadata(ctx context.Context, in *types.QueryDenomMetadataRequest, opts ...grpc.CallOption) (*types.QueryDenomMetadataResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DenomMetadata") + } + + var r0 *types.QueryDenomMetadataResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomMetadataRequest, ...grpc.CallOption) (*types.QueryDenomMetadataResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomMetadataRequest, ...grpc.CallOption) *types.QueryDenomMetadataResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDenomMetadataResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDenomMetadataRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_DenomMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenomMetadata' +type BankClient_DenomMetadata_Call struct { + *mock.Call +} + +// DenomMetadata is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDenomMetadataRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) DenomMetadata(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_DenomMetadata_Call { + return &BankClient_DenomMetadata_Call{Call: _e.mock.On("DenomMetadata", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_DenomMetadata_Call) Run(run func(ctx context.Context, in *types.QueryDenomMetadataRequest, opts ...grpc.CallOption)) *BankClient_DenomMetadata_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDenomMetadataRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_DenomMetadata_Call) Return(_a0 *types.QueryDenomMetadataResponse, _a1 error) *BankClient_DenomMetadata_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_DenomMetadata_Call) RunAndReturn(run func(context.Context, *types.QueryDenomMetadataRequest, ...grpc.CallOption) (*types.QueryDenomMetadataResponse, error)) *BankClient_DenomMetadata_Call { + _c.Call.Return(run) + return _c +} + +// DenomMetadataByQueryString provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) DenomMetadataByQueryString(ctx context.Context, in *types.QueryDenomMetadataByQueryStringRequest, opts ...grpc.CallOption) (*types.QueryDenomMetadataByQueryStringResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DenomMetadataByQueryString") + } + + var r0 *types.QueryDenomMetadataByQueryStringResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomMetadataByQueryStringRequest, ...grpc.CallOption) (*types.QueryDenomMetadataByQueryStringResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomMetadataByQueryStringRequest, ...grpc.CallOption) *types.QueryDenomMetadataByQueryStringResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDenomMetadataByQueryStringResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDenomMetadataByQueryStringRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_DenomMetadataByQueryString_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenomMetadataByQueryString' +type BankClient_DenomMetadataByQueryString_Call struct { + *mock.Call +} + +// DenomMetadataByQueryString is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDenomMetadataByQueryStringRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) DenomMetadataByQueryString(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_DenomMetadataByQueryString_Call { + return &BankClient_DenomMetadataByQueryString_Call{Call: _e.mock.On("DenomMetadataByQueryString", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_DenomMetadataByQueryString_Call) Run(run func(ctx context.Context, in *types.QueryDenomMetadataByQueryStringRequest, opts ...grpc.CallOption)) *BankClient_DenomMetadataByQueryString_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDenomMetadataByQueryStringRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_DenomMetadataByQueryString_Call) Return(_a0 *types.QueryDenomMetadataByQueryStringResponse, _a1 error) *BankClient_DenomMetadataByQueryString_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_DenomMetadataByQueryString_Call) RunAndReturn(run func(context.Context, *types.QueryDenomMetadataByQueryStringRequest, ...grpc.CallOption) (*types.QueryDenomMetadataByQueryStringResponse, error)) *BankClient_DenomMetadataByQueryString_Call { + _c.Call.Return(run) + return _c +} + +// DenomOwners provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) DenomOwners(ctx context.Context, in *types.QueryDenomOwnersRequest, opts ...grpc.CallOption) (*types.QueryDenomOwnersResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DenomOwners") + } + + var r0 *types.QueryDenomOwnersResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomOwnersRequest, ...grpc.CallOption) (*types.QueryDenomOwnersResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomOwnersRequest, ...grpc.CallOption) *types.QueryDenomOwnersResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDenomOwnersResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDenomOwnersRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_DenomOwners_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenomOwners' +type BankClient_DenomOwners_Call struct { + *mock.Call +} + +// DenomOwners is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDenomOwnersRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) DenomOwners(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_DenomOwners_Call { + return &BankClient_DenomOwners_Call{Call: _e.mock.On("DenomOwners", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_DenomOwners_Call) Run(run func(ctx context.Context, in *types.QueryDenomOwnersRequest, opts ...grpc.CallOption)) *BankClient_DenomOwners_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDenomOwnersRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_DenomOwners_Call) Return(_a0 *types.QueryDenomOwnersResponse, _a1 error) *BankClient_DenomOwners_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_DenomOwners_Call) RunAndReturn(run func(context.Context, *types.QueryDenomOwnersRequest, ...grpc.CallOption) (*types.QueryDenomOwnersResponse, error)) *BankClient_DenomOwners_Call { + _c.Call.Return(run) + return _c +} + +// DenomOwnersByQuery provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) DenomOwnersByQuery(ctx context.Context, in *types.QueryDenomOwnersByQueryRequest, opts ...grpc.CallOption) (*types.QueryDenomOwnersByQueryResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DenomOwnersByQuery") + } + + var r0 *types.QueryDenomOwnersByQueryResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomOwnersByQueryRequest, ...grpc.CallOption) (*types.QueryDenomOwnersByQueryResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomOwnersByQueryRequest, ...grpc.CallOption) *types.QueryDenomOwnersByQueryResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDenomOwnersByQueryResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDenomOwnersByQueryRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_DenomOwnersByQuery_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenomOwnersByQuery' +type BankClient_DenomOwnersByQuery_Call struct { + *mock.Call +} + +// DenomOwnersByQuery is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDenomOwnersByQueryRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) DenomOwnersByQuery(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_DenomOwnersByQuery_Call { + return &BankClient_DenomOwnersByQuery_Call{Call: _e.mock.On("DenomOwnersByQuery", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_DenomOwnersByQuery_Call) Run(run func(ctx context.Context, in *types.QueryDenomOwnersByQueryRequest, opts ...grpc.CallOption)) *BankClient_DenomOwnersByQuery_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDenomOwnersByQueryRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_DenomOwnersByQuery_Call) Return(_a0 *types.QueryDenomOwnersByQueryResponse, _a1 error) *BankClient_DenomOwnersByQuery_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_DenomOwnersByQuery_Call) RunAndReturn(run func(context.Context, *types.QueryDenomOwnersByQueryRequest, ...grpc.CallOption) (*types.QueryDenomOwnersByQueryResponse, error)) *BankClient_DenomOwnersByQuery_Call { + _c.Call.Return(run) + return _c +} + +// DenomsMetadata provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) DenomsMetadata(ctx context.Context, in *types.QueryDenomsMetadataRequest, opts ...grpc.CallOption) (*types.QueryDenomsMetadataResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DenomsMetadata") + } + + var r0 *types.QueryDenomsMetadataResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomsMetadataRequest, ...grpc.CallOption) (*types.QueryDenomsMetadataResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDenomsMetadataRequest, ...grpc.CallOption) *types.QueryDenomsMetadataResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDenomsMetadataResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDenomsMetadataRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_DenomsMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenomsMetadata' +type BankClient_DenomsMetadata_Call struct { + *mock.Call +} + +// DenomsMetadata is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDenomsMetadataRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) DenomsMetadata(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_DenomsMetadata_Call { + return &BankClient_DenomsMetadata_Call{Call: _e.mock.On("DenomsMetadata", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_DenomsMetadata_Call) Run(run func(ctx context.Context, in *types.QueryDenomsMetadataRequest, opts ...grpc.CallOption)) *BankClient_DenomsMetadata_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDenomsMetadataRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_DenomsMetadata_Call) Return(_a0 *types.QueryDenomsMetadataResponse, _a1 error) *BankClient_DenomsMetadata_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_DenomsMetadata_Call) RunAndReturn(run func(context.Context, *types.QueryDenomsMetadataRequest, ...grpc.CallOption) (*types.QueryDenomsMetadataResponse, error)) *BankClient_DenomsMetadata_Call { + _c.Call.Return(run) + return _c +} + +// Params provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Params") + } + + var r0 *types.QueryParamsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryParamsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_Params_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Params' +type BankClient_Params_Call struct { + *mock.Call +} + +// Params is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryParamsRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) Params(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_Params_Call { + return &BankClient_Params_Call{Call: _e.mock.On("Params", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_Params_Call) Run(run func(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption)) *BankClient_Params_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryParamsRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_Params_Call) Return(_a0 *types.QueryParamsResponse, _a1 error) *BankClient_Params_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_Params_Call) RunAndReturn(run func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)) *BankClient_Params_Call { + _c.Call.Return(run) + return _c +} + +// SendEnabled provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) SendEnabled(ctx context.Context, in *types.QuerySendEnabledRequest, opts ...grpc.CallOption) (*types.QuerySendEnabledResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for SendEnabled") + } + + var r0 *types.QuerySendEnabledResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySendEnabledRequest, ...grpc.CallOption) (*types.QuerySendEnabledResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySendEnabledRequest, ...grpc.CallOption) *types.QuerySendEnabledResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QuerySendEnabledResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QuerySendEnabledRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_SendEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendEnabled' +type BankClient_SendEnabled_Call struct { + *mock.Call +} + +// SendEnabled is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QuerySendEnabledRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) SendEnabled(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_SendEnabled_Call { + return &BankClient_SendEnabled_Call{Call: _e.mock.On("SendEnabled", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_SendEnabled_Call) Run(run func(ctx context.Context, in *types.QuerySendEnabledRequest, opts ...grpc.CallOption)) *BankClient_SendEnabled_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QuerySendEnabledRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_SendEnabled_Call) Return(_a0 *types.QuerySendEnabledResponse, _a1 error) *BankClient_SendEnabled_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_SendEnabled_Call) RunAndReturn(run func(context.Context, *types.QuerySendEnabledRequest, ...grpc.CallOption) (*types.QuerySendEnabledResponse, error)) *BankClient_SendEnabled_Call { + _c.Call.Return(run) + return _c +} + +// SpendableBalanceByDenom provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) SpendableBalanceByDenom(ctx context.Context, in *types.QuerySpendableBalanceByDenomRequest, opts ...grpc.CallOption) (*types.QuerySpendableBalanceByDenomResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for SpendableBalanceByDenom") + } + + var r0 *types.QuerySpendableBalanceByDenomResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySpendableBalanceByDenomRequest, ...grpc.CallOption) (*types.QuerySpendableBalanceByDenomResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySpendableBalanceByDenomRequest, ...grpc.CallOption) *types.QuerySpendableBalanceByDenomResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QuerySpendableBalanceByDenomResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QuerySpendableBalanceByDenomRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_SpendableBalanceByDenom_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SpendableBalanceByDenom' +type BankClient_SpendableBalanceByDenom_Call struct { + *mock.Call +} + +// SpendableBalanceByDenom is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QuerySpendableBalanceByDenomRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) SpendableBalanceByDenom(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_SpendableBalanceByDenom_Call { + return &BankClient_SpendableBalanceByDenom_Call{Call: _e.mock.On("SpendableBalanceByDenom", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_SpendableBalanceByDenom_Call) Run(run func(ctx context.Context, in *types.QuerySpendableBalanceByDenomRequest, opts ...grpc.CallOption)) *BankClient_SpendableBalanceByDenom_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QuerySpendableBalanceByDenomRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_SpendableBalanceByDenom_Call) Return(_a0 *types.QuerySpendableBalanceByDenomResponse, _a1 error) *BankClient_SpendableBalanceByDenom_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_SpendableBalanceByDenom_Call) RunAndReturn(run func(context.Context, *types.QuerySpendableBalanceByDenomRequest, ...grpc.CallOption) (*types.QuerySpendableBalanceByDenomResponse, error)) *BankClient_SpendableBalanceByDenom_Call { + _c.Call.Return(run) + return _c +} + +// SpendableBalances provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) SpendableBalances(ctx context.Context, in *types.QuerySpendableBalancesRequest, opts ...grpc.CallOption) (*types.QuerySpendableBalancesResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for SpendableBalances") + } + + var r0 *types.QuerySpendableBalancesResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySpendableBalancesRequest, ...grpc.CallOption) (*types.QuerySpendableBalancesResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySpendableBalancesRequest, ...grpc.CallOption) *types.QuerySpendableBalancesResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QuerySpendableBalancesResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QuerySpendableBalancesRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_SpendableBalances_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SpendableBalances' +type BankClient_SpendableBalances_Call struct { + *mock.Call +} + +// SpendableBalances is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QuerySpendableBalancesRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) SpendableBalances(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_SpendableBalances_Call { + return &BankClient_SpendableBalances_Call{Call: _e.mock.On("SpendableBalances", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_SpendableBalances_Call) Run(run func(ctx context.Context, in *types.QuerySpendableBalancesRequest, opts ...grpc.CallOption)) *BankClient_SpendableBalances_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QuerySpendableBalancesRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_SpendableBalances_Call) Return(_a0 *types.QuerySpendableBalancesResponse, _a1 error) *BankClient_SpendableBalances_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_SpendableBalances_Call) RunAndReturn(run func(context.Context, *types.QuerySpendableBalancesRequest, ...grpc.CallOption) (*types.QuerySpendableBalancesResponse, error)) *BankClient_SpendableBalances_Call { + _c.Call.Return(run) + return _c +} + +// SupplyOf provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) SupplyOf(ctx context.Context, in *types.QuerySupplyOfRequest, opts ...grpc.CallOption) (*types.QuerySupplyOfResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for SupplyOf") + } + + var r0 *types.QuerySupplyOfResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySupplyOfRequest, ...grpc.CallOption) (*types.QuerySupplyOfResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySupplyOfRequest, ...grpc.CallOption) *types.QuerySupplyOfResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QuerySupplyOfResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QuerySupplyOfRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_SupplyOf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SupplyOf' +type BankClient_SupplyOf_Call struct { + *mock.Call +} + +// SupplyOf is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QuerySupplyOfRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) SupplyOf(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_SupplyOf_Call { + return &BankClient_SupplyOf_Call{Call: _e.mock.On("SupplyOf", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_SupplyOf_Call) Run(run func(ctx context.Context, in *types.QuerySupplyOfRequest, opts ...grpc.CallOption)) *BankClient_SupplyOf_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QuerySupplyOfRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_SupplyOf_Call) Return(_a0 *types.QuerySupplyOfResponse, _a1 error) *BankClient_SupplyOf_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_SupplyOf_Call) RunAndReturn(run func(context.Context, *types.QuerySupplyOfRequest, ...grpc.CallOption) (*types.QuerySupplyOfResponse, error)) *BankClient_SupplyOf_Call { + _c.Call.Return(run) + return _c +} + +// TotalSupply provides a mock function with given fields: ctx, in, opts +func (_m *BankClient) TotalSupply(ctx context.Context, in *types.QueryTotalSupplyRequest, opts ...grpc.CallOption) (*types.QueryTotalSupplyResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for TotalSupply") + } + + var r0 *types.QueryTotalSupplyResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryTotalSupplyRequest, ...grpc.CallOption) (*types.QueryTotalSupplyResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryTotalSupplyRequest, ...grpc.CallOption) *types.QueryTotalSupplyResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryTotalSupplyResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryTotalSupplyRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BankClient_TotalSupply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TotalSupply' +type BankClient_TotalSupply_Call struct { + *mock.Call +} + +// TotalSupply is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryTotalSupplyRequest +// - opts ...grpc.CallOption +func (_e *BankClient_Expecter) TotalSupply(ctx interface{}, in interface{}, opts ...interface{}) *BankClient_TotalSupply_Call { + return &BankClient_TotalSupply_Call{Call: _e.mock.On("TotalSupply", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *BankClient_TotalSupply_Call) Run(run func(ctx context.Context, in *types.QueryTotalSupplyRequest, opts ...grpc.CallOption)) *BankClient_TotalSupply_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryTotalSupplyRequest), variadicArgs...) + }) + return _c +} + +func (_c *BankClient_TotalSupply_Call) Return(_a0 *types.QueryTotalSupplyResponse, _a1 error) *BankClient_TotalSupply_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *BankClient_TotalSupply_Call) RunAndReturn(run func(context.Context, *types.QueryTotalSupplyRequest, ...grpc.CallOption) (*types.QueryTotalSupplyResponse, error)) *BankClient_TotalSupply_Call { + _c.Call.Return(run) + return _c +} + +// NewBankClient creates a new instance of BankClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewBankClient(t interface { + mock.TestingT + Cleanup(func()) +}) *BankClient { + mock := &BankClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/chain.go b/network/network/mocks/chain.go new file mode 100644 index 00000000..8fe12b9c --- /dev/null +++ b/network/network/mocks/chain.go @@ -0,0 +1,658 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/stretchr/testify/mock" +) + +// Chain is an autogenerated mock type for the Chain type +type Chain struct { + mock.Mock +} + +type Chain_Expecter struct { + mock *mock.Mock +} + +func (_m *Chain) EXPECT() *Chain_Expecter { + return &Chain_Expecter{mock: &_m.Mock} +} + +// AppTOMLPath provides a mock function with given fields: +func (_m *Chain) AppTOMLPath() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for AppTOMLPath") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Chain_AppTOMLPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AppTOMLPath' +type Chain_AppTOMLPath_Call struct { + *mock.Call +} + +// AppTOMLPath is a helper method to define mock.On call +func (_e *Chain_Expecter) AppTOMLPath() *Chain_AppTOMLPath_Call { + return &Chain_AppTOMLPath_Call{Call: _e.mock.On("AppTOMLPath")} +} + +func (_c *Chain_AppTOMLPath_Call) Run(run func()) *Chain_AppTOMLPath_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_AppTOMLPath_Call) Return(_a0 string, _a1 error) *Chain_AppTOMLPath_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Chain_AppTOMLPath_Call) RunAndReturn(run func() (string, error)) *Chain_AppTOMLPath_Call { + _c.Call.Return(run) + return _c +} + +// CacheBinary provides a mock function with given fields: launchID +func (_m *Chain) CacheBinary(launchID uint64) error { + ret := _m.Called(launchID) + + if len(ret) == 0 { + panic("no return value specified for CacheBinary") + } + + var r0 error + if rf, ok := ret.Get(0).(func(uint64) error); ok { + r0 = rf(launchID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Chain_CacheBinary_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CacheBinary' +type Chain_CacheBinary_Call struct { + *mock.Call +} + +// CacheBinary is a helper method to define mock.On call +// - launchID uint64 +func (_e *Chain_Expecter) CacheBinary(launchID interface{}) *Chain_CacheBinary_Call { + return &Chain_CacheBinary_Call{Call: _e.mock.On("CacheBinary", launchID)} +} + +func (_c *Chain_CacheBinary_Call) Run(run func(launchID uint64)) *Chain_CacheBinary_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(uint64)) + }) + return _c +} + +func (_c *Chain_CacheBinary_Call) Return(_a0 error) *Chain_CacheBinary_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Chain_CacheBinary_Call) RunAndReturn(run func(uint64) error) *Chain_CacheBinary_Call { + _c.Call.Return(run) + return _c +} + +// ChainID provides a mock function with given fields: +func (_m *Chain) ChainID() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Chain_ChainID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ChainID' +type Chain_ChainID_Call struct { + *mock.Call +} + +// ChainID is a helper method to define mock.On call +func (_e *Chain_Expecter) ChainID() *Chain_ChainID_Call { + return &Chain_ChainID_Call{Call: _e.mock.On("ChainID")} +} + +func (_c *Chain_ChainID_Call) Run(run func()) *Chain_ChainID_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_ChainID_Call) Return(_a0 string, _a1 error) *Chain_ChainID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Chain_ChainID_Call) RunAndReturn(run func() (string, error)) *Chain_ChainID_Call { + _c.Call.Return(run) + return _c +} + +// ConfigTOMLPath provides a mock function with given fields: +func (_m *Chain) ConfigTOMLPath() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ConfigTOMLPath") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Chain_ConfigTOMLPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfigTOMLPath' +type Chain_ConfigTOMLPath_Call struct { + *mock.Call +} + +// ConfigTOMLPath is a helper method to define mock.On call +func (_e *Chain_Expecter) ConfigTOMLPath() *Chain_ConfigTOMLPath_Call { + return &Chain_ConfigTOMLPath_Call{Call: _e.mock.On("ConfigTOMLPath")} +} + +func (_c *Chain_ConfigTOMLPath_Call) Run(run func()) *Chain_ConfigTOMLPath_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_ConfigTOMLPath_Call) Return(_a0 string, _a1 error) *Chain_ConfigTOMLPath_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Chain_ConfigTOMLPath_Call) RunAndReturn(run func() (string, error)) *Chain_ConfigTOMLPath_Call { + _c.Call.Return(run) + return _c +} + +// DefaultGentxPath provides a mock function with given fields: +func (_m *Chain) DefaultGentxPath() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DefaultGentxPath") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Chain_DefaultGentxPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DefaultGentxPath' +type Chain_DefaultGentxPath_Call struct { + *mock.Call +} + +// DefaultGentxPath is a helper method to define mock.On call +func (_e *Chain_Expecter) DefaultGentxPath() *Chain_DefaultGentxPath_Call { + return &Chain_DefaultGentxPath_Call{Call: _e.mock.On("DefaultGentxPath")} +} + +func (_c *Chain_DefaultGentxPath_Call) Run(run func()) *Chain_DefaultGentxPath_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_DefaultGentxPath_Call) Return(_a0 string, _a1 error) *Chain_DefaultGentxPath_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Chain_DefaultGentxPath_Call) RunAndReturn(run func() (string, error)) *Chain_DefaultGentxPath_Call { + _c.Call.Return(run) + return _c +} + +// GenesisPath provides a mock function with given fields: +func (_m *Chain) GenesisPath() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GenesisPath") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Chain_GenesisPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenesisPath' +type Chain_GenesisPath_Call struct { + *mock.Call +} + +// GenesisPath is a helper method to define mock.On call +func (_e *Chain_Expecter) GenesisPath() *Chain_GenesisPath_Call { + return &Chain_GenesisPath_Call{Call: _e.mock.On("GenesisPath")} +} + +func (_c *Chain_GenesisPath_Call) Run(run func()) *Chain_GenesisPath_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_GenesisPath_Call) Return(_a0 string, _a1 error) *Chain_GenesisPath_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Chain_GenesisPath_Call) RunAndReturn(run func() (string, error)) *Chain_GenesisPath_Call { + _c.Call.Return(run) + return _c +} + +// GentxsPath provides a mock function with given fields: +func (_m *Chain) GentxsPath() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GentxsPath") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Chain_GentxsPath_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GentxsPath' +type Chain_GentxsPath_Call struct { + *mock.Call +} + +// GentxsPath is a helper method to define mock.On call +func (_e *Chain_Expecter) GentxsPath() *Chain_GentxsPath_Call { + return &Chain_GentxsPath_Call{Call: _e.mock.On("GentxsPath")} +} + +func (_c *Chain_GentxsPath_Call) Run(run func()) *Chain_GentxsPath_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_GentxsPath_Call) Return(_a0 string, _a1 error) *Chain_GentxsPath_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Chain_GentxsPath_Call) RunAndReturn(run func() (string, error)) *Chain_GentxsPath_Call { + _c.Call.Return(run) + return _c +} + +// ID provides a mock function with given fields: +func (_m *Chain) ID() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ID") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Chain_ID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ID' +type Chain_ID_Call struct { + *mock.Call +} + +// ID is a helper method to define mock.On call +func (_e *Chain_Expecter) ID() *Chain_ID_Call { + return &Chain_ID_Call{Call: _e.mock.On("ID")} +} + +func (_c *Chain_ID_Call) Run(run func()) *Chain_ID_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_ID_Call) Return(_a0 string, _a1 error) *Chain_ID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Chain_ID_Call) RunAndReturn(run func() (string, error)) *Chain_ID_Call { + _c.Call.Return(run) + return _c +} + +// Name provides a mock function with given fields: +func (_m *Chain) Name() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Name") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Chain_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' +type Chain_Name_Call struct { + *mock.Call +} + +// Name is a helper method to define mock.On call +func (_e *Chain_Expecter) Name() *Chain_Name_Call { + return &Chain_Name_Call{Call: _e.mock.On("Name")} +} + +func (_c *Chain_Name_Call) Run(run func()) *Chain_Name_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_Name_Call) Return(_a0 string) *Chain_Name_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Chain_Name_Call) RunAndReturn(run func() string) *Chain_Name_Call { + _c.Call.Return(run) + return _c +} + +// NodeID provides a mock function with given fields: ctx +func (_m *Chain) NodeID(ctx context.Context) (string, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for NodeID") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) string); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Chain_NodeID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeID' +type Chain_NodeID_Call struct { + *mock.Call +} + +// NodeID is a helper method to define mock.On call +// - ctx context.Context +func (_e *Chain_Expecter) NodeID(ctx interface{}) *Chain_NodeID_Call { + return &Chain_NodeID_Call{Call: _e.mock.On("NodeID", ctx)} +} + +func (_c *Chain_NodeID_Call) Run(run func(ctx context.Context)) *Chain_NodeID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *Chain_NodeID_Call) Return(_a0 string, _a1 error) *Chain_NodeID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Chain_NodeID_Call) RunAndReturn(run func(context.Context) (string, error)) *Chain_NodeID_Call { + _c.Call.Return(run) + return _c +} + +// SourceHash provides a mock function with given fields: +func (_m *Chain) SourceHash() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for SourceHash") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Chain_SourceHash_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SourceHash' +type Chain_SourceHash_Call struct { + *mock.Call +} + +// SourceHash is a helper method to define mock.On call +func (_e *Chain_Expecter) SourceHash() *Chain_SourceHash_Call { + return &Chain_SourceHash_Call{Call: _e.mock.On("SourceHash")} +} + +func (_c *Chain_SourceHash_Call) Run(run func()) *Chain_SourceHash_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_SourceHash_Call) Return(_a0 string) *Chain_SourceHash_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Chain_SourceHash_Call) RunAndReturn(run func() string) *Chain_SourceHash_Call { + _c.Call.Return(run) + return _c +} + +// SourceURL provides a mock function with given fields: +func (_m *Chain) SourceURL() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for SourceURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Chain_SourceURL_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SourceURL' +type Chain_SourceURL_Call struct { + *mock.Call +} + +// SourceURL is a helper method to define mock.On call +func (_e *Chain_Expecter) SourceURL() *Chain_SourceURL_Call { + return &Chain_SourceURL_Call{Call: _e.mock.On("SourceURL")} +} + +func (_c *Chain_SourceURL_Call) Run(run func()) *Chain_SourceURL_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Chain_SourceURL_Call) Return(_a0 string) *Chain_SourceURL_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Chain_SourceURL_Call) RunAndReturn(run func() string) *Chain_SourceURL_Call { + _c.Call.Return(run) + return _c +} + +// NewChain creates a new instance of Chain. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewChain(t interface { + mock.TestingT + Cleanup(func()) +}) *Chain { + mock := &Chain{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/cosmos_client.go b/network/network/mocks/cosmos_client.go new file mode 100644 index 00000000..04191e13 --- /dev/null +++ b/network/network/mocks/cosmos_client.go @@ -0,0 +1,278 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + client "github.com/cosmos/cosmos-sdk/client" + + coretypes "github.com/cometbft/cometbft/rpc/core/types" + + cosmosaccount "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" + + cosmosclient "github.com/ignite/cli/v28/ignite/pkg/cosmosclient" + + mock "github.com/stretchr/testify/mock" + + types "github.com/cosmos/cosmos-sdk/types" +) + +// CosmosClient is an autogenerated mock type for the CosmosClient type +type CosmosClient struct { + mock.Mock +} + +type CosmosClient_Expecter struct { + mock *mock.Mock +} + +func (_m *CosmosClient) EXPECT() *CosmosClient_Expecter { + return &CosmosClient_Expecter{mock: &_m.Mock} +} + +// BroadcastTx provides a mock function with given fields: ctx, account, msgs +func (_m *CosmosClient) BroadcastTx(ctx context.Context, account cosmosaccount.Account, msgs ...types.Msg) (cosmosclient.Response, error) { + _va := make([]interface{}, len(msgs)) + for _i := range msgs { + _va[_i] = msgs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, account) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for BroadcastTx") + } + + var r0 cosmosclient.Response + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, cosmosaccount.Account, ...types.Msg) (cosmosclient.Response, error)); ok { + return rf(ctx, account, msgs...) + } + if rf, ok := ret.Get(0).(func(context.Context, cosmosaccount.Account, ...types.Msg) cosmosclient.Response); ok { + r0 = rf(ctx, account, msgs...) + } else { + r0 = ret.Get(0).(cosmosclient.Response) + } + + if rf, ok := ret.Get(1).(func(context.Context, cosmosaccount.Account, ...types.Msg) error); ok { + r1 = rf(ctx, account, msgs...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CosmosClient_BroadcastTx_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BroadcastTx' +type CosmosClient_BroadcastTx_Call struct { + *mock.Call +} + +// BroadcastTx is a helper method to define mock.On call +// - ctx context.Context +// - account cosmosaccount.Account +// - msgs ...types.Msg +func (_e *CosmosClient_Expecter) BroadcastTx(ctx interface{}, account interface{}, msgs ...interface{}) *CosmosClient_BroadcastTx_Call { + return &CosmosClient_BroadcastTx_Call{Call: _e.mock.On("BroadcastTx", + append([]interface{}{ctx, account}, msgs...)...)} +} + +func (_c *CosmosClient_BroadcastTx_Call) Run(run func(ctx context.Context, account cosmosaccount.Account, msgs ...types.Msg)) *CosmosClient_BroadcastTx_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]types.Msg, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(types.Msg) + } + } + run(args[0].(context.Context), args[1].(cosmosaccount.Account), variadicArgs...) + }) + return _c +} + +func (_c *CosmosClient_BroadcastTx_Call) Return(_a0 cosmosclient.Response, _a1 error) *CosmosClient_BroadcastTx_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *CosmosClient_BroadcastTx_Call) RunAndReturn(run func(context.Context, cosmosaccount.Account, ...types.Msg) (cosmosclient.Response, error)) *CosmosClient_BroadcastTx_Call { + _c.Call.Return(run) + return _c +} + +// ConsensusInfo provides a mock function with given fields: ctx, height +func (_m *CosmosClient) ConsensusInfo(ctx context.Context, height int64) (cosmosclient.ConsensusInfo, error) { + ret := _m.Called(ctx, height) + + if len(ret) == 0 { + panic("no return value specified for ConsensusInfo") + } + + var r0 cosmosclient.ConsensusInfo + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (cosmosclient.ConsensusInfo, error)); ok { + return rf(ctx, height) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) cosmosclient.ConsensusInfo); ok { + r0 = rf(ctx, height) + } else { + r0 = ret.Get(0).(cosmosclient.ConsensusInfo) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, height) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CosmosClient_ConsensusInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConsensusInfo' +type CosmosClient_ConsensusInfo_Call struct { + *mock.Call +} + +// ConsensusInfo is a helper method to define mock.On call +// - ctx context.Context +// - height int64 +func (_e *CosmosClient_Expecter) ConsensusInfo(ctx interface{}, height interface{}) *CosmosClient_ConsensusInfo_Call { + return &CosmosClient_ConsensusInfo_Call{Call: _e.mock.On("ConsensusInfo", ctx, height)} +} + +func (_c *CosmosClient_ConsensusInfo_Call) Run(run func(ctx context.Context, height int64)) *CosmosClient_ConsensusInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64)) + }) + return _c +} + +func (_c *CosmosClient_ConsensusInfo_Call) Return(_a0 cosmosclient.ConsensusInfo, _a1 error) *CosmosClient_ConsensusInfo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *CosmosClient_ConsensusInfo_Call) RunAndReturn(run func(context.Context, int64) (cosmosclient.ConsensusInfo, error)) *CosmosClient_ConsensusInfo_Call { + _c.Call.Return(run) + return _c +} + +// Context provides a mock function with given fields: +func (_m *CosmosClient) Context() client.Context { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Context") + } + + var r0 client.Context + if rf, ok := ret.Get(0).(func() client.Context); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(client.Context) + } + + return r0 +} + +// CosmosClient_Context_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Context' +type CosmosClient_Context_Call struct { + *mock.Call +} + +// Context is a helper method to define mock.On call +func (_e *CosmosClient_Expecter) Context() *CosmosClient_Context_Call { + return &CosmosClient_Context_Call{Call: _e.mock.On("Context")} +} + +func (_c *CosmosClient_Context_Call) Run(run func()) *CosmosClient_Context_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *CosmosClient_Context_Call) Return(_a0 client.Context) *CosmosClient_Context_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *CosmosClient_Context_Call) RunAndReturn(run func() client.Context) *CosmosClient_Context_Call { + _c.Call.Return(run) + return _c +} + +// Status provides a mock function with given fields: ctx +func (_m *CosmosClient) Status(ctx context.Context) (*coretypes.ResultStatus, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Status") + } + + var r0 *coretypes.ResultStatus + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*coretypes.ResultStatus, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *coretypes.ResultStatus); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*coretypes.ResultStatus) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CosmosClient_Status_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Status' +type CosmosClient_Status_Call struct { + *mock.Call +} + +// Status is a helper method to define mock.On call +// - ctx context.Context +func (_e *CosmosClient_Expecter) Status(ctx interface{}) *CosmosClient_Status_Call { + return &CosmosClient_Status_Call{Call: _e.mock.On("Status", ctx)} +} + +func (_c *CosmosClient_Status_Call) Run(run func(ctx context.Context)) *CosmosClient_Status_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *CosmosClient_Status_Call) Return(_a0 *coretypes.ResultStatus, _a1 error) *CosmosClient_Status_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *CosmosClient_Status_Call) RunAndReturn(run func(context.Context) (*coretypes.ResultStatus, error)) *CosmosClient_Status_Call { + _c.Call.Return(run) + return _c +} + +// NewCosmosClient creates a new instance of CosmosClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewCosmosClient(t interface { + mock.TestingT + Cleanup(func()) +}) *CosmosClient { + mock := &CosmosClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/data/genesis.json b/network/network/mocks/data/genesis.json new file mode 100644 index 00000000..9b1206d7 --- /dev/null +++ b/network/network/mocks/data/genesis.json @@ -0,0 +1,80 @@ +{ + "genesis_time": "2022-04-07T17:41:59.206851Z", + "chain_id": "test-custom-1", + "initial_height": "1", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1", + "time_iota_ms": "1000" + }, + "evidence": { + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": {} + }, + "app_hash": "", + "app_state": { + "bank": { + "balances": [ + { + "address": "cosmos1p5y33h5t8gw4dd2shdtdcv3a89mkyhsm6f2552", + "coins": [ + { + "denom": "stake", + "amount": "200000000" + }, + { + "denom": "token", + "amount": "20000" + } + ] + }, + { + "address": "cosmos10zv6xg8uxdnffkgc7s23hytxxa58q6mhy4tt8e", + "coins": [ + { + "denom": "stake", + "amount": "100000000" + }, + { + "denom": "token", + "amount": "10000" + } + ] + } + ] + }, + "staking": { + "delegations": [], + "exported": false, + "last_total_power": "0", + "last_validator_powers": [], + "params": { + "bond_denom": "stake", + "historical_entries": 10000, + "max_entries": 7, + "max_validators": 100, + "unbonding_time": "1814400s" + }, + "redelegations": [], + "unbonding_delegations": [], + "validators": [] + }, + "transfer": { + "denom_traces": [], + "params": { + "receive_enabled": true, + "send_enabled": true + }, + "port_id": "transfer" + } + } +} \ No newline at end of file diff --git a/network/network/mocks/launch_client.go b/network/network/mocks/launch_client.go new file mode 100644 index 00000000..1ae5d429 --- /dev/null +++ b/network/network/mocks/launch_client.go @@ -0,0 +1,926 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/ignite/network/x/launch/types" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +// LaunchClient is an autogenerated mock type for the LaunchClient type +type LaunchClient struct { + mock.Mock +} + +type LaunchClient_Expecter struct { + mock *mock.Mock +} + +func (_m *LaunchClient) EXPECT() *LaunchClient_Expecter { + return &LaunchClient_Expecter{mock: &_m.Mock} +} + +// GetChain provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) GetChain(ctx context.Context, in *types.QueryGetChainRequest, opts ...grpc.CallOption) (*types.QueryGetChainResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetChain") + } + + var r0 *types.QueryGetChainResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetChainRequest, ...grpc.CallOption) (*types.QueryGetChainResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetChainRequest, ...grpc.CallOption) *types.QueryGetChainResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetChainResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetChainRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_GetChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetChain' +type LaunchClient_GetChain_Call struct { + *mock.Call +} + +// GetChain is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetChainRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) GetChain(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_GetChain_Call { + return &LaunchClient_GetChain_Call{Call: _e.mock.On("GetChain", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_GetChain_Call) Run(run func(ctx context.Context, in *types.QueryGetChainRequest, opts ...grpc.CallOption)) *LaunchClient_GetChain_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetChainRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_GetChain_Call) Return(_a0 *types.QueryGetChainResponse, _a1 error) *LaunchClient_GetChain_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_GetChain_Call) RunAndReturn(run func(context.Context, *types.QueryGetChainRequest, ...grpc.CallOption) (*types.QueryGetChainResponse, error)) *LaunchClient_GetChain_Call { + _c.Call.Return(run) + return _c +} + +// GetGenesisAccount provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) GetGenesisAccount(ctx context.Context, in *types.QueryGetGenesisAccountRequest, opts ...grpc.CallOption) (*types.QueryGetGenesisAccountResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetGenesisAccount") + } + + var r0 *types.QueryGetGenesisAccountResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetGenesisAccountRequest, ...grpc.CallOption) (*types.QueryGetGenesisAccountResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetGenesisAccountRequest, ...grpc.CallOption) *types.QueryGetGenesisAccountResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetGenesisAccountResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetGenesisAccountRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_GetGenesisAccount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGenesisAccount' +type LaunchClient_GetGenesisAccount_Call struct { + *mock.Call +} + +// GetGenesisAccount is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetGenesisAccountRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) GetGenesisAccount(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_GetGenesisAccount_Call { + return &LaunchClient_GetGenesisAccount_Call{Call: _e.mock.On("GetGenesisAccount", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_GetGenesisAccount_Call) Run(run func(ctx context.Context, in *types.QueryGetGenesisAccountRequest, opts ...grpc.CallOption)) *LaunchClient_GetGenesisAccount_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetGenesisAccountRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_GetGenesisAccount_Call) Return(_a0 *types.QueryGetGenesisAccountResponse, _a1 error) *LaunchClient_GetGenesisAccount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_GetGenesisAccount_Call) RunAndReturn(run func(context.Context, *types.QueryGetGenesisAccountRequest, ...grpc.CallOption) (*types.QueryGetGenesisAccountResponse, error)) *LaunchClient_GetGenesisAccount_Call { + _c.Call.Return(run) + return _c +} + +// GetGenesisValidator provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) GetGenesisValidator(ctx context.Context, in *types.QueryGetGenesisValidatorRequest, opts ...grpc.CallOption) (*types.QueryGetGenesisValidatorResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetGenesisValidator") + } + + var r0 *types.QueryGetGenesisValidatorResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetGenesisValidatorRequest, ...grpc.CallOption) (*types.QueryGetGenesisValidatorResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetGenesisValidatorRequest, ...grpc.CallOption) *types.QueryGetGenesisValidatorResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetGenesisValidatorResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetGenesisValidatorRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_GetGenesisValidator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGenesisValidator' +type LaunchClient_GetGenesisValidator_Call struct { + *mock.Call +} + +// GetGenesisValidator is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetGenesisValidatorRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) GetGenesisValidator(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_GetGenesisValidator_Call { + return &LaunchClient_GetGenesisValidator_Call{Call: _e.mock.On("GetGenesisValidator", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_GetGenesisValidator_Call) Run(run func(ctx context.Context, in *types.QueryGetGenesisValidatorRequest, opts ...grpc.CallOption)) *LaunchClient_GetGenesisValidator_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetGenesisValidatorRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_GetGenesisValidator_Call) Return(_a0 *types.QueryGetGenesisValidatorResponse, _a1 error) *LaunchClient_GetGenesisValidator_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_GetGenesisValidator_Call) RunAndReturn(run func(context.Context, *types.QueryGetGenesisValidatorRequest, ...grpc.CallOption) (*types.QueryGetGenesisValidatorResponse, error)) *LaunchClient_GetGenesisValidator_Call { + _c.Call.Return(run) + return _c +} + +// GetRequest provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) GetRequest(ctx context.Context, in *types.QueryGetRequestRequest, opts ...grpc.CallOption) (*types.QueryGetRequestResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetRequest") + } + + var r0 *types.QueryGetRequestResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetRequestRequest, ...grpc.CallOption) (*types.QueryGetRequestResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetRequestRequest, ...grpc.CallOption) *types.QueryGetRequestResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetRequestResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetRequestRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_GetRequest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRequest' +type LaunchClient_GetRequest_Call struct { + *mock.Call +} + +// GetRequest is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetRequestRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) GetRequest(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_GetRequest_Call { + return &LaunchClient_GetRequest_Call{Call: _e.mock.On("GetRequest", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_GetRequest_Call) Run(run func(ctx context.Context, in *types.QueryGetRequestRequest, opts ...grpc.CallOption)) *LaunchClient_GetRequest_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetRequestRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_GetRequest_Call) Return(_a0 *types.QueryGetRequestResponse, _a1 error) *LaunchClient_GetRequest_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_GetRequest_Call) RunAndReturn(run func(context.Context, *types.QueryGetRequestRequest, ...grpc.CallOption) (*types.QueryGetRequestResponse, error)) *LaunchClient_GetRequest_Call { + _c.Call.Return(run) + return _c +} + +// GetVestingAccount provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) GetVestingAccount(ctx context.Context, in *types.QueryGetVestingAccountRequest, opts ...grpc.CallOption) (*types.QueryGetVestingAccountResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetVestingAccount") + } + + var r0 *types.QueryGetVestingAccountResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetVestingAccountRequest, ...grpc.CallOption) (*types.QueryGetVestingAccountResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetVestingAccountRequest, ...grpc.CallOption) *types.QueryGetVestingAccountResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetVestingAccountResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetVestingAccountRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_GetVestingAccount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetVestingAccount' +type LaunchClient_GetVestingAccount_Call struct { + *mock.Call +} + +// GetVestingAccount is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetVestingAccountRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) GetVestingAccount(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_GetVestingAccount_Call { + return &LaunchClient_GetVestingAccount_Call{Call: _e.mock.On("GetVestingAccount", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_GetVestingAccount_Call) Run(run func(ctx context.Context, in *types.QueryGetVestingAccountRequest, opts ...grpc.CallOption)) *LaunchClient_GetVestingAccount_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetVestingAccountRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_GetVestingAccount_Call) Return(_a0 *types.QueryGetVestingAccountResponse, _a1 error) *LaunchClient_GetVestingAccount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_GetVestingAccount_Call) RunAndReturn(run func(context.Context, *types.QueryGetVestingAccountRequest, ...grpc.CallOption) (*types.QueryGetVestingAccountResponse, error)) *LaunchClient_GetVestingAccount_Call { + _c.Call.Return(run) + return _c +} + +// ListChain provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) ListChain(ctx context.Context, in *types.QueryAllChainRequest, opts ...grpc.CallOption) (*types.QueryAllChainResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListChain") + } + + var r0 *types.QueryAllChainResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllChainRequest, ...grpc.CallOption) (*types.QueryAllChainResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllChainRequest, ...grpc.CallOption) *types.QueryAllChainResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllChainResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllChainRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_ListChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListChain' +type LaunchClient_ListChain_Call struct { + *mock.Call +} + +// ListChain is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllChainRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) ListChain(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_ListChain_Call { + return &LaunchClient_ListChain_Call{Call: _e.mock.On("ListChain", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_ListChain_Call) Run(run func(ctx context.Context, in *types.QueryAllChainRequest, opts ...grpc.CallOption)) *LaunchClient_ListChain_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllChainRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_ListChain_Call) Return(_a0 *types.QueryAllChainResponse, _a1 error) *LaunchClient_ListChain_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_ListChain_Call) RunAndReturn(run func(context.Context, *types.QueryAllChainRequest, ...grpc.CallOption) (*types.QueryAllChainResponse, error)) *LaunchClient_ListChain_Call { + _c.Call.Return(run) + return _c +} + +// ListGenesisAccount provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) ListGenesisAccount(ctx context.Context, in *types.QueryAllGenesisAccountRequest, opts ...grpc.CallOption) (*types.QueryAllGenesisAccountResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListGenesisAccount") + } + + var r0 *types.QueryAllGenesisAccountResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllGenesisAccountRequest, ...grpc.CallOption) (*types.QueryAllGenesisAccountResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllGenesisAccountRequest, ...grpc.CallOption) *types.QueryAllGenesisAccountResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllGenesisAccountResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllGenesisAccountRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_ListGenesisAccount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListGenesisAccount' +type LaunchClient_ListGenesisAccount_Call struct { + *mock.Call +} + +// ListGenesisAccount is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllGenesisAccountRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) ListGenesisAccount(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_ListGenesisAccount_Call { + return &LaunchClient_ListGenesisAccount_Call{Call: _e.mock.On("ListGenesisAccount", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_ListGenesisAccount_Call) Run(run func(ctx context.Context, in *types.QueryAllGenesisAccountRequest, opts ...grpc.CallOption)) *LaunchClient_ListGenesisAccount_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllGenesisAccountRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_ListGenesisAccount_Call) Return(_a0 *types.QueryAllGenesisAccountResponse, _a1 error) *LaunchClient_ListGenesisAccount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_ListGenesisAccount_Call) RunAndReturn(run func(context.Context, *types.QueryAllGenesisAccountRequest, ...grpc.CallOption) (*types.QueryAllGenesisAccountResponse, error)) *LaunchClient_ListGenesisAccount_Call { + _c.Call.Return(run) + return _c +} + +// ListGenesisValidator provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) ListGenesisValidator(ctx context.Context, in *types.QueryAllGenesisValidatorRequest, opts ...grpc.CallOption) (*types.QueryAllGenesisValidatorResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListGenesisValidator") + } + + var r0 *types.QueryAllGenesisValidatorResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllGenesisValidatorRequest, ...grpc.CallOption) (*types.QueryAllGenesisValidatorResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllGenesisValidatorRequest, ...grpc.CallOption) *types.QueryAllGenesisValidatorResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllGenesisValidatorResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllGenesisValidatorRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_ListGenesisValidator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListGenesisValidator' +type LaunchClient_ListGenesisValidator_Call struct { + *mock.Call +} + +// ListGenesisValidator is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllGenesisValidatorRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) ListGenesisValidator(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_ListGenesisValidator_Call { + return &LaunchClient_ListGenesisValidator_Call{Call: _e.mock.On("ListGenesisValidator", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_ListGenesisValidator_Call) Run(run func(ctx context.Context, in *types.QueryAllGenesisValidatorRequest, opts ...grpc.CallOption)) *LaunchClient_ListGenesisValidator_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllGenesisValidatorRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_ListGenesisValidator_Call) Return(_a0 *types.QueryAllGenesisValidatorResponse, _a1 error) *LaunchClient_ListGenesisValidator_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_ListGenesisValidator_Call) RunAndReturn(run func(context.Context, *types.QueryAllGenesisValidatorRequest, ...grpc.CallOption) (*types.QueryAllGenesisValidatorResponse, error)) *LaunchClient_ListGenesisValidator_Call { + _c.Call.Return(run) + return _c +} + +// ListParamChange provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) ListParamChange(ctx context.Context, in *types.QueryAllParamChangeRequest, opts ...grpc.CallOption) (*types.QueryAllParamChangeResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListParamChange") + } + + var r0 *types.QueryAllParamChangeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllParamChangeRequest, ...grpc.CallOption) (*types.QueryAllParamChangeResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllParamChangeRequest, ...grpc.CallOption) *types.QueryAllParamChangeResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllParamChangeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllParamChangeRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_ListParamChange_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListParamChange' +type LaunchClient_ListParamChange_Call struct { + *mock.Call +} + +// ListParamChange is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllParamChangeRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) ListParamChange(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_ListParamChange_Call { + return &LaunchClient_ListParamChange_Call{Call: _e.mock.On("ListParamChange", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_ListParamChange_Call) Run(run func(ctx context.Context, in *types.QueryAllParamChangeRequest, opts ...grpc.CallOption)) *LaunchClient_ListParamChange_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllParamChangeRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_ListParamChange_Call) Return(_a0 *types.QueryAllParamChangeResponse, _a1 error) *LaunchClient_ListParamChange_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_ListParamChange_Call) RunAndReturn(run func(context.Context, *types.QueryAllParamChangeRequest, ...grpc.CallOption) (*types.QueryAllParamChangeResponse, error)) *LaunchClient_ListParamChange_Call { + _c.Call.Return(run) + return _c +} + +// ListRequest provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) ListRequest(ctx context.Context, in *types.QueryAllRequestRequest, opts ...grpc.CallOption) (*types.QueryAllRequestResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListRequest") + } + + var r0 *types.QueryAllRequestResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllRequestRequest, ...grpc.CallOption) (*types.QueryAllRequestResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllRequestRequest, ...grpc.CallOption) *types.QueryAllRequestResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllRequestResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllRequestRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_ListRequest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListRequest' +type LaunchClient_ListRequest_Call struct { + *mock.Call +} + +// ListRequest is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllRequestRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) ListRequest(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_ListRequest_Call { + return &LaunchClient_ListRequest_Call{Call: _e.mock.On("ListRequest", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_ListRequest_Call) Run(run func(ctx context.Context, in *types.QueryAllRequestRequest, opts ...grpc.CallOption)) *LaunchClient_ListRequest_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllRequestRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_ListRequest_Call) Return(_a0 *types.QueryAllRequestResponse, _a1 error) *LaunchClient_ListRequest_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_ListRequest_Call) RunAndReturn(run func(context.Context, *types.QueryAllRequestRequest, ...grpc.CallOption) (*types.QueryAllRequestResponse, error)) *LaunchClient_ListRequest_Call { + _c.Call.Return(run) + return _c +} + +// ListVestingAccount provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) ListVestingAccount(ctx context.Context, in *types.QueryAllVestingAccountRequest, opts ...grpc.CallOption) (*types.QueryAllVestingAccountResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListVestingAccount") + } + + var r0 *types.QueryAllVestingAccountResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllVestingAccountRequest, ...grpc.CallOption) (*types.QueryAllVestingAccountResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllVestingAccountRequest, ...grpc.CallOption) *types.QueryAllVestingAccountResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllVestingAccountResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllVestingAccountRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_ListVestingAccount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListVestingAccount' +type LaunchClient_ListVestingAccount_Call struct { + *mock.Call +} + +// ListVestingAccount is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllVestingAccountRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) ListVestingAccount(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_ListVestingAccount_Call { + return &LaunchClient_ListVestingAccount_Call{Call: _e.mock.On("ListVestingAccount", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_ListVestingAccount_Call) Run(run func(ctx context.Context, in *types.QueryAllVestingAccountRequest, opts ...grpc.CallOption)) *LaunchClient_ListVestingAccount_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllVestingAccountRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_ListVestingAccount_Call) Return(_a0 *types.QueryAllVestingAccountResponse, _a1 error) *LaunchClient_ListVestingAccount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_ListVestingAccount_Call) RunAndReturn(run func(context.Context, *types.QueryAllVestingAccountRequest, ...grpc.CallOption) (*types.QueryAllVestingAccountResponse, error)) *LaunchClient_ListVestingAccount_Call { + _c.Call.Return(run) + return _c +} + +// Params provides a mock function with given fields: ctx, in, opts +func (_m *LaunchClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Params") + } + + var r0 *types.QueryParamsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryParamsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchClient_Params_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Params' +type LaunchClient_Params_Call struct { + *mock.Call +} + +// Params is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryParamsRequest +// - opts ...grpc.CallOption +func (_e *LaunchClient_Expecter) Params(ctx interface{}, in interface{}, opts ...interface{}) *LaunchClient_Params_Call { + return &LaunchClient_Params_Call{Call: _e.mock.On("Params", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *LaunchClient_Params_Call) Run(run func(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption)) *LaunchClient_Params_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryParamsRequest), variadicArgs...) + }) + return _c +} + +func (_c *LaunchClient_Params_Call) Return(_a0 *types.QueryParamsResponse, _a1 error) *LaunchClient_Params_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LaunchClient_Params_Call) RunAndReturn(run func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)) *LaunchClient_Params_Call { + _c.Call.Return(run) + return _c +} + +// NewLaunchClient creates a new instance of LaunchClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewLaunchClient(t interface { + mock.TestingT + Cleanup(func()) +}) *LaunchClient { + mock := &LaunchClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/monitoringc_client.go b/network/network/mocks/monitoringc_client.go new file mode 100644 index 00000000..a6a7f98f --- /dev/null +++ b/network/network/mocks/monitoringc_client.go @@ -0,0 +1,556 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/ignite/network/x/monitoringc/types" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +// MonitoringcClient is an autogenerated mock type for the MonitoringcClient type +type MonitoringcClient struct { + mock.Mock +} + +type MonitoringcClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MonitoringcClient) EXPECT() *MonitoringcClient_Expecter { + return &MonitoringcClient_Expecter{mock: &_m.Mock} +} + +// GetLaunchIDFromChannelID provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringcClient) GetLaunchIDFromChannelID(ctx context.Context, in *types.QueryGetLaunchIDFromChannelIDRequest, opts ...grpc.CallOption) (*types.QueryGetLaunchIDFromChannelIDResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetLaunchIDFromChannelID") + } + + var r0 *types.QueryGetLaunchIDFromChannelIDResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetLaunchIDFromChannelIDRequest, ...grpc.CallOption) (*types.QueryGetLaunchIDFromChannelIDResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetLaunchIDFromChannelIDRequest, ...grpc.CallOption) *types.QueryGetLaunchIDFromChannelIDResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetLaunchIDFromChannelIDResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetLaunchIDFromChannelIDRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringcClient_GetLaunchIDFromChannelID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLaunchIDFromChannelID' +type MonitoringcClient_GetLaunchIDFromChannelID_Call struct { + *mock.Call +} + +// GetLaunchIDFromChannelID is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetLaunchIDFromChannelIDRequest +// - opts ...grpc.CallOption +func (_e *MonitoringcClient_Expecter) GetLaunchIDFromChannelID(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringcClient_GetLaunchIDFromChannelID_Call { + return &MonitoringcClient_GetLaunchIDFromChannelID_Call{Call: _e.mock.On("GetLaunchIDFromChannelID", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringcClient_GetLaunchIDFromChannelID_Call) Run(run func(ctx context.Context, in *types.QueryGetLaunchIDFromChannelIDRequest, opts ...grpc.CallOption)) *MonitoringcClient_GetLaunchIDFromChannelID_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetLaunchIDFromChannelIDRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringcClient_GetLaunchIDFromChannelID_Call) Return(_a0 *types.QueryGetLaunchIDFromChannelIDResponse, _a1 error) *MonitoringcClient_GetLaunchIDFromChannelID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringcClient_GetLaunchIDFromChannelID_Call) RunAndReturn(run func(context.Context, *types.QueryGetLaunchIDFromChannelIDRequest, ...grpc.CallOption) (*types.QueryGetLaunchIDFromChannelIDResponse, error)) *MonitoringcClient_GetLaunchIDFromChannelID_Call { + _c.Call.Return(run) + return _c +} + +// GetMonitoringHistory provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringcClient) GetMonitoringHistory(ctx context.Context, in *types.QueryGetMonitoringHistoryRequest, opts ...grpc.CallOption) (*types.QueryGetMonitoringHistoryResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetMonitoringHistory") + } + + var r0 *types.QueryGetMonitoringHistoryResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetMonitoringHistoryRequest, ...grpc.CallOption) (*types.QueryGetMonitoringHistoryResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetMonitoringHistoryRequest, ...grpc.CallOption) *types.QueryGetMonitoringHistoryResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetMonitoringHistoryResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetMonitoringHistoryRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringcClient_GetMonitoringHistory_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetMonitoringHistory' +type MonitoringcClient_GetMonitoringHistory_Call struct { + *mock.Call +} + +// GetMonitoringHistory is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetMonitoringHistoryRequest +// - opts ...grpc.CallOption +func (_e *MonitoringcClient_Expecter) GetMonitoringHistory(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringcClient_GetMonitoringHistory_Call { + return &MonitoringcClient_GetMonitoringHistory_Call{Call: _e.mock.On("GetMonitoringHistory", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringcClient_GetMonitoringHistory_Call) Run(run func(ctx context.Context, in *types.QueryGetMonitoringHistoryRequest, opts ...grpc.CallOption)) *MonitoringcClient_GetMonitoringHistory_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetMonitoringHistoryRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringcClient_GetMonitoringHistory_Call) Return(_a0 *types.QueryGetMonitoringHistoryResponse, _a1 error) *MonitoringcClient_GetMonitoringHistory_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringcClient_GetMonitoringHistory_Call) RunAndReturn(run func(context.Context, *types.QueryGetMonitoringHistoryRequest, ...grpc.CallOption) (*types.QueryGetMonitoringHistoryResponse, error)) *MonitoringcClient_GetMonitoringHistory_Call { + _c.Call.Return(run) + return _c +} + +// GetProviderClientID provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringcClient) GetProviderClientID(ctx context.Context, in *types.QueryGetProviderClientIDRequest, opts ...grpc.CallOption) (*types.QueryGetProviderClientIDResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetProviderClientID") + } + + var r0 *types.QueryGetProviderClientIDResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetProviderClientIDRequest, ...grpc.CallOption) (*types.QueryGetProviderClientIDResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetProviderClientIDRequest, ...grpc.CallOption) *types.QueryGetProviderClientIDResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetProviderClientIDResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetProviderClientIDRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringcClient_GetProviderClientID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProviderClientID' +type MonitoringcClient_GetProviderClientID_Call struct { + *mock.Call +} + +// GetProviderClientID is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetProviderClientIDRequest +// - opts ...grpc.CallOption +func (_e *MonitoringcClient_Expecter) GetProviderClientID(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringcClient_GetProviderClientID_Call { + return &MonitoringcClient_GetProviderClientID_Call{Call: _e.mock.On("GetProviderClientID", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringcClient_GetProviderClientID_Call) Run(run func(ctx context.Context, in *types.QueryGetProviderClientIDRequest, opts ...grpc.CallOption)) *MonitoringcClient_GetProviderClientID_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetProviderClientIDRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringcClient_GetProviderClientID_Call) Return(_a0 *types.QueryGetProviderClientIDResponse, _a1 error) *MonitoringcClient_GetProviderClientID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringcClient_GetProviderClientID_Call) RunAndReturn(run func(context.Context, *types.QueryGetProviderClientIDRequest, ...grpc.CallOption) (*types.QueryGetProviderClientIDResponse, error)) *MonitoringcClient_GetProviderClientID_Call { + _c.Call.Return(run) + return _c +} + +// GetVerifiedClientID provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringcClient) GetVerifiedClientID(ctx context.Context, in *types.QueryGetVerifiedClientIDRequest, opts ...grpc.CallOption) (*types.QueryGetVerifiedClientIDResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetVerifiedClientID") + } + + var r0 *types.QueryGetVerifiedClientIDResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetVerifiedClientIDRequest, ...grpc.CallOption) (*types.QueryGetVerifiedClientIDResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetVerifiedClientIDRequest, ...grpc.CallOption) *types.QueryGetVerifiedClientIDResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetVerifiedClientIDResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetVerifiedClientIDRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringcClient_GetVerifiedClientID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetVerifiedClientID' +type MonitoringcClient_GetVerifiedClientID_Call struct { + *mock.Call +} + +// GetVerifiedClientID is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetVerifiedClientIDRequest +// - opts ...grpc.CallOption +func (_e *MonitoringcClient_Expecter) GetVerifiedClientID(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringcClient_GetVerifiedClientID_Call { + return &MonitoringcClient_GetVerifiedClientID_Call{Call: _e.mock.On("GetVerifiedClientID", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringcClient_GetVerifiedClientID_Call) Run(run func(ctx context.Context, in *types.QueryGetVerifiedClientIDRequest, opts ...grpc.CallOption)) *MonitoringcClient_GetVerifiedClientID_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetVerifiedClientIDRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringcClient_GetVerifiedClientID_Call) Return(_a0 *types.QueryGetVerifiedClientIDResponse, _a1 error) *MonitoringcClient_GetVerifiedClientID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringcClient_GetVerifiedClientID_Call) RunAndReturn(run func(context.Context, *types.QueryGetVerifiedClientIDRequest, ...grpc.CallOption) (*types.QueryGetVerifiedClientIDResponse, error)) *MonitoringcClient_GetVerifiedClientID_Call { + _c.Call.Return(run) + return _c +} + +// ListLaunchIDFromChannelID provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringcClient) ListLaunchIDFromChannelID(ctx context.Context, in *types.QueryAllLaunchIDFromChannelIDRequest, opts ...grpc.CallOption) (*types.QueryAllLaunchIDFromChannelIDResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListLaunchIDFromChannelID") + } + + var r0 *types.QueryAllLaunchIDFromChannelIDResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllLaunchIDFromChannelIDRequest, ...grpc.CallOption) (*types.QueryAllLaunchIDFromChannelIDResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllLaunchIDFromChannelIDRequest, ...grpc.CallOption) *types.QueryAllLaunchIDFromChannelIDResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllLaunchIDFromChannelIDResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllLaunchIDFromChannelIDRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringcClient_ListLaunchIDFromChannelID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListLaunchIDFromChannelID' +type MonitoringcClient_ListLaunchIDFromChannelID_Call struct { + *mock.Call +} + +// ListLaunchIDFromChannelID is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllLaunchIDFromChannelIDRequest +// - opts ...grpc.CallOption +func (_e *MonitoringcClient_Expecter) ListLaunchIDFromChannelID(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringcClient_ListLaunchIDFromChannelID_Call { + return &MonitoringcClient_ListLaunchIDFromChannelID_Call{Call: _e.mock.On("ListLaunchIDFromChannelID", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringcClient_ListLaunchIDFromChannelID_Call) Run(run func(ctx context.Context, in *types.QueryAllLaunchIDFromChannelIDRequest, opts ...grpc.CallOption)) *MonitoringcClient_ListLaunchIDFromChannelID_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllLaunchIDFromChannelIDRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringcClient_ListLaunchIDFromChannelID_Call) Return(_a0 *types.QueryAllLaunchIDFromChannelIDResponse, _a1 error) *MonitoringcClient_ListLaunchIDFromChannelID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringcClient_ListLaunchIDFromChannelID_Call) RunAndReturn(run func(context.Context, *types.QueryAllLaunchIDFromChannelIDRequest, ...grpc.CallOption) (*types.QueryAllLaunchIDFromChannelIDResponse, error)) *MonitoringcClient_ListLaunchIDFromChannelID_Call { + _c.Call.Return(run) + return _c +} + +// ListProviderClientID provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringcClient) ListProviderClientID(ctx context.Context, in *types.QueryAllProviderClientIDRequest, opts ...grpc.CallOption) (*types.QueryAllProviderClientIDResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListProviderClientID") + } + + var r0 *types.QueryAllProviderClientIDResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllProviderClientIDRequest, ...grpc.CallOption) (*types.QueryAllProviderClientIDResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllProviderClientIDRequest, ...grpc.CallOption) *types.QueryAllProviderClientIDResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllProviderClientIDResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllProviderClientIDRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringcClient_ListProviderClientID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListProviderClientID' +type MonitoringcClient_ListProviderClientID_Call struct { + *mock.Call +} + +// ListProviderClientID is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllProviderClientIDRequest +// - opts ...grpc.CallOption +func (_e *MonitoringcClient_Expecter) ListProviderClientID(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringcClient_ListProviderClientID_Call { + return &MonitoringcClient_ListProviderClientID_Call{Call: _e.mock.On("ListProviderClientID", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringcClient_ListProviderClientID_Call) Run(run func(ctx context.Context, in *types.QueryAllProviderClientIDRequest, opts ...grpc.CallOption)) *MonitoringcClient_ListProviderClientID_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllProviderClientIDRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringcClient_ListProviderClientID_Call) Return(_a0 *types.QueryAllProviderClientIDResponse, _a1 error) *MonitoringcClient_ListProviderClientID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringcClient_ListProviderClientID_Call) RunAndReturn(run func(context.Context, *types.QueryAllProviderClientIDRequest, ...grpc.CallOption) (*types.QueryAllProviderClientIDResponse, error)) *MonitoringcClient_ListProviderClientID_Call { + _c.Call.Return(run) + return _c +} + +// Params provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringcClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Params") + } + + var r0 *types.QueryParamsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryParamsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringcClient_Params_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Params' +type MonitoringcClient_Params_Call struct { + *mock.Call +} + +// Params is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryParamsRequest +// - opts ...grpc.CallOption +func (_e *MonitoringcClient_Expecter) Params(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringcClient_Params_Call { + return &MonitoringcClient_Params_Call{Call: _e.mock.On("Params", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringcClient_Params_Call) Run(run func(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption)) *MonitoringcClient_Params_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryParamsRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringcClient_Params_Call) Return(_a0 *types.QueryParamsResponse, _a1 error) *MonitoringcClient_Params_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringcClient_Params_Call) RunAndReturn(run func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)) *MonitoringcClient_Params_Call { + _c.Call.Return(run) + return _c +} + +// NewMonitoringcClient creates a new instance of MonitoringcClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMonitoringcClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MonitoringcClient { + mock := &MonitoringcClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/monitoringp_client.go b/network/network/mocks/monitoringp_client.go new file mode 100644 index 00000000..b3a1dca7 --- /dev/null +++ b/network/network/mocks/monitoringp_client.go @@ -0,0 +1,334 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/ignite/network/x/monitoringp/types" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +// MonitoringpClient is an autogenerated mock type for the MonitoringpClient type +type MonitoringpClient struct { + mock.Mock +} + +type MonitoringpClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MonitoringpClient) EXPECT() *MonitoringpClient_Expecter { + return &MonitoringpClient_Expecter{mock: &_m.Mock} +} + +// GetConnectionChannelID provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringpClient) GetConnectionChannelID(ctx context.Context, in *types.QueryGetConnectionChannelIDRequest, opts ...grpc.CallOption) (*types.QueryGetConnectionChannelIDResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetConnectionChannelID") + } + + var r0 *types.QueryGetConnectionChannelIDResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetConnectionChannelIDRequest, ...grpc.CallOption) (*types.QueryGetConnectionChannelIDResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetConnectionChannelIDRequest, ...grpc.CallOption) *types.QueryGetConnectionChannelIDResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetConnectionChannelIDResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetConnectionChannelIDRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringpClient_GetConnectionChannelID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetConnectionChannelID' +type MonitoringpClient_GetConnectionChannelID_Call struct { + *mock.Call +} + +// GetConnectionChannelID is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetConnectionChannelIDRequest +// - opts ...grpc.CallOption +func (_e *MonitoringpClient_Expecter) GetConnectionChannelID(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringpClient_GetConnectionChannelID_Call { + return &MonitoringpClient_GetConnectionChannelID_Call{Call: _e.mock.On("GetConnectionChannelID", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringpClient_GetConnectionChannelID_Call) Run(run func(ctx context.Context, in *types.QueryGetConnectionChannelIDRequest, opts ...grpc.CallOption)) *MonitoringpClient_GetConnectionChannelID_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetConnectionChannelIDRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringpClient_GetConnectionChannelID_Call) Return(_a0 *types.QueryGetConnectionChannelIDResponse, _a1 error) *MonitoringpClient_GetConnectionChannelID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringpClient_GetConnectionChannelID_Call) RunAndReturn(run func(context.Context, *types.QueryGetConnectionChannelIDRequest, ...grpc.CallOption) (*types.QueryGetConnectionChannelIDResponse, error)) *MonitoringpClient_GetConnectionChannelID_Call { + _c.Call.Return(run) + return _c +} + +// GetConsumerClientID provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringpClient) GetConsumerClientID(ctx context.Context, in *types.QueryGetConsumerClientIDRequest, opts ...grpc.CallOption) (*types.QueryGetConsumerClientIDResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetConsumerClientID") + } + + var r0 *types.QueryGetConsumerClientIDResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetConsumerClientIDRequest, ...grpc.CallOption) (*types.QueryGetConsumerClientIDResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetConsumerClientIDRequest, ...grpc.CallOption) *types.QueryGetConsumerClientIDResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetConsumerClientIDResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetConsumerClientIDRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringpClient_GetConsumerClientID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetConsumerClientID' +type MonitoringpClient_GetConsumerClientID_Call struct { + *mock.Call +} + +// GetConsumerClientID is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetConsumerClientIDRequest +// - opts ...grpc.CallOption +func (_e *MonitoringpClient_Expecter) GetConsumerClientID(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringpClient_GetConsumerClientID_Call { + return &MonitoringpClient_GetConsumerClientID_Call{Call: _e.mock.On("GetConsumerClientID", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringpClient_GetConsumerClientID_Call) Run(run func(ctx context.Context, in *types.QueryGetConsumerClientIDRequest, opts ...grpc.CallOption)) *MonitoringpClient_GetConsumerClientID_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetConsumerClientIDRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringpClient_GetConsumerClientID_Call) Return(_a0 *types.QueryGetConsumerClientIDResponse, _a1 error) *MonitoringpClient_GetConsumerClientID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringpClient_GetConsumerClientID_Call) RunAndReturn(run func(context.Context, *types.QueryGetConsumerClientIDRequest, ...grpc.CallOption) (*types.QueryGetConsumerClientIDResponse, error)) *MonitoringpClient_GetConsumerClientID_Call { + _c.Call.Return(run) + return _c +} + +// GetMonitoringInfo provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringpClient) GetMonitoringInfo(ctx context.Context, in *types.QueryGetMonitoringInfoRequest, opts ...grpc.CallOption) (*types.QueryGetMonitoringInfoResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetMonitoringInfo") + } + + var r0 *types.QueryGetMonitoringInfoResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetMonitoringInfoRequest, ...grpc.CallOption) (*types.QueryGetMonitoringInfoResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetMonitoringInfoRequest, ...grpc.CallOption) *types.QueryGetMonitoringInfoResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetMonitoringInfoResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetMonitoringInfoRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringpClient_GetMonitoringInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetMonitoringInfo' +type MonitoringpClient_GetMonitoringInfo_Call struct { + *mock.Call +} + +// GetMonitoringInfo is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetMonitoringInfoRequest +// - opts ...grpc.CallOption +func (_e *MonitoringpClient_Expecter) GetMonitoringInfo(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringpClient_GetMonitoringInfo_Call { + return &MonitoringpClient_GetMonitoringInfo_Call{Call: _e.mock.On("GetMonitoringInfo", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringpClient_GetMonitoringInfo_Call) Run(run func(ctx context.Context, in *types.QueryGetMonitoringInfoRequest, opts ...grpc.CallOption)) *MonitoringpClient_GetMonitoringInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetMonitoringInfoRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringpClient_GetMonitoringInfo_Call) Return(_a0 *types.QueryGetMonitoringInfoResponse, _a1 error) *MonitoringpClient_GetMonitoringInfo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringpClient_GetMonitoringInfo_Call) RunAndReturn(run func(context.Context, *types.QueryGetMonitoringInfoRequest, ...grpc.CallOption) (*types.QueryGetMonitoringInfoResponse, error)) *MonitoringpClient_GetMonitoringInfo_Call { + _c.Call.Return(run) + return _c +} + +// Params provides a mock function with given fields: ctx, in, opts +func (_m *MonitoringpClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Params") + } + + var r0 *types.QueryParamsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryParamsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MonitoringpClient_Params_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Params' +type MonitoringpClient_Params_Call struct { + *mock.Call +} + +// Params is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryParamsRequest +// - opts ...grpc.CallOption +func (_e *MonitoringpClient_Expecter) Params(ctx interface{}, in interface{}, opts ...interface{}) *MonitoringpClient_Params_Call { + return &MonitoringpClient_Params_Call{Call: _e.mock.On("Params", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MonitoringpClient_Params_Call) Run(run func(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption)) *MonitoringpClient_Params_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryParamsRequest), variadicArgs...) + }) + return _c +} + +func (_c *MonitoringpClient_Params_Call) Return(_a0 *types.QueryParamsResponse, _a1 error) *MonitoringpClient_Params_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MonitoringpClient_Params_Call) RunAndReturn(run func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)) *MonitoringpClient_Params_Call { + _c.Call.Return(run) + return _c +} + +// NewMonitoringpClient creates a new instance of MonitoringpClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMonitoringpClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MonitoringpClient { + mock := &MonitoringpClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/profile_client.go b/network/network/mocks/profile_client.go new file mode 100644 index 00000000..3288ae2d --- /dev/null +++ b/network/network/mocks/profile_client.go @@ -0,0 +1,556 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/ignite/network/x/profile/types" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +// ProfileClient is an autogenerated mock type for the ProfileClient type +type ProfileClient struct { + mock.Mock +} + +type ProfileClient_Expecter struct { + mock *mock.Mock +} + +func (_m *ProfileClient) EXPECT() *ProfileClient_Expecter { + return &ProfileClient_Expecter{mock: &_m.Mock} +} + +// GetCoordinator provides a mock function with given fields: ctx, in, opts +func (_m *ProfileClient) GetCoordinator(ctx context.Context, in *types.QueryGetCoordinatorRequest, opts ...grpc.CallOption) (*types.QueryGetCoordinatorResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetCoordinator") + } + + var r0 *types.QueryGetCoordinatorResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetCoordinatorRequest, ...grpc.CallOption) (*types.QueryGetCoordinatorResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetCoordinatorRequest, ...grpc.CallOption) *types.QueryGetCoordinatorResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetCoordinatorResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetCoordinatorRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProfileClient_GetCoordinator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCoordinator' +type ProfileClient_GetCoordinator_Call struct { + *mock.Call +} + +// GetCoordinator is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetCoordinatorRequest +// - opts ...grpc.CallOption +func (_e *ProfileClient_Expecter) GetCoordinator(ctx interface{}, in interface{}, opts ...interface{}) *ProfileClient_GetCoordinator_Call { + return &ProfileClient_GetCoordinator_Call{Call: _e.mock.On("GetCoordinator", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProfileClient_GetCoordinator_Call) Run(run func(ctx context.Context, in *types.QueryGetCoordinatorRequest, opts ...grpc.CallOption)) *ProfileClient_GetCoordinator_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetCoordinatorRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProfileClient_GetCoordinator_Call) Return(_a0 *types.QueryGetCoordinatorResponse, _a1 error) *ProfileClient_GetCoordinator_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProfileClient_GetCoordinator_Call) RunAndReturn(run func(context.Context, *types.QueryGetCoordinatorRequest, ...grpc.CallOption) (*types.QueryGetCoordinatorResponse, error)) *ProfileClient_GetCoordinator_Call { + _c.Call.Return(run) + return _c +} + +// GetCoordinatorByAddress provides a mock function with given fields: ctx, in, opts +func (_m *ProfileClient) GetCoordinatorByAddress(ctx context.Context, in *types.QueryGetCoordinatorByAddressRequest, opts ...grpc.CallOption) (*types.QueryGetCoordinatorByAddressResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetCoordinatorByAddress") + } + + var r0 *types.QueryGetCoordinatorByAddressResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetCoordinatorByAddressRequest, ...grpc.CallOption) (*types.QueryGetCoordinatorByAddressResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetCoordinatorByAddressRequest, ...grpc.CallOption) *types.QueryGetCoordinatorByAddressResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetCoordinatorByAddressResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetCoordinatorByAddressRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProfileClient_GetCoordinatorByAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCoordinatorByAddress' +type ProfileClient_GetCoordinatorByAddress_Call struct { + *mock.Call +} + +// GetCoordinatorByAddress is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetCoordinatorByAddressRequest +// - opts ...grpc.CallOption +func (_e *ProfileClient_Expecter) GetCoordinatorByAddress(ctx interface{}, in interface{}, opts ...interface{}) *ProfileClient_GetCoordinatorByAddress_Call { + return &ProfileClient_GetCoordinatorByAddress_Call{Call: _e.mock.On("GetCoordinatorByAddress", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProfileClient_GetCoordinatorByAddress_Call) Run(run func(ctx context.Context, in *types.QueryGetCoordinatorByAddressRequest, opts ...grpc.CallOption)) *ProfileClient_GetCoordinatorByAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetCoordinatorByAddressRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProfileClient_GetCoordinatorByAddress_Call) Return(_a0 *types.QueryGetCoordinatorByAddressResponse, _a1 error) *ProfileClient_GetCoordinatorByAddress_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProfileClient_GetCoordinatorByAddress_Call) RunAndReturn(run func(context.Context, *types.QueryGetCoordinatorByAddressRequest, ...grpc.CallOption) (*types.QueryGetCoordinatorByAddressResponse, error)) *ProfileClient_GetCoordinatorByAddress_Call { + _c.Call.Return(run) + return _c +} + +// GetValidator provides a mock function with given fields: ctx, in, opts +func (_m *ProfileClient) GetValidator(ctx context.Context, in *types.QueryGetValidatorRequest, opts ...grpc.CallOption) (*types.QueryGetValidatorResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetValidator") + } + + var r0 *types.QueryGetValidatorResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetValidatorRequest, ...grpc.CallOption) (*types.QueryGetValidatorResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetValidatorRequest, ...grpc.CallOption) *types.QueryGetValidatorResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetValidatorResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetValidatorRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProfileClient_GetValidator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetValidator' +type ProfileClient_GetValidator_Call struct { + *mock.Call +} + +// GetValidator is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetValidatorRequest +// - opts ...grpc.CallOption +func (_e *ProfileClient_Expecter) GetValidator(ctx interface{}, in interface{}, opts ...interface{}) *ProfileClient_GetValidator_Call { + return &ProfileClient_GetValidator_Call{Call: _e.mock.On("GetValidator", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProfileClient_GetValidator_Call) Run(run func(ctx context.Context, in *types.QueryGetValidatorRequest, opts ...grpc.CallOption)) *ProfileClient_GetValidator_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetValidatorRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProfileClient_GetValidator_Call) Return(_a0 *types.QueryGetValidatorResponse, _a1 error) *ProfileClient_GetValidator_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProfileClient_GetValidator_Call) RunAndReturn(run func(context.Context, *types.QueryGetValidatorRequest, ...grpc.CallOption) (*types.QueryGetValidatorResponse, error)) *ProfileClient_GetValidator_Call { + _c.Call.Return(run) + return _c +} + +// GetValidatorByOperatorAddress provides a mock function with given fields: ctx, in, opts +func (_m *ProfileClient) GetValidatorByOperatorAddress(ctx context.Context, in *types.QueryGetValidatorByOperatorAddressRequest, opts ...grpc.CallOption) (*types.QueryGetValidatorByOperatorAddressResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetValidatorByOperatorAddress") + } + + var r0 *types.QueryGetValidatorByOperatorAddressResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetValidatorByOperatorAddressRequest, ...grpc.CallOption) (*types.QueryGetValidatorByOperatorAddressResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetValidatorByOperatorAddressRequest, ...grpc.CallOption) *types.QueryGetValidatorByOperatorAddressResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetValidatorByOperatorAddressResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetValidatorByOperatorAddressRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProfileClient_GetValidatorByOperatorAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetValidatorByOperatorAddress' +type ProfileClient_GetValidatorByOperatorAddress_Call struct { + *mock.Call +} + +// GetValidatorByOperatorAddress is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetValidatorByOperatorAddressRequest +// - opts ...grpc.CallOption +func (_e *ProfileClient_Expecter) GetValidatorByOperatorAddress(ctx interface{}, in interface{}, opts ...interface{}) *ProfileClient_GetValidatorByOperatorAddress_Call { + return &ProfileClient_GetValidatorByOperatorAddress_Call{Call: _e.mock.On("GetValidatorByOperatorAddress", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProfileClient_GetValidatorByOperatorAddress_Call) Run(run func(ctx context.Context, in *types.QueryGetValidatorByOperatorAddressRequest, opts ...grpc.CallOption)) *ProfileClient_GetValidatorByOperatorAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetValidatorByOperatorAddressRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProfileClient_GetValidatorByOperatorAddress_Call) Return(_a0 *types.QueryGetValidatorByOperatorAddressResponse, _a1 error) *ProfileClient_GetValidatorByOperatorAddress_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProfileClient_GetValidatorByOperatorAddress_Call) RunAndReturn(run func(context.Context, *types.QueryGetValidatorByOperatorAddressRequest, ...grpc.CallOption) (*types.QueryGetValidatorByOperatorAddressResponse, error)) *ProfileClient_GetValidatorByOperatorAddress_Call { + _c.Call.Return(run) + return _c +} + +// ListCoordinator provides a mock function with given fields: ctx, in, opts +func (_m *ProfileClient) ListCoordinator(ctx context.Context, in *types.QueryAllCoordinatorRequest, opts ...grpc.CallOption) (*types.QueryAllCoordinatorResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListCoordinator") + } + + var r0 *types.QueryAllCoordinatorResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllCoordinatorRequest, ...grpc.CallOption) (*types.QueryAllCoordinatorResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllCoordinatorRequest, ...grpc.CallOption) *types.QueryAllCoordinatorResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllCoordinatorResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllCoordinatorRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProfileClient_ListCoordinator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListCoordinator' +type ProfileClient_ListCoordinator_Call struct { + *mock.Call +} + +// ListCoordinator is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllCoordinatorRequest +// - opts ...grpc.CallOption +func (_e *ProfileClient_Expecter) ListCoordinator(ctx interface{}, in interface{}, opts ...interface{}) *ProfileClient_ListCoordinator_Call { + return &ProfileClient_ListCoordinator_Call{Call: _e.mock.On("ListCoordinator", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProfileClient_ListCoordinator_Call) Run(run func(ctx context.Context, in *types.QueryAllCoordinatorRequest, opts ...grpc.CallOption)) *ProfileClient_ListCoordinator_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllCoordinatorRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProfileClient_ListCoordinator_Call) Return(_a0 *types.QueryAllCoordinatorResponse, _a1 error) *ProfileClient_ListCoordinator_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProfileClient_ListCoordinator_Call) RunAndReturn(run func(context.Context, *types.QueryAllCoordinatorRequest, ...grpc.CallOption) (*types.QueryAllCoordinatorResponse, error)) *ProfileClient_ListCoordinator_Call { + _c.Call.Return(run) + return _c +} + +// ListValidator provides a mock function with given fields: ctx, in, opts +func (_m *ProfileClient) ListValidator(ctx context.Context, in *types.QueryAllValidatorRequest, opts ...grpc.CallOption) (*types.QueryAllValidatorResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListValidator") + } + + var r0 *types.QueryAllValidatorResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllValidatorRequest, ...grpc.CallOption) (*types.QueryAllValidatorResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllValidatorRequest, ...grpc.CallOption) *types.QueryAllValidatorResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllValidatorResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllValidatorRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProfileClient_ListValidator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListValidator' +type ProfileClient_ListValidator_Call struct { + *mock.Call +} + +// ListValidator is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllValidatorRequest +// - opts ...grpc.CallOption +func (_e *ProfileClient_Expecter) ListValidator(ctx interface{}, in interface{}, opts ...interface{}) *ProfileClient_ListValidator_Call { + return &ProfileClient_ListValidator_Call{Call: _e.mock.On("ListValidator", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProfileClient_ListValidator_Call) Run(run func(ctx context.Context, in *types.QueryAllValidatorRequest, opts ...grpc.CallOption)) *ProfileClient_ListValidator_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllValidatorRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProfileClient_ListValidator_Call) Return(_a0 *types.QueryAllValidatorResponse, _a1 error) *ProfileClient_ListValidator_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProfileClient_ListValidator_Call) RunAndReturn(run func(context.Context, *types.QueryAllValidatorRequest, ...grpc.CallOption) (*types.QueryAllValidatorResponse, error)) *ProfileClient_ListValidator_Call { + _c.Call.Return(run) + return _c +} + +// Params provides a mock function with given fields: ctx, in, opts +func (_m *ProfileClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Params") + } + + var r0 *types.QueryParamsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryParamsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProfileClient_Params_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Params' +type ProfileClient_Params_Call struct { + *mock.Call +} + +// Params is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryParamsRequest +// - opts ...grpc.CallOption +func (_e *ProfileClient_Expecter) Params(ctx interface{}, in interface{}, opts ...interface{}) *ProfileClient_Params_Call { + return &ProfileClient_Params_Call{Call: _e.mock.On("Params", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProfileClient_Params_Call) Run(run func(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption)) *ProfileClient_Params_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryParamsRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProfileClient_Params_Call) Return(_a0 *types.QueryParamsResponse, _a1 error) *ProfileClient_Params_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProfileClient_Params_Call) RunAndReturn(run func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)) *ProfileClient_Params_Call { + _c.Call.Return(run) + return _c +} + +// NewProfileClient creates a new instance of ProfileClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProfileClient(t interface { + mock.TestingT + Cleanup(func()) +}) *ProfileClient { + mock := &ProfileClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/project_client.go b/network/network/mocks/project_client.go new file mode 100644 index 00000000..9d7e8c01 --- /dev/null +++ b/network/network/mocks/project_client.go @@ -0,0 +1,778 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/ignite/network/x/project/types" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +// ProjectClient is an autogenerated mock type for the ProjectClient type +type ProjectClient struct { + mock.Mock +} + +type ProjectClient_Expecter struct { + mock *mock.Mock +} + +func (_m *ProjectClient) EXPECT() *ProjectClient_Expecter { + return &ProjectClient_Expecter{mock: &_m.Mock} +} + +// GetMainnetAccount provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) GetMainnetAccount(ctx context.Context, in *types.QueryGetMainnetAccountRequest, opts ...grpc.CallOption) (*types.QueryGetMainnetAccountResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetMainnetAccount") + } + + var r0 *types.QueryGetMainnetAccountResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetMainnetAccountRequest, ...grpc.CallOption) (*types.QueryGetMainnetAccountResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetMainnetAccountRequest, ...grpc.CallOption) *types.QueryGetMainnetAccountResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetMainnetAccountResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetMainnetAccountRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_GetMainnetAccount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetMainnetAccount' +type ProjectClient_GetMainnetAccount_Call struct { + *mock.Call +} + +// GetMainnetAccount is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetMainnetAccountRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) GetMainnetAccount(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_GetMainnetAccount_Call { + return &ProjectClient_GetMainnetAccount_Call{Call: _e.mock.On("GetMainnetAccount", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_GetMainnetAccount_Call) Run(run func(ctx context.Context, in *types.QueryGetMainnetAccountRequest, opts ...grpc.CallOption)) *ProjectClient_GetMainnetAccount_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetMainnetAccountRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_GetMainnetAccount_Call) Return(_a0 *types.QueryGetMainnetAccountResponse, _a1 error) *ProjectClient_GetMainnetAccount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_GetMainnetAccount_Call) RunAndReturn(run func(context.Context, *types.QueryGetMainnetAccountRequest, ...grpc.CallOption) (*types.QueryGetMainnetAccountResponse, error)) *ProjectClient_GetMainnetAccount_Call { + _c.Call.Return(run) + return _c +} + +// GetProject provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) GetProject(ctx context.Context, in *types.QueryGetProjectRequest, opts ...grpc.CallOption) (*types.QueryGetProjectResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetProject") + } + + var r0 *types.QueryGetProjectResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetProjectRequest, ...grpc.CallOption) (*types.QueryGetProjectResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetProjectRequest, ...grpc.CallOption) *types.QueryGetProjectResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetProjectResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetProjectRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_GetProject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProject' +type ProjectClient_GetProject_Call struct { + *mock.Call +} + +// GetProject is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetProjectRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) GetProject(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_GetProject_Call { + return &ProjectClient_GetProject_Call{Call: _e.mock.On("GetProject", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_GetProject_Call) Run(run func(ctx context.Context, in *types.QueryGetProjectRequest, opts ...grpc.CallOption)) *ProjectClient_GetProject_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetProjectRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_GetProject_Call) Return(_a0 *types.QueryGetProjectResponse, _a1 error) *ProjectClient_GetProject_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_GetProject_Call) RunAndReturn(run func(context.Context, *types.QueryGetProjectRequest, ...grpc.CallOption) (*types.QueryGetProjectResponse, error)) *ProjectClient_GetProject_Call { + _c.Call.Return(run) + return _c +} + +// GetProjectChains provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) GetProjectChains(ctx context.Context, in *types.QueryGetProjectChainsRequest, opts ...grpc.CallOption) (*types.QueryGetProjectChainsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetProjectChains") + } + + var r0 *types.QueryGetProjectChainsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetProjectChainsRequest, ...grpc.CallOption) (*types.QueryGetProjectChainsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetProjectChainsRequest, ...grpc.CallOption) *types.QueryGetProjectChainsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetProjectChainsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetProjectChainsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_GetProjectChains_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProjectChains' +type ProjectClient_GetProjectChains_Call struct { + *mock.Call +} + +// GetProjectChains is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetProjectChainsRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) GetProjectChains(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_GetProjectChains_Call { + return &ProjectClient_GetProjectChains_Call{Call: _e.mock.On("GetProjectChains", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_GetProjectChains_Call) Run(run func(ctx context.Context, in *types.QueryGetProjectChainsRequest, opts ...grpc.CallOption)) *ProjectClient_GetProjectChains_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetProjectChainsRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_GetProjectChains_Call) Return(_a0 *types.QueryGetProjectChainsResponse, _a1 error) *ProjectClient_GetProjectChains_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_GetProjectChains_Call) RunAndReturn(run func(context.Context, *types.QueryGetProjectChainsRequest, ...grpc.CallOption) (*types.QueryGetProjectChainsResponse, error)) *ProjectClient_GetProjectChains_Call { + _c.Call.Return(run) + return _c +} + +// ListMainnetAccount provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) ListMainnetAccount(ctx context.Context, in *types.QueryAllMainnetAccountRequest, opts ...grpc.CallOption) (*types.QueryAllMainnetAccountResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListMainnetAccount") + } + + var r0 *types.QueryAllMainnetAccountResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllMainnetAccountRequest, ...grpc.CallOption) (*types.QueryAllMainnetAccountResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllMainnetAccountRequest, ...grpc.CallOption) *types.QueryAllMainnetAccountResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllMainnetAccountResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllMainnetAccountRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_ListMainnetAccount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListMainnetAccount' +type ProjectClient_ListMainnetAccount_Call struct { + *mock.Call +} + +// ListMainnetAccount is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllMainnetAccountRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) ListMainnetAccount(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_ListMainnetAccount_Call { + return &ProjectClient_ListMainnetAccount_Call{Call: _e.mock.On("ListMainnetAccount", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_ListMainnetAccount_Call) Run(run func(ctx context.Context, in *types.QueryAllMainnetAccountRequest, opts ...grpc.CallOption)) *ProjectClient_ListMainnetAccount_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllMainnetAccountRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_ListMainnetAccount_Call) Return(_a0 *types.QueryAllMainnetAccountResponse, _a1 error) *ProjectClient_ListMainnetAccount_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_ListMainnetAccount_Call) RunAndReturn(run func(context.Context, *types.QueryAllMainnetAccountRequest, ...grpc.CallOption) (*types.QueryAllMainnetAccountResponse, error)) *ProjectClient_ListMainnetAccount_Call { + _c.Call.Return(run) + return _c +} + +// ListMainnetAccountBalance provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) ListMainnetAccountBalance(ctx context.Context, in *types.QueryListMainnetAccountBalanceRequest, opts ...grpc.CallOption) (*types.QueryListMainnetAccountBalanceResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListMainnetAccountBalance") + } + + var r0 *types.QueryListMainnetAccountBalanceResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryListMainnetAccountBalanceRequest, ...grpc.CallOption) (*types.QueryListMainnetAccountBalanceResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryListMainnetAccountBalanceRequest, ...grpc.CallOption) *types.QueryListMainnetAccountBalanceResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryListMainnetAccountBalanceResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryListMainnetAccountBalanceRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_ListMainnetAccountBalance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListMainnetAccountBalance' +type ProjectClient_ListMainnetAccountBalance_Call struct { + *mock.Call +} + +// ListMainnetAccountBalance is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryListMainnetAccountBalanceRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) ListMainnetAccountBalance(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_ListMainnetAccountBalance_Call { + return &ProjectClient_ListMainnetAccountBalance_Call{Call: _e.mock.On("ListMainnetAccountBalance", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_ListMainnetAccountBalance_Call) Run(run func(ctx context.Context, in *types.QueryListMainnetAccountBalanceRequest, opts ...grpc.CallOption)) *ProjectClient_ListMainnetAccountBalance_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryListMainnetAccountBalanceRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_ListMainnetAccountBalance_Call) Return(_a0 *types.QueryListMainnetAccountBalanceResponse, _a1 error) *ProjectClient_ListMainnetAccountBalance_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_ListMainnetAccountBalance_Call) RunAndReturn(run func(context.Context, *types.QueryListMainnetAccountBalanceRequest, ...grpc.CallOption) (*types.QueryListMainnetAccountBalanceResponse, error)) *ProjectClient_ListMainnetAccountBalance_Call { + _c.Call.Return(run) + return _c +} + +// ListProject provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) ListProject(ctx context.Context, in *types.QueryAllProjectRequest, opts ...grpc.CallOption) (*types.QueryAllProjectResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListProject") + } + + var r0 *types.QueryAllProjectResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllProjectRequest, ...grpc.CallOption) (*types.QueryAllProjectResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllProjectRequest, ...grpc.CallOption) *types.QueryAllProjectResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllProjectResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllProjectRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_ListProject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListProject' +type ProjectClient_ListProject_Call struct { + *mock.Call +} + +// ListProject is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllProjectRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) ListProject(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_ListProject_Call { + return &ProjectClient_ListProject_Call{Call: _e.mock.On("ListProject", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_ListProject_Call) Run(run func(ctx context.Context, in *types.QueryAllProjectRequest, opts ...grpc.CallOption)) *ProjectClient_ListProject_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllProjectRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_ListProject_Call) Return(_a0 *types.QueryAllProjectResponse, _a1 error) *ProjectClient_ListProject_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_ListProject_Call) RunAndReturn(run func(context.Context, *types.QueryAllProjectRequest, ...grpc.CallOption) (*types.QueryAllProjectResponse, error)) *ProjectClient_ListProject_Call { + _c.Call.Return(run) + return _c +} + +// MainnetAccountBalance provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) MainnetAccountBalance(ctx context.Context, in *types.QueryMainnetAccountBalanceRequest, opts ...grpc.CallOption) (*types.QueryMainnetAccountBalanceResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for MainnetAccountBalance") + } + + var r0 *types.QueryMainnetAccountBalanceResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryMainnetAccountBalanceRequest, ...grpc.CallOption) (*types.QueryMainnetAccountBalanceResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryMainnetAccountBalanceRequest, ...grpc.CallOption) *types.QueryMainnetAccountBalanceResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryMainnetAccountBalanceResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryMainnetAccountBalanceRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_MainnetAccountBalance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MainnetAccountBalance' +type ProjectClient_MainnetAccountBalance_Call struct { + *mock.Call +} + +// MainnetAccountBalance is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryMainnetAccountBalanceRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) MainnetAccountBalance(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_MainnetAccountBalance_Call { + return &ProjectClient_MainnetAccountBalance_Call{Call: _e.mock.On("MainnetAccountBalance", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_MainnetAccountBalance_Call) Run(run func(ctx context.Context, in *types.QueryMainnetAccountBalanceRequest, opts ...grpc.CallOption)) *ProjectClient_MainnetAccountBalance_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryMainnetAccountBalanceRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_MainnetAccountBalance_Call) Return(_a0 *types.QueryMainnetAccountBalanceResponse, _a1 error) *ProjectClient_MainnetAccountBalance_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_MainnetAccountBalance_Call) RunAndReturn(run func(context.Context, *types.QueryMainnetAccountBalanceRequest, ...grpc.CallOption) (*types.QueryMainnetAccountBalanceResponse, error)) *ProjectClient_MainnetAccountBalance_Call { + _c.Call.Return(run) + return _c +} + +// Params provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Params") + } + + var r0 *types.QueryParamsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryParamsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_Params_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Params' +type ProjectClient_Params_Call struct { + *mock.Call +} + +// Params is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryParamsRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) Params(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_Params_Call { + return &ProjectClient_Params_Call{Call: _e.mock.On("Params", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_Params_Call) Run(run func(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption)) *ProjectClient_Params_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryParamsRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_Params_Call) Return(_a0 *types.QueryParamsResponse, _a1 error) *ProjectClient_Params_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_Params_Call) RunAndReturn(run func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)) *ProjectClient_Params_Call { + _c.Call.Return(run) + return _c +} + +// SpecialAllocationsBalance provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) SpecialAllocationsBalance(ctx context.Context, in *types.QuerySpecialAllocationsBalanceRequest, opts ...grpc.CallOption) (*types.QuerySpecialAllocationsBalanceResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for SpecialAllocationsBalance") + } + + var r0 *types.QuerySpecialAllocationsBalanceResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySpecialAllocationsBalanceRequest, ...grpc.CallOption) (*types.QuerySpecialAllocationsBalanceResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QuerySpecialAllocationsBalanceRequest, ...grpc.CallOption) *types.QuerySpecialAllocationsBalanceResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QuerySpecialAllocationsBalanceResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QuerySpecialAllocationsBalanceRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_SpecialAllocationsBalance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SpecialAllocationsBalance' +type ProjectClient_SpecialAllocationsBalance_Call struct { + *mock.Call +} + +// SpecialAllocationsBalance is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QuerySpecialAllocationsBalanceRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) SpecialAllocationsBalance(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_SpecialAllocationsBalance_Call { + return &ProjectClient_SpecialAllocationsBalance_Call{Call: _e.mock.On("SpecialAllocationsBalance", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_SpecialAllocationsBalance_Call) Run(run func(ctx context.Context, in *types.QuerySpecialAllocationsBalanceRequest, opts ...grpc.CallOption)) *ProjectClient_SpecialAllocationsBalance_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QuerySpecialAllocationsBalanceRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_SpecialAllocationsBalance_Call) Return(_a0 *types.QuerySpecialAllocationsBalanceResponse, _a1 error) *ProjectClient_SpecialAllocationsBalance_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_SpecialAllocationsBalance_Call) RunAndReturn(run func(context.Context, *types.QuerySpecialAllocationsBalanceRequest, ...grpc.CallOption) (*types.QuerySpecialAllocationsBalanceResponse, error)) *ProjectClient_SpecialAllocationsBalance_Call { + _c.Call.Return(run) + return _c +} + +// TotalShares provides a mock function with given fields: ctx, in, opts +func (_m *ProjectClient) TotalShares(ctx context.Context, in *types.QueryTotalSharesRequest, opts ...grpc.CallOption) (*types.QueryTotalSharesResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for TotalShares") + } + + var r0 *types.QueryTotalSharesResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryTotalSharesRequest, ...grpc.CallOption) (*types.QueryTotalSharesResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryTotalSharesRequest, ...grpc.CallOption) *types.QueryTotalSharesResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryTotalSharesResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryTotalSharesRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProjectClient_TotalShares_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TotalShares' +type ProjectClient_TotalShares_Call struct { + *mock.Call +} + +// TotalShares is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryTotalSharesRequest +// - opts ...grpc.CallOption +func (_e *ProjectClient_Expecter) TotalShares(ctx interface{}, in interface{}, opts ...interface{}) *ProjectClient_TotalShares_Call { + return &ProjectClient_TotalShares_Call{Call: _e.mock.On("TotalShares", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *ProjectClient_TotalShares_Call) Run(run func(ctx context.Context, in *types.QueryTotalSharesRequest, opts ...grpc.CallOption)) *ProjectClient_TotalShares_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryTotalSharesRequest), variadicArgs...) + }) + return _c +} + +func (_c *ProjectClient_TotalShares_Call) Return(_a0 *types.QueryTotalSharesResponse, _a1 error) *ProjectClient_TotalShares_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProjectClient_TotalShares_Call) RunAndReturn(run func(context.Context, *types.QueryTotalSharesRequest, ...grpc.CallOption) (*types.QueryTotalSharesResponse, error)) *ProjectClient_TotalShares_Call { + _c.Call.Return(run) + return _c +} + +// NewProjectClient creates a new instance of ProjectClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProjectClient(t interface { + mock.TestingT + Cleanup(func()) +}) *ProjectClient { + mock := &ProjectClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/reward_client.go b/network/network/mocks/reward_client.go new file mode 100644 index 00000000..ab26fd33 --- /dev/null +++ b/network/network/mocks/reward_client.go @@ -0,0 +1,260 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/ignite/network/x/reward/types" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +// RewardClient is an autogenerated mock type for the RewardClient type +type RewardClient struct { + mock.Mock +} + +type RewardClient_Expecter struct { + mock *mock.Mock +} + +func (_m *RewardClient) EXPECT() *RewardClient_Expecter { + return &RewardClient_Expecter{mock: &_m.Mock} +} + +// GetRewardPool provides a mock function with given fields: ctx, in, opts +func (_m *RewardClient) GetRewardPool(ctx context.Context, in *types.QueryGetRewardPoolRequest, opts ...grpc.CallOption) (*types.QueryGetRewardPoolResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetRewardPool") + } + + var r0 *types.QueryGetRewardPoolResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetRewardPoolRequest, ...grpc.CallOption) (*types.QueryGetRewardPoolResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetRewardPoolRequest, ...grpc.CallOption) *types.QueryGetRewardPoolResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetRewardPoolResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetRewardPoolRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RewardClient_GetRewardPool_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRewardPool' +type RewardClient_GetRewardPool_Call struct { + *mock.Call +} + +// GetRewardPool is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryGetRewardPoolRequest +// - opts ...grpc.CallOption +func (_e *RewardClient_Expecter) GetRewardPool(ctx interface{}, in interface{}, opts ...interface{}) *RewardClient_GetRewardPool_Call { + return &RewardClient_GetRewardPool_Call{Call: _e.mock.On("GetRewardPool", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *RewardClient_GetRewardPool_Call) Run(run func(ctx context.Context, in *types.QueryGetRewardPoolRequest, opts ...grpc.CallOption)) *RewardClient_GetRewardPool_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryGetRewardPoolRequest), variadicArgs...) + }) + return _c +} + +func (_c *RewardClient_GetRewardPool_Call) Return(_a0 *types.QueryGetRewardPoolResponse, _a1 error) *RewardClient_GetRewardPool_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *RewardClient_GetRewardPool_Call) RunAndReturn(run func(context.Context, *types.QueryGetRewardPoolRequest, ...grpc.CallOption) (*types.QueryGetRewardPoolResponse, error)) *RewardClient_GetRewardPool_Call { + _c.Call.Return(run) + return _c +} + +// ListRewardPool provides a mock function with given fields: ctx, in, opts +func (_m *RewardClient) ListRewardPool(ctx context.Context, in *types.QueryAllRewardPoolRequest, opts ...grpc.CallOption) (*types.QueryAllRewardPoolResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListRewardPool") + } + + var r0 *types.QueryAllRewardPoolResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllRewardPoolRequest, ...grpc.CallOption) (*types.QueryAllRewardPoolResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllRewardPoolRequest, ...grpc.CallOption) *types.QueryAllRewardPoolResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllRewardPoolResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllRewardPoolRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RewardClient_ListRewardPool_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListRewardPool' +type RewardClient_ListRewardPool_Call struct { + *mock.Call +} + +// ListRewardPool is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryAllRewardPoolRequest +// - opts ...grpc.CallOption +func (_e *RewardClient_Expecter) ListRewardPool(ctx interface{}, in interface{}, opts ...interface{}) *RewardClient_ListRewardPool_Call { + return &RewardClient_ListRewardPool_Call{Call: _e.mock.On("ListRewardPool", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *RewardClient_ListRewardPool_Call) Run(run func(ctx context.Context, in *types.QueryAllRewardPoolRequest, opts ...grpc.CallOption)) *RewardClient_ListRewardPool_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryAllRewardPoolRequest), variadicArgs...) + }) + return _c +} + +func (_c *RewardClient_ListRewardPool_Call) Return(_a0 *types.QueryAllRewardPoolResponse, _a1 error) *RewardClient_ListRewardPool_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *RewardClient_ListRewardPool_Call) RunAndReturn(run func(context.Context, *types.QueryAllRewardPoolRequest, ...grpc.CallOption) (*types.QueryAllRewardPoolResponse, error)) *RewardClient_ListRewardPool_Call { + _c.Call.Return(run) + return _c +} + +// Params provides a mock function with given fields: ctx, in, opts +func (_m *RewardClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Params") + } + + var r0 *types.QueryParamsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryParamsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RewardClient_Params_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Params' +type RewardClient_Params_Call struct { + *mock.Call +} + +// Params is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryParamsRequest +// - opts ...grpc.CallOption +func (_e *RewardClient_Expecter) Params(ctx interface{}, in interface{}, opts ...interface{}) *RewardClient_Params_Call { + return &RewardClient_Params_Call{Call: _e.mock.On("Params", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *RewardClient_Params_Call) Run(run func(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption)) *RewardClient_Params_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryParamsRequest), variadicArgs...) + }) + return _c +} + +func (_c *RewardClient_Params_Call) Return(_a0 *types.QueryParamsResponse, _a1 error) *RewardClient_Params_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *RewardClient_Params_Call) RunAndReturn(run func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)) *RewardClient_Params_Call { + _c.Call.Return(run) + return _c +} + +// NewRewardClient creates a new instance of RewardClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewRewardClient(t interface { + mock.TestingT + Cleanup(func()) +}) *RewardClient { + mock := &RewardClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/mocks/staking_client.go b/network/network/mocks/staking_client.go new file mode 100644 index 00000000..d33c9b42 --- /dev/null +++ b/network/network/mocks/staking_client.go @@ -0,0 +1,1074 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" +) + +// StakingClient is an autogenerated mock type for the StakingClient type +type StakingClient struct { + mock.Mock +} + +type StakingClient_Expecter struct { + mock *mock.Mock +} + +func (_m *StakingClient) EXPECT() *StakingClient_Expecter { + return &StakingClient_Expecter{mock: &_m.Mock} +} + +// Delegation provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) Delegation(ctx context.Context, in *types.QueryDelegationRequest, opts ...grpc.CallOption) (*types.QueryDelegationResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Delegation") + } + + var r0 *types.QueryDelegationResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegationRequest, ...grpc.CallOption) (*types.QueryDelegationResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegationRequest, ...grpc.CallOption) *types.QueryDelegationResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDelegationResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDelegationRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_Delegation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delegation' +type StakingClient_Delegation_Call struct { + *mock.Call +} + +// Delegation is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDelegationRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) Delegation(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_Delegation_Call { + return &StakingClient_Delegation_Call{Call: _e.mock.On("Delegation", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_Delegation_Call) Run(run func(ctx context.Context, in *types.QueryDelegationRequest, opts ...grpc.CallOption)) *StakingClient_Delegation_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDelegationRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_Delegation_Call) Return(_a0 *types.QueryDelegationResponse, _a1 error) *StakingClient_Delegation_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_Delegation_Call) RunAndReturn(run func(context.Context, *types.QueryDelegationRequest, ...grpc.CallOption) (*types.QueryDelegationResponse, error)) *StakingClient_Delegation_Call { + _c.Call.Return(run) + return _c +} + +// DelegatorDelegations provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) DelegatorDelegations(ctx context.Context, in *types.QueryDelegatorDelegationsRequest, opts ...grpc.CallOption) (*types.QueryDelegatorDelegationsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DelegatorDelegations") + } + + var r0 *types.QueryDelegatorDelegationsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegatorDelegationsRequest, ...grpc.CallOption) (*types.QueryDelegatorDelegationsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegatorDelegationsRequest, ...grpc.CallOption) *types.QueryDelegatorDelegationsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDelegatorDelegationsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDelegatorDelegationsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_DelegatorDelegations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DelegatorDelegations' +type StakingClient_DelegatorDelegations_Call struct { + *mock.Call +} + +// DelegatorDelegations is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDelegatorDelegationsRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) DelegatorDelegations(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_DelegatorDelegations_Call { + return &StakingClient_DelegatorDelegations_Call{Call: _e.mock.On("DelegatorDelegations", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_DelegatorDelegations_Call) Run(run func(ctx context.Context, in *types.QueryDelegatorDelegationsRequest, opts ...grpc.CallOption)) *StakingClient_DelegatorDelegations_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDelegatorDelegationsRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_DelegatorDelegations_Call) Return(_a0 *types.QueryDelegatorDelegationsResponse, _a1 error) *StakingClient_DelegatorDelegations_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_DelegatorDelegations_Call) RunAndReturn(run func(context.Context, *types.QueryDelegatorDelegationsRequest, ...grpc.CallOption) (*types.QueryDelegatorDelegationsResponse, error)) *StakingClient_DelegatorDelegations_Call { + _c.Call.Return(run) + return _c +} + +// DelegatorUnbondingDelegations provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) DelegatorUnbondingDelegations(ctx context.Context, in *types.QueryDelegatorUnbondingDelegationsRequest, opts ...grpc.CallOption) (*types.QueryDelegatorUnbondingDelegationsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DelegatorUnbondingDelegations") + } + + var r0 *types.QueryDelegatorUnbondingDelegationsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegatorUnbondingDelegationsRequest, ...grpc.CallOption) (*types.QueryDelegatorUnbondingDelegationsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegatorUnbondingDelegationsRequest, ...grpc.CallOption) *types.QueryDelegatorUnbondingDelegationsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDelegatorUnbondingDelegationsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDelegatorUnbondingDelegationsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_DelegatorUnbondingDelegations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DelegatorUnbondingDelegations' +type StakingClient_DelegatorUnbondingDelegations_Call struct { + *mock.Call +} + +// DelegatorUnbondingDelegations is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDelegatorUnbondingDelegationsRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) DelegatorUnbondingDelegations(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_DelegatorUnbondingDelegations_Call { + return &StakingClient_DelegatorUnbondingDelegations_Call{Call: _e.mock.On("DelegatorUnbondingDelegations", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_DelegatorUnbondingDelegations_Call) Run(run func(ctx context.Context, in *types.QueryDelegatorUnbondingDelegationsRequest, opts ...grpc.CallOption)) *StakingClient_DelegatorUnbondingDelegations_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDelegatorUnbondingDelegationsRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_DelegatorUnbondingDelegations_Call) Return(_a0 *types.QueryDelegatorUnbondingDelegationsResponse, _a1 error) *StakingClient_DelegatorUnbondingDelegations_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_DelegatorUnbondingDelegations_Call) RunAndReturn(run func(context.Context, *types.QueryDelegatorUnbondingDelegationsRequest, ...grpc.CallOption) (*types.QueryDelegatorUnbondingDelegationsResponse, error)) *StakingClient_DelegatorUnbondingDelegations_Call { + _c.Call.Return(run) + return _c +} + +// DelegatorValidator provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) DelegatorValidator(ctx context.Context, in *types.QueryDelegatorValidatorRequest, opts ...grpc.CallOption) (*types.QueryDelegatorValidatorResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DelegatorValidator") + } + + var r0 *types.QueryDelegatorValidatorResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegatorValidatorRequest, ...grpc.CallOption) (*types.QueryDelegatorValidatorResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegatorValidatorRequest, ...grpc.CallOption) *types.QueryDelegatorValidatorResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDelegatorValidatorResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDelegatorValidatorRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_DelegatorValidator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DelegatorValidator' +type StakingClient_DelegatorValidator_Call struct { + *mock.Call +} + +// DelegatorValidator is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDelegatorValidatorRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) DelegatorValidator(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_DelegatorValidator_Call { + return &StakingClient_DelegatorValidator_Call{Call: _e.mock.On("DelegatorValidator", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_DelegatorValidator_Call) Run(run func(ctx context.Context, in *types.QueryDelegatorValidatorRequest, opts ...grpc.CallOption)) *StakingClient_DelegatorValidator_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDelegatorValidatorRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_DelegatorValidator_Call) Return(_a0 *types.QueryDelegatorValidatorResponse, _a1 error) *StakingClient_DelegatorValidator_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_DelegatorValidator_Call) RunAndReturn(run func(context.Context, *types.QueryDelegatorValidatorRequest, ...grpc.CallOption) (*types.QueryDelegatorValidatorResponse, error)) *StakingClient_DelegatorValidator_Call { + _c.Call.Return(run) + return _c +} + +// DelegatorValidators provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) DelegatorValidators(ctx context.Context, in *types.QueryDelegatorValidatorsRequest, opts ...grpc.CallOption) (*types.QueryDelegatorValidatorsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DelegatorValidators") + } + + var r0 *types.QueryDelegatorValidatorsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegatorValidatorsRequest, ...grpc.CallOption) (*types.QueryDelegatorValidatorsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryDelegatorValidatorsRequest, ...grpc.CallOption) *types.QueryDelegatorValidatorsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryDelegatorValidatorsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryDelegatorValidatorsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_DelegatorValidators_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DelegatorValidators' +type StakingClient_DelegatorValidators_Call struct { + *mock.Call +} + +// DelegatorValidators is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryDelegatorValidatorsRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) DelegatorValidators(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_DelegatorValidators_Call { + return &StakingClient_DelegatorValidators_Call{Call: _e.mock.On("DelegatorValidators", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_DelegatorValidators_Call) Run(run func(ctx context.Context, in *types.QueryDelegatorValidatorsRequest, opts ...grpc.CallOption)) *StakingClient_DelegatorValidators_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryDelegatorValidatorsRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_DelegatorValidators_Call) Return(_a0 *types.QueryDelegatorValidatorsResponse, _a1 error) *StakingClient_DelegatorValidators_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_DelegatorValidators_Call) RunAndReturn(run func(context.Context, *types.QueryDelegatorValidatorsRequest, ...grpc.CallOption) (*types.QueryDelegatorValidatorsResponse, error)) *StakingClient_DelegatorValidators_Call { + _c.Call.Return(run) + return _c +} + +// HistoricalInfo provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) HistoricalInfo(ctx context.Context, in *types.QueryHistoricalInfoRequest, opts ...grpc.CallOption) (*types.QueryHistoricalInfoResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for HistoricalInfo") + } + + var r0 *types.QueryHistoricalInfoResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryHistoricalInfoRequest, ...grpc.CallOption) (*types.QueryHistoricalInfoResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryHistoricalInfoRequest, ...grpc.CallOption) *types.QueryHistoricalInfoResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryHistoricalInfoResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryHistoricalInfoRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_HistoricalInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HistoricalInfo' +type StakingClient_HistoricalInfo_Call struct { + *mock.Call +} + +// HistoricalInfo is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryHistoricalInfoRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) HistoricalInfo(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_HistoricalInfo_Call { + return &StakingClient_HistoricalInfo_Call{Call: _e.mock.On("HistoricalInfo", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_HistoricalInfo_Call) Run(run func(ctx context.Context, in *types.QueryHistoricalInfoRequest, opts ...grpc.CallOption)) *StakingClient_HistoricalInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryHistoricalInfoRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_HistoricalInfo_Call) Return(_a0 *types.QueryHistoricalInfoResponse, _a1 error) *StakingClient_HistoricalInfo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_HistoricalInfo_Call) RunAndReturn(run func(context.Context, *types.QueryHistoricalInfoRequest, ...grpc.CallOption) (*types.QueryHistoricalInfoResponse, error)) *StakingClient_HistoricalInfo_Call { + _c.Call.Return(run) + return _c +} + +// Params provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Params") + } + + var r0 *types.QueryParamsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryParamsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_Params_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Params' +type StakingClient_Params_Call struct { + *mock.Call +} + +// Params is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryParamsRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) Params(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_Params_Call { + return &StakingClient_Params_Call{Call: _e.mock.On("Params", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_Params_Call) Run(run func(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption)) *StakingClient_Params_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryParamsRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_Params_Call) Return(_a0 *types.QueryParamsResponse, _a1 error) *StakingClient_Params_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_Params_Call) RunAndReturn(run func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) (*types.QueryParamsResponse, error)) *StakingClient_Params_Call { + _c.Call.Return(run) + return _c +} + +// Pool provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) Pool(ctx context.Context, in *types.QueryPoolRequest, opts ...grpc.CallOption) (*types.QueryPoolResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Pool") + } + + var r0 *types.QueryPoolResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryPoolRequest, ...grpc.CallOption) (*types.QueryPoolResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryPoolRequest, ...grpc.CallOption) *types.QueryPoolResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryPoolResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryPoolRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_Pool_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pool' +type StakingClient_Pool_Call struct { + *mock.Call +} + +// Pool is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryPoolRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) Pool(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_Pool_Call { + return &StakingClient_Pool_Call{Call: _e.mock.On("Pool", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_Pool_Call) Run(run func(ctx context.Context, in *types.QueryPoolRequest, opts ...grpc.CallOption)) *StakingClient_Pool_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryPoolRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_Pool_Call) Return(_a0 *types.QueryPoolResponse, _a1 error) *StakingClient_Pool_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_Pool_Call) RunAndReturn(run func(context.Context, *types.QueryPoolRequest, ...grpc.CallOption) (*types.QueryPoolResponse, error)) *StakingClient_Pool_Call { + _c.Call.Return(run) + return _c +} + +// Redelegations provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) Redelegations(ctx context.Context, in *types.QueryRedelegationsRequest, opts ...grpc.CallOption) (*types.QueryRedelegationsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Redelegations") + } + + var r0 *types.QueryRedelegationsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryRedelegationsRequest, ...grpc.CallOption) (*types.QueryRedelegationsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryRedelegationsRequest, ...grpc.CallOption) *types.QueryRedelegationsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryRedelegationsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryRedelegationsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_Redelegations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Redelegations' +type StakingClient_Redelegations_Call struct { + *mock.Call +} + +// Redelegations is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryRedelegationsRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) Redelegations(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_Redelegations_Call { + return &StakingClient_Redelegations_Call{Call: _e.mock.On("Redelegations", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_Redelegations_Call) Run(run func(ctx context.Context, in *types.QueryRedelegationsRequest, opts ...grpc.CallOption)) *StakingClient_Redelegations_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryRedelegationsRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_Redelegations_Call) Return(_a0 *types.QueryRedelegationsResponse, _a1 error) *StakingClient_Redelegations_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_Redelegations_Call) RunAndReturn(run func(context.Context, *types.QueryRedelegationsRequest, ...grpc.CallOption) (*types.QueryRedelegationsResponse, error)) *StakingClient_Redelegations_Call { + _c.Call.Return(run) + return _c +} + +// UnbondingDelegation provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) UnbondingDelegation(ctx context.Context, in *types.QueryUnbondingDelegationRequest, opts ...grpc.CallOption) (*types.QueryUnbondingDelegationResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for UnbondingDelegation") + } + + var r0 *types.QueryUnbondingDelegationResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryUnbondingDelegationRequest, ...grpc.CallOption) (*types.QueryUnbondingDelegationResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryUnbondingDelegationRequest, ...grpc.CallOption) *types.QueryUnbondingDelegationResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryUnbondingDelegationResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryUnbondingDelegationRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_UnbondingDelegation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UnbondingDelegation' +type StakingClient_UnbondingDelegation_Call struct { + *mock.Call +} + +// UnbondingDelegation is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryUnbondingDelegationRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) UnbondingDelegation(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_UnbondingDelegation_Call { + return &StakingClient_UnbondingDelegation_Call{Call: _e.mock.On("UnbondingDelegation", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_UnbondingDelegation_Call) Run(run func(ctx context.Context, in *types.QueryUnbondingDelegationRequest, opts ...grpc.CallOption)) *StakingClient_UnbondingDelegation_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryUnbondingDelegationRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_UnbondingDelegation_Call) Return(_a0 *types.QueryUnbondingDelegationResponse, _a1 error) *StakingClient_UnbondingDelegation_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_UnbondingDelegation_Call) RunAndReturn(run func(context.Context, *types.QueryUnbondingDelegationRequest, ...grpc.CallOption) (*types.QueryUnbondingDelegationResponse, error)) *StakingClient_UnbondingDelegation_Call { + _c.Call.Return(run) + return _c +} + +// Validator provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) Validator(ctx context.Context, in *types.QueryValidatorRequest, opts ...grpc.CallOption) (*types.QueryValidatorResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Validator") + } + + var r0 *types.QueryValidatorResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryValidatorRequest, ...grpc.CallOption) (*types.QueryValidatorResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryValidatorRequest, ...grpc.CallOption) *types.QueryValidatorResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryValidatorResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryValidatorRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_Validator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Validator' +type StakingClient_Validator_Call struct { + *mock.Call +} + +// Validator is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryValidatorRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) Validator(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_Validator_Call { + return &StakingClient_Validator_Call{Call: _e.mock.On("Validator", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_Validator_Call) Run(run func(ctx context.Context, in *types.QueryValidatorRequest, opts ...grpc.CallOption)) *StakingClient_Validator_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryValidatorRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_Validator_Call) Return(_a0 *types.QueryValidatorResponse, _a1 error) *StakingClient_Validator_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_Validator_Call) RunAndReturn(run func(context.Context, *types.QueryValidatorRequest, ...grpc.CallOption) (*types.QueryValidatorResponse, error)) *StakingClient_Validator_Call { + _c.Call.Return(run) + return _c +} + +// ValidatorDelegations provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) ValidatorDelegations(ctx context.Context, in *types.QueryValidatorDelegationsRequest, opts ...grpc.CallOption) (*types.QueryValidatorDelegationsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ValidatorDelegations") + } + + var r0 *types.QueryValidatorDelegationsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryValidatorDelegationsRequest, ...grpc.CallOption) (*types.QueryValidatorDelegationsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryValidatorDelegationsRequest, ...grpc.CallOption) *types.QueryValidatorDelegationsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryValidatorDelegationsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryValidatorDelegationsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_ValidatorDelegations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ValidatorDelegations' +type StakingClient_ValidatorDelegations_Call struct { + *mock.Call +} + +// ValidatorDelegations is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryValidatorDelegationsRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) ValidatorDelegations(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_ValidatorDelegations_Call { + return &StakingClient_ValidatorDelegations_Call{Call: _e.mock.On("ValidatorDelegations", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_ValidatorDelegations_Call) Run(run func(ctx context.Context, in *types.QueryValidatorDelegationsRequest, opts ...grpc.CallOption)) *StakingClient_ValidatorDelegations_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryValidatorDelegationsRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_ValidatorDelegations_Call) Return(_a0 *types.QueryValidatorDelegationsResponse, _a1 error) *StakingClient_ValidatorDelegations_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_ValidatorDelegations_Call) RunAndReturn(run func(context.Context, *types.QueryValidatorDelegationsRequest, ...grpc.CallOption) (*types.QueryValidatorDelegationsResponse, error)) *StakingClient_ValidatorDelegations_Call { + _c.Call.Return(run) + return _c +} + +// ValidatorUnbondingDelegations provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) ValidatorUnbondingDelegations(ctx context.Context, in *types.QueryValidatorUnbondingDelegationsRequest, opts ...grpc.CallOption) (*types.QueryValidatorUnbondingDelegationsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ValidatorUnbondingDelegations") + } + + var r0 *types.QueryValidatorUnbondingDelegationsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryValidatorUnbondingDelegationsRequest, ...grpc.CallOption) (*types.QueryValidatorUnbondingDelegationsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryValidatorUnbondingDelegationsRequest, ...grpc.CallOption) *types.QueryValidatorUnbondingDelegationsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryValidatorUnbondingDelegationsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryValidatorUnbondingDelegationsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_ValidatorUnbondingDelegations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ValidatorUnbondingDelegations' +type StakingClient_ValidatorUnbondingDelegations_Call struct { + *mock.Call +} + +// ValidatorUnbondingDelegations is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryValidatorUnbondingDelegationsRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) ValidatorUnbondingDelegations(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_ValidatorUnbondingDelegations_Call { + return &StakingClient_ValidatorUnbondingDelegations_Call{Call: _e.mock.On("ValidatorUnbondingDelegations", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_ValidatorUnbondingDelegations_Call) Run(run func(ctx context.Context, in *types.QueryValidatorUnbondingDelegationsRequest, opts ...grpc.CallOption)) *StakingClient_ValidatorUnbondingDelegations_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryValidatorUnbondingDelegationsRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_ValidatorUnbondingDelegations_Call) Return(_a0 *types.QueryValidatorUnbondingDelegationsResponse, _a1 error) *StakingClient_ValidatorUnbondingDelegations_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_ValidatorUnbondingDelegations_Call) RunAndReturn(run func(context.Context, *types.QueryValidatorUnbondingDelegationsRequest, ...grpc.CallOption) (*types.QueryValidatorUnbondingDelegationsResponse, error)) *StakingClient_ValidatorUnbondingDelegations_Call { + _c.Call.Return(run) + return _c +} + +// Validators provides a mock function with given fields: ctx, in, opts +func (_m *StakingClient) Validators(ctx context.Context, in *types.QueryValidatorsRequest, opts ...grpc.CallOption) (*types.QueryValidatorsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Validators") + } + + var r0 *types.QueryValidatorsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryValidatorsRequest, ...grpc.CallOption) (*types.QueryValidatorsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryValidatorsRequest, ...grpc.CallOption) *types.QueryValidatorsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryValidatorsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryValidatorsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// StakingClient_Validators_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Validators' +type StakingClient_Validators_Call struct { + *mock.Call +} + +// Validators is a helper method to define mock.On call +// - ctx context.Context +// - in *types.QueryValidatorsRequest +// - opts ...grpc.CallOption +func (_e *StakingClient_Expecter) Validators(ctx interface{}, in interface{}, opts ...interface{}) *StakingClient_Validators_Call { + return &StakingClient_Validators_Call{Call: _e.mock.On("Validators", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *StakingClient_Validators_Call) Run(run func(ctx context.Context, in *types.QueryValidatorsRequest, opts ...grpc.CallOption)) *StakingClient_Validators_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*types.QueryValidatorsRequest), variadicArgs...) + }) + return _c +} + +func (_c *StakingClient_Validators_Call) Return(_a0 *types.QueryValidatorsResponse, _a1 error) *StakingClient_Validators_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *StakingClient_Validators_Call) RunAndReturn(run func(context.Context, *types.QueryValidatorsRequest, ...grpc.CallOption) (*types.QueryValidatorsResponse, error)) *StakingClient_Validators_Call { + _c.Call.Return(run) + return _c +} + +// NewStakingClient creates a new instance of StakingClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewStakingClient(t interface { + mock.TestingT + Cleanup(func()) +}) *StakingClient { + mock := &StakingClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/network/network/network.go b/network/network/network.go new file mode 100644 index 00000000..1d9a971b --- /dev/null +++ b/network/network/network.go @@ -0,0 +1,155 @@ +package network + +import ( + "context" + "strconv" + + ctypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/cosmos/cosmos-sdk/client" + sdktypes "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" + "github.com/ignite/cli/v28/ignite/pkg/cosmosclient" + "github.com/ignite/cli/v28/ignite/pkg/events" + "github.com/ignite/cli/v28/ignite/pkg/xtime" + launchtypes "github.com/ignite/network/x/launch/types" + monitoringctypes "github.com/ignite/network/x/monitoringc/types" + profiletypes "github.com/ignite/network/x/profile/types" + projecttypes "github.com/ignite/network/x/project/types" + rewardtypes "github.com/ignite/network/x/reward/types" + "github.com/pkg/errors" + + "github.com/ignite/apps/network/network/networktypes" +) + +//go:generate mockery --name CosmosClient +type CosmosClient interface { + Context() client.Context + Status(ctx context.Context) (*ctypes.ResultStatus, error) + ConsensusInfo(ctx context.Context, height int64) (cosmosclient.ConsensusInfo, error) + BroadcastTx(ctx context.Context, account cosmosaccount.Account, msgs ...sdktypes.Msg) (cosmosclient.Response, error) +} + +// Network is network builder. +type Network struct { + node Node + ev events.Bus + cosmos CosmosClient + account cosmosaccount.Account + projectQuery projecttypes.QueryClient + launchQuery launchtypes.QueryClient + profileQuery profiletypes.QueryClient + rewardQuery rewardtypes.QueryClient + stakingQuery stakingtypes.QueryClient + bankQuery banktypes.QueryClient + monitoringConsumerQuery monitoringctypes.QueryClient + clock xtime.Clock +} + +//go:generate mockery --name Chain +type Chain interface { + ID() (string, error) + ChainID() (string, error) + Name() string + SourceURL() string + SourceHash() string + GenesisPath() (string, error) + GentxsPath() (string, error) + DefaultGentxPath() (string, error) + AppTOMLPath() (string, error) + ConfigTOMLPath() (string, error) + NodeID(ctx context.Context) (string, error) + CacheBinary(launchID uint64) error +} + +type Option func(*Network) + +func WithProjectQueryClient(client projecttypes.QueryClient) Option { + return func(n *Network) { + n.projectQuery = client + } +} + +func WithProfileQueryClient(client profiletypes.QueryClient) Option { + return func(n *Network) { + n.profileQuery = client + } +} + +func WithLaunchQueryClient(client launchtypes.QueryClient) Option { + return func(n *Network) { + n.launchQuery = client + } +} + +func WithRewardQueryClient(client rewardtypes.QueryClient) Option { + return func(n *Network) { + n.rewardQuery = client + } +} + +func WithStakingQueryClient(client stakingtypes.QueryClient) Option { + return func(n *Network) { + n.node.stakingQuery = client + } +} + +func WithMonitoringConsumerQueryClient(client monitoringctypes.QueryClient) Option { + return func(n *Network) { + n.monitoringConsumerQuery = client + } +} + +func WithBankQueryClient(client banktypes.QueryClient) Option { + return func(n *Network) { + n.bankQuery = client + } +} + +func WithCustomClock(clock xtime.Clock) Option { + return func(n *Network) { + n.clock = clock + } +} + +// CollectEvents collects events from the network builder. +func CollectEvents(ev events.Bus) Option { + return func(n *Network) { + n.ev = ev + } +} + +// New creates a Builder. +func New(cosmos CosmosClient, account cosmosaccount.Account, options ...Option) Network { + n := Network{ + cosmos: cosmos, + account: account, + node: NewNode(cosmos), + projectQuery: projecttypes.NewQueryClient(cosmos.Context()), + launchQuery: launchtypes.NewQueryClient(cosmos.Context()), + profileQuery: profiletypes.NewQueryClient(cosmos.Context()), + rewardQuery: rewardtypes.NewQueryClient(cosmos.Context()), + stakingQuery: stakingtypes.NewQueryClient(cosmos.Context()), + bankQuery: banktypes.NewQueryClient(cosmos.Context()), + monitoringConsumerQuery: monitoringctypes.NewQueryClient(cosmos.Context()), + clock: xtime.NewClockSystem(), + } + for _, opt := range options { + opt(&n) + } + return n +} + +func ParseID(id string) (uint64, error) { + objID, err := strconv.ParseUint(id, 10, 64) + if err != nil { + return 0, errors.Wrap(err, "error parsing ID") + } + return objID, nil +} + +// AccountAddress returns the address of the account used by the network builder. +func (n Network) AccountAddress() (string, error) { + return n.account.Address(networktypes.SPN) +} diff --git a/network/network/network_test.go b/network/network/network_test.go new file mode 100644 index 00000000..131479cc --- /dev/null +++ b/network/network/network_test.go @@ -0,0 +1,74 @@ +package network + +import ( + "errors" + "testing" + "time" + + "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" + "github.com/ignite/cli/v28/ignite/pkg/xtime" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/testutil" +) + +var sampleTime = time.Unix(1000, 1000) + +func newSuite(account cosmosaccount.Account) (testutil.Suite, Network) { + suite := testutil.NewSuite() + return suite, New( + suite.CosmosClientMock, + account, + WithProjectQueryClient(suite.ProjectQueryMock), + WithLaunchQueryClient(suite.LaunchQueryMock), + WithProfileQueryClient(suite.ProfileQueryMock), + WithRewardQueryClient(suite.RewardClient), + WithStakingQueryClient(suite.StakingClient), + WithMonitoringConsumerQueryClient(suite.MonitoringConsumerClient), + WithBankQueryClient(suite.BankClient), + WithCustomClock(xtime.NewClockMock(sampleTime)), + ) +} + +func TestParseID(t *testing.T) { + tests := []struct { + name string + id string + want uint64 + err error + }{ + { + name: "valid number", + id: "10", + want: 10, + }, + { + name: "invalid uint", + id: "-10", + err: errors.New("error parsing ID: strconv.ParseUint: parsing \"-10\": invalid syntax"), + }, + { + name: "invalid string", + id: "test", + err: errors.New("error parsing ID: strconv.ParseUint: parsing \"test\": invalid syntax"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseID(tt.id) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func SampleSharePercent(t *testing.T, denom string, nominator, denominator uint64) SharePercent { + sp, err := NewSharePercent(denom, nominator, denominator) + require.NoError(t, err) + return sp +} diff --git a/network/network/networkchain/account.go b/network/network/networkchain/account.go new file mode 100644 index 00000000..b1c0be4d --- /dev/null +++ b/network/network/networkchain/account.go @@ -0,0 +1,108 @@ +package networkchain + +import ( + "context" + "errors" + "os" + "path/filepath" + + chaincmdrunner "github.com/ignite/cli/v28/ignite/pkg/chaincmd/runner" + "github.com/ignite/cli/v28/ignite/pkg/cosmosutil" + "github.com/ignite/cli/v28/ignite/pkg/randstr" + "github.com/ignite/cli/v28/ignite/pkg/xos" + "github.com/ignite/cli/v28/ignite/services/chain" +) + +const ( + passphraseLength = 32 + sampleAccount = "alice" + gentxFilename = "gentx.json" +) + +// InitAccount initializes an account for the blockchain and issue a gentx in config/gentx/gentx.json. +func (c Chain) InitAccount(ctx context.Context, v chain.Validator, accountName string) (string, error) { + if !c.isInitialized { + return "", errors.New("the blockchain must be initialized to initialize an account") + } + + chainCmd, err := c.chain.Commands(ctx) + if err != nil { + return "", err + } + + // create the chain account. + address, err := c.ImportAccount(ctx, accountName) + if err != nil { + return "", err + } + + // add account into the genesis + err = chainCmd.AddGenesisAccount(ctx, address, v.StakingAmount) + if err != nil { + return "", err + } + + // create the gentx. + issuedGentxPath, err := c.chain.IssueGentx(ctx, v) + if err != nil { + return "", err + } + + // rename the issued gentx into gentx.json + gentxPath := filepath.Join(filepath.Dir(issuedGentxPath), gentxFilename) + return gentxPath, xos.Rename(issuedGentxPath, gentxPath) +} + +// ImportAccount imports an account from Starport into the chain. +// we first export the account into a temporary key file and import it with the chain CLI. +func (c *Chain) ImportAccount(ctx context.Context, name string) (string, error) { + // keys import command of chain CLI requires that the key file is encrypted with a passphrase of at least 8 characters + // we generate a random passphrase to import the account + passphrase := randstr.Runes(passphraseLength) + + // export the key in a temporary file. + armored, err := c.ar.Export(name, passphrase) + if err != nil { + return "", err + } + + keyFile, err := os.CreateTemp("", "") + if err != nil { + return "", err + } + defer os.Remove(keyFile.Name()) + + if _, err := keyFile.Write([]byte(armored)); err != nil { + return "", err + } + + // import the key file into the chain. + chainCmd, err := c.chain.Commands(ctx) + if err != nil { + return "", err + } + + acc, err := chainCmd.ImportAccount(ctx, name, keyFile.Name(), passphrase) + return acc.Address, err +} + +// detectPrefix detects the account address prefix for the chain +// the method, creates a sample account and parses the address prefix from it. +func (c Chain) detectPrefix(ctx context.Context) (string, error) { + chainCmd, err := c.chain.Commands(ctx) + if err != nil { + return "", err + } + + var acc chaincmdrunner.Account + acc, err = chainCmd.ShowAccount(ctx, sampleAccount) + if errors.Is(err, chaincmdrunner.ErrAccountDoesNotExist) { + // the sample account doesn't exist, we create it + acc, err = chainCmd.AddAccount(ctx, sampleAccount, "", "") + } + if err != nil { + return "", err + } + + return cosmosutil.GetAddressPrefix(acc.Address) +} diff --git a/network/network/networkchain/binarycache.go b/network/network/networkchain/binarycache.go new file mode 100644 index 00000000..fe223bc0 --- /dev/null +++ b/network/network/networkchain/binarycache.go @@ -0,0 +1,86 @@ +package networkchain + +import ( + "github.com/ignite/cli/v28/ignite/config" + "github.com/ignite/cli/v28/ignite/pkg/checksum" + "github.com/ignite/cli/v28/ignite/pkg/confile" + "github.com/ignite/cli/v28/ignite/pkg/xfilepath" +) + +const ( + SPNCacheDirectory = "spn" + BinaryCacheDirectory = "binary-cache" + BinaryCacheFilename = "checksums.yml" +) + +type BinaryCacheList struct { + CachedBinaries []Binary `yaml:"cached_binaries"` +} + +// Binary associates launch id with build hash where build hash is sha256(binary, source).. +type Binary struct { + LaunchID uint64 + BuildHash string +} + +func (l *BinaryCacheList) Set(launchID uint64, buildHash string) { + for i, binary := range l.CachedBinaries { + if binary.LaunchID == launchID { + l.CachedBinaries[i].BuildHash = buildHash + return + } + } + l.CachedBinaries = append(l.CachedBinaries, Binary{ + LaunchID: launchID, + BuildHash: buildHash, + }) +} + +func (l *BinaryCacheList) Get(launchID uint64) (string, bool) { + for _, binary := range l.CachedBinaries { + if binary.LaunchID == launchID { + return binary.BuildHash, true + } + } + return "", false +} + +// cacheBinaryForLaunchID caches hash sha256(sha256(binary) + sourcehash) for launch id. +func cacheBinaryForLaunchID(launchID uint64, binaryHash, sourceHash string) error { + cachePath, err := getBinaryCacheFilepath() + if err != nil { + return err + } + cacheList := BinaryCacheList{} + err = confile.New(confile.DefaultYAMLEncodingCreator, cachePath).Load(&cacheList) + if err != nil { + return err + } + cacheList.Set(launchID, checksum.Strings(binaryHash, sourceHash)) + + return confile.New(confile.DefaultYAMLEncodingCreator, cachePath).Save(cacheList) +} + +// checkBinaryCacheForLaunchID checks if binary for the given launch was already built. +func checkBinaryCacheForLaunchID(launchID uint64, binaryHash, sourceHash string) (bool, error) { + cachePath, err := getBinaryCacheFilepath() + if err != nil { + return false, err + } + cacheList := BinaryCacheList{} + err = confile.New(confile.DefaultYAMLEncodingCreator, cachePath).Load(&cacheList) + if err != nil { + return false, err + } + buildHash, ok := cacheList.Get(launchID) + return ok && buildHash == checksum.Strings(binaryHash, sourceHash), nil +} + +func getBinaryCacheFilepath() (string, error) { + return xfilepath.Join( + config.DirPath, + xfilepath.Path(SPNCacheDirectory), + xfilepath.Path(BinaryCacheDirectory), + xfilepath.Path(BinaryCacheFilename), + )() +} diff --git a/network/network/networkchain/config.go b/network/network/networkchain/config.go new file mode 100644 index 00000000..617a2de7 --- /dev/null +++ b/network/network/networkchain/config.go @@ -0,0 +1,50 @@ +package networkchain + +import ( + "path/filepath" + + "github.com/ignite/cli/v28/ignite/pkg/confile" + "github.com/ignite/cli/v28/ignite/pkg/cosmosutil" +) + +const ( + HTTPTunnelChisel = "chisel" +) + +const SPNConfigFile = "spn.yml" + +type Config struct { + TunneledPeers []TunneledPeer `json:"tunneled_peers" yaml:"tunneled_peers"` +} + +// TunneledPeer represents http tunnel to a peer which can't be reached via regular tcp connection. +type TunneledPeer struct { + // Name represents tunnel type e.g. "chisel" + Name string `json:"name" yaml:"name"` + + // Address represents http address of the tunnel e.g. "https://tendermint-starport-i5e75cplx02.ws-eu31.gitpod.io/" + Address string `json:"address" yaml:"address"` + + // NodeID tendermint node id of the node behind the tunnel e.g. "e6a59e37b2761f26a21c9168f78a7f2b07c120c7" + NodeID string `json:"node_id" yaml:"node_id"` + + // LocalPort specifies port which has to be used for local tunnel client + LocalPort string `json:"local_port" yaml:"local_port"` +} + +func GetSPNConfig(path string) (conf Config, err error) { + err = confile.New(confile.DefaultYAMLEncodingCreator, path).Load(&conf) + return +} + +func SetSPNConfig(config Config, path string) error { + return confile.New(confile.DefaultYAMLEncodingCreator, path).Save(config) +} + +func (c *Chain) SPNConfigPath() (string, error) { + home, err := c.Home() + if err != nil { + return "", err + } + return filepath.Join(home, cosmosutil.ChainConfigDir, SPNConfigFile), nil +} diff --git a/network/network/networkchain/home.go b/network/network/networkchain/home.go new file mode 100644 index 00000000..ea640363 --- /dev/null +++ b/network/network/networkchain/home.go @@ -0,0 +1,30 @@ +package networkchain + +import ( + "os" + "path/filepath" + "strconv" + + "github.com/ignite/apps/network/network/networktypes" +) + +// ChainHome returns the default home dir used for a chain from SPN. +func ChainHome(launchID uint64) (path string) { + home, err := os.UserHomeDir() + if err != nil { + panic(err) + } + + return filepath.Join(home, networktypes.SPN, strconv.FormatUint(launchID, 10)) +} + +// IsChainHomeExist checks if a home with the provided launchID already exist. +func IsChainHomeExist(launchID uint64) (path string, ok bool, err error) { + home := ChainHome(launchID) + + if _, err := os.Stat(home); os.IsNotExist(err) { + return home, false, nil + } + + return home, true, nil +} diff --git a/network/network/networkchain/home_test.go b/network/network/networkchain/home_test.go new file mode 100644 index 00000000..6d920924 --- /dev/null +++ b/network/network/networkchain/home_test.go @@ -0,0 +1,23 @@ +package networkchain_test + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networkchain" + "github.com/ignite/apps/network/network/networktypes" +) + +func TestChainHome(t *testing.T) { + home, err := os.UserHomeDir() + require.NoError(t, err) + + chainHome := networkchain.ChainHome(0) + require.Equal(t, filepath.Join(home, networktypes.SPN, "0"), chainHome) + + chainHome = networkchain.ChainHome(10) + require.Equal(t, filepath.Join(home, networktypes.SPN, "10"), chainHome) +} diff --git a/network/network/networkchain/init.go b/network/network/networkchain/init.go new file mode 100644 index 00000000..bf990960 --- /dev/null +++ b/network/network/networkchain/init.go @@ -0,0 +1,206 @@ +package networkchain + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + + chainconfig "github.com/ignite/cli/v28/ignite/config/chain" + "github.com/ignite/cli/v28/ignite/pkg/cache" + cosmosgenesis "github.com/ignite/cli/v28/ignite/pkg/cosmosutil/genesis" + "github.com/ignite/cli/v28/ignite/pkg/events" + "github.com/ignite/cli/v28/ignite/services/chain" +) + +// Init initializes blockchain by building the binaries and running the init command, +// creates the initial genesis of the chain, and sets up a validator key. +func (c *Chain) Init(ctx context.Context, cacheStorage cache.Storage) error { + chainHome, err := c.chain.Home() + if err != nil { + return err + } + + // cleanup home dir of app if exists. + if err = os.RemoveAll(chainHome); err != nil { + return err + } + + // build the chain and initialize it with a new validator key + if _, err := c.Build(ctx, cacheStorage); err != nil { + return err + } + + c.ev.Send("Initializing the blockchain", events.ProgressStart()) + + if err = c.chain.Init(ctx, chain.InitArgsNone); err != nil { + return err + } + + c.ev.Send("Blockchain initialized", events.ProgressFinish()) + + // initialize and verify the genesis + if err = c.initGenesis(ctx); err != nil { + return err + } + + c.isInitialized = true + + return nil +} + +// initGenesis creates the initial genesis of the genesis depending on the initial genesis type (default, url, ...) +func (c *Chain) initGenesis(ctx context.Context) error { + c.ev.Send("Computing the Genesis", events.ProgressStart()) + + genesisPath, err := c.chain.GenesisPath() + if err != nil { + return err + } + + // remove existing genesis + if err := os.RemoveAll(genesisPath); err != nil { + return err + } + + // if the blockchain has a genesis URL, the initial genesis is fetched from the URL + // otherwise, the default genesis is used, which requires no action since the default genesis is generated from the init command + switch { + case c.genesisURL != "": + c.ev.Send("Fetching custom Genesis from URL", events.ProgressUpdate()) + genesis, err := cosmosgenesis.FromURL(ctx, c.genesisURL, genesisPath) + if err != nil { + return err + } + + if genesis.TarballPath() != "" { + c.ev.Send( + fmt.Sprintf("Extracted custom Genesis from tarball at %s", genesis.TarballPath()), + events.ProgressFinish(), + ) + } else { + c.ev.Send("Custom Genesis JSON from URL fetched", events.ProgressFinish()) + } + + hash, err := genesis.Hash() + if err != nil { + return err + } + + // if the blockchain has been initialized with no genesis hash, we assign the fetched hash to it + // otherwise we check the genesis integrity with the existing hash + if c.genesisHash == "" { + c.genesisHash = hash + } else if hash != c.genesisHash { + return fmt.Errorf("genesis from URL %s is invalid. expected hash %s, actual hash %s", c.genesisURL, c.genesisHash, hash) + } + + genBytes, err := genesis.Bytes() + if err != nil { + return err + } + + // replace the default genesis with the fetched genesis + if err := os.WriteFile(genesisPath, genBytes, 0o644); err != nil { + return err + } + case c.genesisConfig != "": + c.ev.Send("Fetching custom genesis from chain config", events.ProgressUpdate()) + + // first, initialize with default genesis + cmd, err := c.chain.Commands(ctx) + if err != nil { + return err + } + + // TODO: use validator moniker https://github.com/ignite/cli/issues/1834 + if err := cmd.Init(ctx, "moniker"); err != nil { + return err + } + + // find config in downloaded source + path := filepath.Join(c.path, c.genesisConfig) + if _, err := os.Stat(path); err != nil { + return fmt.Errorf("the config for genesis doesn't exist: %w", err) + } + + config, err := chainconfig.ParseNetworkFile(path) + if err != nil { + return err + } + + // make sure that chain id given during chain.New() has the most priority. + chainID, err := c.ID() + if err != nil { + return err + } + if config.Genesis != nil { + config.Genesis["chain_id"] = chainID + } + + // update genesis file with the genesis values defined in the config + if err := c.chain.UpdateGenesisFile(config.Genesis); err != nil { + return err + } + + if err := c.chain.InitAccounts(ctx, config); err != nil { + return err + } + + default: + // default genesis is used, init CLI command is used to generate it + cmd, err := c.chain.Commands(ctx) + if err != nil { + return err + } + + // TODO: use validator moniker https://github.com/ignite/cli/issues/1834 + if err := cmd.Init(ctx, "moniker"); err != nil { + return err + } + } + + // check the initial genesis is valid + if err := c.checkInitialGenesis(ctx); err != nil { + return err + } + + c.ev.Send("Genesis initialized", events.ProgressFinish()) + return nil +} + +// checkGenesis checks the stored genesis is valid. +func (c *Chain) checkInitialGenesis(ctx context.Context) error { + // perform static analysis of the chain with the validate-genesis command. + chainCmd, err := c.chain.Commands(ctx) + if err != nil { + return err + } + + // the chain initial genesis should not contain gentx, gentxs should be added through requests + genesisPath, err := c.chain.GenesisPath() + if err != nil { + return err + } + + chainGenesis, err := cosmosgenesis.FromPath(genesisPath) + if err != nil { + return err + } + + gentxCount, err := chainGenesis.GentxCount() + if err != nil { + return err + } + + if gentxCount > 0 { + return errors.New("the initial genesis for the chain should not contain gentx") + } + + return chainCmd.ValidateGenesis(ctx) + + // TODO: static analysis of the genesis with validate-genesis doesn't check the full validity of the genesis + // example: gentxs formats are not checked + // to perform a full validity check of the genesis we must try to start the chain with sample accounts +} diff --git a/network/network/networkchain/networkchain.go b/network/network/networkchain/networkchain.go new file mode 100644 index 00000000..e6ba2c38 --- /dev/null +++ b/network/network/networkchain/networkchain.go @@ -0,0 +1,430 @@ +package networkchain + +import ( + "context" + "errors" + "os" + "os/exec" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + chainconfig "github.com/ignite/cli/v28/ignite/config/chain" + "github.com/ignite/cli/v28/ignite/pkg/cache" + "github.com/ignite/cli/v28/ignite/pkg/chaincmd" + "github.com/ignite/cli/v28/ignite/pkg/checksum" + "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" + "github.com/ignite/cli/v28/ignite/pkg/events" + "github.com/ignite/cli/v28/ignite/pkg/gitpod" + "github.com/ignite/cli/v28/ignite/services/chain" + "github.com/ignite/network/pkg/chainid" + + "github.com/ignite/apps/network/network/networktypes" +) + +// Chain represents a network blockchain and lets you interact with its source code and binary. +type Chain struct { + id string + launchID uint64 + + path string + home string + + url string + hash string + genesisURL string + genesisHash string + genesisConfig string + launchTime time.Time + + accountBalance sdk.Coins + + keyringBackend chaincmd.KeyringBackend + + isInitialized bool + checkDependencies bool + + ref plumbing.ReferenceName + + chain *chain.Chain + ev events.Bus + ar cosmosaccount.Registry +} + +// SourceOption sets the source for blockchain. +type SourceOption func(*Chain) + +// Option sets other initialization options. +type Option func(*Chain) + +// SourceRemote sets the default branch on a remote as source for the blockchain. +func SourceRemote(url string) SourceOption { + return func(c *Chain) { + c.url = url + } +} + +// SourceRemoteBranch sets the branch on a remote as source for the blockchain. +func SourceRemoteBranch(url, branch string) SourceOption { + return func(c *Chain) { + c.url = url + c.ref = plumbing.NewBranchReferenceName(branch) + } +} + +// SourceRemoteTag sets the tag on a remote as source for the blockchain. +func SourceRemoteTag(url, tag string) SourceOption { + return func(c *Chain) { + c.url = url + c.ref = plumbing.NewTagReferenceName(tag) + } +} + +// SourceRemoteHash uses a remote hash as source for the blockchain. +func SourceRemoteHash(url, hash string) SourceOption { + return func(c *Chain) { + c.url = url + c.hash = hash + } +} + +// SourceLaunch returns a source option for initializing a chain from a launch. +func SourceLaunch(launch networktypes.ChainLaunch) SourceOption { + return func(c *Chain) { + c.id = launch.ChainID + c.launchID = launch.ID + c.url = launch.SourceURL + c.hash = launch.SourceHash + c.genesisURL = launch.GenesisURL + c.genesisHash = launch.GenesisHash + c.genesisConfig = launch.GenesisConfig + c.home = ChainHome(launch.ID) + c.launchTime = launch.LaunchTime + c.accountBalance = launch.AccountBalance + } +} + +// WithHome provides a specific home path for the blockchain for the initialization. +func WithHome(path string) Option { + return func(c *Chain) { + c.home = path + } +} + +// WithKeyringBackend provides the keyring backend to use to initialize the blockchain. +func WithKeyringBackend(keyringBackend chaincmd.KeyringBackend) Option { + return func(c *Chain) { + c.keyringBackend = keyringBackend + } +} + +// WithGenesisFromURL provides a genesis url for the initial genesis of the chain blockchain. +func WithGenesisFromURL(genesisURL string) Option { + return func(c *Chain) { + c.genesisURL = genesisURL + } +} + +// WithGenesisFromConfig provides a config file for the initial genesis of the chain blockchain. +func WithGenesisFromConfig(genesisConfig string) Option { + return func(c *Chain) { + c.genesisConfig = genesisConfig + } +} + +// CollectEvents collects events from the chain. +func CollectEvents(ev events.Bus) Option { + return func(c *Chain) { + c.ev = ev + } +} + +// CheckDependencies checks that cached Go dependencies of the chain have +// not been modified since they were downloaded. Dependencies are checked +// by running `go mod verify`. +func CheckDependencies() Option { + return func(c *Chain) { + c.checkDependencies = true + } +} + +// New initializes a network blockchain from source and options. +func New(ctx context.Context, ar cosmosaccount.Registry, source SourceOption, options ...Option) (*Chain, error) { + c := &Chain{ + ar: ar, + } + source(c) + for _, apply := range options { + apply(c) + } + + c.ev.Send("Fetching the source code", events.ProgressStart()) + + var err error + if c.path, c.hash, err = fetchSource(ctx, c.url, c.ref, c.hash); err != nil { + return nil, err + } + + c.ev.Send("Source code fetched", events.ProgressFinish()) + c.ev.Send("Setting up the blockchain", events.ProgressStart()) + + chainOption := []chain.Option{ + chain.ID(c.id), + chain.HomePath(c.home), + } + + if c.checkDependencies { + chainOption = append(chainOption, chain.CheckDependencies()) + } + + // use test keyring backend on Gitpod in order to prevent prompting for keyring + // password. This happens because Gitpod uses containers. + if gitpod.IsOnGitpod() { + c.keyringBackend = chaincmd.KeyringBackendTest + } + + chainOption = append(chainOption, chain.KeyringBackend(c.keyringBackend)) + + chain, err := chain.New(c.path, chainOption...) + if err != nil { + return nil, err + } + + c.chain = chain + c.ev.Send("Blockchain set up", events.ProgressFinish()) + + return c, nil +} + +func (c Chain) ChainID() (string, error) { + return chainid.NewGenesisChainID(c.Name(), 1), nil +} + +func (c Chain) ID() (string, error) { + return c.chain.ID() +} + +func (c Chain) Name() string { + return c.chain.Name() +} + +func (c Chain) SetHome(home string) { + c.chain.SetHome(home) +} + +func (c Chain) Home() (path string, err error) { + return c.chain.Home() +} + +func (c Chain) BinaryName() (name string, err error) { + return c.chain.Binary() +} + +func (c Chain) GenesisPath() (path string, err error) { + return c.chain.GenesisPath() +} + +func (c Chain) GentxsPath() (path string, err error) { + return c.chain.GentxsPath() +} + +func (c Chain) DefaultGentxPath() (path string, err error) { + return c.chain.DefaultGentxPath() +} + +func (c Chain) AppTOMLPath() (string, error) { + return c.chain.AppTOMLPath() +} + +func (c Chain) ConfigTOMLPath() (string, error) { + return c.chain.ConfigTOMLPath() +} + +func (c Chain) SourceURL() string { + return c.url +} + +func (c Chain) SourceHash() string { + return c.hash +} + +func (c Chain) IsAccountBalanceFixed() bool { + return !c.accountBalance.IsZero() +} + +func (c Chain) AccountBalance() sdk.Coins { + return c.accountBalance +} + +func (c Chain) IsHomeDirExist() (ok bool, err error) { + home, err := c.chain.Home() + if err != nil { + return false, err + } + + _, err = os.Stat(home) + if os.IsNotExist(err) { + return false, nil + } + return err == nil, err +} + +// NodeID returns the chain node id. +func (c Chain) NodeID(ctx context.Context) (string, error) { + chainCmd, err := c.chain.Commands(ctx) + if err != nil { + return "", err + } + + nodeID, err := chainCmd.ShowNodeID(ctx) + if err != nil { + return "", err + } + return nodeID, nil +} + +// CheckConfigVersion checks that the config version is the latest. +func (c Chain) CheckConfigVersion() error { + configPath := c.chain.ConfigPath() + if configPath == "" { + return chainconfig.ErrConfigNotFound + } + + file, err := os.Open(configPath) + if err != nil { + return err + } + + defer file.Close() + + return chainconfig.CheckVersion(file) +} + +// Build builds chain sources, also checks if source was already built. +func (c *Chain) Build(ctx context.Context, cacheStorage cache.Storage) (binaryName string, err error) { + // Check that the config version is the latest before building the binary + if err = c.CheckConfigVersion(); err != nil && !errors.Is(err, chainconfig.ErrConfigNotFound) { + return "", err + } + + // if chain was already published and has launch id check binary cache + if c.launchID != 0 { + if binaryName, err = c.chain.Binary(); err != nil { + return "", err + } + binaryChecksum, err := checksum.Binary(binaryName) + if err != nil && !errors.Is(err, exec.ErrNotFound) { + return "", err + } + binaryMatch, err := checkBinaryCacheForLaunchID(c.launchID, binaryChecksum, c.hash) + if err != nil { + return "", err + } + if binaryMatch { + return binaryName, nil + } + } + + c.ev.Send("Building the chain's binary", events.ProgressStart()) + + // build binary + if binaryName, err = c.chain.Build( + ctx, + cacheStorage, + // []string{cosmosver.DefaultVersion().String()}, // TODO check why this build tag was set + []string{}, + "", + true, + false, + ); err != nil { + return "", err + } + + c.ev.Send("Chain's binary built", events.ProgressFinish()) + + // cache built binary for launch id + if c.launchID != 0 { + if err := c.CacheBinary(c.launchID); err != nil { + return "", nil + } + } + + return binaryName, nil +} + +// CacheBinary caches last built chain binary associated with launch id. +func (c *Chain) CacheBinary(launchID uint64) error { + binaryName, err := c.chain.Binary() + if err != nil { + return err + } + binaryChecksum, err := checksum.Binary(binaryName) + if err != nil { + return err + } + return cacheBinaryForLaunchID(launchID, binaryChecksum, c.hash) +} + +// fetchSource fetches the chain source from url and returns a temporary path where source is saved. +func fetchSource( + ctx context.Context, + url string, + ref plumbing.ReferenceName, + customHash string, +) (path, hash string, err error) { + var repo *git.Repository + + if path, err = os.MkdirTemp("", ""); err != nil { + return "", "", err + } + + // ensure the path for chain source exists + if err := os.MkdirAll(path, 0o755); err != nil { + return "", "", err + } + + // prepare clone options. + gitoptions := &git.CloneOptions{ + URL: url, + } + + // clone the ref when specified, this is used by chain coordinators on create. + if ref != "" { + gitoptions.ReferenceName = ref + gitoptions.SingleBranch = true + } + if repo, err = git.PlainCloneContext(ctx, path, false, gitoptions); err != nil { + return "", "", err + } + + if customHash != "" { + hash = customHash + + // checkout to a certain hash when specified. this is used by validators to make sure to use + // the locked version of the blockchain. + wt, err := repo.Worktree() + if err != nil { + return "", "", err + } + h, err := repo.ResolveRevision(plumbing.Revision(customHash)) + if err != nil { + return "", "", err + } + githash := *h + if err := wt.Checkout(&git.CheckoutOptions{ + Hash: githash, + }); err != nil { + return "", "", err + } + } else { + // when no specific hash is provided. HEAD is fetched + ref, err := repo.Head() + if err != nil { + return "", "", err + } + hash = ref.Hash().String() + } + + return path, hash, nil +} diff --git a/network/network/networkchain/prepare.go b/network/network/networkchain/prepare.go new file mode 100644 index 00000000..704cd678 --- /dev/null +++ b/network/network/networkchain/prepare.go @@ -0,0 +1,347 @@ +package networkchain + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/ignite/cli/v28/ignite/pkg/cache" + "github.com/ignite/cli/v28/ignite/pkg/cosmosutil" + cosmosgenesis "github.com/ignite/cli/v28/ignite/pkg/cosmosutil/genesis" + "github.com/ignite/cli/v28/ignite/pkg/events" + "github.com/ignite/cli/v28/ignite/pkg/jsonfile" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/pelletier/go-toml" + "github.com/pkg/errors" + + "github.com/ignite/apps/network/network/networktypes" +) + +// Prepare prepares the chain to be launched from genesis information. +func (c Chain) Prepare( + ctx context.Context, + cacheStorage cache.Storage, + gi networktypes.GenesisInformation, + rewardsInfo networktypes.Reward, + spnChainID string, + lastBlockHeight, + consumerUnbondingTime int64, +) error { + // chain initialization + genesisPath, err := c.chain.GenesisPath() + if err != nil { + return err + } + + _, err = os.Stat(genesisPath) + + switch { + case os.IsNotExist(err): + // if no config exists, perform a full initialization of the chain with a new validator key + if err = c.Init(ctx, cacheStorage); err != nil { + return err + } + case err != nil: + return err + default: + // if config and validator key already exists, build the chain and initialize the genesis + if _, err := c.Build(ctx, cacheStorage); err != nil { + return err + } + + if err := c.initGenesis(ctx); err != nil { + return err + } + } + + if err := c.buildGenesis( + ctx, + gi, + rewardsInfo, + spnChainID, + lastBlockHeight, + consumerUnbondingTime, + ); err != nil { + return err + } + + cmd, err := c.chain.Commands(ctx) + if err != nil { + return err + } + + // ensure genesis has a valid format + if err := cmd.ValidateGenesis(ctx); err != nil { + return err + } + + // reset the saved state in case the chain has been started before + return cmd.UnsafeReset(ctx) +} + +// buildGenesis builds the genesis for the chain from the launch approved requests. +func (c Chain) buildGenesis( + ctx context.Context, + gi networktypes.GenesisInformation, + rewardsInfo networktypes.Reward, + spnChainID string, + lastBlockHeight, + consumerUnbondingTime int64, +) error { + c.ev.Send("Building the genesis", events.ProgressStart()) + + addressPrefix, err := c.detectPrefix(ctx) + if err != nil { + return errors.Wrap(err, "error detecting chain prefix") + } + + // apply genesis information to the genesis + if err := c.applyGenesisAccounts(ctx, gi.GenesisAccounts, addressPrefix); err != nil { + return errors.Wrap(err, "error applying genesis accounts to genesis") + } + if err := c.applyVestingAccounts(ctx, gi.VestingAccounts, addressPrefix); err != nil { + return errors.Wrap(err, "error applying vesting accounts to genesis") + } + if err := c.applyGenesisValidators(ctx, gi.GenesisValidators); err != nil { + return errors.Wrap(err, "error applying genesis validators to genesis") + } + + genesisPath, err := c.chain.GenesisPath() + if err != nil { + return errors.Wrap(err, "genesis of the blockchain can't be read") + } + + genesis, err := cosmosgenesis.FromPath(genesisPath) + if err != nil { + return errors.Wrap(err, "genesis of the blockchain can't be parsed") + } + + // update chain ID and launch time + if err := genesis.Update( + jsonfile.WithKeyValue(cosmosgenesis.FieldChainID, c.id), + jsonfile.WithKeyValueTimestamp(cosmosgenesis.FieldGenesisTime, c.launchTime.Unix()), + ); err != nil { + return errors.Wrap(err, "genesis cannot be updated") + } + + // update reward related fields if the testnet is incentivized (with a last block height for reward distribution) + if lastBlockHeight > 0 { + if err := genesis.Update( + jsonfile.WithKeyValue(cosmosgenesis.FieldConsumerChainID, spnChainID), + jsonfile.WithKeyValueInt(cosmosgenesis.FieldLastBlockHeight, lastBlockHeight), + jsonfile.WithKeyValue(cosmosgenesis.FieldConsensusTimestamp, rewardsInfo.ConsensusState.Timestamp), + jsonfile.WithKeyValue(cosmosgenesis.FieldConsensusNextValidatorsHash, rewardsInfo.ConsensusState.NextValidatorsHash), + jsonfile.WithKeyValue(cosmosgenesis.FieldConsensusRootHash, rewardsInfo.ConsensusState.Root.Hash), + jsonfile.WithKeyValueInt(cosmosgenesis.FieldConsumerUnbondingPeriod, consumerUnbondingTime), + jsonfile.WithKeyValueUint(cosmosgenesis.FieldConsumerRevisionHeight, rewardsInfo.RevisionHeight), + ); err != nil { + return errors.Wrap(err, "genesis cannot be updated for reward related fields") + } + } + + if err := applyParamChanges(genesis, gi.ParamChanges); err != nil { + return fmt.Errorf("error applying param changes to genesis: %w", err) + } + + c.ev.Send("Genesis built", events.ProgressFinish()) + + return nil +} + +// applyGenesisAccounts adds the genesis account into the genesis using the chain CLI. +func (c Chain) applyGenesisAccounts( + ctx context.Context, + genesisAccs []networktypes.GenesisAccount, + addressPrefix string, +) error { + var err error + + cmd, err := c.chain.Commands(ctx) + if err != nil { + return err + } + + for _, acc := range genesisAccs { + // change the address prefix to the target chain prefix + acc.Address, err = cosmosutil.ChangeAddressPrefix(acc.Address, addressPrefix) + if err != nil { + return err + } + + // call the add genesis account CLI command + err = cmd.AddGenesisAccount(ctx, acc.Address, acc.Coins.String()) + if err != nil { + return err + } + } + + return nil +} + +// applyVestingAccounts adds the genesis vesting account into the genesis using the chain CLI. +func (c Chain) applyVestingAccounts( + ctx context.Context, + vestingAccs []networktypes.VestingAccount, + addressPrefix string, +) error { + cmd, err := c.chain.Commands(ctx) + if err != nil { + return err + } + + for _, acc := range vestingAccs { + acc.Address, err = cosmosutil.ChangeAddressPrefix(acc.Address, addressPrefix) + if err != nil { + return err + } + + // call the add genesis account CLI command with delayed vesting option + err = cmd.AddVestingAccount( + ctx, + acc.Address, + acc.TotalBalance.String(), + acc.Vesting.String(), + acc.EndTime, + ) + if err != nil { + return err + } + } + + return nil +} + +// applyGenesisValidators gathers the validator gentxs into the genesis and adds peers in config. +func (c Chain) applyGenesisValidators(ctx context.Context, genesisVals []networktypes.GenesisValidator) error { + // no validator + if len(genesisVals) == 0 { + return nil + } + + // reset the gentx directory + gentxDir, err := c.chain.GentxsPath() + if err != nil { + return err + } + if err := os.RemoveAll(gentxDir); err != nil { + return err + } + if err := os.MkdirAll(gentxDir, 0o700); err != nil { + return err + } + + // write gentxs + for i, val := range genesisVals { + gentxPath := filepath.Join(gentxDir, fmt.Sprintf("gentx%d.json", i)) + if err = os.WriteFile(gentxPath, val.Gentx, 0o666); err != nil { + return err + } + } + + // gather gentxs + cmd, err := c.chain.Commands(ctx) + if err != nil { + return err + } + if err := cmd.CollectGentxs(ctx); err != nil { + return err + } + + return c.updateConfigFromGenesisValidators(genesisVals) +} + +// applyParamChanges applies the param changes into the genesis. +func applyParamChanges( + genesis *cosmosgenesis.Genesis, + paramChanges []networktypes.ParamChange, +) error { + changes := make([]jsonfile.UpdateFileOption, len(paramChanges)) + + for i, pc := range paramChanges { + changes[i] = jsonfile.WithKeyValueByte(cosmosgenesis.ModuleParamField(pc.Module, pc.Param), pc.Value) + } + + if err := genesis.Update(changes...); err != nil { + return errors.Wrap(err, "failed to apply param change to genesis") + } + + return nil +} + +// updateConfigFromGenesisValidators adds the peer addresses into the config.toml of the chain. +func (c Chain) updateConfigFromGenesisValidators(genesisVals []networktypes.GenesisValidator) error { + var ( + p2pAddresses []string + tunnelAddresses []TunneledPeer + ) + for i, val := range genesisVals { + if !networktypes.VerifyPeerFormat(val.Peer) { + return errors.Errorf("invalid peer: %s", val.Peer.Id) + } + switch conn := val.Peer.Connection.(type) { + case *launchtypes.Peer_TcpAddress: + p2pAddresses = append(p2pAddresses, fmt.Sprintf("%s@%s", val.Peer.Id, conn.TcpAddress)) + case *launchtypes.Peer_HttpTunnel: + tunneledPeer := TunneledPeer{ + Name: conn.HttpTunnel.Name, + Address: conn.HttpTunnel.Address, + NodeID: val.Peer.Id, + LocalPort: strconv.Itoa(i + 22000), + } + tunnelAddresses = append(tunnelAddresses, tunneledPeer) + p2pAddresses = append(p2pAddresses, fmt.Sprintf("%s@127.0.0.1:%s", tunneledPeer.NodeID, tunneledPeer.LocalPort)) + default: + return fmt.Errorf("invalid peer type") + } + } + + if len(p2pAddresses) > 0 { + // set persistent peers + configPath, err := c.chain.ConfigTOMLPath() + if err != nil { + return err + } + configToml, err := toml.LoadFile(configPath) + if err != nil { + return err + } + configToml.Set("p2p.persistent_peers", strings.Join(p2pAddresses, ",")) + if err != nil { + return err + } + + // if there are tunneled peers they will be connected with tunnel clients via localhost, + // so we need to allow to have few nodes with the same ip + if len(tunnelAddresses) > 0 { + configToml.Set("p2p.allow_duplicate_ip", true) + } + + // save config.toml file + configTomlFile, err := os.OpenFile(configPath, os.O_RDWR|os.O_TRUNC, 0o644) + if err != nil { + return err + } + defer configTomlFile.Close() + + if _, err = configToml.WriteTo(configTomlFile); err != nil { + return err + } + } + + if len(tunnelAddresses) > 0 { + tunneledPeersConfigPath, err := c.SPNConfigPath() + if err != nil { + return err + } + + if err = SetSPNConfig(Config{ + TunneledPeers: tunnelAddresses, + }, tunneledPeersConfigPath); err != nil { + return err + } + } + return nil +} diff --git a/network/network/networkchain/request.go b/network/network/networkchain/request.go new file mode 100644 index 00000000..b335c681 --- /dev/null +++ b/network/network/networkchain/request.go @@ -0,0 +1,62 @@ +package networkchain + +import ( + "context" + "fmt" + + cosmosgenesis "github.com/ignite/cli/v28/ignite/pkg/cosmosutil/genesis" + "github.com/ignite/cli/v28/ignite/pkg/events" + "github.com/pkg/errors" + + "github.com/ignite/apps/network/network/networktypes" +) + +// CheckRequestChangeParam builds the genesis for the chain from the launch approved requests. +func (c Chain) CheckRequestChangeParam( + ctx context.Context, + module, + param string, + value []byte, +) error { + c.ev.Send("Checking the param change", events.ProgressStart()) + + if err := c.initGenesis(ctx); err != nil { + return err + } + + genesisPath, err := c.chain.GenesisPath() + if err != nil { + return errors.Wrap(err, "genesis of the blockchain can't be read") + } + + genesis, err := cosmosgenesis.FromPath(genesisPath) + if err != nil { + return errors.Wrap(err, "genesis of the blockchain can't be parsed") + } + + pc := []networktypes.ParamChange{ + { + Module: module, + Param: param, + Value: value, + }, + } + + if err := applyParamChanges(genesis, pc); err != nil { + return fmt.Errorf("error applying param changes to genesis: %w", err) + } + + cmd, err := c.chain.Commands(ctx) + if err != nil { + return err + } + + // ensure genesis has a valid format + if err := cmd.ValidateGenesis(ctx); err != nil { + return fmt.Errorf("invalid parameter change requested: %w", err) + } + + c.ev.Send("Param change verified", events.ProgressFinish()) + + return nil +} diff --git a/network/network/networkchain/simulate.go b/network/network/networkchain/simulate.go new file mode 100644 index 00000000..dc370c66 --- /dev/null +++ b/network/network/networkchain/simulate.go @@ -0,0 +1,226 @@ +package networkchain + +import ( + "context" + "fmt" + "os" + "strings" + "time" + + "github.com/cenkalti/backoff" + sdktypes "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/availableport" + "github.com/ignite/cli/v28/ignite/pkg/cache" + "github.com/ignite/cli/v28/ignite/pkg/events" + "github.com/ignite/cli/v28/ignite/pkg/httpstatuschecker" + "github.com/ignite/cli/v28/ignite/pkg/xurl" + "github.com/pelletier/go-toml" + "github.com/pkg/errors" + + "github.com/ignite/apps/network/network/networktypes" +) + +// listeningTimeout is the maximum time to wait for the chain start. +const listeningTimeout = time.Minute * 1 + +// validatorSetNilErrorMessages contains variation for SDK validator set empty error message/ +// to detect if the chain fails to start because the validator set is nil. +var validatorSetNilErrorMessages = []string{ + "validator set is nil in genesis and still empty after InitChain", + "validator set is empty after InitGenesis", +} + +// SimulateRequests simulates the genesis creation and the start of the network from the provided requests. +func (c Chain) SimulateRequests( + ctx context.Context, + cacheStorage cache.Storage, + gi networktypes.GenesisInformation, + reqs []networktypes.Request, +) (err error) { + c.ev.Send("Verifying requests format", events.ProgressStart()) + for _, req := range reqs { + // static verification of the request + if err := networktypes.VerifyRequest(req); err != nil { + return err + } + + // apply the request to the genesis information + gi, err = gi.ApplyRequest(req) + if err != nil { + return err + } + } + c.ev.Send("Requests format verified", events.ProgressFinish()) + + // prepare the chain with the requests + if err := c.Prepare( + ctx, + cacheStorage, + gi, + networktypes.Reward{RevisionHeight: 1}, + networktypes.SPNChainID, + 1, + 2, + ); err != nil { + return err + } + + c.ev.Send("Trying starting the network with the requests", events.ProgressStart()) + if err := c.simulateChainStart(ctx); err != nil { + return err + } + c.ev.Send("The network can be started", events.ProgressFinish()) + + return nil +} + +// simulateChainStart simulates and verify the chain start by starting it with a simulation config +// and checking if the gentxs execution is successful. +func (c Chain) simulateChainStart(ctx context.Context) error { + cmd, err := c.chain.Commands(ctx) + if err != nil { + return err + } + + // set the config with random ports to test the start command + rpcAddr, err := c.setSimulationConfig() + if err != nil { + return err + } + + // verify that the chain can be started with a valid genesis + ctx, cancel := context.WithTimeout(ctx, listeningTimeout) + exit := make(chan error) + + // routine to check the app is listening + go func() { + defer cancel() + exit <- isChainListening(ctx, rpcAddr) + }() + + // check an error is realted to validator set empty + checkValidatorSetEmptyError := func(err error) bool { + if err != nil { + for _, errStr := range validatorSetNilErrorMessages { + if strings.Contains(err.Error(), errStr) { + return true + } + } + } + + return false + } + + // routine chain start + go func() { + // if the error is validator set is nil, it means the genesis didn't get broken after an applied request + // the genesis was correctly generated but there is no gentxs so far + // so we don't consider it as an error making requests to verify as invalid + err := cmd.Start(ctx) + if checkValidatorSetEmptyError(err) { + err = nil + } + exit <- errors.Wrap(err, "the chain failed to start") + }() + + return <-exit +} + +// setSimulationConfig sets in the config random available ports to allow check if the chain network can start. +func (c Chain) setSimulationConfig() (string, error) { + // generate random server ports and servers list + ports, err := availableport.Find(5) + if err != nil { + return "", err + } + genAddr := func(port uint) string { + return fmt.Sprintf("0.0.0.0:%d", port) + } + + // updating app toml + appPath, err := c.AppTOMLPath() + if err != nil { + return "", err + } + config, err := toml.LoadFile(appPath) + if err != nil { + return "", err + } + + apiAddr, err := xurl.TCP(genAddr(ports[0])) + if err != nil { + return "", err + } + + config.Set("api.enable", true) + config.Set("api.enabled-unsafe-cors", true) + config.Set("rpc.cors_allowed_origins", []string{"*"}) + config.Set("api.address", apiAddr) + config.Set("grpc.address", genAddr(ports[1])) + gas := sdktypes.NewInt64Coin(networktypes.SPNDenom, 0) + config.Set("minimum-gas-prices", gas.String()) + + file, err := os.OpenFile(appPath, os.O_RDWR|os.O_TRUNC, 0o644) + if err != nil { + return "", err + } + defer file.Close() + + if _, err := config.WriteTo(file); err != nil { + return "", err + } + + // updating config toml + configPath, err := c.ConfigTOMLPath() + if err != nil { + return "", err + } + config, err = toml.LoadFile(configPath) + if err != nil { + return "", err + } + + rpcAddr, err := xurl.TCP(genAddr(ports[2])) + if err != nil { + return "", err + } + + p2pAddr, err := xurl.TCP(genAddr(ports[3])) + if err != nil { + return "", err + } + + config.Set("rpc.cors_allowed_origins", []string{"*"}) + config.Set("consensus.timeout_commit", "1s") + config.Set("consensus.timeout_propose", "1s") + config.Set("rpc.laddr", rpcAddr) + config.Set("p2p.laddr", p2pAddr) + config.Set("rpc.pprof_laddr", genAddr(ports[4])) + + file, err = os.OpenFile(configPath, os.O_RDWR|os.O_TRUNC, 0o644) + if err != nil { + return "", err + } + defer file.Close() + + _, err = config.WriteTo(file) + + return genAddr(ports[2]), err +} + +// isChainListening checks if the chain is listening for RPC queries on the specified address. +func isChainListening(ctx context.Context, rpcAddr string) error { + checkAlive := func() error { + addr, err := xurl.HTTP(rpcAddr) + if err != nil { + return fmt.Errorf("invalid rpc address format %s: %w", rpcAddr, err) + } + + ok, err := httpstatuschecker.Check(ctx, fmt.Sprintf("%s/health", addr)) + if err == nil && !ok { + err = errors.New("app is not online") + } + return err + } + return backoff.Retry(checkAlive, backoff.WithContext(backoff.NewConstantBackOff(time.Second), ctx)) +} diff --git a/network/network/networktypes/chainlaunch.go b/network/network/networktypes/chainlaunch.go new file mode 100644 index 00000000..58953a81 --- /dev/null +++ b/network/network/networktypes/chainlaunch.go @@ -0,0 +1,87 @@ +package networktypes + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/goccy/go-yaml" + launchtypes "github.com/ignite/network/x/launch/types" +) + +type ( + NetworkType string + + // ChainLaunch represents the launch of a chain on SPN. + ChainLaunch struct { + ID uint64 `json:"ID"` + ConsumerRevisionHeight int64 `json:"ConsumerRevisionHeight"` + ChainID string `json:"ChainID"` + SourceURL string `json:"SourceURL"` + SourceHash string `json:"SourceHash"` + GenesisURL string `json:"GenesisURL"` + GenesisHash string `json:"GenesisHash"` + GenesisConfig string `json:"GenesisConfig"` + LaunchTime time.Time `json:"LaunchTime"` + ProjectID uint64 `json:"ProjectID"` + LaunchTriggered bool `json:"LaunchTriggered"` + Network NetworkType `json:"Network"` + Reward string `json:"Reward,omitempty"` + AccountBalance sdk.Coins `json:"AccountBalance"` + Metadata Metadata `json:"Metadata"` + } +) + +const ( + NetworkTypeMainnet NetworkType = "mainnet" + NetworkTypeTestnet NetworkType = "testnet" +) + +func (n NetworkType) String() string { + return string(n) +} + +// ToChainLaunch converts a chain launch data from SPN and returns a ChainLaunch object. +func ToChainLaunch(chain launchtypes.Chain) ChainLaunch { + var launchTime time.Time + if chain.LaunchTriggered { + launchTime = chain.LaunchTime + } + + network := NetworkTypeTestnet + if chain.IsMainnet { + network = NetworkTypeMainnet + } + + launch := ChainLaunch{ + ID: chain.LaunchId, + ConsumerRevisionHeight: chain.ConsumerRevisionHeight, + ChainID: chain.GenesisChainId, + SourceURL: chain.SourceUrl, + SourceHash: chain.SourceHash, + LaunchTime: launchTime, + ProjectID: chain.ProjectId, + LaunchTriggered: chain.LaunchTriggered, + Network: network, + AccountBalance: chain.AccountBalance, + } + + err := yaml.Unmarshal(chain.Metadata, &launch.Metadata) + if err != nil { + // an error shouldn't happen + // in case it occurs, we consider metadata as invalid and dismiss those + launch.Metadata = Metadata{} + } + + // check if custom genesis URL is provided. + if customGenesisURL := chain.InitialGenesis.GetGenesisUrl(); customGenesisURL != nil { + launch.GenesisURL = customGenesisURL.Url + launch.GenesisHash = customGenesisURL.Hash + } + + // check if custom config genesis if provided. + if customGenesisConfig := chain.InitialGenesis.GetGenesisConfig(); customGenesisConfig != nil { + launch.GenesisConfig = customGenesisConfig.File + } + + return launch +} diff --git a/network/network/networktypes/chainlaunch_test.go b/network/network/networktypes/chainlaunch_test.go new file mode 100644 index 00000000..c2f66603 --- /dev/null +++ b/network/network/networktypes/chainlaunch_test.go @@ -0,0 +1,75 @@ +package networktypes_test + +import ( + "testing" + "time" + + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networktypes" +) + +func TestToChainLaunch(t *testing.T) { + tests := []struct { + name string + fetched launchtypes.Chain + expected networktypes.ChainLaunch + }{ + { + name: "chain with default genesis", + fetched: launchtypes.Chain{ + LaunchId: 1, + GenesisChainId: "foo-1", + SourceUrl: "foo.com", + SourceHash: "0xaaa", + HasProject: true, + ProjectId: 1, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + }, + expected: networktypes.ChainLaunch{ + ID: 1, + ChainID: "foo-1", + SourceURL: "foo.com", + SourceHash: "0xaaa", + GenesisURL: "", + GenesisHash: "", + LaunchTriggered: false, + ProjectID: 1, + Network: "testnet", + }, + }, + { + name: "launched chain with custom genesis url and no project", + fetched: launchtypes.Chain{ + LaunchId: 1, + GenesisChainId: "bar-1", + SourceUrl: "bar.com", + SourceHash: "0xbbb", + LaunchTriggered: true, + LaunchTime: time.Unix(100, 100).UTC(), + InitialGenesis: launchtypes.NewGenesisURL( + "genesisfoo.com", + "0xccc", + ), + }, + expected: networktypes.ChainLaunch{ + ID: 1, + ChainID: "bar-1", + SourceURL: "bar.com", + SourceHash: "0xbbb", + GenesisURL: "genesisfoo.com", + GenesisHash: "0xccc", + LaunchTriggered: true, + LaunchTime: time.Unix(100, 100).UTC(), + ProjectID: 0, + Network: "testnet", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.EqualValues(t, tt.expected, networktypes.ToChainLaunch(tt.fetched)) + }) + } +} diff --git a/network/network/networktypes/error.go b/network/network/networktypes/error.go new file mode 100644 index 00000000..93357397 --- /dev/null +++ b/network/network/networktypes/error.go @@ -0,0 +1,22 @@ +package networktypes + +import ( + "fmt" + + "github.com/pkg/errors" +) + +// ErrInvalidRequest is an error returned in methods manipulating requests when they are invalid. +type ErrInvalidRequest struct { + requestID uint64 +} + +// Error implements error. +func (err ErrInvalidRequest) Error() string { + return fmt.Sprintf("request %d is invalid", err.requestID) +} + +// NewWrappedErrInvalidRequest returns a wrapped ErrInvalidRequest. +func NewWrappedErrInvalidRequest(requestID uint64, message string) error { + return errors.Wrap(ErrInvalidRequest{requestID: requestID}, message) +} diff --git a/network/network/networktypes/genesisinformation.go b/network/network/networktypes/genesisinformation.go new file mode 100644 index 00000000..16c1c41b --- /dev/null +++ b/network/network/networktypes/genesisinformation.go @@ -0,0 +1,263 @@ +package networktypes + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/pkg/errors" +) + +// GenesisInformation represents all information for a chain to construct the genesis. +// This structure indexes accounts and validators by their address for better performance. +type GenesisInformation struct { + // make sure to use slices for the following because slices are ordered. + // they later used to create a Genesis so, having them ordered is important to + // be able to produce a deterministic Genesis. + + GenesisAccounts []GenesisAccount + VestingAccounts []VestingAccount + GenesisValidators []GenesisValidator + ParamChanges []ParamChange +} + +// GenesisAccount represents an account with initial coin allocation for the chain for the chain genesis. +type GenesisAccount struct { + Address string `json:"Address,omitempty"` + Coins sdk.Coins `json:"Coins,omitempty"` +} + +// VestingAccount represents a vesting account with initial coin allocation and vesting option for the chain genesis. +// VestingAccount supports currently only delayed vesting option. +type VestingAccount struct { + Address string `json:"Address,omitempty"` + TotalBalance sdk.Coins `json:"TotalBalance,omitempty"` + Vesting sdk.Coins `json:"Vesting,omitempty"` + EndTime int64 `json:"EndTime,omitempty"` +} + +// GenesisValidator represents a genesis validator associated with a gentx in the chain genesis. +type GenesisValidator struct { + Address string `json:"Address,omitempty"` + Gentx []byte `json:"Gentx,omitempty"` + Peer launchtypes.Peer `json:"Peer,omitempty"` + SelfDelegation sdk.Coin `json:"SelfDelegation,omitempty"` +} + +// ParamChange represents a parameter change to be applied to the chain genesis. +type ParamChange struct { + Module string `json:"Module,omitempty"` + Param string `json:"Param,omitempty"` + Value []byte `json:"Value,omitempty"` +} + +// ToGenesisAccount converts genesis account from SPN. +func ToGenesisAccount(acc launchtypes.GenesisAccount) GenesisAccount { + return GenesisAccount{ + Address: acc.Address, + Coins: acc.Coins, + } +} + +// ToVestingAccount converts vesting account from SPN. +func ToVestingAccount(acc launchtypes.VestingAccount) (VestingAccount, error) { + delayedVesting := acc.VestingOptions.GetDelayedVesting() + if delayedVesting == nil { + return VestingAccount{}, errors.New("only delayed vesting option is supported") + } + + return VestingAccount{ + Address: acc.Address, + TotalBalance: delayedVesting.TotalBalance, + Vesting: delayedVesting.Vesting, + EndTime: delayedVesting.EndTime.Unix(), + }, nil +} + +// ToGenesisValidator converts genesis validator from SPN. +func ToGenesisValidator(val launchtypes.GenesisValidator) GenesisValidator { + return GenesisValidator{ + Address: val.Address, + Gentx: val.GenTx, + Peer: val.Peer, + SelfDelegation: val.SelfDelegation, + } +} + +// ToParamChange converts param change from SPN. +func ToParamChange(pc launchtypes.ParamChange) ParamChange { + return ParamChange{ + Param: pc.Param, + Module: pc.Module, + Value: pc.Value, + } +} + +// NewGenesisInformation initializes new GenesisInformation. +func NewGenesisInformation( + genAccs []GenesisAccount, + vestingAccs []VestingAccount, + genVals []GenesisValidator, + paramChanges []ParamChange, +) (gi GenesisInformation) { + return GenesisInformation{ + GenesisAccounts: genAccs, + VestingAccounts: vestingAccs, + GenesisValidators: genVals, + ParamChanges: paramChanges, + } +} + +// ContainsGenesisAccount returns true if GenesisInformation contains given address. +// Returns index if true, -1 if false. +func (gi GenesisInformation) ContainsGenesisAccount(address string) (bool, int) { + for i, account := range gi.GenesisAccounts { + if account.Address == address { + return true, i + } + } + return false, -1 +} + +// ContainsVestingAccount returns true if GenesisInformation contains given address. +// Returns index if true, -1 if false. +func (gi GenesisInformation) ContainsVestingAccount(address string) (bool, int) { + for i, account := range gi.VestingAccounts { + if account.Address == address { + return true, i + } + } + return false, -1 +} + +// ContainsGenesisValidator returns true if GenesisInformation contains given address. +// Returns index if true, -1 if false. +func (gi GenesisInformation) ContainsGenesisValidator(address string) (bool, int) { + for i, account := range gi.GenesisValidators { + if account.Address == address { + return true, i + } + } + return false, -1 +} + +// ContainsParamChange returns true if GenesisInformation contains given module-param pair. +// Returns index if true, -1 if false. +func (gi GenesisInformation) ContainsParamChange(module, param string) (bool, int) { + for i, paramChange := range gi.ParamChanges { + if paramChange.Module == module && paramChange.Param == param { + return true, i + } + } + return false, -1 +} + +func (gi *GenesisInformation) AddGenesisAccount(acc GenesisAccount) { + gi.GenesisAccounts = append(gi.GenesisAccounts, acc) +} + +func (gi *GenesisInformation) AddVestingAccount(acc VestingAccount) { + gi.VestingAccounts = append(gi.VestingAccounts, acc) +} + +func (gi *GenesisInformation) AddGenesisValidator(val GenesisValidator) { + gi.GenesisValidators = append(gi.GenesisValidators, val) +} + +func (gi *GenesisInformation) RemoveGenesisAccount(address string) { + for i, account := range gi.GenesisAccounts { + if account.Address == address { + gi.GenesisAccounts = append(gi.GenesisAccounts[:i], gi.GenesisAccounts[i+1:]...) + } + } +} + +func (gi *GenesisInformation) RemoveVestingAccount(address string) { + for i, account := range gi.VestingAccounts { + if account.Address == address { + gi.VestingAccounts = append(gi.VestingAccounts[:i], gi.VestingAccounts[i+1:]...) + } + } +} + +func (gi *GenesisInformation) RemoveGenesisValidator(address string) { + for i, account := range gi.GenesisValidators { + if account.Address == address { + gi.GenesisValidators = append(gi.GenesisValidators[:i], gi.GenesisValidators[i+1:]...) + } + } +} + +// AddParamChange adds a ParamChange to the GenesisInformation. +// Appends if entry does not exist. Updates if it already exists. +func (gi *GenesisInformation) AddParamChange(pc ParamChange) { + contains, index := gi.ContainsParamChange(pc.Module, pc.Param) + if contains { + gi.ParamChanges[index] = pc + return + } + gi.ParamChanges = append(gi.ParamChanges, pc) +} + +// ApplyRequest applies to the genesisInformation the changes implied by the approval of a request. +func (gi GenesisInformation) ApplyRequest(request Request) (GenesisInformation, error) { + switch requestContent := request.Content.Content.(type) { + case *launchtypes.RequestContent_GenesisAccount: + // new genesis account in the genesis + ga := ToGenesisAccount(*requestContent.GenesisAccount) + genExist, _ := gi.ContainsGenesisAccount(ga.Address) + vestingExist, _ := gi.ContainsVestingAccount(ga.Address) + if genExist || vestingExist { + return gi, NewWrappedErrInvalidRequest(request.RequestID, "genesis account already in genesis") + } + gi.AddGenesisAccount(ga) + + case *launchtypes.RequestContent_VestingAccount: + // new vesting account in the genesis + va, err := ToVestingAccount(*requestContent.VestingAccount) + if err != nil { + // we don't treat this error as errInvalidRequests + // because it can occur if we don't support this format of vesting account + // but the request is still correct + return gi, err + } + + genExist, _ := gi.ContainsGenesisAccount(va.Address) + vestingExist, _ := gi.ContainsVestingAccount(va.Address) + if genExist || vestingExist { + return gi, NewWrappedErrInvalidRequest(request.RequestID, "vesting account already in genesis") + } + gi.AddVestingAccount(va) + + case *launchtypes.RequestContent_AccountRemoval: + // account removed from the genesis + ar := requestContent.AccountRemoval + genExist, _ := gi.ContainsGenesisAccount(ar.Address) + vestingExist, _ := gi.ContainsVestingAccount(ar.Address) + if !genExist && !vestingExist { + return gi, NewWrappedErrInvalidRequest(request.RequestID, "account can't be removed because it doesn't exist") + } + gi.RemoveGenesisAccount(ar.Address) + gi.RemoveVestingAccount(ar.Address) + + case *launchtypes.RequestContent_GenesisValidator: + // new genesis validator in the genesis + gv := ToGenesisValidator(*requestContent.GenesisValidator) + if contains, _ := gi.ContainsGenesisValidator(gv.Address); contains { + return gi, NewWrappedErrInvalidRequest(request.RequestID, "genesis validator already in genesis") + } + gi.AddGenesisValidator(gv) + + case *launchtypes.RequestContent_ValidatorRemoval: + // validator removed from the genesis + vr := requestContent.ValidatorRemoval + if contains, _ := gi.ContainsGenesisValidator(vr.ValAddress); !contains { + return gi, NewWrappedErrInvalidRequest(request.RequestID, "genesis validator can't be removed because it doesn't exist") + } + + case *launchtypes.RequestContent_ParamChange: + // param changed in genesis file + pc := ToParamChange(*requestContent.ParamChange) + gi.AddParamChange(pc) + } + + return gi, nil +} diff --git a/network/network/networktypes/genesisinformation_test.go b/network/network/networktypes/genesisinformation_test.go new file mode 100644 index 00000000..e3e6dd97 --- /dev/null +++ b/network/network/networktypes/genesisinformation_test.go @@ -0,0 +1,392 @@ +package networktypes_test + +import ( + "testing" + "time" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networktypes" +) + +var sampleCoins = sdk.NewCoins(sdk.NewCoin("bar", sdkmath.NewInt(1000)), sdk.NewCoin("foo", sdkmath.NewInt(2000))) + +func TestToGenesisAccount(t *testing.T) { + tests := []struct { + name string + fetched launchtypes.GenesisAccount + expected networktypes.GenesisAccount + }{ + { + name: "genesis account", + fetched: launchtypes.GenesisAccount{ + Address: "spn123", + Coins: sampleCoins, + }, + expected: networktypes.GenesisAccount{ + Address: "spn123", + Coins: sampleCoins, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.EqualValues(t, tt.expected, networktypes.ToGenesisAccount(tt.fetched)) + }) + } +} + +func TestToVestingAccount(t *testing.T) { + tests := []struct { + name string + fetched launchtypes.VestingAccount + expected networktypes.VestingAccount + isError bool + }{ + { + name: "vesting account", + fetched: launchtypes.VestingAccount{ + Address: "spn123", + VestingOptions: *launchtypes.NewDelayedVesting( + sampleCoins, + sampleCoins, + time.Unix(0, 0), + ), + }, + expected: networktypes.VestingAccount{ + Address: "spn123", + TotalBalance: sampleCoins, + Vesting: sampleCoins, + EndTime: time.Unix(0, 0).Unix(), + }, + }, + { + name: "unrecognized vesting option", + fetched: launchtypes.VestingAccount{ + Address: "spn123", + VestingOptions: launchtypes.VestingOptions{ + Options: nil, + }, + }, + isError: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + vestingAcc, err := networktypes.ToVestingAccount(tt.fetched) + require.EqualValues(t, tt.isError, err != nil) + require.EqualValues(t, tt.expected, vestingAcc) + }) + } +} + +func TestToGenesisValidator(t *testing.T) { + tests := []struct { + name string + fetched launchtypes.GenesisValidator + expected networktypes.GenesisValidator + }{ + { + name: "genesis validator", + fetched: launchtypes.GenesisValidator{ + GenTx: []byte("abc"), + Peer: launchtypes.NewPeerConn("abc", "abc@0.0.0.0"), + }, + expected: networktypes.GenesisValidator{ + Gentx: []byte("abc"), + Peer: launchtypes.NewPeerConn("abc", "abc@0.0.0.0"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.EqualValues(t, tt.expected, networktypes.ToGenesisValidator(tt.fetched)) + }) + } +} + +func TestToParamChange(t *testing.T) { + tests := []struct { + name string + fetched launchtypes.ParamChange + expected networktypes.ParamChange + }{ + { + name: "param change", + fetched: launchtypes.ParamChange{ + LaunchId: 0, + Module: "foo", + Param: "bar", + Value: []byte("value"), + }, + expected: networktypes.ParamChange{ + Module: "foo", + Param: "bar", + Value: []byte("value"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.EqualValues(t, tt.expected, networktypes.ToParamChange(tt.fetched)) + }) + } +} + +func TestGenesisInformation_ApplyRequest(t *testing.T) { + newCoin := func(str string) sdk.Coin { + c, err := sdk.ParseCoinNormalized(str) + require.NoError(t, err) + return c + } + newCoins := func(str string) sdk.Coins { + c, err := sdk.ParseCoinsNormalized(str) + require.NoError(t, err) + return c + } + + // used as a template for tests + genesisInformation := networktypes.NewGenesisInformation( + []networktypes.GenesisAccount{ + { + Address: "spn1g50xher44l9hjuatjdfxgv254jh2wgzfs55yu3", + Coins: sdk.NewCoins(sdk.NewCoin("foo", sdkmath.NewInt(1000))), + }, + }, + []networktypes.VestingAccount{ + { + Address: "spn1gkzf4e0x6wr4djfd8h82v6cy507gy5v4spaus3", + TotalBalance: sdk.NewCoins(sdk.NewCoin("foo", sdkmath.NewInt(1000))), + Vesting: sdk.NewCoins(sdk.NewCoin("foo", sdkmath.NewInt(500))), + EndTime: time.Now().Unix(), + }, + }, + []networktypes.GenesisValidator{ + { + Address: "spn1pquxnnpnjyl3ptz3uxs0lrs93s5ljepzq4wyp6", + Gentx: []byte("aaa"), + Peer: launchtypes.NewPeerConn("foo", "foo"), + }, + }, + []networktypes.ParamChange{ + { + Module: "mint", + Param: "mint_denom", + Value: []byte("\"bar\""), + }, + }, + ) + + tests := []struct { + name string + gi networktypes.GenesisInformation + r networktypes.Request + invalidRequest bool + }{ + { + name: "genesis account request", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewGenesisAccount( + 0, + "spn1sgphx4vxt63xhvgp9wpewajyxeqt04twfj7gcc", + newCoins("1000bar"), + ), + }, + }, + { + name: "vesting account request", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewVestingAccount( + 0, + "spn19klee4szqpeu0laqze5srhdxtp6fuhcztdrh7c", + *launchtypes.NewDelayedVesting( + newCoins("1000bar"), + newCoins("500bar"), + time.Now(), + ), + ), + }, + }, + { + name: "genesis validator request", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewGenesisValidator( + 0, + "spn1xnn9w76mf42t249486ss65lvga7gqs02erpw24", + []byte("bbb"), + []byte("ccc"), + newCoin("1000bar"), + launchtypes.NewPeerConn("bar", "bar"), + ), + }, + }, + { + name: "genesis account: existing genesis account", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewGenesisAccount( + 0, + "spn1g50xher44l9hjuatjdfxgv254jh2wgzfs55yu3", + newCoins("1000bar"), + ), + }, + invalidRequest: true, + }, + { + name: "genesis account: existing vesting account", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewGenesisAccount( + 0, + "spn1gkzf4e0x6wr4djfd8h82v6cy507gy5v4spaus3", + newCoins("1000bar"), + ), + }, + invalidRequest: true, + }, + { + name: "vesting account: existing genesis account", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewVestingAccount( + 0, + "spn1g50xher44l9hjuatjdfxgv254jh2wgzfs55yu3", + *launchtypes.NewDelayedVesting( + newCoins("1000bar"), + newCoins("500bar"), + time.Now(), + ), + ), + }, + invalidRequest: true, + }, + { + name: "vesting account: existing vesting account", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewVestingAccount( + 0, + "spn1gkzf4e0x6wr4djfd8h82v6cy507gy5v4spaus3", + *launchtypes.NewDelayedVesting( + newCoins("1000bar"), + newCoins("500bar"), + time.Now(), + ), + ), + }, + invalidRequest: true, + }, + { + name: "existing genesis validator", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewGenesisValidator( + 0, + "spn1pquxnnpnjyl3ptz3uxs0lrs93s5ljepzq4wyp6", + []byte("bbb"), + []byte("ccc"), + newCoin("1000bar"), + launchtypes.NewPeerConn("bar", "bar"), + ), + }, + invalidRequest: true, + }, + { + name: "remove genesis account", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewAccountRemoval("spn1g50xher44l9hjuatjdfxgv254jh2wgzfs55yu3"), + }, + }, + { + name: "remove vesting account", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewAccountRemoval("spn1gkzf4e0x6wr4djfd8h82v6cy507gy5v4spaus3"), + }, + }, + { + name: "remove genesis validator", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewValidatorRemoval("spn1pquxnnpnjyl3ptz3uxs0lrs93s5ljepzq4wyp6"), + }, + }, + { + name: "remove account: non-existent account", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewAccountRemoval("spn1pquxnnpnjyl3ptz3uxs0lrs93s5ljepzq4wyp6"), + }, + invalidRequest: true, + }, + { + name: "remove account: non-existent genesis validator", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewValidatorRemoval("spn1g50xher44l9hjuatjdfxgv254jh2wgzfs55yu3"), + }, + invalidRequest: true, + }, + { + name: "change param", + gi: genesisInformation, + r: networktypes.Request{ + Content: launchtypes.NewParamChange(0, "mint", "mint_denom", []byte("\"foo\"")), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + newGi, err := tt.gi.ApplyRequest(tt.r) + if tt.invalidRequest { + require.ErrorAs(t, err, &networktypes.ErrInvalidRequest{}) + return + } + + // parse difference following request + switch rc := tt.r.Content.Content.(type) { + case *launchtypes.RequestContent_GenesisAccount: + ga := networktypes.ToGenesisAccount(*rc.GenesisAccount) + contains, index := newGi.ContainsGenesisAccount(ga.Address) + require.True(t, contains) + require.EqualValues(t, ga, newGi.GenesisAccounts[index]) + + case *launchtypes.RequestContent_VestingAccount: + va, err := networktypes.ToVestingAccount(*rc.VestingAccount) + require.NoError(t, err) + contains, index := newGi.ContainsVestingAccount(va.Address) + require.True(t, contains) + require.EqualValues(t, va, newGi.VestingAccounts[index]) + + case *launchtypes.RequestContent_AccountRemoval: + contains, _ := newGi.ContainsGenesisAccount(rc.AccountRemoval.Address) + require.False(t, contains) + contains, _ = newGi.ContainsVestingAccount(rc.AccountRemoval.Address) + require.False(t, contains) + + case *launchtypes.RequestContent_GenesisValidator: + gv := networktypes.ToGenesisValidator(*rc.GenesisValidator) + contains, index := newGi.ContainsGenesisValidator(gv.Address) + require.True(t, contains) + require.EqualValues(t, gv, newGi.GenesisValidators[index]) + + case *launchtypes.RequestContent_ValidatorRemoval: + contains, _ := newGi.ContainsGenesisAccount(rc.ValidatorRemoval.ValAddress) + require.False(t, contains) + + case *launchtypes.RequestContent_ParamChange: + pc := networktypes.ToParamChange(*rc.ParamChange) + contains, index := newGi.ContainsParamChange(pc.Module, pc.Param) + require.True(t, contains) + require.EqualValues(t, pc, newGi.ParamChanges[index]) + } + }) + } +} diff --git a/network/network/networktypes/metadata.go b/network/network/networktypes/metadata.go new file mode 100644 index 00000000..bf86bed9 --- /dev/null +++ b/network/network/networktypes/metadata.go @@ -0,0 +1,21 @@ +package networktypes + +// Version current version of the network plugin. +const Version = "1" + +// Cli holds information about the CLI used to interact with the chain. +type Cli struct { + Version string `json:"version"` +} + +// Metadata is an object that contains the metadata of a chain. +// the metadata represents generic data set by the coordinator. +// these information can be formatted and interpreted by the CLI for specific purposes. +type Metadata struct { + Cli Cli `json:"cli"` +} + +// IsCurrentVersion checks if the version of the CLI is equal to the current version. +func (m Metadata) IsCurrentVersion() bool { + return m.Cli.Version == Version +} diff --git a/network/network/networktypes/metadata_test.go b/network/network/networktypes/metadata_test.go new file mode 100644 index 00000000..70b14e12 --- /dev/null +++ b/network/network/networktypes/metadata_test.go @@ -0,0 +1,41 @@ +package networktypes_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networktypes" +) + +func TestMetadata_IsCurrentVersion(t *testing.T) { + tests := []struct { + name string + m networktypes.Metadata + want bool + }{ + { + name: "current version", + m: networktypes.Metadata{ + Cli: networktypes.Cli{ + Version: networktypes.Version, + }, + }, + want: true, + }, + { + name: "not current version", + m: networktypes.Metadata{ + Cli: networktypes.Cli{ + Version: "0", + }, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.want, tt.m.IsCurrentVersion()) + }) + } +} diff --git a/network/network/networktypes/networktypes.go b/network/network/networktypes/networktypes.go new file mode 100644 index 00000000..a74f071a --- /dev/null +++ b/network/network/networktypes/networktypes.go @@ -0,0 +1,21 @@ +package networktypes + +const ( + // SPNChainID name used as SPN chain id. + SPNChainID = "spn-1" + + // SPN name used as an address prefix and as a home dir for chains to publish. + SPN = "spn" + + // SPNDenom is the denom used for the spn chain native token. + SPNDenom = "uspn" + + // SPNVersion is the spn ibc version used for the relayer connection. + SPNVersion = "monitoring-1" + + // SPNPortID is the spn ibc port id used for the relayer connection. + SPNPortID = "monitoringc" + + // ChainPortID is the chain ibc port id used for the relayer connection. + ChainPortID = "monitoringp" +) diff --git a/network/network/networktypes/peer.go b/network/network/networktypes/peer.go new file mode 100644 index 00000000..a896817c --- /dev/null +++ b/network/network/networktypes/peer.go @@ -0,0 +1,28 @@ +package networktypes + +import ( + "strings" + + launchtypes "github.com/ignite/network/x/launch/types" + + "github.com/ignite/cli/v28/ignite/pkg/xurl" +) + +// VerifyPeerFormat checks if the peer address format is valid. +func VerifyPeerFormat(peer launchtypes.Peer) bool { + // Check the format of the peer + switch conn := peer.Connection.(type) { + case *launchtypes.Peer_TcpAddress: + nodeHost := strings.Split(conn.TcpAddress, ":") + if len(nodeHost) != 2 || + len(nodeHost[0]) == 0 || + len(nodeHost[1]) == 0 { + return false + } + return true + case *launchtypes.Peer_HttpTunnel: + return xurl.IsHTTP(conn.HttpTunnel.Address) + default: + return false + } +} diff --git a/network/network/networktypes/peer_test.go b/network/network/networktypes/peer_test.go new file mode 100644 index 00000000..d0372a70 --- /dev/null +++ b/network/network/networktypes/peer_test.go @@ -0,0 +1,50 @@ +package networktypes_test + +import ( + "testing" + + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networktypes" +) + +func TestVerifyPeerFormat(t *testing.T) { + tests := []struct { + name string + peer launchtypes.Peer + want bool + }{ + { + name: "valid peer connection", + peer: launchtypes.NewPeerConn("node", "peer:port"), + want: true, + }, + { + name: "peer connection without port", + peer: launchtypes.NewPeerConn("node", "peer"), + want: false, + }, + { + name: "peer connection without the node address", + peer: launchtypes.NewPeerConn("node", ":port"), + want: false, + }, + { + name: "peer connection without the separator", + peer: launchtypes.NewPeerConn("node", "peerport"), + want: false, + }, + { + name: "invalid peer tunnel", + peer: launchtypes.NewPeerTunnel("", "", ""), + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := networktypes.VerifyPeerFormat(tt.peer) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/network/network/networktypes/profile.go b/network/network/networktypes/profile.go new file mode 100644 index 00000000..cfe096f6 --- /dev/null +++ b/network/network/networktypes/profile.go @@ -0,0 +1,117 @@ +package networktypes + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + profiletypes "github.com/ignite/network/x/profile/types" + projecttypes "github.com/ignite/network/x/project/types" +) + +// Validator represents the Validator profile on SPN. +type Validator struct { + Address string `json:"Address"` + OperatorAddresses []string `json:"OperatorAddresses"` + Identity string `json:"Identity"` + Website string `json:"Website"` + Details string `json:"Details"` + Moniker string `json:"Moniker"` + SecurityContact string `json:"SecurityContact"` +} + +func (v Validator) ToProfile( + projectID uint64, + vouchers sdk.Coins, + shares projecttypes.Shares, +) Profile { + return Profile{ + ProjectID: projectID, + Address: v.Address, + Identity: v.Identity, + Website: v.Website, + Details: v.Details, + Moniker: v.Moniker, + SecurityContact: v.SecurityContact, + Vouchers: vouchers, + Shares: shares, + } +} + +// ToValidator converts a Validator data from SPN and returns a Validator object. +func ToValidator(val profiletypes.Validator) Validator { + return Validator{ + Address: val.Address, + OperatorAddresses: val.OperatorAddresses, + Identity: val.Description.Identity, + Website: val.Description.Website, + Details: val.Description.Details, + Moniker: val.Description.Moniker, + SecurityContact: val.Description.SecurityContact, + } +} + +// Coordinator represents the Coordinator profile on SPN. +type Coordinator struct { + CoordinatorID uint64 `json:"ID"` + Address string `json:"Address"` + Active bool `json:"Active"` + Identity string `json:"Identity"` + Website string `json:"Website"` + Details string `json:"Details"` +} + +func (c Coordinator) ToProfile( + projectID uint64, + vouchers sdk.Coins, + shares projecttypes.Shares, +) Profile { + return Profile{ + ProjectID: projectID, + Address: c.Address, + Identity: c.Identity, + Website: c.Website, + Details: c.Details, + Vouchers: vouchers, + Shares: shares, + } +} + +// ToCoordinator converts a Coordinator data from SPN and returns a Coordinator object. +func ToCoordinator(coord profiletypes.Coordinator) Coordinator { + return Coordinator{ + CoordinatorID: coord.CoordinatorId, + Address: coord.Address, + Active: coord.Active, + Identity: coord.Description.Identity, + Website: coord.Description.Website, + Details: coord.Description.Details, + } +} + +type ( + // ChainShare represents the share of a chain on SPN. + ChainShare struct { + LaunchID uint64 `json:"LaunchID"` + Shares sdk.Coins `json:"Shares"` + } + + // Profile represents the address profile on SPN. + Profile struct { + Address string `json:"Address"` + ProjectID uint64 `json:"ProjectID,omitempty"` + Identity string `json:"Identity,omitempty"` + Website string `json:"Website,omitempty"` + Details string `json:"Details,omitempty"` + Moniker string `json:"Moniker,omitempty"` + SecurityContact string `json:"SecurityContact,omitempty"` + Vouchers sdk.Coins `json:"Vouchers,omitempty"` + Shares projecttypes.Shares `json:"Shares,omitempty"` + } + + // ProfileAcc represents the address profile method interface. + ProfileAcc interface { + ToProfile( + projectID uint64, + vouchers sdk.Coins, + shares projecttypes.Shares, + ) Profile + } +) diff --git a/network/network/networktypes/project.go b/network/network/networktypes/project.go new file mode 100644 index 00000000..d18073d1 --- /dev/null +++ b/network/network/networktypes/project.go @@ -0,0 +1,60 @@ +package networktypes + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + projecttypes "github.com/ignite/network/x/project/types" +) + +// Project represents the project of a chain on SPN. +type Project struct { + ID uint64 `json:"ID"` + Name string `json:"Name"` + CoordinatorID uint64 `json:"CoordinatorID"` + MainnetID uint64 `json:"MainnetID"` + MainnetInitialized bool `json:"MainnetInitialized"` + TotalSupply sdk.Coins `json:"TotalSupply"` + AllocatedShares string `json:"AllocatedShares"` + Metadata string `json:"Metadata"` +} + +// ToProject converts a project data from SPN and returns a Project object. +func ToProject(project projecttypes.Project) Project { + return Project{ + ID: project.ProjectId, + Name: project.ProjectName, + CoordinatorID: project.CoordinatorId, + MainnetID: project.MainnetId, + MainnetInitialized: project.MainnetInitialized, + TotalSupply: project.TotalSupply, + AllocatedShares: project.AllocatedShares.String(), + Metadata: string(project.Metadata), + } +} + +// MainnetAccount represents the project mainnet account of a chain on SPN. +type MainnetAccount struct { + Address string `json:"Address"` + Shares projecttypes.Shares `json:"Shares"` +} + +// ToMainnetAccount converts a mainnet account data from SPN and returns a MainnetAccount object. +func ToMainnetAccount(acc projecttypes.MainnetAccount) MainnetAccount { + return MainnetAccount{ + Address: acc.Address, + Shares: acc.Shares, + } +} + +// ProjectChains represents the chains of a project on SPN. +type ProjectChains struct { + ProjectID uint64 `json:"ProjectID"` + Chains []uint64 `json:"Chains"` +} + +// ToProjectChains converts a project chains data from SPN and returns a ProjectChains object. +func ToProjectChains(c projecttypes.ProjectChains) ProjectChains { + return ProjectChains{ + ProjectID: c.ProjectId, + Chains: c.Chains, + } +} diff --git a/network/network/networktypes/request.go b/network/network/networktypes/request.go new file mode 100644 index 00000000..1c65a757 --- /dev/null +++ b/network/network/networktypes/request.go @@ -0,0 +1,183 @@ +package networktypes + +import ( + "fmt" + + "github.com/cometbft/cometbft/crypto/ed25519" + "github.com/ignite/cli/v28/ignite/pkg/xtime" + launchtypes "github.com/ignite/network/x/launch/types" + + "github.com/ignite/apps/network/network/address" + "github.com/ignite/apps/network/network/gentx" +) + +// Request action descriptions. +const ( + RequestActionAddAccount = "add account to the network" + RequestActionAddValidator = "join the network as a validator" + RequestActionAddVestingAccount = "add vesting account to the network" + RequestActionRemoveAccount = "remove account from the network" + RequestActionRemoveValidator = "remove validator from the network" + RequestActionChangeParams = "change param on the network" + + RequestActionResultAddAccount = "account added to the network" + RequestActionResultAddValidator = "Validator added to the network" + RequestActionResultAddVestingAccount = "vesting account added to the network" + RequestActionResultRemoveAccount = "account removed from network" + RequestActionResultRemoveValidator = "validator removed from network" + RequestActionResultChangeParams = "param changed on network" + + RequestActionUnrecognized = "" +) + +type ( + // Request represents the launch Request of a chain on SPN. + Request struct { + LaunchID uint64 `json:"LaunchID"` + RequestID uint64 `json:"RequestID"` + Creator string `json:"Creator"` + CreatedAt string `json:"CreatedAt"` + Content launchtypes.RequestContent `json:"Content"` + Status string `json:"Status"` + } +) + +// ToRequest converts a request data from SPN and returns a Request object. +func ToRequest(request launchtypes.Request) Request { + return Request{ + LaunchID: request.LaunchId, + RequestID: request.RequestId, + Creator: request.Creator, + CreatedAt: xtime.FormatUnixInt(request.CreatedAt), + Content: request.Content, + Status: launchtypes.Request_Status_name[int32(request.Status)], + } +} + +// RequestsFromRequestContents creates a list of requests from a list request contents to simulate requests that have not been sent to request pool yet. +// The request ID is set to 0 for the first request and incremented for each request, other values are not set. +func RequestsFromRequestContents(launchID uint64, contents []launchtypes.RequestContent) []Request { + requests := make([]Request, len(contents)) + for i, content := range contents { + requests[i] = Request{ + LaunchID: launchID, + RequestID: uint64(i), + Content: content, + } + } + return requests +} + +// RequestActionDescriptionFromContent describes the action of the request from its content. +func RequestActionDescriptionFromContent(content launchtypes.RequestContent) string { + switch content.Content.(type) { + case *launchtypes.RequestContent_GenesisAccount: + return RequestActionAddAccount + case *launchtypes.RequestContent_GenesisValidator: + return RequestActionAddValidator + case *launchtypes.RequestContent_VestingAccount: + return RequestActionAddVestingAccount + case *launchtypes.RequestContent_AccountRemoval: + return RequestActionRemoveAccount + case *launchtypes.RequestContent_ValidatorRemoval: + return RequestActionRemoveValidator + case *launchtypes.RequestContent_ParamChange: + return RequestActionChangeParams + default: + return RequestActionUnrecognized + } +} + +// RequestActionResultDescriptionFromContent describe the result of the action of the request from its content. +func RequestActionResultDescriptionFromContent(content launchtypes.RequestContent) string { + switch content.Content.(type) { + case *launchtypes.RequestContent_GenesisAccount: + return RequestActionResultAddAccount + case *launchtypes.RequestContent_GenesisValidator: + return RequestActionResultAddValidator + case *launchtypes.RequestContent_VestingAccount: + return RequestActionResultAddVestingAccount + case *launchtypes.RequestContent_AccountRemoval: + return RequestActionResultRemoveAccount + case *launchtypes.RequestContent_ValidatorRemoval: + return RequestActionResultRemoveValidator + case *launchtypes.RequestContent_ParamChange: + return RequestActionResultChangeParams + default: + return RequestActionUnrecognized + } +} + +// VerifyRequest verifies the validity of the request from its content (static check). +func VerifyRequest(request Request) error { + req, ok := request.Content.Content.(*launchtypes.RequestContent_GenesisValidator) + if ok { + err := VerifyAddValidatorRequest(req) + if err != nil { + return NewWrappedErrInvalidRequest(request.RequestID, err.Error()) + } + } + + return nil +} + +// VerifyAddValidatorRequest verifies the validator request parameters. +func VerifyAddValidatorRequest(req *launchtypes.RequestContent_GenesisValidator) error { + // If this is an add validator request + var ( + peer = req.GenesisValidator.Peer + valAddress = req.GenesisValidator.Address + consPubKey = req.GenesisValidator.ConsPubKey + selfDelegation = req.GenesisValidator.SelfDelegation + ) + + // Check values inside the gentx are correct + info, err := gentx.ParseGentx(req.GenesisValidator.GenTx) + if err != nil { + return fmt.Errorf("cannot parse gentx %w", err) + } + + // Change the address prefix fetched from the gentx to the one used on SPN + // Because all on-chain stored address on SPN uses the SPN prefix + spnFetchedAddress, err := address.ChangeValidatorAddressPrefix(info.ValidatorAddress, SPN) + if err != nil { + return err + } + + // Check validator address + if valAddress != spnFetchedAddress { + return fmt.Errorf( + "the validator address %s doesn't match the one inside the gentx %s", + valAddress, + spnFetchedAddress, + ) + } + + // Check validator address + if !info.PubKey.Equals(ed25519.PubKey(consPubKey)) { + return fmt.Errorf( + "the consensus pub key %s doesn't match the one inside the gentx %s", + ed25519.PubKey(consPubKey).String(), + info.PubKey.String(), + ) + } + + // Check self delegation + if selfDelegation.Denom != info.SelfDelegation.Denom || + !selfDelegation.Equal(info.SelfDelegation) { + return fmt.Errorf( + "the self delegation %s doesn't match the one inside the gentx %s", + selfDelegation.String(), + info.SelfDelegation.String(), + ) + } + + // Check the format of the peer + if !VerifyPeerFormat(peer) { + return fmt.Errorf( + "the peer address %s doesn't match the peer format :", + peer.String(), + ) + } + return nil +} diff --git a/network/network/networktypes/request_test.go b/network/network/networktypes/request_test.go new file mode 100644 index 00000000..6d41976e --- /dev/null +++ b/network/network/networktypes/request_test.go @@ -0,0 +1,349 @@ +package networktypes_test + +import ( + "encoding/base64" + "fmt" + "math/rand" + "testing" + + sdkmath "cosmossdk.io/math" + "github.com/cometbft/cometbft/crypto/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + spnsample "github.com/ignite/network/testutil/sample" + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networktypes" +) + +var ( + r = rand.New(rand.NewSource(1)) + SampleRequestAddAccount = launchtypes.NewGenesisAccount(0, "spn1dd246y", spnsample.Coins(r)) + SampleRequestAddValidator = launchtypes.NewGenesisValidator( + 0, + "spn1dd246y", + spnsample.Bytes(r, 300), + spnsample.Bytes(r, 30), + spnsample.Coin(r), + spnsample.GenesisValidatorPeer(r), + ) + SampleRequestAddVestingAccount = launchtypes.NewVestingAccount(0, "spn1dd246y", spnsample.VestingOptions(r)) + SampleRequestRemoveAccount = launchtypes.NewAccountRemoval("spn1dd246y") + SampleRequestRemoveValidator = launchtypes.NewValidatorRemoval("spn1dd246y") + SampleRequestChangeParam = launchtypes.NewParamChange(0, "foo", "bar", spnsample.Bytes(r, 30)) +) + +func TestRequestsFromRequestContents(t *testing.T) { + tests := []struct { + name string + launchID uint64 + reqs []launchtypes.RequestContent + want []networktypes.Request + }{ + { + name: "empty request contents", + launchID: 0, + reqs: []launchtypes.RequestContent{}, + want: []networktypes.Request{}, + }, + { + name: "one request content", + launchID: 1, + reqs: []launchtypes.RequestContent{ + launchtypes.NewGenesisAccount( + 1, + "spn1dd246y", + sdk.NewCoins(sdk. + NewCoin("stake", sdkmath.NewInt(1000)), + ), + ), + }, + want: []networktypes.Request{ + { + LaunchID: 1, + RequestID: 0, + Content: launchtypes.NewGenesisAccount( + 1, + "spn1dd246y", + sdk.NewCoins(sdk. + NewCoin("stake", sdkmath.NewInt(1000)), + ), + ), + }, + }, + }, + { + name: "multiple request contents", + launchID: 2, + reqs: []launchtypes.RequestContent{ + launchtypes.NewGenesisAccount( + 2, + "spn5s5z2x", + sdk.NewCoins(sdk. + NewCoin("foo", sdkmath.NewInt(2000)), + ), + ), + launchtypes.NewGenesisAccount( + 2, + "spn2x2x2x", + sdk.NewCoins(sdk. + NewCoin("bar", sdkmath.NewInt(5000)), + ), + ), + }, + want: []networktypes.Request{ + { + LaunchID: 2, + RequestID: 0, + Content: launchtypes.NewGenesisAccount( + 2, + "spn5s5z2x", + sdk.NewCoins(sdk. + NewCoin("foo", sdkmath.NewInt(2000)), + ), + ), + }, + { + LaunchID: 2, + RequestID: 1, + Content: launchtypes.NewGenesisAccount( + 2, + "spn2x2x2x", + sdk.NewCoins(sdk. + NewCoin("bar", sdkmath.NewInt(5000)), + ), + ), + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := networktypes.RequestsFromRequestContents(tt.launchID, tt.reqs) + require.Equal(t, tt.want, got) + }) + } +} + +func TestRequestActionDescriptionFromContent(t *testing.T) { + tests := []struct { + name string + req launchtypes.RequestContent + want string + }{ + { + name: "add account request content should return correct description", + req: SampleRequestAddAccount, + want: networktypes.RequestActionAddAccount, + }, + { + name: "add validator request content should return correct description", + req: SampleRequestAddValidator, + want: networktypes.RequestActionAddValidator, + }, + { + name: "add vesting account request content should return correct description", + req: SampleRequestAddVestingAccount, + want: networktypes.RequestActionAddVestingAccount, + }, + { + name: "remove account request content should return correct description", + req: SampleRequestRemoveAccount, + want: networktypes.RequestActionRemoveAccount, + }, + { + name: "remove validator request content should return correct description", + req: SampleRequestRemoveValidator, + want: networktypes.RequestActionRemoveValidator, + }, + { + name: "change params request content should return correct description", + req: SampleRequestChangeParam, + want: networktypes.RequestActionChangeParams, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := networktypes.RequestActionDescriptionFromContent(tt.req) + require.Equal(t, tt.want, got) + }) + } +} + +func TestRequestActionResultDescriptionFromContent(t *testing.T) { + tests := []struct { + name string + req launchtypes.RequestContent + want string + }{ + { + name: "add account request content should return correct result description", + req: SampleRequestAddAccount, + want: networktypes.RequestActionResultAddAccount, + }, + { + name: "add validator request content should return correct result description", + req: SampleRequestAddValidator, + want: networktypes.RequestActionResultAddValidator, + }, + { + name: "add vesting account request content should return correct result description", + req: SampleRequestAddVestingAccount, + want: networktypes.RequestActionResultAddVestingAccount, + }, + { + name: "remove account request content should return correct result description", + req: SampleRequestRemoveAccount, + want: networktypes.RequestActionResultRemoveAccount, + }, + { + name: "remove validator request content should return correct result description", + req: SampleRequestRemoveValidator, + want: networktypes.RequestActionResultRemoveValidator, + }, + { + name: "change params request content should return correct result description", + req: SampleRequestChangeParam, + want: networktypes.RequestActionResultChangeParams, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := networktypes.RequestActionResultDescriptionFromContent(tt.req) + require.Equal(t, tt.want, got) + }) + } +} + +func TestVerifyAddValidatorRequest(t *testing.T) { + gentx := []byte(`{ + "body": { + "messages": [ + { + "delegator_address": "cosmos1dd246yq6z5vzjz9gh8cff46pll75yyl8ygndsj", + "pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "aeQLCJOjXUyB7evOodI4mbrshIt3vhHGlycJDbUkaMs=" + }, + "validator_address": "cosmosvaloper1dd246yq6z5vzjz9gh8cff46pll75yyl8pu8cup", + "value": { + "amount": "95000000", + "denom": "stake" + } + } + ] + } +}`) + pk, err := base64.StdEncoding.DecodeString("aeQLCJOjXUyB7evOodI4mbrshIt3vhHGlycJDbUkaMs=") + require.NoError(t, err) + + tests := []struct { + name string + req *launchtypes.RequestContent_GenesisValidator + want error + }{ + { + name: "valid genesis validator request", + req: &launchtypes.RequestContent_GenesisValidator{ + GenesisValidator: &launchtypes.GenesisValidator{ + Address: "spn1dd246yq6z5vzjz9gh8cff46pll75yyl8c5tt7g", + GenTx: gentx, + ConsPubKey: ed25519.PubKey(pk), + SelfDelegation: sdk.NewCoin("stake", sdkmath.NewInt(95000000)), + Peer: launchtypes.NewPeerConn("nodeid", "127.163.0.1:2446"), + }, + }, + }, + { + name: "invalid peer host", + req: &launchtypes.RequestContent_GenesisValidator{ + GenesisValidator: &launchtypes.GenesisValidator{ + Address: "spn1dd246yq6z5vzjz9gh8cff46pll75yyl8c5tt7g", + GenTx: gentx, + ConsPubKey: ed25519.PubKey(pk), + SelfDelegation: sdk.NewCoin("stake", sdkmath.NewInt(95000000)), + Peer: launchtypes.NewPeerConn("nodeid", "122.114.800.11"), + }, + }, + want: fmt.Errorf("the peer address id:\"nodeid\" tcp_address:\"122.114.800.11\" doesn't match the peer format :"), + }, + { + name: "invalid gentx", + req: &launchtypes.RequestContent_GenesisValidator{ + GenesisValidator: &launchtypes.GenesisValidator{ + Address: "spn1dd246yq6z5vzjz9gh8cff46pll75yyl8c5tt7g", + GenTx: []byte(`{}`), + ConsPubKey: ed25519.PubKey(pk), + SelfDelegation: sdk.NewCoin("stake", sdkmath.NewInt(95000000)), + Peer: launchtypes.NewPeerConn("nodeid", "127.163.0.1:2446"), + }, + }, + want: fmt.Errorf("cannot parse gentx the gentx cannot be parsed"), + }, + { + name: "invalid self delegation denom", + req: &launchtypes.RequestContent_GenesisValidator{ + GenesisValidator: &launchtypes.GenesisValidator{ + Address: "spn1dd246yq6z5vzjz9gh8cff46pll75yyl8c5tt7g", + GenTx: gentx, + ConsPubKey: ed25519.PubKey(pk), + SelfDelegation: sdk.NewCoin("foo", sdkmath.NewInt(95000000)), + Peer: launchtypes.NewPeerConn("nodeid", "127.163.0.1:2446"), + }, + }, + want: fmt.Errorf("the self delegation 95000000foo doesn't match the one inside the gentx 95000000stake"), + }, + { + name: "invalid self delegation value", + req: &launchtypes.RequestContent_GenesisValidator{ + GenesisValidator: &launchtypes.GenesisValidator{ + Address: "spn1dd246yq6z5vzjz9gh8cff46pll75yyl8c5tt7g", + GenTx: gentx, + ConsPubKey: ed25519.PubKey(pk), + SelfDelegation: sdk.NewCoin("stake", sdkmath.NewInt(3)), + Peer: launchtypes.NewPeerConn("nodeid", "127.163.0.1:2446"), + }, + }, + want: fmt.Errorf("the self delegation 3stake doesn't match the one inside the gentx 95000000stake"), + }, + { + name: "invalid consensus pub key", + req: &launchtypes.RequestContent_GenesisValidator{ + GenesisValidator: &launchtypes.GenesisValidator{ + Address: "spn1dd246yq6z5vzjz9gh8cff46pll75yyl8c5tt7g", + GenTx: gentx, + ConsPubKey: ed25519.PubKey("cosmos1gkheudhhjsvq0s8fxt7p6pwe0k3k30kepcnz9p="), + SelfDelegation: sdk.NewCoin("stake", sdkmath.NewInt(95000000)), + Peer: launchtypes.NewPeerConn("nodeid", "127.163.0.1:2446"), + }, + }, + want: fmt.Errorf("the consensus pub key PubKeyEd25519{636F736D6F7331676B6865756468686A737671307338667874377036707765306B336B33306B6570636E7A39703D} doesn't match the one inside the gentx PubKeyEd25519{69E40B0893A35D4C81EDEBCEA1D23899BAEC848B77BE11C69727090DB52468CB}"), + }, + { + name: "invalid validator address", + req: &launchtypes.RequestContent_GenesisValidator{ + GenesisValidator: &launchtypes.GenesisValidator{ + Address: "spn1gkheudhhjsvq0s8fxt7p6pwe0k3k30keaytytm", + GenTx: gentx, + ConsPubKey: ed25519.PubKey(pk), + SelfDelegation: sdk.NewCoin("stake", sdkmath.NewInt(95000000)), + Peer: launchtypes.NewPeerConn("nodeid", "127.163.0.1:2446"), + }, + }, + want: fmt.Errorf("the validator address spn1gkheudhhjsvq0s8fxt7p6pwe0k3k30keaytytm doesn't match the one inside the gentx spn1dd246yq6z5vzjz9gh8cff46pll75yyl8c5tt7g"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := networktypes.VerifyAddValidatorRequest(tt.req) + if tt.want != nil { + require.Error(t, err) + require.Equal(t, tt.want.Error(), err.Error()) + return + } + require.NoError(t, err) + }) + } +} diff --git a/network/network/networktypes/reward.go b/network/network/networktypes/reward.go new file mode 100644 index 00000000..8cae5e99 --- /dev/null +++ b/network/network/networktypes/reward.go @@ -0,0 +1,22 @@ +package networktypes + +import ( + spntypes "github.com/ignite/network/pkg/types" +) + +type ( + // Reward is node reward info. + Reward struct { + ConsensusState spntypes.ConsensusState + ValidatorSet spntypes.ValidatorSet + RevisionHeight uint64 + } + + // RewardIBCInfo holds IBC info to relay packets to claim rewards. + RewardIBCInfo struct { + ChainID string + ClientID string + ConnectionID string + ChannelID string + } +) diff --git a/network/network/node.go b/network/network/node.go new file mode 100644 index 00000000..998b0ebe --- /dev/null +++ b/network/network/node.go @@ -0,0 +1,191 @@ +package network + +import ( + "context" + "encoding/base64" + "errors" + + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibcconntypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + ibcchanneltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + spntypes "github.com/ignite/network/pkg/types" + monitoringptypes "github.com/ignite/network/x/monitoringp/types" + + "github.com/ignite/apps/network/network/networktypes" +) + +// Node is node builder. +type Node struct { + cosmos CosmosClient + stakingQuery stakingtypes.QueryClient + ibcClientQuery ibcclienttypes.QueryClient + ibcConnQuery ibcconntypes.QueryClient + ibcChannelQuery ibcchanneltypes.QueryClient + monitoringProviderQuery monitoringptypes.QueryClient +} + +// NewNode creates a new client for node API. +func NewNode(cosmos CosmosClient) Node { + return Node{ + cosmos: cosmos, + stakingQuery: stakingtypes.NewQueryClient(cosmos.Context()), + ibcClientQuery: ibcclienttypes.NewQueryClient(cosmos.Context()), + ibcConnQuery: ibcconntypes.NewQueryClient(cosmos.Context()), + ibcChannelQuery: ibcchanneltypes.NewQueryClient(cosmos.Context()), + monitoringProviderQuery: monitoringptypes.NewQueryClient(cosmos.Context()), + } +} + +// RewardsInfo Fetches the consensus state with the validator set and the unbounding time. +func (n Node) RewardsInfo(ctx context.Context) ( + reward networktypes.Reward, + chainID string, + unbondingTimeSeconds int64, + err error, +) { + status, err := n.cosmos.Status(ctx) + if err != nil { + return networktypes.Reward{}, "", 0, err + } + lastBlockHeight := status.SyncInfo.LatestBlockHeight + + info, err := n.consensus(ctx, n.cosmos, lastBlockHeight) + if err != nil { + return networktypes.Reward{}, "", 0, err + } + + stakingParams, err := n.stakingParams(ctx) + if err != nil { + return networktypes.Reward{}, "", 0, err + } + + return info, + status.NodeInfo.Network, + int64(stakingParams.UnbondingTime.Seconds()), + nil +} + +// RewardIBCInfo returns IBC info to relay packets to claim rewards for the chain. +func (n Node) RewardIBCInfo(ctx context.Context) (networktypes.RewardIBCInfo, error) { + clientID, err := n.consumerClientID(ctx) + if err != nil && !errors.Is(err, ErrObjectNotFound) { + return networktypes.RewardIBCInfo{}, err + } + + channelID, err := n.connectionChannelID(ctx) + if err != nil && !errors.Is(err, ErrObjectNotFound) { + return networktypes.RewardIBCInfo{}, err + } + + connections, err := n.clientConnections(ctx, clientID) + if err != nil && !errors.Is(err, ErrObjectNotFound) { + return networktypes.RewardIBCInfo{}, err + } + + info := networktypes.RewardIBCInfo{ + ClientID: clientID, + ChannelID: channelID, + } + + if len(connections) > 0 { + info.ConnectionID = connections[0] + } + + return info, nil +} + +// consensus Fetches the consensus state with the validator set. +func (n Node) consensus(ctx context.Context, client CosmosClient, height int64) (networktypes.Reward, error) { + consensusState, err := client.ConsensusInfo(ctx, height) + if err != nil { + return networktypes.Reward{}, err + } + + spnConsensusState := spntypes.NewConsensusState( + consensusState.Timestamp, + consensusState.NextValidatorsHash, + consensusState.Root, + ) + + validators := make([]spntypes.Validator, len(consensusState.ValidatorSet.Validators)) + for i, validator := range consensusState.ValidatorSet.Validators { + validators[i] = spntypes.NewValidator( + base64.StdEncoding.EncodeToString(validator.PubKey.GetEd25519()), + validator.ProposerPriority, + validator.VotingPower, + ) + } + + reward := networktypes.Reward{ + ConsensusState: spnConsensusState, + ValidatorSet: spntypes.NewValidatorSet(validators...), + RevisionHeight: uint64(height), + } + + return reward, nil +} + +// connectionChannels fetches the chain connection channels by connection id. +func (n Node) connectionChannels(ctx context.Context, connectionID string) (channels []string, err error) { + res, err := n.ibcChannelQuery.ConnectionChannels(ctx, &ibcchanneltypes.QueryConnectionChannelsRequest{ + Connection: connectionID, + }) + if isNotFoundErr(err) { + return channels, nil + } else if err != nil { + return nil, err + } + for _, channel := range res.Channels { + channels = append(channels, channel.ChannelId) + } + return +} + +// clientConnections fetches the chain client connections by client id. +func (n Node) clientConnections(ctx context.Context, clientID string) ([]string, error) { + res, err := n.ibcConnQuery.ClientConnections(ctx, &ibcconntypes.QueryClientConnectionsRequest{ + ClientId: clientID, + }) + if isNotFoundErr(err) { + return []string{}, nil + } else if err != nil { + return nil, err + } + return res.ConnectionPaths, err +} + +// stakingParams fetches the staking module params. +func (n Node) stakingParams(ctx context.Context) (stakingtypes.Params, error) { + res, err := n.stakingQuery.Params(ctx, &stakingtypes.QueryParamsRequest{}) + if err != nil { + return stakingtypes.Params{}, err + } + return res.Params, nil +} + +// consumerClientID fetches the consumer client id from the monitoring provider. +func (n Node) consumerClientID(ctx context.Context) (string, error) { + res, err := n.monitoringProviderQuery.GetConsumerClientID( + ctx, &monitoringptypes.QueryGetConsumerClientIDRequest{}, + ) + if isNotFoundErr(err) { + return "", ErrObjectNotFound + } else if err != nil { + return "", err + } + return res.ConsumerClientId.ClientId, nil +} + +// connectionChannelID fetches the consumer connection chnnael id from the monitoring provider. +func (n Node) connectionChannelID(ctx context.Context) (string, error) { + res, err := n.monitoringProviderQuery.GetConnectionChannelID( + ctx, &monitoringptypes.QueryGetConnectionChannelIDRequest{}, + ) + if isNotFoundErr(err) { + return "", ErrObjectNotFound + } else if err != nil { + return "", err + } + return res.ConnectionChannelId.ChannelId, nil +} diff --git a/network/network/peer.go b/network/network/peer.go new file mode 100644 index 00000000..78304982 --- /dev/null +++ b/network/network/peer.go @@ -0,0 +1,30 @@ +package network + +import ( + "fmt" + "strings" + + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/pkg/errors" +) + +func PeerAddress(peer launchtypes.Peer) (string, error) { + var peerAddr string + switch conn := peer.Connection.(type) { + case *launchtypes.Peer_TcpAddress: + peerAddr = fmt.Sprintf("%s@%s", peer.Id, conn.TcpAddress) + case *launchtypes.Peer_HttpTunnel: + peerAddr = fmt.Sprintf("%s@%s", peer.Id, conn.HttpTunnel.Address) + default: + return peerAddr, fmt.Errorf("invalid peer connection type: %T", peer.Connection) + } + return peerAddr, nil +} + +func ParsePeerAddress(addr string) (launchtypes.Peer, error) { + sp := strings.Split(addr, "@") + if len(sp) != 2 { + return launchtypes.Peer{}, errors.New("invalid peer address format") + } + return launchtypes.NewPeerConn(sp[0], sp[1]), nil +} diff --git a/network/network/peer_test.go b/network/network/peer_test.go new file mode 100644 index 00000000..a3937022 --- /dev/null +++ b/network/network/peer_test.go @@ -0,0 +1,46 @@ +package network + +import ( + "errors" + "testing" + + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/stretchr/testify/require" +) + +func TestPeerAddress(t *testing.T) { + tests := []struct { + name string + peer launchtypes.Peer + want string + err error + }{ + { + name: "simple peer connection", + peer: launchtypes.NewPeerConn("simple-conn", "200.100.50.20"), + want: "simple-conn@200.100.50.20", + }, + { + name: "http tunnel peer", + peer: launchtypes.NewPeerTunnel("httpTunnel", "tunnel", "200.100.50.20"), + want: "httpTunnel@200.100.50.20", + }, + { + name: "invalid peer", + peer: launchtypes.Peer{Id: "invalid-peer", Connection: nil}, + err: errors.New("invalid peer connection type: "), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := PeerAddress(tt.peer) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/network/network/profile.go b/network/network/profile.go new file mode 100644 index 00000000..2f62ab19 --- /dev/null +++ b/network/network/profile.go @@ -0,0 +1,200 @@ +package network + +import ( + "context" + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ignite/cli/v28/ignite/pkg/events" + profiletypes "github.com/ignite/network/x/profile/types" + projecttypes "github.com/ignite/network/x/project/types" + + "github.com/ignite/apps/network/network/networktypes" +) + +// CoordinatorIDByAddress returns the CoordinatorByAddress from SPN. +func (n Network) CoordinatorIDByAddress(ctx context.Context, address string) (uint64, error) { + n.ev.Send("Fetching coordinator by address", events.ProgressStart()) + resCoordByAddr, err := n.profileQuery.GetCoordinatorByAddress(ctx, + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: address, + }, + ) + + if isNotFoundErr(err) { + return 0, ErrObjectNotFound + } else if err != nil { + return 0, err + } + return resCoordByAddr.Coordinator.CoordinatorId, nil +} + +// SetCoordinatorDescription set the description of a coordinator +// or creates the coordinator if it doesn't exist yet for the sender address. +func (n Network) SetCoordinatorDescription(ctx context.Context, description profiletypes.CoordinatorDescription) error { + n.ev.Send("Setting coordinator description", events.ProgressStart()) + + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return err + } + + // check if coordinator exists + _, err = n.CoordinatorIDByAddress(ctx, addr) + if errors.Is(err, ErrObjectNotFound) { + // create a new coordinator + msgCreateCoordinator := profiletypes.NewMsgCreateCoordinator( + addr, + description.Identity, + description.Website, + description.Details, + ) + res, err := n.cosmos.BroadcastTx(ctx, n.account, msgCreateCoordinator) + if err != nil { + return err + } + var requestRes profiletypes.MsgCreateCoordinatorResponse + return res.Decode(&requestRes) + } else if err == nil { + // update the description for the coordinator + msgUpdateCoordinatorDescription := profiletypes.NewMsgUpdateCoordinatorDescription( + addr, + description.Identity, + description.Website, + description.Details, + ) + res, err := n.cosmos.BroadcastTx(ctx, n.account, msgUpdateCoordinatorDescription) + if err != nil { + return err + } + var requestRes profiletypes.MsgUpdateCoordinatorDescriptionResponse + return res.Decode(&requestRes) + } + return err +} + +// Coordinator returns the Coordinator by address from SPN. +func (n Network) Coordinator(ctx context.Context, address string) (networktypes.Coordinator, error) { + n.ev.Send("Fetching coordinator details", events.ProgressStart()) + coordinatorID, err := n.CoordinatorIDByAddress(ctx, address) + if err != nil { + return networktypes.Coordinator{}, err + } + resCoord, err := n.profileQuery.GetCoordinator(ctx, + &profiletypes.QueryGetCoordinatorRequest{ + CoordinatorId: coordinatorID, + }, + ) + if isNotFoundErr(err) { + return networktypes.Coordinator{}, ErrObjectNotFound + } else if err != nil { + return networktypes.Coordinator{}, err + } + return networktypes.ToCoordinator(resCoord.Coordinator), nil +} + +// SetValidatorDescription set a validator profile. +func (n Network) SetValidatorDescription(ctx context.Context, validator profiletypes.Validator) error { + n.ev.Send("Setting validator description", events.ProgressStart()) + + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return err + } + + message := profiletypes.NewMsgUpdateValidatorDescription( + addr, + validator.Description.Identity, + validator.Description.Moniker, + validator.Description.Website, + validator.Description.SecurityContact, + validator.Description.Details, + ) + + res, err := n.cosmos.BroadcastTx(ctx, n.account, message) + if err != nil { + return err + } + + var requestRes profiletypes.MsgUpdateValidatorDescriptionResponse + return res.Decode(&requestRes) +} + +// Validator returns the Validator by address from SPN. +func (n Network) Validator(ctx context.Context, address string) (networktypes.Validator, error) { + n.ev.Send("Fetching validator description", events.ProgressStart()) + res, err := n.profileQuery.GetValidator(ctx, &profiletypes.QueryGetValidatorRequest{ + Address: address, + }) + if isNotFoundErr(err) { + return networktypes.Validator{}, ErrObjectNotFound + } else if err != nil { + return networktypes.Validator{}, err + } + return networktypes.ToValidator(res.Validator), nil +} + +// Balances returns the all balances by address from SPN. +func (n Network) Balances(ctx context.Context, address string) (sdk.Coins, error) { + n.ev.Send("Fetching address balances", events.ProgressStart()) + res, err := banktypes.NewQueryClient(n.cosmos.Context()).AllBalances(ctx, + &banktypes.QueryAllBalancesRequest{ + Address: address, + }, + ) + if isNotFoundErr(err) { + return sdk.Coins{}, ErrObjectNotFound + } else if err != nil { + return sdk.Coins{}, err + } + return res.Balances, nil +} + +// Profile returns the address profile info. +func (n Network) Profile(ctx context.Context, projectID uint64) (networktypes.Profile, error) { + address, err := n.account.Address(networktypes.SPN) + if err != nil { + return networktypes.Profile{}, err + } + + // fetch vouchers held by the account + coins, err := n.Balances(ctx, address) + if err != nil { + return networktypes.Profile{}, err + } + vouchers := sdk.NewCoins() + for _, coin := range coins { + // parse the coin to filter all non-voucher coins from the balance + _, err := projecttypes.VoucherProject(coin.Denom) + if err == nil { + vouchers = append(vouchers, coin) + } + } + vouchers = vouchers.Sort() + + var shares projecttypes.Shares + + // if a project ID is specified, fetches the shares of the project + if projectID > 0 { + acc, err := n.MainnetAccount(ctx, projectID, address) + if err != nil && !errors.Is(err, ErrObjectNotFound) { + return networktypes.Profile{}, err + } + shares = acc.Shares + } + + var p networktypes.ProfileAcc + p, err = n.Validator(ctx, address) + if errors.Is(err, ErrObjectNotFound) { + p, err = n.Coordinator(ctx, address) + if errors.Is(err, ErrObjectNotFound) { + p = networktypes.Coordinator{Address: address} + } else if err != nil { + return networktypes.Profile{}, err + } + } else if err != nil { + return networktypes.Profile{}, err + } + return p.ToProfile(projectID, vouchers, shares), nil +} diff --git a/network/network/project.go b/network/network/project.go new file mode 100644 index 00000000..06c42cc1 --- /dev/null +++ b/network/network/project.go @@ -0,0 +1,183 @@ +package network + +import ( + "context" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/events" + projecttypes "github.com/ignite/network/x/project/types" + + "github.com/ignite/apps/network/network/networktypes" +) + +type ( + // Prop updates project proposal. + Prop func(*updateProp) + + // updateProp represents the update project proposal. + updateProp struct { + name string + metadata []byte + totalSupply sdk.Coins + } +) + +// WithProjectName provides a name proposal to update the project. +func WithProjectName(name string) Prop { + return func(c *updateProp) { + c.name = name + } +} + +// WithProjectMetadata provides a meta data proposal to update the project. +func WithProjectMetadata(metadata string) Prop { + return func(c *updateProp) { + c.metadata = []byte(metadata) + } +} + +// WithProjectTotalSupply provides a total supply proposal to update the project. +func WithProjectTotalSupply(totalSupply sdk.Coins) Prop { + return func(c *updateProp) { + c.totalSupply = totalSupply + } +} + +// Project fetches the project from Network. +func (n Network) Project(ctx context.Context, projectID uint64) (networktypes.Project, error) { + n.ev.Send("Fetching project information", events.ProgressStart()) + res, err := n.projectQuery.GetProject(ctx, &projecttypes.QueryGetProjectRequest{ + ProjectId: projectID, + }) + if isNotFoundErr(err) { + return networktypes.Project{}, ErrObjectNotFound + } else if err != nil { + return networktypes.Project{}, err + } + return networktypes.ToProject(res.Project), nil +} + +// Projects fetches the projects from Network. +func (n Network) Projects(ctx context.Context) ([]networktypes.Project, error) { + var projects []networktypes.Project + + n.ev.Send("Fetching projects information", events.ProgressStart()) + res, err := n.projectQuery.ListProject(ctx, &projecttypes.QueryAllProjectRequest{}) + if err != nil { + return projects, err + } + + // Parse fetched projects + for _, project := range res.Project { + projects = append(projects, networktypes.ToProject(project)) + } + + return projects, nil +} + +// CreateProject creates a project in Network. +func (n Network) CreateProject(ctx context.Context, name, metadata string, totalSupply sdk.Coins) (int64, error) { + n.ev.Send(fmt.Sprintf("Creating project %s", name), events.ProgressStart()) + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return 0, err + } + + msgCreateProject := projecttypes.NewMsgCreateProject( + addr, + name, + totalSupply, + []byte(metadata), + ) + res, err := n.cosmos.BroadcastTx(ctx, n.account, msgCreateProject) + if err != nil { + return 0, err + } + + var createProjectRes projecttypes.MsgCreateProjectResponse + if err := res.Decode(&createProjectRes); err != nil { + return 0, err + } + + return int64(createProjectRes.ProjectId), nil +} + +// InitializeMainnet Initialize the mainnet of the project. +func (n Network) InitializeMainnet( + ctx context.Context, + projectID uint64, + sourceURL, + sourceHash string, + mainnetChainID string, +) (uint64, error) { + n.ev.Send("Initializing the mainnet project", events.ProgressStart()) + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return 0, err + } + + msg := projecttypes.NewMsgInitializeMainnet( + addr, + projectID, + sourceURL, + sourceHash, + mainnetChainID, + ) + + res, err := n.cosmos.BroadcastTx(ctx, n.account, msg) + if err != nil { + return 0, err + } + + var initMainnetRes projecttypes.MsgInitializeMainnetResponse + if err := res.Decode(&initMainnetRes); err != nil { + return 0, err + } + + n.ev.Send(fmt.Sprintf("Project %d initialized on mainnet", projectID), events.ProgressFinish()) + + return initMainnetRes.MainnetId, nil +} + +// UpdateProject updates the project name or metadata. +func (n Network) UpdateProject( + ctx context.Context, + id uint64, + props ...Prop, +) error { + // Apply the options provided by the user + p := updateProp{} + for _, apply := range props { + apply(&p) + } + + n.ev.Send(fmt.Sprintf("Updating the project %d", id), events.ProgressStart()) + account, err := n.account.Address(networktypes.SPN) + if err != nil { + return err + } + + msgs := make([]sdk.Msg, 0) + if p.name != "" || len(p.metadata) > 0 { + msgs = append(msgs, projecttypes.NewMsgEditProject( + account, + id, + p.name, + p.metadata, + )) + } + if !p.totalSupply.Empty() { + msgs = append(msgs, projecttypes.NewMsgUpdateTotalSupply( + account, + id, + p.totalSupply, + )) + } + + if _, err := n.cosmos.BroadcastTx(ctx, n.account, msgs...); err != nil { + return err + } + n.ev.Send(fmt.Sprintf("Project %d updated", id), events.ProgressFinish()) + return nil +} diff --git a/network/network/publish.go b/network/network/publish.go new file mode 100644 index 00000000..98a8a772 --- /dev/null +++ b/network/network/publish.go @@ -0,0 +1,310 @@ +package network + +import ( + "context" + "encoding/json" + "errors" + "os" + "path/filepath" + + sdk "github.com/cosmos/cosmos-sdk/types" + cosmosgenesis "github.com/ignite/cli/v28/ignite/pkg/cosmosutil/genesis" + "github.com/ignite/cli/v28/ignite/pkg/events" + launchtypes "github.com/ignite/network/x/launch/types" + profiletypes "github.com/ignite/network/x/profile/types" + projecttypes "github.com/ignite/network/x/project/types" + + "github.com/ignite/apps/network/network/networktypes" +) + +// publishOptions holds info about how to create a chain. +type publishOptions struct { + genesisURL string + genesisConfig string + chainID string + projectID int64 + metadata string + totalSupply sdk.Coins + sharePercentages SharePercents + mainnet bool + accountBalance sdk.Coins +} + +// hasProject check if the option has a project set. +func (o publishOptions) hasProject() bool { + return o.projectID >= 0 +} + +// PublishOption configures chain creation. +type PublishOption func(*publishOptions) + +// WithProject add a project id. +func WithProject(id int64) PublishOption { + return func(o *publishOptions) { + o.projectID = id + } +} + +// WithChainID use a custom chain id. +func WithChainID(chainID string) PublishOption { + return func(o *publishOptions) { + o.chainID = chainID + } +} + +// WithCustomGenesisURL enables using a custom genesis during publish. +func WithCustomGenesisURL(url string) PublishOption { + return func(o *publishOptions) { + o.genesisURL = url + } +} + +// WithCustomGenesisConfig enables using a custom genesis during publish. +func WithCustomGenesisConfig(configFile string) PublishOption { + return func(o *publishOptions) { + o.genesisConfig = configFile + } +} + +// WithMetadata provides a meta data proposal to update the project. +func WithMetadata(metadata string) PublishOption { + return func(c *publishOptions) { + c.metadata = metadata + } +} + +// WithTotalSupply provides a total supply proposal to update the project. +func WithTotalSupply(totalSupply sdk.Coins) PublishOption { + return func(c *publishOptions) { + c.totalSupply = totalSupply + } +} + +// WithPercentageShares enables minting vouchers for shares. +func WithPercentageShares(sharePercentages []SharePercent) PublishOption { + return func(c *publishOptions) { + c.sharePercentages = sharePercentages + } +} + +// WithAccountBalance set a balance used for all genesis account of the chain. +func WithAccountBalance(accountBalance sdk.Coins) PublishOption { + return func(c *publishOptions) { + c.accountBalance = accountBalance + } +} + +// Mainnet initialize a published chain into the mainnet. +func Mainnet() PublishOption { + return func(o *publishOptions) { + o.mainnet = true + } +} + +// Publish submits Genesis to SPN to announce a new network. +func (n Network) Publish(ctx context.Context, c Chain, options ...PublishOption) (launchID uint64, projectID int64, err error) { + o := publishOptions{projectID: -1} + for _, apply := range options { + apply(&o) + } + + var ( + genesisHash string + genesis *cosmosgenesis.Genesis + chainID string + ) + + // if the initial genesis is a genesis URL and no check are performed, we simply fetch it and get its hash. + if o.genesisURL != "" { + genesis, err = cosmosgenesis.FromURL(ctx, o.genesisURL, filepath.Join(os.TempDir(), "genesis.json")) + if err != nil { + return 0, 0, err + } + genesisHash, err = genesis.Hash() + if err != nil { + return 0, 0, err + } + chainID, err = genesis.ChainID() + if err != nil { + return 0, 0, err + } + } + + // use chain id flag always in the highest priority. + if o.chainID != "" { + chainID = o.chainID + } + // if the chain id is empty, use a default one. + if chainID == "" { + chainID, err = c.ChainID() + if err != nil { + return 0, 0, err + } + } + + coordinatorAddress, err := n.account.Address(networktypes.SPN) + if err != nil { + return 0, 0, err + } + projectID = o.projectID + pID := uint64(0) + if o.hasProject() { + pID = uint64(o.projectID) + } + + n.ev.Send("Publishing the network", events.ProgressStart()) + + // a coordinator profile is necessary to publish a chain + // if the user doesn't have an associated coordinator profile, we create one + if _, err := n.CoordinatorIDByAddress(ctx, coordinatorAddress); errors.Is(err, ErrObjectNotFound) { + msgCreateCoordinator := profiletypes.NewMsgCreateCoordinator( + coordinatorAddress, + "", + "", + "", + ) + if _, err := n.cosmos.BroadcastTx(ctx, n.account, msgCreateCoordinator); err != nil { + return 0, 0, err + } + } else if err != nil { + return 0, 0, err + } + + // check if a project associated to the chain is provided + if o.hasProject() { + _, err = n.projectQuery.GetProject(ctx, &projecttypes.QueryGetProjectRequest{ + ProjectId: pID, + }) + if err != nil { + return 0, 0, err + } + } else if o.mainnet { + // a mainnet is always associated to a project + // if no project is provided, we create one, and we directly initialize the mainnet + projectID, err = n.CreateProject(ctx, c.Name(), "", o.totalSupply) + if err != nil { + return 0, 0, err + } + } + + // mint vouchers + if o.hasProject() && !o.sharePercentages.Empty() { + totalSharesResp, err := n.projectQuery.TotalShares(ctx, &projecttypes.QueryTotalSharesRequest{}) + if err != nil { + return 0, 0, err + } + + var coins []sdk.Coin + for _, percentage := range o.sharePercentages { + coin, err := percentage.Share(totalSharesResp.TotalShares) + if err != nil { + return 0, 0, err + } + coins = append(coins, coin) + } + // TODO consider moving to UpdateProject, but not sure, may not be relevant. + // It is better to send multiple message in a single tx too. + // consider ways to refactor to accomplish a better API and efficiency. + + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return 0, 0, err + } + + msgMintVouchers := projecttypes.NewMsgMintVouchers( + addr, + pID, + projecttypes.NewSharesFromCoins(sdk.NewCoins(coins...)), + ) + _, err = n.cosmos.BroadcastTx(ctx, n.account, msgMintVouchers) + if err != nil { + return 0, 0, err + } + } + + // depending on mainnet flag initialize mainnet or testnet + if o.mainnet { + launchID, err = n.InitializeMainnet(ctx, pID, c.SourceURL(), c.SourceHash(), chainID) + if err != nil { + return 0, 0, err + } + } else { + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return 0, 0, err + } + + // get initial genesis + initialGenesis := launchtypes.NewDefaultInitialGenesis() + switch { + case o.genesisURL != "": + initialGenesis = launchtypes.NewGenesisURL( + o.genesisURL, + genesisHash, + ) + case o.genesisConfig != "": + initialGenesis = launchtypes.NewGenesisConfig( + o.genesisConfig, + ) + } + + // set plugin version in metadata + metadata, err := FillMetadata([]byte(o.metadata)) + if err != nil { + return 0, 0, err + } + + msgCreateChain := launchtypes.NewMsgCreateChain( + addr, + chainID, + c.SourceURL(), + c.SourceHash(), + initialGenesis, + o.hasProject(), + pID, + o.accountBalance, + metadata, + ) + res, err := n.cosmos.BroadcastTx(ctx, n.account, msgCreateChain) + if err != nil { + return 0, 0, err + } + var createChainRes launchtypes.MsgCreateChainResponse + if err := res.Decode(&createChainRes); err != nil { + return 0, 0, err + } + launchID = createChainRes.LaunchId + } + if err := c.CacheBinary(launchID); err != nil { + return 0, 0, err + } + + return launchID, projectID, nil +} + +// FillMetadata fills the metadata of the chain with the plugin version. +func FillMetadata(metadata []byte) ([]byte, error) { + cli := networktypes.Cli{ + Version: networktypes.Version, + } + + // if no metadata provided, create one with just the version + if len(metadata) == 0 { + newMetadata := networktypes.Metadata{ + Cli: cli, + } + + return json.Marshal(newMetadata) + } + + // if metadata has been provided by the coordinator, set the version for the cli + var newMetadata map[string]interface{} + err := json.Unmarshal(metadata, &newMetadata) + if err != nil { + return metadata, errors.New("metadata of the chain must be in json format") + } + + newMetadata["cli"] = cli + + return json.Marshal(newMetadata) +} diff --git a/network/network/publish_test.go b/network/network/publish_test.go new file mode 100644 index 00000000..f58050bf --- /dev/null +++ b/network/network/publish_test.go @@ -0,0 +1,971 @@ +package network + +import ( + "context" + "errors" + "net/http" + "net/http/httptest" + "os" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + launchtypes "github.com/ignite/network/x/launch/types" + profiletypes "github.com/ignite/network/x/profile/types" + projecttypes "github.com/ignite/network/x/project/types" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networktypes" + "github.com/ignite/apps/network/network/testutil" +) + +var metadata = []byte(`{"cli":{"version":"1"}}`) + +func startGenesisTestServer(filepath string) *httptest.Server { + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + file, err := os.ReadFile(filepath) + if err != nil { + panic(err) + } + if _, err = w.Write(file); err != nil { + panic(err) + } + })) +} + +func startInvalidJSONServer() *httptest.Server { + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("invalid json")) + })) +} + +func TestPublish(t *testing.T) { + t.Run("publish chain without project", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + HasProject: false, + ProjectId: 0, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish(context.Background(), suite.ChainMock) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, int64(-1), projectID) + suite.AssertAllMocks(t) + }) + + t.Run("publish chain with custom account balance", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + accountBalance, err := sdk.ParseCoinsNormalized("1000foo,500bar") + require.NoError(t, err) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + HasProject: false, + ProjectId: 0, + AccountBalance: accountBalance, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish( + context.Background(), + suite.ChainMock, + WithAccountBalance(accountBalance), + ) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, int64(-1), projectID) + suite.AssertAllMocks(t) + }) + + t.Run("publish chain with pre created project", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.ProjectQueryMock. + On( + "GetProject", + context.Background(), + &projecttypes.QueryGetProjectRequest{ + ProjectId: testutil.ProjectID, + }, + ). + Return(nil, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + HasProject: true, + ProjectId: testutil.ProjectID, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish(context.Background(), suite.ChainMock, WithProject(int64(testutil.ProjectID))) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, testutil.ProjectID, uint64(projectID)) + suite.AssertAllMocks(t) + }) + + t.Run("publish chain with a pre created project with shares", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.ProjectQueryMock. + On( + "GetProject", + context.Background(), + &projecttypes.QueryGetProjectRequest{ + ProjectId: testutil.ProjectID, + }, + ). + Return(nil, nil). + Once() + suite.ProjectQueryMock. + On( + "TotalShares", + context.Background(), + &projecttypes.QueryTotalSharesRequest{}, + ). + Return(&projecttypes.QueryTotalSharesResponse{ + TotalShares: 100000, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + projecttypes.NewMsgMintVouchers( + addr, + testutil.ProjectID, + projecttypes.NewSharesFromCoins(sdk.NewCoins(sdk.NewInt64Coin("foo", 2000), sdk.NewInt64Coin("staking", 50000))), + ), + ). + Return(testutil.NewResponse(&projecttypes.MsgMintVouchersResponse{}), nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + HasProject: true, + ProjectId: testutil.ProjectID, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish(context.Background(), suite.ChainMock, WithProject(int64(testutil.ProjectID)), + WithPercentageShares([]SharePercent{ + SampleSharePercent(t, "foo", 2, 100), + SampleSharePercent(t, "staking", 50, 100), + }), + ) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, testutil.ProjectID, uint64(projectID)) + suite.AssertAllMocks(t) + }) + + t.Run("publish chain with custom genesis url", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + customGenesisChainID = "test-custom-1" + customGenesisHash = "86167654c1af18c801837d443563fd98b3fe5e8d337e70faad181cdf2100da52" + gts = startGenesisTestServer("mocks/data/genesis.json") + suite, network = newSuite(account) + ) + defer gts.Close() + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: customGenesisChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewGenesisURL( + gts.URL, + customGenesisHash, + ), + HasProject: false, + ProjectId: 0, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish( + context.Background(), + suite.ChainMock, + WithCustomGenesisURL(gts.URL), + ) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, int64(-1), projectID) + suite.AssertAllMocks(t) + }) + + t.Run("publish chain with custom chain id", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + HasProject: false, + ProjectId: 0, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish(context.Background(), suite.ChainMock, WithChainID(testutil.ChainID)) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, int64(-1), projectID) + suite.AssertAllMocks(t) + }) + + t.Run("publish chain with custom genesis config", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewGenesisConfig( + testutil.ChainConfigYML, + ), + HasProject: false, + ProjectId: 0, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish( + context.Background(), + suite.ChainMock, + WithCustomGenesisConfig(testutil.ChainConfigYML), + ) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, int64(-1), projectID) + suite.AssertAllMocks(t) + }) + + t.Run("publish chain with custom chain id", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + HasProject: false, + ProjectId: 0, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish(context.Background(), suite.ChainMock, WithChainID(testutil.ChainID)) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, int64(-1), projectID) + suite.AssertAllMocks(t) + }) + + t.Run("publish chain with mainnet", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + gts = startGenesisTestServer("mocks/data/genesis.json") + suite, network = newSuite(account) + ) + defer gts.Close() + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &projecttypes.MsgCreateProject{ + Coordinator: addr, + ProjectName: testutil.ChainName, + Metadata: []byte{}, + }, + ). + Return(testutil.NewResponse(&projecttypes.MsgCreateProjectResponse{ + ProjectId: testutil.ProjectID, + }), nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &projecttypes.MsgInitializeMainnet{ + Coordinator: addr, + ProjectId: testutil.ProjectID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + MainnetChainId: testutil.ChainID, + }, + ). + Return(testutil.NewResponse(&projecttypes.MsgInitializeMainnetResponse{ + MainnetId: testutil.MainnetID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("Name").Return(testutil.ChainName).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish(context.Background(), suite.ChainMock, Mainnet()) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, testutil.ProjectID, uint64(projectID)) + suite.AssertAllMocks(t) + }) + + t.Run("failed to publish chain with mainnet, failed to initialize mainnet", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + expectedError = errors.New("failed to initialize mainnet") + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &projecttypes.MsgCreateProject{ + Coordinator: addr, + ProjectName: testutil.ChainName, + Metadata: []byte{}, + }, + ). + Return(testutil.NewResponse(&projecttypes.MsgCreateProjectResponse{ + ProjectId: testutil.ProjectID, + }), nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &projecttypes.MsgInitializeMainnet{ + Coordinator: addr, + ProjectId: testutil.ProjectID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + MainnetChainId: testutil.ChainID, + }, + ). + Return(testutil.NewResponse(&projecttypes.MsgInitializeMainnetResponse{ + MainnetId: testutil.MainnetID, + }), expectedError). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("Name").Return(testutil.ChainName).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + + _, _, publishError := network.Publish(context.Background(), suite.ChainMock, Mainnet()) + require.Error(t, publishError) + require.ErrorIs(t, publishError, expectedError) + suite.AssertAllMocks(t) + }) + + t.Run("failed to publish chain with custom genesis, failed to parse custom genesis", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + gts = startInvalidJSONServer() + expectedError = errors.New("JSON field not found") + ) + defer gts.Close() + + _, _, publishError := network.Publish( + context.Background(), + suite.ChainMock, + WithCustomGenesisURL(gts.URL), + ) + require.Error(t, publishError) + require.Equal(t, expectedError.Error(), publishError.Error()) + suite.AssertAllMocks(t) + }) + + t.Run("publish chain with coordinator creation", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On("GetCoordinatorByAddress", mock.Anything, &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }). + Return(nil, sdkerrors.ErrNotFound). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + HasProject: false, + ProjectId: 0, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &profiletypes.MsgCreateCoordinator{ + Address: addr, + }, + ). + Return(testutil.NewResponse(&profiletypes.MsgCreateCoordinatorResponse{}), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() + + launchID, projectID, publishError := network.Publish(context.Background(), suite.ChainMock) + require.NoError(t, publishError) + require.Equal(t, testutil.LaunchID, launchID) + require.Equal(t, int64(-1), projectID) + suite.AssertAllMocks(t) + }) + + t.Run("failed to publish chain, failed to fetch coordinator profile", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + expectedError = errors.New("failed to fetch coordinator") + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On("GetCoordinatorByAddress", mock.Anything, &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }). + Return(nil, expectedError). + Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + + _, _, publishError := network.Publish(context.Background(), suite.ChainMock) + require.Error(t, publishError) + require.ErrorIs(t, publishError, expectedError) + suite.AssertAllMocks(t) + }) + + t.Run("failed to publish chain, failed to read chain id", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + expectedError = errors.New("failed to get chainID") + ) + + suite.ChainMock. + On("ChainID"). + Return("", expectedError). + Once() + + _, _, publishError := network.Publish(context.Background(), suite.ChainMock) + require.Error(t, publishError) + require.ErrorIs(t, publishError, expectedError) + suite.AssertAllMocks(t) + }) + + t.Run("failed to publish chain, failed to fetch existed project", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.ProjectQueryMock. + On("GetProject", mock.Anything, &projecttypes.QueryGetProjectRequest{ + ProjectId: testutil.ProjectID, + }). + Return(nil, sdkerrors.ErrNotFound). + Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + + _, _, publishError := network.Publish(context.Background(), suite.ChainMock, WithProject(int64(testutil.ProjectID))) + require.Error(t, publishError) + require.ErrorIs(t, publishError, sdkerrors.ErrNotFound) + suite.AssertAllMocks(t) + }) + + t.Run("failed to publish chain, failed to create chain", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + expectedError = errors.New("failed to create chain") + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + HasProject: false, + ProjectId: 0, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), expectedError). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + + _, _, publishError := network.Publish(context.Background(), suite.ChainMock) + require.Error(t, publishError) + require.Equal(t, expectedError, publishError) + suite.AssertAllMocks(t) + }) + + t.Run("failed to publish chain, failed to cache binary", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + expectedError = errors.New("failed to cache binary") + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.ProfileQueryMock. + On( + "GetCoordinatorByAddress", + context.Background(), + &profiletypes.QueryGetCoordinatorByAddressRequest{ + Address: addr, + }, + ). + Return(&profiletypes.QueryGetCoordinatorByAddressResponse{ + Coordinator: profiletypes.Coordinator{ + Address: addr, + CoordinatorId: 1, + }, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &launchtypes.MsgCreateChain{ + Coordinator: addr, + GenesisChainId: testutil.ChainID, + SourceUrl: testutil.ChainSourceURL, + SourceHash: testutil.ChainSourceHash, + InitialGenesis: launchtypes.NewDefaultInitialGenesis(), + HasProject: false, + ProjectId: 0, + Metadata: metadata, + }, + ). + Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ + LaunchId: testutil.LaunchID, + }), nil). + Once() + suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Once() + suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Once() + suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() + suite.ChainMock. + On("CacheBinary", testutil.LaunchID). + Return(expectedError). + Once() + + _, _, publishError := network.Publish(context.Background(), suite.ChainMock) + require.Error(t, publishError) + require.ErrorIs(t, publishError, expectedError) + suite.AssertAllMocks(t) + }) +} diff --git a/network/network/queries.go b/network/network/queries.go new file mode 100644 index 00000000..be31a449 --- /dev/null +++ b/network/network/queries.go @@ -0,0 +1,279 @@ +package network + +import ( + "context" + "fmt" + "sort" + "sync" + + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/ignite/cli/v28/ignite/pkg/events" + launchtypes "github.com/ignite/network/x/launch/types" + projecttypes "github.com/ignite/network/x/project/types" + rewardtypes "github.com/ignite/network/x/reward/types" + "github.com/pkg/errors" + "golang.org/x/sync/errgroup" + + "github.com/ignite/apps/network/network/networktypes" +) + +// ErrObjectNotFound is returned when the query returns a not found error. +var ErrObjectNotFound = errors.New("query object not found") + +// ChainLaunch fetches the chain launch from Network by launch id. +func (n Network) ChainLaunch(ctx context.Context, id uint64) (networktypes.ChainLaunch, error) { + n.ev.Send("Fetching chain information", events.ProgressStart()) + + res, err := n.launchQuery.GetChain(ctx, &launchtypes.QueryGetChainRequest{ + LaunchId: id, + }) + if err != nil { + return networktypes.ChainLaunch{}, err + } + + return networktypes.ToChainLaunch(res.Chain), nil +} + +// ChainLaunchesWithReward fetches the chain launches with rewards from Network. +func (n Network) ChainLaunchesWithReward(ctx context.Context, pagination *query.PageRequest) ([]networktypes.ChainLaunch, error) { + g, ctx := errgroup.WithContext(ctx) + + n.ev.Send("Fetching chains information", events.ProgressStart()) + res, err := n.launchQuery.ListChain(ctx, &launchtypes.QueryAllChainRequest{ + Pagination: pagination, + }) + if err != nil { + return nil, err + } + + n.ev.Send("Fetching reward information", events.ProgressUpdate()) + var chainLaunches []networktypes.ChainLaunch + var mu sync.Mutex + + // Parse fetched chains and fetch rewards + for _, chain := range res.Chain { + chain := chain + g.Go(func() error { + chainLaunch := networktypes.ToChainLaunch(chain) + reward, err := n.ChainReward(ctx, chain.LaunchId) + if err != nil && !errors.Is(err, ErrObjectNotFound) { + return err + } + chainLaunch.Reward = reward.RemainingCoins.String() + mu.Lock() + chainLaunches = append(chainLaunches, chainLaunch) + mu.Unlock() + return nil + }) + } + if err := g.Wait(); err != nil { + return nil, err + } + // sort filenames by launch id + sort.Slice(chainLaunches, func(i, j int) bool { + return chainLaunches[i].ID > chainLaunches[j].ID + }) + return chainLaunches, nil +} + +// GenesisInformation returns all the information to construct the genesis from a chain ID. +func (n Network) GenesisInformation(ctx context.Context, launchID uint64) (gi networktypes.GenesisInformation, err error) { + genAccs, err := n.GenesisAccounts(ctx, launchID) + if err != nil { + return gi, fmt.Errorf("error querying genesis accounts: %w", err) + } + + vestingAccs, err := n.VestingAccounts(ctx, launchID) + if err != nil { + return gi, fmt.Errorf("error querying vesting accounts: %w", err) + } + + genVals, err := n.GenesisValidators(ctx, launchID) + if err != nil { + return gi, fmt.Errorf("error querying genesis validators: %w", err) + } + + paramChanges, err := n.ParamChanges(ctx, launchID) + if err != nil { + return gi, fmt.Errorf("error querying param changes: %w", err) + } + + return networktypes.NewGenesisInformation(genAccs, vestingAccs, genVals, paramChanges), nil +} + +// GenesisAccounts returns the list of approved genesis accounts for a launch from SPN. +func (n Network) GenesisAccounts(ctx context.Context, launchID uint64) (genAccs []networktypes.GenesisAccount, err error) { + n.ev.Send("Fetching genesis accounts", events.ProgressStart()) + res, err := n.launchQuery.ListGenesisAccount(ctx, &launchtypes.QueryAllGenesisAccountRequest{ + LaunchId: launchID, + }) + if err != nil { + return genAccs, err + } + + for _, acc := range res.GenesisAccount { + genAccs = append(genAccs, networktypes.ToGenesisAccount(acc)) + } + + return genAccs, nil +} + +// VestingAccounts returns the list of approved genesis vesting accounts for a launch from SPN. +func (n Network) VestingAccounts(ctx context.Context, launchID uint64) (vestingAccs []networktypes.VestingAccount, err error) { + n.ev.Send("Fetching genesis vesting accounts", events.ProgressStart()) + res, err := n.launchQuery.ListVestingAccount(ctx, &launchtypes.QueryAllVestingAccountRequest{ + LaunchId: launchID, + }) + if err != nil { + return vestingAccs, err + } + + for i, acc := range res.VestingAccount { + parsedAcc, err := networktypes.ToVestingAccount(acc) + if err != nil { + return vestingAccs, errors.Wrapf(err, "error parsing vesting account %d", i) + } + + vestingAccs = append(vestingAccs, parsedAcc) + } + + return vestingAccs, nil +} + +// GenesisValidators returns the list of approved genesis validators for a launch from SPN. +func (n Network) GenesisValidators(ctx context.Context, launchID uint64) (genVals []networktypes.GenesisValidator, err error) { + n.ev.Send("Fetching genesis validators", events.ProgressStart()) + res, err := n.launchQuery.ListGenesisValidator(ctx, &launchtypes.QueryAllGenesisValidatorRequest{ + LaunchId: launchID, + }) + if err != nil { + return genVals, err + } + + for _, acc := range res.GenesisValidator { + genVals = append(genVals, networktypes.ToGenesisValidator(acc)) + } + + return genVals, nil +} + +// ParamChanges returns the list of approved param changes for a launch from SPN. +func (n Network) ParamChanges(ctx context.Context, launchID uint64) (paramChanges []networktypes.ParamChange, err error) { + n.ev.Send("Fetching param changes", events.ProgressStart()) + res, err := n.launchQuery.ListParamChange(ctx, &launchtypes.QueryAllParamChangeRequest{ + LaunchId: launchID, + }) + if err != nil { + return paramChanges, err + } + + for _, pc := range res.ParamChange { + paramChanges = append(paramChanges, networktypes.ToParamChange(pc)) + } + + return paramChanges, nil +} + +// MainnetAccount returns the project mainnet account for a launch from SPN. +func (n Network) MainnetAccount( + ctx context.Context, + projectID uint64, + address string, +) (acc networktypes.MainnetAccount, err error) { + n.ev.Send( + fmt.Sprintf("Fetching project %d mainnet account %s", projectID, address), + events.ProgressStart(), + ) + res, err := n.projectQuery.GetMainnetAccount(ctx, &projecttypes.QueryGetMainnetAccountRequest{ + ProjectId: projectID, + Address: address, + }) + if isNotFoundErr(err) { + return networktypes.MainnetAccount{}, ErrObjectNotFound + } else if err != nil { + return acc, err + } + + return networktypes.ToMainnetAccount(res.MainnetAccount), nil +} + +// MainnetAccounts returns the list of project mainnet accounts for a launch from SPN. +func (n Network) MainnetAccounts(ctx context.Context, projectID uint64) (genAccs []networktypes.MainnetAccount, err error) { + n.ev.Send("Fetching project mainnet accounts", events.ProgressStart()) + res, err := n.projectQuery.ListMainnetAccount(ctx, &projecttypes.QueryAllMainnetAccountRequest{ + ProjectId: projectID, + }) + if err != nil { + return genAccs, err + } + + for _, acc := range res.MainnetAccount { + genAccs = append(genAccs, networktypes.ToMainnetAccount(acc)) + } + + return genAccs, nil +} + +func (n Network) GenesisAccount(ctx context.Context, launchID uint64, address string) (networktypes.GenesisAccount, error) { + n.ev.Send("Fetching genesis accounts", events.ProgressStart()) + res, err := n.launchQuery.GetGenesisAccount(ctx, &launchtypes.QueryGetGenesisAccountRequest{ + LaunchId: launchID, + Address: address, + }) + if isNotFoundErr(err) { + return networktypes.GenesisAccount{}, ErrObjectNotFound + } else if err != nil { + return networktypes.GenesisAccount{}, err + } + return networktypes.ToGenesisAccount(res.GenesisAccount), nil +} + +func (n Network) VestingAccount(ctx context.Context, launchID uint64, address string) (networktypes.VestingAccount, error) { + n.ev.Send("Fetching vesting accounts", events.ProgressStart()) + res, err := n.launchQuery.GetVestingAccount(ctx, &launchtypes.QueryGetVestingAccountRequest{ + LaunchId: launchID, + Address: address, + }) + if isNotFoundErr(err) { + return networktypes.VestingAccount{}, ErrObjectNotFound + } else if err != nil { + return networktypes.VestingAccount{}, err + } + return networktypes.ToVestingAccount(res.VestingAccount) +} + +func (n Network) GenesisValidator(ctx context.Context, launchID uint64, address string) (networktypes.GenesisValidator, error) { + n.ev.Send("Fetching genesis validator", events.ProgressStart()) + res, err := n.launchQuery.GetGenesisValidator(ctx, &launchtypes.QueryGetGenesisValidatorRequest{ + LaunchId: launchID, + Address: address, + }) + if isNotFoundErr(err) { + return networktypes.GenesisValidator{}, ErrObjectNotFound + } else if err != nil { + return networktypes.GenesisValidator{}, err + } + return networktypes.ToGenesisValidator(res.GenesisValidator), nil +} + +// ChainReward fetches the chain reward from SPN by launch id. +func (n Network) ChainReward(ctx context.Context, launchID uint64) (rewardtypes.RewardPool, error) { + res, err := n.rewardQuery.GetRewardPool(ctx, &rewardtypes.QueryGetRewardPoolRequest{ + LaunchId: launchID, + }) + if isNotFoundErr(err) { + return rewardtypes.RewardPool{}, ErrObjectNotFound + } else if err != nil { + return rewardtypes.RewardPool{}, err + } + return res.RewardPool, nil +} + +// ChainID fetches the network chain id. +func (n Network) ChainID(ctx context.Context) (string, error) { + status, err := n.cosmos.Status(ctx) + if err != nil { + return "", err + } + return status.NodeInfo.Network, nil +} diff --git a/network/network/request.go b/network/network/request.go new file mode 100644 index 00000000..d0fdebae --- /dev/null +++ b/network/network/request.go @@ -0,0 +1,163 @@ +package network + +import ( + "context" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/events" + launchtypes "github.com/ignite/network/x/launch/types" + + "github.com/ignite/apps/network/network/networktypes" +) + +// Reviewal keeps a request's reviewal. +type Reviewal struct { + RequestID uint64 + IsApproved bool +} + +// ApproveRequest returns approval for a request with id. +func ApproveRequest(requestID uint64) Reviewal { + return Reviewal{ + RequestID: requestID, + IsApproved: true, + } +} + +// RejectRequest returns rejection for a request with id. +func RejectRequest(requestID uint64) Reviewal { + return Reviewal{ + RequestID: requestID, + IsApproved: false, + } +} + +// Requests fetches all the chain requests from SPN by launch id. +func (n Network) Requests(ctx context.Context, launchID uint64) ([]networktypes.Request, error) { + res, err := n.launchQuery.ListRequest(ctx, &launchtypes.QueryAllRequestRequest{ + LaunchId: launchID, + }) + if err != nil { + return nil, err + } + requests := make([]networktypes.Request, len(res.Request)) + for i, req := range res.Request { + requests[i] = networktypes.ToRequest(req) + } + return requests, nil +} + +// Request fetches the chain request from SPN by launch and request id. +func (n Network) Request(ctx context.Context, launchID, requestID uint64) (networktypes.Request, error) { + res, err := n.launchQuery.GetRequest(ctx, &launchtypes.QueryGetRequestRequest{ + LaunchId: launchID, + RequestId: requestID, + }) + if err != nil { + return networktypes.Request{}, err + } + return networktypes.ToRequest(res.Request), nil +} + +// RequestFromIDs fetches the chain requested from SPN by launch and provided request IDs +// TODO: once implemented, use the SPN query from https://github.com/ignite/network/issues/420 +func (n Network) RequestFromIDs(ctx context.Context, launchID uint64, requestIDs ...uint64) (reqs []networktypes.Request, err error) { + for _, id := range requestIDs { + req, err := n.Request(ctx, launchID, id) + if err != nil { + return reqs, err + } + reqs = append(reqs, req) + } + return reqs, nil +} + +// SubmitRequestReviewals submits reviewals for proposals in batch for chain. +func (n Network) SubmitRequestReviewals(ctx context.Context, launchID uint64, reviewal ...Reviewal) error { + n.ev.Send("Submitting requests...", events.ProgressStart()) + + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return err + } + + messages := make([]sdk.Msg, len(reviewal)) + for i, reviewal := range reviewal { + messages[i] = launchtypes.NewMsgSettleRequest( + addr, + launchID, + reviewal.RequestID, + reviewal.IsApproved, + ) + } + + res, err := n.cosmos.BroadcastTx(ctx, n.account, messages...) + if err != nil { + return err + } + + var requestRes launchtypes.MsgSettleRequestResponse + return res.Decode(&requestRes) +} + +// SendRequest creates and sends the Request message to SPN. +func (n Network) SendRequest( + ctx context.Context, + launchID uint64, + content launchtypes.RequestContent, +) error { + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return err + } + + msg := launchtypes.NewMsgSendRequest( + addr, + launchID, + content, + ) + + n.ev.Send("Broadcasting transaction", events.ProgressStart()) + + res, err := n.cosmos.BroadcastTx(ctx, n.account, msg) + if err != nil { + return err + } + + var requestRes launchtypes.MsgSendRequestResponse + if err := res.Decode(&requestRes); err != nil { + return err + } + + if requestRes.AutoApproved { + n.ev.Send(fmt.Sprintf( + "%s by the coordinator!", networktypes.RequestActionResultDescriptionFromContent(content), + ), + events.ProgressFinish()) + } else { + n.ev.Send( + fmt.Sprintf( + "Request %d to %s has been submitted!", + requestRes.RequestId, + networktypes.RequestActionDescriptionFromContent(content), + ), + events.ProgressFinish(), + ) + } + return nil +} + +// SendRequests creates and sends the Request message to SPN. +func (n Network) SendRequests( + ctx context.Context, + launchID uint64, + contents []launchtypes.RequestContent, +) error { + for _, content := range contents { + if err := n.SendRequest(ctx, launchID, content); err != nil { + return err + } + } + return nil +} diff --git a/network/network/request_test.go b/network/network/request_test.go new file mode 100644 index 00000000..07335a04 --- /dev/null +++ b/network/network/request_test.go @@ -0,0 +1,58 @@ +package network + +import ( + "context" + "testing" + + launchtypes "github.com/ignite/network/x/launch/types" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networktypes" + "github.com/ignite/apps/network/network/testutil" +) + +func TestSendRequest(t *testing.T) { + t.Run("successfully send request", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + module = "module" + param = "param" + value = []byte("value") + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + launchtypes.NewMsgSendRequest( + addr, + testutil.LaunchID, + launchtypes.NewParamChange( + testutil.LaunchID, + module, + param, + value, + ), + ), + ). + Return(testutil.NewResponse(&launchtypes.MsgSendRequestResponse{ + RequestId: 0, + AutoApproved: false, + }), nil). + Once() + + sendRequestError := network.SendRequest(context.Background(), testutil.LaunchID, launchtypes.NewParamChange( + testutil.LaunchID, + module, + param, + value, + )) + require.NoError(t, sendRequestError) + suite.AssertAllMocks(t) + }) +} diff --git a/network/network/reward.go b/network/network/reward.go new file mode 100644 index 00000000..9590ec1d --- /dev/null +++ b/network/network/reward.go @@ -0,0 +1,102 @@ +package network + +import ( + "context" + "errors" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" + "github.com/ignite/cli/v28/ignite/pkg/events" + rewardtypes "github.com/ignite/network/x/reward/types" + + "github.com/ignite/apps/network/network/networktypes" +) + +// SetReward set a chain reward. +func (n Network) SetReward(ctx context.Context, launchID uint64, lastRewardHeight int64, coins sdk.Coins) error { + n.ev.Send( + fmt.Sprintf("Setting reward %s to the chain %d at height %d", coins, launchID, lastRewardHeight), + events.ProgressStart(), + ) + + addr, err := n.account.Address(networktypes.SPN) + if err != nil { + return err + } + + msg := rewardtypes.NewMsgSetRewards( + addr, + launchID, + coins, + lastRewardHeight, + ) + res, err := n.cosmos.BroadcastTx(ctx, n.account, msg) + if err != nil { + return err + } + + var setRewardRes rewardtypes.MsgSetRewardsResponse + if err := res.Decode(&setRewardRes); err != nil { + return err + } + + if setRewardRes.PreviousCoins.Empty() { + n.ev.Send("The reward pool was empty", events.Icon(icons.Info), events.ProgressFinish()) + } else { + n.ev.Send( + fmt.Sprintf("Previous reward pool %s at height %d is overwritten", coins, lastRewardHeight), + events.Icon(icons.Info), + events.ProgressFinish(), + ) + } + + if setRewardRes.NewCoins.Empty() { + n.ev.Send("The reward pool is removed", events.ProgressFinish()) + } else { + n.ev.Send( + fmt.Sprintf( + "%s will be distributed to validators at height %d. The chain %d is now an incentivized testnet", + coins, + lastRewardHeight, + launchID, + ), + events.ProgressFinish(), + ) + } + return nil +} + +// RewardsInfo Fetches the consensus state with the validator set, +// the unbounding time, and the last block height from chain rewards. +func (n Network) RewardsInfo( + ctx context.Context, + launchID uint64, + height int64, +) ( + rewardsInfo networktypes.Reward, + lastRewardHeight int64, + unboundingTime int64, + err error, +) { + rewardsInfo, err = n.node.consensus(ctx, n.cosmos, height) + if err != nil { + return rewardsInfo, 0, 0, err + } + + stakingParams, err := n.node.stakingParams(ctx) + if err != nil { + return rewardsInfo, 0, 0, err + } + unboundingTime = int64(stakingParams.UnbondingTime.Seconds()) + + chainReward, err := n.ChainReward(ctx, launchID) + if errors.Is(err, ErrObjectNotFound) { + return rewardsInfo, 1, unboundingTime, nil + } else if err != nil { + return rewardsInfo, 0, 0, err + } + lastRewardHeight = chainReward.LastRewardHeight + + return +} diff --git a/network/network/reward_test.go b/network/network/reward_test.go new file mode 100644 index 00000000..da35d725 --- /dev/null +++ b/network/network/reward_test.go @@ -0,0 +1,84 @@ +package network + +import ( + "context" + "errors" + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + rewardtypes "github.com/ignite/network/x/reward/types" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network/networktypes" + "github.com/ignite/apps/network/network/testutil" +) + +func TestSetReward(t *testing.T) { + t.Run("successfully set reward", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + coins = sdk.NewCoins(sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt))) + lastRewardHeight = int64(10) + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &rewardtypes.MsgSetRewards{ + Provider: addr, + LaunchId: testutil.LaunchID, + Coins: coins, + LastRewardHeight: lastRewardHeight, + }, + ). + Return(testutil.NewResponse(&rewardtypes.MsgSetRewardsResponse{ + PreviousCoins: nil, + PreviousLastRewardHeight: lastRewardHeight - 1, + NewCoins: coins, + NewLastRewardHeight: lastRewardHeight, + }), nil). + Once() + + setRewardError := network.SetReward(context.Background(), testutil.LaunchID, lastRewardHeight, coins) + require.NoError(t, setRewardError) + suite.AssertAllMocks(t) + }) + t.Run("failed to set reward, failed to broadcast set reward tx", func(t *testing.T) { + var ( + account = testutil.NewTestAccount(t, testutil.TestAccountName) + suite, network = newSuite(account) + coins = sdk.NewCoins(sdk.NewCoin(TestDenom, sdkmath.NewInt(TestAmountInt))) + lastRewardHeight = int64(10) + expectedErr = errors.New("failed to set reward") + ) + + addr, err := account.Address(networktypes.SPN) + require.NoError(t, err) + + suite.CosmosClientMock. + On( + "BroadcastTx", + context.Background(), + account, + &rewardtypes.MsgSetRewards{ + Provider: addr, + LaunchId: testutil.LaunchID, + Coins: coins, + LastRewardHeight: lastRewardHeight, + }, + ). + Return(testutil.NewResponse(&rewardtypes.MsgSetRewardsResponse{}), expectedErr). + Once() + setRewardError := network.SetReward(context.Background(), testutil.LaunchID, lastRewardHeight, coins) + require.Error(t, setRewardError) + require.Equal(t, expectedErr, setRewardError) + suite.AssertAllMocks(t) + }) +} diff --git a/network/network/share_percent.go b/network/network/share_percent.go new file mode 100644 index 00000000..44d9b553 --- /dev/null +++ b/network/network/share_percent.go @@ -0,0 +1,114 @@ +package network + +import ( + "fmt" + "regexp" + "strconv" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type SharePercents []SharePercent + +func (sp SharePercents) Empty() bool { + return len(sp) == 0 +} + +var rePercentageRequired = regexp.MustCompile(`^[0-9]+.[0-9]*%`) + +// SharePercent represent percent of total share. +type SharePercent struct { + denom string + // in order to avoid using numbers with floating point + // fractional representation is used: 297/10000 instead of 2.97% + nominator, denominator uint64 +} + +// NewSharePercent creates new share percent representation. +func NewSharePercent(denom string, nominator, denominator uint64) (SharePercent, error) { + if denominator < nominator { + return SharePercent{}, fmt.Errorf("%q can not be bigger than 100", denom) + } + return SharePercent{ + denom: denom, + nominator: nominator, + denominator: denominator, + }, nil +} + +// Share returns coin share of total according to underlying percent. +func (p SharePercent) Share(total uint64) (sdk.Coin, error) { + resultNominator := total * p.nominator + if resultNominator%p.denominator != 0 { + err := fmt.Errorf("%s share from total %d is not integer: %f", + p.denom, + total, + float64(resultNominator)/float64(p.denominator), + ) + return sdk.Coin{}, err + } + return sdk.NewInt64Coin(p.denom, int64(resultNominator/p.denominator)), nil +} + +// SharePercentFromString parses share percent from string +// format: 11.87%foo +func SharePercentFromString(str string) (SharePercent, error) { + // validate raw percentage format + if len(rePercentageRequired.FindStringIndex(str)) == 0 { + return SharePercent{}, newInvalidPercentageFormat(str) + } + var ( + foo = strings.Split(str, "%") + fractional = strings.Split(foo[0], ".") + denom = foo[1] + ) + + switch len(fractional) { + case 1: + nominator, err := strconv.ParseUint(fractional[0], 10, 64) + if err != nil { + return SharePercent{}, newInvalidPercentageFormat(str) + } + return NewSharePercent(denom, nominator, 100) + case 2: + trimmedFractionalPart := strings.TrimRight(fractional[1], "0") + nominator, err := strconv.ParseUint(fractional[0]+trimmedFractionalPart, 10, 64) + if err != nil { + return SharePercent{}, newInvalidPercentageFormat(str) + } + return NewSharePercent(denom, nominator, uintPow(10, uint64(len(trimmedFractionalPart)+2))) + + default: + return SharePercent{}, newInvalidPercentageFormat(str) + } +} + +// ParseSharePercents parses SharePercentage list from string +// format: 12.4%foo,10%bar,0.133%baz +func ParseSharePercents(percents string) (SharePercents, error) { + rawPercentages := strings.Split(percents, ",") + ps := make([]SharePercent, len(rawPercentages)) + for i, percentage := range rawPercentages { + sp, err := SharePercentFromString(percentage) + if err != nil { + return nil, err + } + ps[i] = sp + + } + + return ps, nil +} + +func uintPow(x, y uint64) uint64 { + result := x + for i := 1; uint64(i) < y; i++ { + result *= x + } + return result +} + +func newInvalidPercentageFormat(s string) error { + return fmt.Errorf("invalid percentage format %s", s) +} diff --git a/network/network/share_percent_test.go b/network/network/share_percent_test.go new file mode 100644 index 00000000..1a1f039d --- /dev/null +++ b/network/network/share_percent_test.go @@ -0,0 +1,134 @@ +package network_test + +import ( + "errors" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/ignite/apps/network/network" +) + +func TestParseSharePercentages(t *testing.T) { + tests := []struct { + name string + shareStr string + want network.SharePercents + err error + }{ + { + name: "valid share percentage", + shareStr: "12.333%def", + want: network.SharePercents{ + network.SampleSharePercent(t, "def", 12333, 100000), + }, + }, + { + name: "valid share percentage", + shareStr: "0.333%def", + want: network.SharePercents{ + network.SampleSharePercent(t, "def", 333, 100000), + }, + }, + { + name: "extra zeroes", + shareStr: "12.33300%def", + want: network.SharePercents{ + network.SampleSharePercent(t, "def", 12333, 100000), + }, + }, + { + name: "100% percentage", + shareStr: "100%def", + want: network.SharePercents{ + network.SampleSharePercent(t, "def", 100, 100), + }, + }, + { + name: "valid share percentages", + shareStr: "12%def,10.3%abc", + want: network.SharePercents{ + network.SampleSharePercent(t, "def", 12, 100), + network.SampleSharePercent(t, "abc", 103, 1000), + }, + }, + { + name: "share percentages greater than 100", + shareStr: "12%def,10.3abc", + err: errors.New("invalid percentage format 10.3abc"), + }, + { + name: "share percentages without % sign", + shareStr: "12%def,103%abc", + err: errors.New("\"abc\" can not be bigger than 100"), + }, + { + name: "invalid percent", + shareStr: "12.3d3%def", + err: errors.New("invalid percentage format 12.3d3%def"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := network.ParseSharePercents(tt.shareStr) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, result) + }) + } +} + +func TestShare(t *testing.T) { + tests := []struct { + name string + percent network.SharePercent + total uint64 + want sdk.Coin + err error + }{ + { + name: "100 fraction", + percent: network.SampleSharePercent(t, "foo", 10, 100), + total: 10000, + want: sdk.NewInt64Coin("foo", 1000), + }, + { + name: "1000 fraction", + percent: network.SampleSharePercent(t, "foo", 133, 1000), + total: 10000, + want: sdk.NewInt64Coin("foo", 1330), + }, + { + name: "10000 fraction", + percent: network.SampleSharePercent(t, "foo", 297, 10000), + total: 10000, + want: sdk.NewInt64Coin("foo", 297), + }, + { + name: "non integer share", + percent: network.SampleSharePercent(t, "foo", 297, 10001), + total: 10000, + want: sdk.NewInt64Coin("foo", 297), + err: errors.New("foo share from total 10000 is not integer: 296.970303"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := tt.percent.Share(tt.total) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, result) + }) + } +} diff --git a/network/network/testutil/account.go b/network/network/testutil/account.go new file mode 100644 index 00000000..07321495 --- /dev/null +++ b/network/network/testutil/account.go @@ -0,0 +1,23 @@ +package testutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" +) + +const ( + TestAccountName = "test" +) + +// NewTestAccount creates an account for test purposes using in-memory keyring backend. +func NewTestAccount(t *testing.T, name string) cosmosaccount.Account { + t.Helper() + r, err := cosmosaccount.NewInMemory() + assert.NoError(t, err) + account, _, err := r.Create(name) + assert.NoError(t, err) + return account +} diff --git a/network/network/testutil/chain.go b/network/network/testutil/chain.go new file mode 100644 index 00000000..ecc6f2e0 --- /dev/null +++ b/network/network/testutil/chain.go @@ -0,0 +1,18 @@ +package testutil + +const ( + ChainSourceHash = "testhash" + ChainSourceURL = "http://example.com/test" + ChainConfigYML = "config.yml" + ChainName = "test" + ChainID = "test-1" + TCPAddress = "1.2.3.4" + NodeID = "9b1f4adbfb0c0b513040d914bfb717303c0eaa71" + PeerAddress = "9b1f4adbfb0c0b513040d914bfb717303c0eaa71@1.2.3.4" +) + +const ( + LaunchID = uint64(0) + ProjectID = uint64(0) + MainnetID = uint64(0) +) diff --git a/network/network/testutil/genesis.go b/network/network/testutil/genesis.go new file mode 100644 index 00000000..3173fdac --- /dev/null +++ b/network/network/testutil/genesis.go @@ -0,0 +1,60 @@ +package testutil + +import ( + "encoding/json" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +type ( + Genesis struct { + ChainID string `json:"chain_id"` + AppState AppState `json:"app_state"` + } + + AppState struct { + Auth Auth `json:"auth"` + Staking Staking `json:"staking"` + } + + Auth struct { + Accounts []GenesisAccount `json:"accounts"` + } + + GenesisAccount struct { + Address string `json:"address"` + } + + Staking struct { + Params StakingParams `json:"params"` + } + + StakingParams struct { + BondDenom string `json:"bond_denom"` + } +) + +// NewGenesis creates easily modifiable genesis object for testing purposes. +func NewGenesis(chainID string) *Genesis { + return &Genesis{ChainID: chainID} +} + +// AddAccount adds account to the genesis. +func (g *Genesis) AddAccount(address string) *Genesis { + g.AppState.Auth.Accounts = append(g.AppState.Auth.Accounts, GenesisAccount{Address: address}) + return g +} + +// SaveTo saves genesis json representation to the specified directory and returns full path. +func (g *Genesis) SaveTo(t *testing.T, dir string) string { + t.Helper() + encoded, err := json.Marshal(g) + assert.NoError(t, err) + savePath := filepath.Join(dir, "genesis.json") + err = os.WriteFile(savePath, encoded, 0o666) + assert.NoError(t, err) + return savePath +} diff --git a/network/network/testutil/gentx.go b/network/network/testutil/gentx.go new file mode 100644 index 00000000..b0a10392 --- /dev/null +++ b/network/network/testutil/gentx.go @@ -0,0 +1,69 @@ +package testutil + +import ( + "encoding/json" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +type ( + Gentx struct { + Body Body `json:"body"` + } + + Body struct { + Messages []Message `json:"messages"` + Memo string `json:"memo"` + } + + Message struct { + ValidatorAddress string `json:"validator_address"` + PubKey MessagePubKey `json:"pubkey"` + Value MessageValue `json:"value"` + } + + MessageValue struct { + Denom string `json:"denom"` + Amount string `json:"amount"` + } + + MessagePubKey struct { + Key string `json:"key"` + } +) + +// NewGentx creates easily modifiable gentx object for testing purposes. +func NewGentx(address, denom, amount, pubkey, memo string) *Gentx { + return &Gentx{Body: Body{ + Memo: memo, + Messages: []Message{ + { + ValidatorAddress: address, + PubKey: MessagePubKey{Key: pubkey}, + Value: MessageValue{Denom: denom, Amount: amount}, + }, + }, + }} +} + +// SaveTo saves gentx json representation to the specified directory and returns full path. +func (g *Gentx) SaveTo(t *testing.T, dir string) string { + t.Helper() + encoded, err := json.Marshal(g) + assert.NoError(t, err) + savePath := filepath.Join(dir, "gentx0.json") + err = os.WriteFile(savePath, encoded, 0o666) + assert.NoError(t, err) + return savePath +} + +// JSON returns json representation of the gentx. +func (g *Gentx) JSON(t *testing.T) []byte { + t.Helper() + data, err := json.Marshal(g) + assert.NoError(t, err) + return data +} diff --git a/network/network/testutil/mocks.go b/network/network/testutil/mocks.go new file mode 100644 index 00000000..3d6c410c --- /dev/null +++ b/network/network/testutil/mocks.go @@ -0,0 +1,58 @@ +package testutil + +import ( + "github.com/cosmos/cosmos-sdk/crypto/keyring" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + launchtypes "github.com/ignite/network/x/launch/types" + monitoringctypes "github.com/ignite/network/x/monitoringc/types" + monitoringptypes "github.com/ignite/network/x/monitoringp/types" + profiletypes "github.com/ignite/network/x/profile/types" + projecttypes "github.com/ignite/network/x/project/types" + rewardtypes "github.com/ignite/network/x/reward/types" +) + +//go:generate mockery --name ProjectClient +type ProjectClient interface { + projecttypes.QueryClient +} + +//go:generate mockery --name ProfileClient +type ProfileClient interface { + profiletypes.QueryClient +} + +//go:generate mockery --name LaunchClient +type LaunchClient interface { + launchtypes.QueryClient +} + +//go:generate mockery --name RewardClient +type RewardClient interface { + rewardtypes.QueryClient +} + +//go:generate mockery --name BankClient +type BankClient interface { + banktypes.QueryClient +} + +//go:generate mockery --name StakingClient +type StakingClient interface { + stakingtypes.QueryClient +} + +//go:generate mockery --name MonitoringcClient +type MonitoringcClient interface { + monitoringctypes.QueryClient +} + +//go:generate mockery --name MonitoringpClient +type MonitoringpClient interface { + monitoringptypes.QueryClient +} + +//go:generate mockery --name AccountInfo +type AccountInfo interface { + keyring.Record +} diff --git a/network/network/testutil/response.go b/network/network/testutil/response.go new file mode 100644 index 00000000..4e3e94e7 --- /dev/null +++ b/network/network/testutil/response.go @@ -0,0 +1,29 @@ +package testutil + +import ( + "encoding/hex" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ignite/cli/v28/ignite/pkg/cosmosclient" + "google.golang.org/protobuf/runtime/protoiface" +) + +// NewResponse creates cosmosclient.Response object from proto struct +// for using as a return result for a cosmosclient mock. +func NewResponse(data protoiface.MessageV1) cosmosclient.Response { + marshaler := codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + anyEncoded, _ := codectypes.NewAnyWithValue(data) + + txData := &sdk.TxMsgData{MsgResponses: []*codectypes.Any{anyEncoded}} + + encodedTxData, _ := marshaler.Marshal(txData) + resp := cosmosclient.Response{ + Codec: marshaler, + TxResponse: &sdk.TxResponse{ + Data: hex.EncodeToString(encodedTxData), + }, + } + return resp +} diff --git a/network/network/testutil/suite.go b/network/network/testutil/suite.go new file mode 100644 index 00000000..bcbe786b --- /dev/null +++ b/network/network/testutil/suite.go @@ -0,0 +1,53 @@ +package testutil + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/client" + + "github.com/ignite/apps/network/network/mocks" +) + +// Suite is a mocks container, used to write less code for tests setup. +type Suite struct { + ChainMock *mocks.Chain + CosmosClientMock *mocks.CosmosClient + LaunchQueryMock *mocks.LaunchClient + ProjectQueryMock *mocks.ProjectClient + ProfileQueryMock *mocks.ProfileClient + RewardClient *mocks.RewardClient + StakingClient *mocks.StakingClient + BankClient *mocks.BankClient + MonitoringConsumerClient *mocks.MonitoringcClient +} + +// AssertAllMocks asserts all suite mocks expectations. +func (s *Suite) AssertAllMocks(t *testing.T) { + t.Helper() + s.ChainMock.AssertExpectations(t) + s.ProfileQueryMock.AssertExpectations(t) + s.LaunchQueryMock.AssertExpectations(t) + s.CosmosClientMock.AssertExpectations(t) + s.ProjectQueryMock.AssertExpectations(t) + s.RewardClient.AssertExpectations(t) + s.StakingClient.AssertExpectations(t) + s.MonitoringConsumerClient.AssertExpectations(t) + s.BankClient.AssertExpectations(t) +} + +// NewSuite creates new suite with mocks. +func NewSuite() Suite { + cosmos := new(mocks.CosmosClient) + cosmos.On("Context").Return(client.Context{}) + return Suite{ + ChainMock: new(mocks.Chain), + CosmosClientMock: cosmos, + LaunchQueryMock: new(mocks.LaunchClient), + ProjectQueryMock: new(mocks.ProjectClient), + ProfileQueryMock: new(mocks.ProfileClient), + RewardClient: new(mocks.RewardClient), + StakingClient: new(mocks.StakingClient), + BankClient: new(mocks.BankClient), + MonitoringConsumerClient: new(mocks.MonitoringcClient), + } +}