diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000000..8cf1cb5902 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,19 @@ +--- +name: Ignite CLI bug report +about: Create a report to help us improve +title: '' +labels: report +assignees: '' +--- + +**Describe the bug** +Tell us what you were doing and provide a clear and concise description of issue you encountered. + +**To reproduce** +Steps to reproduce the behavior: +1. + +**What version are you using?** + +Provide the output of the `ignite version` command. + \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/starport-feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md similarity index 73% rename from .github/ISSUE_TEMPLATE/starport-feature-request.md rename to .github/ISSUE_TEMPLATE/feature-request.md index 2e4b5ca5ef..cce11fe254 100644 --- a/.github/ISSUE_TEMPLATE/starport-feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -7,7 +7,7 @@ assignees: '' --- -**Is your feature request related to a problem? Please describe.** +**Is your feature request related to a problem or issue you encountered? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** @@ -15,3 +15,6 @@ A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. + +Include other useful information that helps us understand your request. + diff --git a/.github/ISSUE_TEMPLATE/starport-bug-report.md b/.github/ISSUE_TEMPLATE/starport-bug-report.md deleted file mode 100644 index bd6db5130b..0000000000 --- a/.github/ISSUE_TEMPLATE/starport-bug-report.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Ignite CLI bug report -about: Create a report to help us improve -title: '' -labels: report -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. - -**Please provide the version output** - - `ignite version`: - \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md index ddb50f0175..b9b83f6e65 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -1,8 +1,9 @@ +Please make sure to check the following for your PR: +- [ ] This PR complies with the [contributing](../../contributing.md) guidelines. +- [ ] Reviewed "Files changed" and left comments if necessary +- [ ] Included relevant documentation changes. ---- +Ignite CLI team only: -Please make sure to check the following for your PR — Ignite CLI Team: - -- [ ] I comply with the contributing.md. - [ ] I have updated the _Unreleased_ section in the changelog.md for my changes. diff --git a/.github/workflows/stats.yaml b/.github/workflows/stats.yaml index c23be89be9..39801ce2e8 100644 --- a/.github/workflows/stats.yaml +++ b/.github/workflows/stats.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: run-ghrs - uses: jgehrcke/github-repo-stats@v1.1.0 + uses: jgehrcke/github-repo-stats@v1.4.0 with: ghtoken: ${{ secrets.ghrs_github_api_token }} diff --git a/.goreleaser.nightly.yml b/.goreleaser.nightly.yml index 1516e6604c..f7906105dd 100644 --- a/.goreleaser.nightly.yml +++ b/.goreleaser.nightly.yml @@ -13,3 +13,4 @@ changelog: skip: true release: prerelease: true + name_template: nightly diff --git a/changelog.md b/changelog.md index ab7a1d8074..99e6320503 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,16 @@ # Changelog +## [`v0.22.0`](https://github.com/ignite-hq/cli/releases/tag/v0.22.0) + +### Features + +- Optimized the build system. The `c serve`, `chain build`, `chain generate` commands and other variants are way faster now +- Upgraded CLI and templates to use IBC v3 + +### Fixes + +- Add a fix in code generation to avoid user's NodeJS configs to break TS client generation routine + ## [`v0.21.2`](https://github.com/ignite-hq/cli/releases/tag/v0.21.2) ### Fixes diff --git a/docs/guide/hello.md b/docs/guide/hello.md index f2b934aa71..40e3127654 100644 --- a/docs/guide/hello.md +++ b/docs/guide/hello.md @@ -14,7 +14,7 @@ In the previous chapter you've learned how to install [Ignite CLI](https://githu This series of tutorials is based on a specific version of Ignite CLI, so be sure to install the correct version. For example, to install Ignite CLI v0.20.0 use the following command: ```bash -curl https://get.ignite.com/cli@v0.20.0! | bash +curl https://get.ignite.com/cli@v0.21.2! | bash ``` Ignite CLI comes with a number of scaffolding commands that are designed to make development easier by creating everything that's required to start working on a particular task. @@ -26,7 +26,7 @@ Are you ready? Open a terminal window and navigate to a directory where you have To create your blockchain with the default directory structure, run this command: ```bash -ignite scaffold chain github.com/username/hello +ignite scaffold chain hello ``` This command creates a Cosmos SDK blockchain called hello in a `hello` directory. The source code inside the `hello` directory contains a fully functional ready-to-use blockchain. @@ -60,13 +60,13 @@ The `hello` directory contains a number of generated files and directories that | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | app/ | Files that wire together the blockchain. The most important file is `app.go` that contains type definition of the blockchain and functions to create and initialize it. | | cmd/ | The main package responsible for the CLI of compiled binary. | -| docs/ | Directory for project documentation. By default, an OpenAPI spec is generated. | +| docs/ | Directory for project documentation. By default, an OpenAPI spec is generated. | | proto/ | Protocol buffer files describing the data structure. | | testutil/ | Helper functions for testing. | | vue/ | A Vue 3 web app template. | | x/ | Cosmos SDK modules and custom modules. | | config.yml | A configuration file for customizing a chain in development. | -| readme.md | A readme file for your sovereign application-specific blockchain project. | +| readme.md | A readme file for your sovereign application-specific blockchain project. | Now you can get your blockchain up and running locally on a single node. @@ -124,40 +124,49 @@ For all subsequent commands, use a terminal window that is different from the wi In a different terminal window, run the commands in your `hello` directory. -Create a `posts` query: +Create a `hello` query: ```bash -ignite scaffold query posts --response title,body +ignite scaffold query hello --response text ``` -`query` accepts a name of the query (in this case, `posts`), an optional list of request parameters (in this case, empty), and an optional comma-separated list of response fields with a `--response` flag (in this case, `body,title`). +`query` accepts a name of the query (in this case, `hello`), an optional list of request parameters (in this case, empty), and an optional comma-separated list of response fields with a `--response` flag (in this case, `text`). The `query` command has created and modified several files: -- modified `proto/hello/query.proto` -- created `x/hello/keeper/grpc_query_posts.go` -- modified `x/hello/client/cli/query.go` -- created `x/hello/client/cli/query_posts.go` +``` +modify proto/hello/query.proto +modify x/hello/client/cli/query.go +create x/hello/client/cli/query_hello.go +create x/hello/keeper/grpc_query_hello.go +``` Let's examine some of these changes. For clarity, the following code blocks do not show the placeholder comments that Ignite CLI uses to scaffold code. Don't delete these placeholders since they are required to continue using Ignite CLI's scaffolding functionality. +Note: it's recommended to commit changes to a version control system (for example, Git) after scaffolding. This allows others to easily distinguish between code generated by Ignite and the code writen by hand. + +``` +git add . +git commit -am "Scaffolded a hello query with Ignite CLI" +``` + ### Updates to the query service -In the `proto/hello/query.proto` file, the `Posts` rpc has been added to the `Query` service. +In the `proto/hello/query.proto` file, the `Hello` rpc has been added to the `Query` service. ```proto service Query { - rpc Posts(QueryPostsRequest) returns (QueryPostsResponse) { - option (google.api.http).get = "/username/hello/hello/posts"; - } + rpc Hello(QueryHelloRequest) returns (QueryHelloResponse) { + option (google.api.http).get = "/hello/hello/hello"; + } } ``` -Here's how the `Posts` rpc for the `Query` service works: +Here's how the `Hello` rpc for the `Query` service works: -- Is responsible for returning a list of all the posts on chain -- Accepts request parameters (`QueryPostsRequest`) -- Returns response of type `QueryPostsResponse` +- Is responsible for returning a `text` string +- Accepts request parameters (`QueryHelloRequest`) +- Returns response of type `QueryHelloResponse` - The `option` defines the endpoint that is used by gRPC to generate an HTTP API ### Request and reponse types @@ -165,57 +174,60 @@ Here's how the `Posts` rpc for the `Query` service works: Now, take a look at the following request and response types: ```proto -message QueryPostsRequest { +message QueryHelloRequest { } -message QueryPostsResponse { - string title = 1; - string body = 2; +message QueryHelloResponse { + string text = 1; } ``` -- The `QueryPostsRequest` message is empty because requesting all posts doesn't require parameters. -- The `QueryPostsResponse` message contains `title` and `body` that is returned from the chain. +- The `QueryHelloRequest` message is empty because this request does not require parameters. +- The `QueryHelloResponse` message contains `text` that is returned from the chain. -## Posts keeper function +## Hello keeper function -The `x/hello/keeper/grpc_query_posts.go` file contains the `Posts` keeper function that handles the query and returns data. +The `x/hello/keeper/grpc_query_hello.go` file contains the `Hello` keeper function that handles the query and returns data. ```go -func (k Keeper) Posts(c context.Context, req *types.QueryPostsRequest) (*types.QueryPostsResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(c) - _ = ctx - return &types.QueryPostsResponse{}, nil +func (k Keeper) Hello(goCtx context.Context, req *types.QueryHelloRequest) (*types.QueryHelloResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + _ = ctx + return &types.QueryHelloResponse{}, nil } ``` -The `Posts` function performs these actions: +The `Hello` function performs these actions: - Makes a basic check on the request and throws an error if it's `nil` - Stores context in a `ctx` variable that contains information about the environment of the request -- Returns a response of type `QueryPostsResponse` +- Returns a response of type `QueryHelloResponse` Right now the response is empty. ### Update keeper function -In the `query.proto` file, the response accepts `title` and `body`. +In the `query.proto` file, the response accepts `text`. -- Use a text editor to modify the `x/hello/keeper/grpc_query_posts.go` file that contains the keeper function. -- On the last line of the keeper function, change the line to return a "Hello!": +- Use a text editor to modify the `x/hello/keeper/grpc_query_hello.go` file that contains the keeper function. +- On the last line of the keeper function, change the line to return "Hello, Ignite CLI!": ```go -func (k Keeper) Posts(c context.Context, req *types.QueryPostsRequest) (*types.QueryPostsResponse, error) { - //... - return &types.QueryPostsResponse{Title: "Hello!", Body: "Ignite CLI"}, nil +func (k Keeper) Hello(c context.Context, req *types.QueryHelloRequest) (*types.QueryHelloResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + _ = ctx + return &types.QueryHelloResponse{Text: "Hello, Ignite CLI!"}, nil // <-- } ``` - Save the file to restart your chain. -- In a web browser, visit the posts endpoint [http://localhost:1317/username/hello/hello/posts](http://localhost:1317/username/hello/hello/posts). +- In a web browser, visit the `hello` endpoint [http://localhost:1317/hello/hello/hello](http://localhost:1317/hello/hello/hello). Because the query handlers are not yet registered with gRPC, you see a not implemented or localhost cannot connect error. This error is expected behavior, because you still need to register the query handlers. @@ -245,19 +257,18 @@ Make the required changes to the `x/hello/module.go` file. } ``` -1. After the chain has been started, visit [http://localhost:1317/username/hello/hello/posts](http://localhost:1317/username/hello/hello/posts) and see your text displayed: +2. After the chain has been started, visit [http://localhost:1317/hello/hello/hello](http://localhost:1317/hello/hello/hello) and see your text displayed: ```go { - "title": "Hello!", - "body": "Ignite CLI" + "text": "Hello, Ignite CLI!", } ``` -The `query` command has also scaffolded `x/hello/client/cli/query_posts.go` that implements a CLI equivalent of the posts query and mounted this command in `x/hello/client/cli/query.go` . Run the following command and get the same JSON response: +The `query` command has also scaffolded `x/hello/client/cli/query_hello.go` that implements a CLI equivalent of the hello query and mounted this command in `x/hello/client/cli/query.go` . Run the following command and get the same JSON response: ```go -hellod q hello posts +hellod q hello hello ``` Congratulations, you have built your first blockchain and your first Cosmos SDK module. Continue the journey to learn more about scaffolding Cosmos SDK messages, types in protocol buffer files, the keeper, and more. diff --git a/docs/guide/loan.md b/docs/guide/loan.md index a3a31999ed..cb2f0066ed 100644 --- a/docs/guide/loan.md +++ b/docs/guide/loan.md @@ -4,7 +4,7 @@ order: 6 title: "Advanced Module: DeFi Loan" --- -# Loan Module +# DeFi loan module As a rapidly growing industry in the blockchain ecosystem, (decentralized finance) DeFi is spurring innovation and revolution in spending, sending, locking, and loaning cryptocurrency tokens. @@ -31,7 +31,7 @@ In this tutorial, you learn about a basic loan system as you use Ignite CLI to b **Note:** The code in this tutorial is written specifically for this learning experience and is intended only for educational purposes. This tutorial code is not intended to be used in production. -## Module Design +## Module design A loan consists of: @@ -53,7 +53,7 @@ The two accounts involved in the loan are: * `borrower` * `lender` -### The Borrower +### The borrower A borrower posts a loan request with loan information such as: @@ -64,7 +64,7 @@ A borrower posts a loan request with loan information such as: The borrower must repay the loan amount and the loan fee to the lender by the deadline risk losing the collateral. -### The Lender +### The lender A lender can approve a loan request from a borrower. @@ -72,12 +72,12 @@ A lender can approve a loan request from a borrower. - If the borrower is unable to pay the loan, the lender can liquidate the loan. - Loan liquidation transfers the collateral and the fees to the lender. -## Scaffold the Blockchain +## Scaffold the blockchain Use Ignite CLI to scaffold a fully functional Cosmos SDK blockchain app named `loan`: ```bash -ignite scaffold chain github.com/username/loan --no-module +ignite scaffold chain loan --no-module ``` The `--no-module` flag prevents scaffolding a default module. Don't worry, you will add the loan module later. @@ -88,7 +88,7 @@ Change into the newly created `loan` directory: cd loan ``` -## Scaffold the Module +## Scaffold the module Scaffold the module to create a new `loan` module. Following the Cosmos SDK convention, all modules are scaffolded inside the `x` directory: @@ -98,7 +98,7 @@ ignite scaffold module loan --dep bank Use the `--dep` flag to specify that this module depends on and is going to interact with the Cosmos SDK `bank` module. -## Scaffold a List +## Scaffold a list Use the [scaffold list](https://docs.ignite.com/cli/#ignite-scaffold-list) command to scaffold code necessary to store loans in an array-like data structure: @@ -132,7 +132,7 @@ git add . git commit -m "Scaffold loan module and loan list" ``` -## Scaffold the Messages +## Scaffold the messages In order to create a loan app, you need the following messages: @@ -148,7 +148,7 @@ You define the details of each message when you scaffold them. Create the messages one at a time with the according application logic. -### Request Loan Message +### Request loan message For a loan, the initial message handles the transaction when a username requests a loan. @@ -175,7 +175,7 @@ package keeper import ( "context" - "github.com/username/loan/x/loan/types" + "loan/x/loan/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -232,7 +232,9 @@ type BankKeeper interface { } ``` -When a loan is created, a certain input validation is required. You want to throw error messages in case the end user tries impossible inputs. +### Validate the input + +When a loan is created, a certain message input validation is required. You want to throw error messages in case the end user tries impossible inputs. You can describe message validation errors in the modules `types` directory. @@ -270,6 +272,8 @@ func (msg *MsgRequestLoan) ValidateBasic() error { Congratulations, you have created the `request-loan` message. +## Run and test your first message + You can run the chain and test your first message. Start the blockchain: @@ -306,6 +310,8 @@ Loan: You can stop the blockchain again with CTRL+C. +### Save iterative changes + This is a good time to add your advancements to git: ```bash @@ -313,7 +319,7 @@ git add . git commit -m "Add request-loan message" ``` -### Approve Loan Message +### Approve loan message After a loan request has been published, another account can approve the loan and agree to the terms of the borrower. @@ -337,7 +343,7 @@ import ( "context" "fmt" - "github.com/username/loan/x/loan/types" + "loan/x/loan/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -491,7 +497,7 @@ import ( "context" "fmt" - "github.com/username/loan/x/loan/types" + "loan/x/loan/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -650,7 +656,7 @@ import ( "fmt" "strconv" - "github.com/username/loan/x/loan/types" + "loan/x/loan/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -713,6 +719,8 @@ var ( These changes are required for the `liquidate-loan` message. +### Test liquidation message + You can test the liquidation message now. Start your chain and reset the state of the app: ```bash @@ -784,7 +792,7 @@ git add . git commit -m "Add liquidate-loan message" ``` -### Cancel Loan Message +### Cancel loan message After a loan request has been made and not been approved, the `borrower` must be able to cancel a loan request. @@ -807,7 +815,7 @@ import ( "context" "fmt" - "github.com/username/loan/x/loan/types" + "loan/x/loan/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -840,6 +848,8 @@ func (k msgServer) CancelLoan(goCtx context.Context, msg *types.MsgCancelLoan) ( } ``` +### Test cancelling a loan + Test the changes for cancelling a loan request: ```bash diff --git a/docs/kb/frontend.md b/docs/kb/frontend.md index 62244dfa24..c08e2ff2da 100644 --- a/docs/kb/frontend.md +++ b/docs/kb/frontend.md @@ -5,9 +5,9 @@ order: 8 # Frontend overview -A Vue frontend app is created in the `vue` directory when a blockchain is scaffolded. To start the frontend app run `npm i && npm run serve` in the `vue` directory. +A Vue frontend app is created in the `vue` directory when a blockchain is scaffolded. To start the frontend app run `npm i && npm run dev` in the `vue` directory. -The frontend app is built using the `@ignt/vue` and `@ignt/vuex` packages. For details, see the [monorepo for Ignite CLI front-end development](https://github.com/ignite-hq/vue). +The frontend app is built using the `@starport/vue` and `@starport/vuex` packages. For details, see the [monorepo for Ignite CLI front-end development](https://github.com/ignite-hq/web). ## Client code generation diff --git a/go.mod b/go.mod index 201ebad8b8..9b8efaf525 100644 --- a/go.mod +++ b/go.mod @@ -7,11 +7,12 @@ require ( github.com/AlecAivazis/survey/v2 v2.1.1 github.com/blang/semver v3.5.1+incompatible github.com/briandowns/spinner v1.11.1 + github.com/buger/jsonparser v1.1.1 github.com/cenkalti/backoff v2.2.1+incompatible github.com/charmbracelet/glow v1.4.0 github.com/cosmos/cosmos-sdk v0.45.4 github.com/cosmos/go-bip39 v1.0.0 - github.com/cosmos/ibc-go/v2 v2.0.3 + github.com/cosmos/ibc-go/v3 v3.0.0 github.com/docker/docker v20.10.7+incompatible github.com/emicklei/proto v1.9.0 github.com/fatih/color v1.13.0 @@ -45,17 +46,18 @@ require ( github.com/stretchr/testify v1.7.1 github.com/takuoki/gocase v1.0.0 github.com/tendermint/flutter/v2 v2.0.4 - github.com/tendermint/spn v0.2.1-0.20220511154430-aeab7a5b2bc0 + github.com/tendermint/spn v0.2.1-0.20220609194312-7833ecf4454a github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.7 github.com/tendermint/vue v0.3.5 github.com/vektra/mockery/v2 v2.11.0 + go.etcd.io/bbolt v1.3.6 golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 golang.org/x/text v0.3.7 - google.golang.org/grpc v1.45.0 - google.golang.org/protobuf v1.27.1 + google.golang.org/grpc v1.46.2 + google.golang.org/protobuf v1.28.0 ) require ( @@ -223,18 +225,17 @@ require ( github.com/yuin/goldmark v1.4.1 // indirect github.com/yuin/goldmark-emoji v1.0.1 // indirect github.com/zondax/hid v0.9.0 // indirect - go.etcd.io/bbolt v1.3.6 // indirect go.opencensus.io v0.23.0 // indirect golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 // indirect golang.org/x/tools v0.1.10 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect + google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect gopkg.in/ini.v1 v1.66.3 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.1.0 // indirect nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/go.sum b/go.sum index fb94ef9c7a..71557d8669 100644 --- a/go.sum +++ b/go.sum @@ -215,7 +215,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= @@ -245,6 +244,8 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +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/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= @@ -304,7 +305,6 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/coinbase/rosetta-sdk-go v0.6.10/go.mod h1:J/JFMsfcePrjJZkwQFLh+hJErkAmdm9Iyy3D5Y0LfXo= github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg= github.com/coinbase/rosetta-sdk-go v0.7.0/go.mod h1:7nD3oBPIiHqhRprqvMgPoGxe/nyq3yftRmpsy29coWE= github.com/confio/ics23/go v0.6.6/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= @@ -422,7 +422,6 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= -github.com/cosmos/cosmos-sdk v0.44.5/go.mod h1:maUA6m2TBxOJZkbwl0eRtEBgTX37kcaiOWU5t1HEGaY= github.com/cosmos/cosmos-sdk v0.45.4 h1:eStDAhJdMY8n5arbBRe+OwpNeBSunxSBHp1g55ulfdA= github.com/cosmos/cosmos-sdk v0.45.4/go.mod h1:WOqtDxN3eCCmnYLVla10xG7lEXkFjpTaqm2a2WasgCc= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= @@ -432,8 +431,8 @@ github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4 github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cosmos/iavl v0.17.3 h1:s2N819a2olOmiauVa0WAhoIJq9EhSXE9HDBAoR9k+8Y= github.com/cosmos/iavl v0.17.3/go.mod h1:prJoErZFABYZGDHka1R6Oay4z9PrNeFFiMKHDAMOi4w= -github.com/cosmos/ibc-go/v2 v2.0.3 h1:kZ6SAj7hyxoixsLEUBx431bVGiBW22PCHwkWHafWhXs= -github.com/cosmos/ibc-go/v2 v2.0.3/go.mod h1:XUmW7wmubCRhIEAGtMGS+5IjiSSmcAwihoN/yPGd6Kk= +github.com/cosmos/ibc-go/v3 v3.0.0 h1:XUNplHVS51Q2gMnTFsFsH9QJ7flsovMamnltKbEgPQ4= +github.com/cosmos/ibc-go/v3 v3.0.0/go.mod h1:Mb+1NXiPOLd+CPFlOC6BKeAUaxXlhuWenMmRiUiSmwY= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= @@ -735,7 +734,7 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/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.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/go-github/v37 v37.0.0 h1:rCspN8/6kB1BAJWZfuafvHhyfIo5fkAulaP/3bOQ/tM= github.com/google/go-github/v37 v37.0.0/go.mod h1:LM7in3NmXDrX58GbEHy7FtNLbI2JijX93RnMKvWG3m4= @@ -783,7 +782,6 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= 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= @@ -910,7 +908,6 @@ github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1C github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.9.0 h1:npqHz788dryJiR/l6K/RUQAyh2SwV91+d1dnh4RjO9w= -github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -984,7 +981,6 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= @@ -1076,7 +1072,6 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu 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.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -1143,7 +1138,6 @@ github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= 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= @@ -1168,7 +1162,6 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= 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 v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= @@ -1239,7 +1232,6 @@ github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7ir 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.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= @@ -1298,7 +1290,6 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8 github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= @@ -1348,9 +1339,7 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.23.0/go.mod h1:6c7hFfxPOy7TacJc4Fcdi24/J0NKYGzjG8FWRI916Qo= github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -1412,7 +1401,6 @@ github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60= github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= @@ -1421,7 +1409,6 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= @@ -1438,7 +1425,6 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= @@ -1487,8 +1473,8 @@ github.com/tendermint/fundraising v0.3.0 h1:VtHfmVlAS93MUDlt6Em21l3taw6s9kLY/w8C github.com/tendermint/fundraising v0.3.0/go.mod h1:oJFZUZ/GsACtkYeWScKpHLdqMUThNWpMAi/G47LJUi4= 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/tendermint/spn v0.2.1-0.20220511154430-aeab7a5b2bc0 h1:kIjnfHO472W2WSzul3ek3p07yKVYxSFUNng4YJmVex4= -github.com/tendermint/spn v0.2.1-0.20220511154430-aeab7a5b2bc0/go.mod h1:xNtBc/jmB1pvb+EJYQtyJdcTZM9dOhJeW3C4Qj9n7tg= +github.com/tendermint/spn v0.2.1-0.20220609194312-7833ecf4454a h1:+xo1H4r/dLkUcx89/jP88TbVQiA40Rcn7yQyPozIj5k= +github.com/tendermint/spn v0.2.1-0.20220609194312-7833ecf4454a/go.mod h1:5w8qNkgtJM24CcMjqTsVOKnSbz+U2fke7bEGzRlcdHA= github.com/tendermint/tendermint v0.34.14/go.mod h1:FrwVm3TvsVicI9Z7FlucHV6Znfd5KBc/Lpp69cCwtk0= github.com/tendermint/tendermint v0.34.19 h1:y0P1qI5wSa9IRuhKnTDA6IUcOrLi1hXJuALR+R7HFEk= github.com/tendermint/tendermint v0.34.19/go.mod h1:R5+wgIwSxMdKQcmOaeudL0Cjkr3HDkhpcdum6VeU3R4= @@ -1773,7 +1759,6 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= @@ -1999,11 +1984,9 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -2058,7 +2041,6 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= @@ -2156,8 +2138,8 @@ google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e h1:fNKDNuUyC4WH+inqDMpfXDdfvwfYILbsX+oskGZ8hxg= -google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -2171,11 +2153,11 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 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.25.1-0.20200805231151-a709e31e5d12/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 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 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= @@ -2192,8 +2174,6 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.3 h1:jRskFVxYaMGAMUbN0UZ7niA9gzL9B49DOqE78vg0k3w= gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -2221,8 +2201,9 @@ 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 h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 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 v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= diff --git a/ignite/cmd/account.go b/ignite/cmd/account.go index 065c6e84d9..b3891fddbb 100644 --- a/ignite/cmd/account.go +++ b/ignite/cmd/account.go @@ -60,7 +60,7 @@ func getKeyringBackend(cmd *cobra.Command) cosmosaccount.KeyringBackend { func flagSetAccountPrefixes() *flag.FlagSet { fs := flag.NewFlagSet("", flag.ContinueOnError) - fs.String(flagAddressPrefix, "cosmos", "Account address prefix") + fs.String(flagAddressPrefix, cosmosaccount.AccountPrefixCosmos, "Account address prefix") return fs } diff --git a/ignite/cmd/chain_build.go b/ignite/cmd/chain_build.go index 3a82edec7f..005734e876 100644 --- a/ignite/cmd/chain_build.go +++ b/ignite/cmd/chain_build.go @@ -39,6 +39,7 @@ Sample usages: } flagSetPath(c) + flagSetClearCache(c) c.Flags().AddFlagSet(flagSetHome()) c.Flags().AddFlagSet(flagSetProto3rdParty("Available only without the --release flag")) c.Flags().Bool(flagRelease, false, "build for a release") @@ -72,8 +73,13 @@ func chainBuildHandler(cmd *cobra.Command, _ []string) error { return err } + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + if isRelease { - releasePath, err := c.BuildRelease(cmd.Context(), output, releasePrefix, releaseTargets...) + releasePath, err := c.BuildRelease(cmd.Context(), cacheStorage, output, releasePrefix, releaseTargets...) if err != nil { return err } @@ -83,7 +89,7 @@ func chainBuildHandler(cmd *cobra.Command, _ []string) error { return nil } - binaryName, err := c.Build(cmd.Context(), output) + binaryName, err := c.Build(cmd.Context(), cacheStorage, output) if err != nil { return err } diff --git a/ignite/cmd/chain_init.go b/ignite/cmd/chain_init.go index 3c887238b8..27026e2345 100644 --- a/ignite/cmd/chain_init.go +++ b/ignite/cmd/chain_init.go @@ -19,6 +19,7 @@ func NewChainInit() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().AddFlagSet(flagSetHome()) return c @@ -35,7 +36,12 @@ func chainInitHandler(cmd *cobra.Command, _ []string) error { return err } - if _, err := c.Build(cmd.Context(), ""); err != nil { + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + if _, err := c.Build(cmd.Context(), cacheStorage, ""); err != nil { return err } diff --git a/ignite/cmd/chain_serve.go b/ignite/cmd/chain_serve.go index 1898e4e3f2..9b8bfcd8ed 100644 --- a/ignite/cmd/chain_serve.go +++ b/ignite/cmd/chain_serve.go @@ -23,6 +23,7 @@ func NewChainServe() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().AddFlagSet(flagSetHome()) c.Flags().AddFlagSet(flagSetProto3rdParty("")) c.Flags().BoolP("verbose", "v", false, "Verbose output") @@ -57,6 +58,11 @@ func chainServeHandler(cmd *cobra.Command, args []string) error { return err } + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + // serve the chain var serveOptions []chain.ServeOption forceUpdate, err := cmd.Flags().GetBool(flagForceReset) @@ -74,5 +80,5 @@ func chainServeHandler(cmd *cobra.Command, args []string) error { serveOptions = append(serveOptions, chain.ServeResetOnce()) } - return c.Serve(cmd.Context(), serveOptions...) + return c.Serve(cmd.Context(), cacheStorage, serveOptions...) } diff --git a/ignite/cmd/cmd.go b/ignite/cmd/cmd.go index d7fa86880b..b4c66704b1 100644 --- a/ignite/cmd/cmd.go +++ b/ignite/cmd/cmd.go @@ -9,12 +9,13 @@ import ( "strings" "time" - "github.com/ignite-hq/cli/ignite/pkg/cliui" - "github.com/fatih/color" "github.com/spf13/cobra" flag "github.com/spf13/pflag" + "github.com/ignite-hq/cli/ignite/chainconfig" + "github.com/ignite-hq/cli/ignite/pkg/cache" + "github.com/ignite-hq/cli/ignite/pkg/cliui" "github.com/ignite-hq/cli/ignite/pkg/cosmosaccount" "github.com/ignite-hq/cli/ignite/pkg/cosmosver" "github.com/ignite-hq/cli/ignite/pkg/gitpod" @@ -30,8 +31,10 @@ const ( flagHome = "home" flagProto3rdParty = "proto-all-modules" flagYes = "yes" + flagClearCache = "clear-cache" checkVersionTimeout = time.Millisecond * 600 + cacheFileName = "ignite_cache.db" ) // New creates a new root command for `Ignite CLI` with its sub commands. @@ -137,6 +140,15 @@ func flagGetProto3rdParty(cmd *cobra.Command) bool { return isEnabled } +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 newChainWithHomeFlags(cmd *cobra.Command, chainOption ...chain.Option) (*chain.Chain, error) { // Check if custom home is provided if home := getHome(cmd); home != "" { @@ -269,3 +281,23 @@ https://docs.ignite.com/migration`, sc.Version.String(), func printSection(session cliui.Session, title string) error { return session.Printf("------\n%s\n------\n\n", title) } + +func newCache(cmd *cobra.Command) (cache.Storage, error) { + cacheRootDir, err := chainconfig.ConfigDirPath() + if err != nil { + return cache.Storage{}, err + } + + 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 +} diff --git a/ignite/cmd/generate.go b/ignite/cmd/generate.go index a2181e768a..f8a87bd737 100644 --- a/ignite/cmd/generate.go +++ b/ignite/cmd/generate.go @@ -17,6 +17,7 @@ Produced source code can be regenerated by running a command again and is not me } flagSetPath(c) + flagSetClearCache(c) c.AddCommand(addGitChangesVerifier(NewGenerateGo())) c.AddCommand(addGitChangesVerifier(NewGenerateVuex())) c.AddCommand(addGitChangesVerifier(NewGenerateDart())) diff --git a/ignite/cmd/generate_dart.go b/ignite/cmd/generate_dart.go index ef9bdd6456..738023e6b1 100644 --- a/ignite/cmd/generate_dart.go +++ b/ignite/cmd/generate_dart.go @@ -27,7 +27,12 @@ func generateDartHandler(cmd *cobra.Command, args []string) error { return err } - if err := c.Generate(cmd.Context(), chain.GenerateDart()); err != nil { + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + if err := c.Generate(cmd.Context(), cacheStorage, chain.GenerateDart()); err != nil { return err } diff --git a/ignite/cmd/generate_go.go b/ignite/cmd/generate_go.go index 5f9d4b0d8d..0fde4daf4a 100644 --- a/ignite/cmd/generate_go.go +++ b/ignite/cmd/generate_go.go @@ -26,7 +26,12 @@ func generateGoHandler(cmd *cobra.Command, args []string) error { return err } - if err := c.Generate(cmd.Context(), chain.GenerateGo()); err != nil { + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + if err := c.Generate(cmd.Context(), cacheStorage, chain.GenerateGo()); err != nil { return err } diff --git a/ignite/cmd/generate_openapi.go b/ignite/cmd/generate_openapi.go index a76ebcb862..71f35b2904 100644 --- a/ignite/cmd/generate_openapi.go +++ b/ignite/cmd/generate_openapi.go @@ -26,7 +26,12 @@ func generateOpenAPIHandler(cmd *cobra.Command, args []string) error { return err } - if err := c.Generate(cmd.Context(), chain.GenerateOpenAPI()); err != nil { + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + if err := c.Generate(cmd.Context(), cacheStorage, chain.GenerateOpenAPI()); err != nil { return err } diff --git a/ignite/cmd/generate_vuex.go b/ignite/cmd/generate_vuex.go index 43816aa385..22b4de430b 100644 --- a/ignite/cmd/generate_vuex.go +++ b/ignite/cmd/generate_vuex.go @@ -28,7 +28,12 @@ func generateVuexHandler(cmd *cobra.Command, args []string) error { return err } - if err := c.Generate(cmd.Context(), chain.GenerateVuex()); err != nil { + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + if err := c.Generate(cmd.Context(), cacheStorage, chain.GenerateVuex()); err != nil { return err } diff --git a/ignite/cmd/network.go b/ignite/cmd/network.go index fbad065f84..250c2f8084 100644 --- a/ignite/cmd/network.go +++ b/ignite/cmd/network.go @@ -3,6 +3,7 @@ package ignitecmd import ( "github.com/pkg/errors" "github.com/spf13/cobra" + flag "github.com/spf13/pflag" "github.com/ignite-hq/cli/ignite/pkg/cosmosaccount" "github.com/ignite-hq/cli/ignite/pkg/cosmosclient" @@ -84,6 +85,12 @@ func CollectEvents(ev events.Bus) NetworkBuilderOption { } } +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 diff --git a/ignite/cmd/network_chain_init.go b/ignite/cmd/network_chain_init.go index 6053cf1626..336954de85 100644 --- a/ignite/cmd/network_chain_init.go +++ b/ignite/cmd/network_chain_init.go @@ -34,6 +34,8 @@ func NewNetworkChainInit() *cobra.Command { 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") @@ -87,6 +89,11 @@ func networkChainInitHandler(cmd *cobra.Command, args []string) error { } } + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + n, err := nb.Network() if err != nil { return err @@ -102,7 +109,7 @@ func networkChainInitHandler(cmd *cobra.Command, args []string) error { return err } - if err := c.Init(cmd.Context()); err != nil { + if err := c.Init(cmd.Context(), cacheStorage); err != nil { return err } diff --git a/ignite/cmd/network_chain_install.go b/ignite/cmd/network_chain_install.go index c57285cc84..90aea0f487 100644 --- a/ignite/cmd/network_chain_install.go +++ b/ignite/cmd/network_chain_install.go @@ -21,6 +21,8 @@ func NewNetworkChainInstall() *cobra.Command { Args: cobra.ExactArgs(1), RunE: networkChainInstallHandler, } + + flagSetClearCache(c) c.Flags().AddFlagSet(flagNetworkFrom()) return c } @@ -29,6 +31,11 @@ func networkChainInstallHandler(cmd *cobra.Command, args []string) error { session := cliui.New() defer session.Cleanup() + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + nb, err := newNetworkBuilder(cmd, CollectEvents(session.EventBus())) if err != nil { return err @@ -55,7 +62,7 @@ func networkChainInstallHandler(cmd *cobra.Command, args []string) error { return err } - binaryName, err := c.Build(cmd.Context()) + binaryName, err := c.Build(cmd.Context(), cacheStorage) if err != nil { return err } diff --git a/ignite/cmd/network_chain_join.go b/ignite/cmd/network_chain_join.go index 83271c2ba0..313675be66 100644 --- a/ignite/cmd/network_chain_join.go +++ b/ignite/cmd/network_chain_join.go @@ -32,12 +32,14 @@ func NewNetworkChainJoin() *cobra.Command { 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") c.Flags().AddFlagSet(flagNetworkFrom()) c.Flags().AddFlagSet(flagSetHome()) c.Flags().AddFlagSet(flagSetKeyringBackend()) c.Flags().AddFlagSet(flagSetYes()) + return c } diff --git a/ignite/cmd/network_chain_prepare.go b/ignite/cmd/network_chain_prepare.go index 31907f3382..1e237e943b 100644 --- a/ignite/cmd/network_chain_prepare.go +++ b/ignite/cmd/network_chain_prepare.go @@ -27,6 +27,7 @@ func NewNetworkChainPrepare() *cobra.Command { 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()) @@ -41,6 +42,11 @@ func networkChainPrepareHandler(cmd *cobra.Command, args []string) error { 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 @@ -64,7 +70,7 @@ func networkChainPrepareHandler(cmd *cobra.Command, args []string) error { } if !force && !chainLaunch.LaunchTriggered { - return fmt.Errorf("chain %d has not launched yet. use --force to prepare anyway", launchID) + return fmt.Errorf("chain %d launch has not been triggered yet. use --force to prepare anyway", launchID) } c, err := nb.Chain(networkchain.SourceLaunch(chainLaunch)) @@ -78,7 +84,29 @@ func networkChainPrepareHandler(cmd *cobra.Command, args []string) error { return err } - if err := c.Prepare(cmd.Context(), genesisInformation); err != nil { + rewardsInfo, lastBlockHeight, unboundingTime, err := n.RewardsInfo( + cmd.Context(), + launchID, + chainLaunch.ConsumerRevisionHeight, + ) + if err != nil { + return err + } + + spnChainID, err := n.ChainID(cmd.Context()) + if err != nil { + return err + } + + if err := c.Prepare( + cmd.Context(), + cacheStorage, + genesisInformation, + rewardsInfo, + spnChainID, + lastBlockHeight, + unboundingTime, + ); err != nil { return err } diff --git a/ignite/cmd/network_chain_publish.go b/ignite/cmd/network_chain_publish.go index 02c3147263..58630ebabb 100644 --- a/ignite/cmd/network_chain_publish.go +++ b/ignite/cmd/network_chain_publish.go @@ -8,11 +8,9 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/tendermint/spn/pkg/chainid" - campaigntypes "github.com/tendermint/spn/x/campaign/types" "github.com/ignite-hq/cli/ignite/pkg/cliui" "github.com/ignite-hq/cli/ignite/pkg/cliui/icons" - "github.com/ignite-hq/cli/ignite/pkg/cosmosutil" "github.com/ignite-hq/cli/ignite/pkg/xurl" "github.com/ignite-hq/cli/ignite/services/network" "github.com/ignite-hq/cli/ignite/services/network/networkchain" @@ -41,6 +39,7 @@ func NewNetworkChainPublish() *cobra.Command { 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") @@ -54,6 +53,7 @@ func NewNetworkChainPublish() *cobra.Command { c.Flags().Bool(flagMainnet, false, "Initialize a mainnet campaign") 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(flagSetHome()) @@ -80,13 +80,25 @@ func networkChainPublishHandler(cmd *cobra.Command, args []string) error { isMainnet, _ = cmd.Flags().GetBool(flagMainnet) 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") + } + 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 campaign != 0 && campaignTotalSupplyStr != "" { return fmt.Errorf("%s and %s flags cannot be set together", flagCampaign, flagCampaignTotalSupply) } @@ -197,12 +209,12 @@ func networkChainPublishHandler(cmd *cobra.Command, args []string) error { } if sharesStr != "" { - coins, err := cosmosutil.ParseCoinsNormalizedWithPercentageRequired(sharesStr) + sharePercentages, err := network.ParseSharePercents(sharesStr) if err != nil { return err } - publishOptions = append(publishOptions, network.WithShares(campaigntypes.NewSharesFromCoins(coins))) + publishOptions = append(publishOptions, network.WithPercentageShares(sharePercentages)) } // init the chain. @@ -213,7 +225,7 @@ func networkChainPublishHandler(cmd *cobra.Command, args []string) error { if noCheck { publishOptions = append(publishOptions, network.WithNoCheck()) - } else if err := c.Init(cmd.Context()); err != nil { // initialize the chain for checking. + } else if err := c.Init(cmd.Context(), cacheStorage); err != nil { // initialize the chain for checking. return err } @@ -224,24 +236,31 @@ func networkChainPublishHandler(cmd *cobra.Command, args []string) error { return err } - launchID, campaignID, mainnetID, err := n.Publish(cmd.Context(), c, publishOptions...) + launchID, campaignID, err := n.Publish(cmd.Context(), c, publishOptions...) if err != nil { return err } - if !rewardCoins.Empty() && rewardDuration > 0 { + if !rewardCoins.IsZero() && rewardDuration > 0 { if err := n.SetReward(launchID, rewardDuration, rewardCoins); err != nil { return err } } + if !amountCoins.IsZero() { + if err := n.SendAccountRequestForCoordinator(launchID, amountCoins); err != nil { + return err + } + } + session.StopSpinner() session.Printf("%s Network published \n", icons.OK) - session.Printf("%s Launch ID: %d \n", icons.Bullet, launchID) - session.Printf("%s Campaign ID: %d \n", icons.Bullet, campaignID) if isMainnet { - session.Printf("%s Mainnet ID: %d \n", icons.Bullet, mainnetID) + session.Printf("%s Mainnet ID: %d \n", icons.Bullet, launchID) + } else { + session.Printf("%s Launch ID: %d \n", icons.Bullet, launchID) } + session.Printf("%s Campaign ID: %d \n", icons.Bullet, campaignID) return nil } diff --git a/ignite/cmd/network_chain_show_accounts.go b/ignite/cmd/network_chain_show_accounts.go index 0024c0e20b..73028d8331 100644 --- a/ignite/cmd/network_chain_show_accounts.go +++ b/ignite/cmd/network_chain_show_accounts.go @@ -7,6 +7,7 @@ import ( "github.com/ignite-hq/cli/ignite/pkg/cliui" "github.com/ignite-hq/cli/ignite/pkg/cliui/icons" + "github.com/ignite-hq/cli/ignite/pkg/cosmosutil" ) var ( @@ -22,6 +23,8 @@ func newNetworkChainShowAccounts() *cobra.Command { RunE: networkChainShowAccountsHandler, } + c.Flags().AddFlagSet(flagSetSPNAccountPrefixes()) + return c } @@ -29,6 +32,8 @@ func networkChainShowAccountsHandler(cmd *cobra.Command, args []string) error { session := cliui.New() defer session.Cleanup() + addressPrefix := getAddressPrefix(cmd) + nb, launchID, err := networkChainLaunch(cmd, args, session) if err != nil { return err @@ -53,12 +58,22 @@ func networkChainShowAccountsHandler(cmd *cobra.Command, args []string) error { genesisAccEntries := make([][]string, 0) for _, acc := range genesisAccs { - genesisAccEntries = append(genesisAccEntries, []string{acc.Address, acc.Coins}) + address, err := cosmosutil.ChangeAddressPrefix(acc.Address, addressPrefix) + if err != nil { + return err + } + + genesisAccEntries = append(genesisAccEntries, []string{address, acc.Coins}) } genesisVestingAccEntries := make([][]string, 0) for _, acc := range vestingAccs { + address, err := cosmosutil.ChangeAddressPrefix(acc.Address, addressPrefix) + if err != nil { + return err + } + genesisVestingAccEntries = append(genesisVestingAccEntries, []string{ - acc.Address, + address, acc.TotalBalance, acc.Vesting, strconv.FormatInt(acc.EndTime, 10), diff --git a/ignite/cmd/network_chain_show_genesis.go b/ignite/cmd/network_chain_show_genesis.go index 3dcf03bfd5..85c6ebe6b3 100644 --- a/ignite/cmd/network_chain_show_genesis.go +++ b/ignite/cmd/network_chain_show_genesis.go @@ -19,6 +19,7 @@ func newNetworkChainShowGenesis() *cobra.Command { RunE: networkChainShowGenesisHandler, } + flagSetClearCache(c) c.Flags().String(flagOut, "./genesis.json", "Path to output Genesis file") return c @@ -30,6 +31,11 @@ func networkChainShowGenesisHandler(cmd *cobra.Command, args []string) error { 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 @@ -54,6 +60,11 @@ func networkChainShowGenesisHandler(cmd *cobra.Command, args []string) error { return err } + spnChainID, err := n.ChainID(cmd.Context()) + if err != nil { + return err + } + // check if the genesis already exists if _, err = os.Stat(genesisPath); os.IsNotExist(err) { // fetch the information to construct genesis @@ -71,11 +82,27 @@ func networkChainShowGenesisHandler(cmd *cobra.Command, args []string) error { c.SetHome(tmpHome) - err = c.Prepare(cmd.Context(), genesisInformation) + rewardsInfo, lastBlockHeight, unboundingTime, err := n.RewardsInfo( + cmd.Context(), + launchID, + chainLaunch.ConsumerRevisionHeight, + ) if err != nil { return err } + if err = c.Prepare( + cmd.Context(), + cacheStorage, + genesisInformation, + rewardsInfo, + spnChainID, + lastBlockHeight, + unboundingTime, + ); err != nil { + return err + } + // get the new genesis path genesisPath, err = c.GenesisPath() if err != nil { diff --git a/ignite/cmd/network_chain_show_validators.go b/ignite/cmd/network_chain_show_validators.go index 7256930c86..0a1c056f91 100644 --- a/ignite/cmd/network_chain_show_validators.go +++ b/ignite/cmd/network_chain_show_validators.go @@ -5,6 +5,7 @@ import ( "github.com/ignite-hq/cli/ignite/pkg/cliui" "github.com/ignite-hq/cli/ignite/pkg/cliui/icons" + "github.com/ignite-hq/cli/ignite/pkg/cosmosutil" "github.com/ignite-hq/cli/ignite/services/network" ) @@ -19,6 +20,9 @@ func newNetworkChainShowValidators() *cobra.Command { Args: cobra.ExactArgs(1), RunE: networkChainShowValidatorsHandler, } + + c.Flags().AddFlagSet(flagSetSPNAccountPrefixes()) + return c } @@ -26,6 +30,8 @@ func networkChainShowValidatorsHandler(cmd *cobra.Command, args []string) error session := cliui.New() defer session.Cleanup() + addressPrefix := getAddressPrefix(cmd) + nb, launchID, err := networkChainLaunch(cmd, args, session) if err != nil { return err @@ -45,8 +51,14 @@ func networkChainShowValidatorsHandler(cmd *cobra.Command, args []string) error if err != nil { return err } + + address, err := cosmosutil.ChangeAddressPrefix(acc.Address, addressPrefix) + if err != nil { + return err + } + validatorEntries = append(validatorEntries, []string{ - acc.Address, + address, acc.SelfDelegation.String(), peer, }) diff --git a/ignite/cmd/network_client_create.go b/ignite/cmd/network_client_create.go index c038dd6579..50ba1838a7 100644 --- a/ignite/cmd/network_client_create.go +++ b/ignite/cmd/network_client_create.go @@ -46,7 +46,7 @@ func networkClientCreateHandler(cmd *cobra.Command, args []string) error { return err } - ibcInfo, err := node.IBCInfo(cmd.Context()) + rewardsInfo, unboundingTime, err := node.RewardsInfo(cmd.Context()) if err != nil { return err } @@ -56,7 +56,7 @@ func networkClientCreateHandler(cmd *cobra.Command, args []string) error { return err } - clientID, err := n.CreateClient(launchID, ibcInfo) + clientID, err := n.CreateClient(launchID, unboundingTime, rewardsInfo) if err != nil { return err } diff --git a/ignite/cmd/network_request_approve.go b/ignite/cmd/network_request_approve.go index 76a4894650..e49d37654f 100644 --- a/ignite/cmd/network_request_approve.go +++ b/ignite/cmd/network_request_approve.go @@ -24,6 +24,8 @@ func NewNetworkRequestApprove() *cobra.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()) @@ -63,9 +65,14 @@ func networkRequestApproveHandler(cmd *cobra.Command, args []string) error { 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 := verifyRequest(cmd.Context(), nb, launchID, ids...); err != nil { + if err := verifyRequest(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, "#")) diff --git a/ignite/cmd/network_request_list.go b/ignite/cmd/network_request_list.go index ffed6c1ad0..55e57eb1e3 100644 --- a/ignite/cmd/network_request_list.go +++ b/ignite/cmd/network_request_list.go @@ -7,6 +7,7 @@ import ( launchtypes "github.com/tendermint/spn/x/launch/types" "github.com/ignite-hq/cli/ignite/pkg/cliui" + "github.com/ignite-hq/cli/ignite/pkg/cosmosutil" "github.com/ignite-hq/cli/ignite/services/network" "github.com/ignite-hq/cli/ignite/services/network/networktypes" ) @@ -22,6 +23,9 @@ func NewNetworkRequestList() *cobra.Command { RunE: networkRequestListHandler, Args: cobra.ExactArgs(1), } + + c.Flags().AddFlagSet(flagSetSPNAccountPrefixes()) + return c } @@ -34,6 +38,8 @@ func networkRequestListHandler(cmd *cobra.Command, args []string) error { return err } + addressPrefix := getAddressPrefix(cmd) + // parse launch ID launchID, err := network.ParseID(args[0]) if err != nil { @@ -52,11 +58,15 @@ func networkRequestListHandler(cmd *cobra.Command, args []string) error { session.StopSpinner() - return renderRequestSummaries(requests, session) + return renderRequestSummaries(requests, session, addressPrefix) } // renderRequestSummaries writes into the provided out, the list of summarized requests -func renderRequestSummaries(requests []networktypes.Request, session cliui.Session) error { +func renderRequestSummaries( + requests []networktypes.Request, + session cliui.Session, + addressPrefix string, +) error { requestEntries := make([][]string, 0) for _, request := range requests { var ( @@ -67,8 +77,17 @@ func renderRequestSummaries(requests []networktypes.Request, session cliui.Sessi switch req := request.Content.Content.(type) { case *launchtypes.RequestContent_GenesisAccount: requestType = "Add Genesis Account" - content = fmt.Sprintf("%s, %s", + + 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" @@ -76,9 +95,18 @@ func renderRequestSummaries(requests []networktypes.Request, session cliui.Sessi 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, - req.GenesisValidator.Address, + address, req.GenesisValidator.SelfDelegation.String()) case *launchtypes.RequestContent_VestingAccount: requestType = "Add Vesting Account" @@ -91,16 +119,43 @@ func renderRequestSummaries(requests []networktypes.Request, session cliui.Sessi } else { vestingCoins = fmt.Sprintf("%s (vesting: %s)", dv.TotalBalance, dv.Vesting) } - content = fmt.Sprintf("%s, %s", + + 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" - content = req.ValidatorRemoval.ValAddress + + address, err := cosmosutil.ChangeAddressPrefix( + req.ValidatorRemoval.ValAddress, + addressPrefix, + ) + if err != nil { + return err + } + + content = address case *launchtypes.RequestContent_AccountRemoval: requestType = "Remove Account" - content = req.AccountRemoval.Address + + address, err := cosmosutil.ChangeAddressPrefix( + req.AccountRemoval.Address, + addressPrefix, + ) + if err != nil { + return err + } + + content = address } requestEntries = append(requestEntries, []string{ diff --git a/ignite/cmd/network_request_verify.go b/ignite/cmd/network_request_verify.go index 5c804b0b53..b85c19b753 100644 --- a/ignite/cmd/network_request_verify.go +++ b/ignite/cmd/network_request_verify.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/cobra" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/chaincmd" "github.com/ignite-hq/cli/ignite/pkg/cliui" "github.com/ignite-hq/cli/ignite/pkg/cliui/icons" @@ -22,6 +23,8 @@ func NewNetworkRequestVerify() *cobra.Command { RunE: networkRequestVerifyHandler, Args: cobra.ExactArgs(2), } + + flagSetClearCache(c) c.Flags().AddFlagSet(flagNetworkFrom()) c.Flags().AddFlagSet(flagSetHome()) c.Flags().AddFlagSet(flagSetKeyringBackend()) @@ -49,8 +52,13 @@ func networkRequestVerifyHandler(cmd *cobra.Command, args []string) error { return err } + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + // verify the requests - if err := verifyRequest(cmd.Context(), nb, launchID, ids...); err != nil { + if err := verifyRequest(cmd.Context(), cacheStorage, nb, launchID, ids...); err != nil { session.Printf("%s Request(s) %s not valid\n", icons.NotOK, numbers.List(ids, "#")) return err } @@ -62,6 +70,7 @@ func networkRequestVerifyHandler(cmd *cobra.Command, args []string) error { // and simulate the launch of the chain from genesis with the request IDs func verifyRequest( ctx context.Context, + cacheStorage cache.Storage, nb NetworkBuilder, launchID uint64, requestIDs ...uint64, @@ -103,5 +112,10 @@ func verifyRequest( return err } - return c.SimulateRequests(ctx, genesisInformation, requests) + return c.SimulateRequests( + ctx, + cacheStorage, + genesisInformation, + requests, + ) } diff --git a/ignite/cmd/relayer_configure.go b/ignite/cmd/relayer_configure.go index 0ab8769dbd..7fbb93ce08 100644 --- a/ignite/cmd/relayer_configure.go +++ b/ignite/cmd/relayer_configure.go @@ -33,6 +33,8 @@ const ( flagTargetAddressPrefix = "target-prefix" flagOrdered = "ordered" flagReset = "reset" + flagSourceClientID = "source-client-id" + flagTargetClientID = "target-client-id" relayerSource = "source" relayerTarget = "target" @@ -58,6 +60,7 @@ func NewRelayerConfigure() *cobra.Command { Aliases: []string{"conf"}, RunE: relayerConfigureHandler, } + c.Flags().BoolP(flagAdvanced, "a", false, "Advanced configuration options for custom IBC modules") c.Flags().String(flagSourceRPC, "", "RPC address of the source chain") c.Flags().String(flagTargetRPC, "", "RPC address of the target chain") @@ -77,6 +80,8 @@ func NewRelayerConfigure() *cobra.Command { c.Flags().String(flagTargetAccount, "", "Target Account") c.Flags().Bool(flagOrdered, false, "Set the channel as ordered") c.Flags().BoolP(flagReset, "r", false, "Reset the relayer config") + c.Flags().String(flagSourceClientID, "", "use a custom client id for source") + c.Flags().String(flagTargetClientID, "", "use a custom client id for target") c.Flags().AddFlagSet(flagSetKeyringBackend()) return c @@ -299,8 +304,11 @@ func relayerConfigureHandler(cmd *cobra.Command, args []string) (err error) { return err } var ( + sourceClientID, _ = cmd.Flags().GetString(flagSourceClientID) + targetClientID, _ = cmd.Flags().GetString(flagTargetClientID) + reset, _ = cmd.Flags().GetBool(flagReset) + questions []cliquiz.Question - reset, _ = cmd.Flags().GetBool(flagReset) ) // get information from prompt if flag not provided @@ -386,6 +394,7 @@ func relayerConfigureHandler(cmd *cobra.Command, args []string) (err error) { sourceGasPrice, sourceGasLimit, sourceAddressPrefix, + sourceClientID, ) if err != nil { return err @@ -402,6 +411,7 @@ func relayerConfigureHandler(cmd *cobra.Command, args []string) (err error) { targetGasPrice, targetGasLimit, targetAddressPrefix, + targetClientID, ) if err != nil { return err @@ -425,7 +435,7 @@ func relayerConfigureHandler(cmd *cobra.Command, args []string) (err error) { } // create the connection configuration - id, err := sourceChain.Connect(cmd.Context(), targetChain, channelOptions...) + id, err := sourceChain.Connect(targetChain, channelOptions...) if err != nil { return err } @@ -447,7 +457,8 @@ func initChain( faucetAddr, gasPrice string, gasLimit int64, - addressPrefix string, + addressPrefix, + clientID string, ) (*relayer.Chain, error) { defer session.StopSpinner() session.StartSpinner("Initializing chain...") @@ -460,6 +471,7 @@ func initChain( relayer.WithGasPrice(gasPrice), relayer.WithGasLimit(gasLimit), relayer.WithAddressPrefix(addressPrefix), + relayer.WithClientID(clientID), ) if err != nil { return nil, errors.Wrapf(err, "cannot resolve %s", name) diff --git a/ignite/cmd/scaffold.go b/ignite/cmd/scaffold.go index 95b8c6598a..465ac7d31f 100644 --- a/ignite/cmd/scaffold.go +++ b/ignite/cmd/scaffold.go @@ -94,7 +94,12 @@ func scaffoldType( return err } - sm, err := sc.AddType(cmd.Context(), typeName, placeholder.New(), kind, options...) + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + sm, err := sc.AddType(cmd.Context(), cacheStorage, typeName, placeholder.New(), kind, options...) if err != nil { return err } diff --git a/ignite/cmd/scaffold_band.go b/ignite/cmd/scaffold_band.go index 6b9c0d732c..1b58505b7d 100644 --- a/ignite/cmd/scaffold_band.go +++ b/ignite/cmd/scaffold_band.go @@ -22,6 +22,7 @@ func NewScaffoldBandchain() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().String(flagModule, "", "IBC Module to add the packet into") c.Flags().String(flagSigner, "", "Label for the message signer (default: creator)") @@ -46,6 +47,11 @@ func createBandchainHandler(cmd *cobra.Command, args []string) error { return errors.New("please specify a module to create the BandChain oracle into: --module ") } + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + var options []scaffolder.OracleOption if signer != "" { options = append(options, scaffolder.OracleWithSigner(signer)) @@ -56,7 +62,7 @@ func createBandchainHandler(cmd *cobra.Command, args []string) error { return err } - sm, err := sc.AddOracle(placeholder.New(), module, oracle, options...) + sm, err := sc.AddOracle(cacheStorage, placeholder.New(), module, oracle, options...) if err != nil { return err } diff --git a/ignite/cmd/scaffold_chain.go b/ignite/cmd/scaffold_chain.go index 14838075ab..0d7b4da7cd 100644 --- a/ignite/cmd/scaffold_chain.go +++ b/ignite/cmd/scaffold_chain.go @@ -17,16 +17,40 @@ const ( // NewScaffoldChain creates new command to scaffold a Comos-SDK based blockchain. func NewScaffoldChain() *cobra.Command { c := &cobra.Command{ - Use: "chain [github.com/org/repo]", + Use: "chain [name]", Short: "Fully-featured Cosmos SDK blockchain", - Long: "Scaffold a new Cosmos SDK blockchain with a default directory structure", - Args: cobra.ExactArgs(1), - RunE: scaffoldChainHandler, + Long: `Create a new application-specific Cosmos SDK blockchain. + +For example, the following command will create a blockchain called "hello" in the "hello/" directory: + + ignite scaffold chain hello + +A project name can be a simple name or a URL. The name will be used as the Go module path for the project. Examples of project names: + + ignite scaffold chain foo + ignite scaffold chain foo/bar + ignite scaffold chain example.org/foo + ignite scaffold chain github.com/username/foo + +A new directory with source code files will be created in the current directory. To use a different path use the "--path" flag. + +Most of the logic of your blockchain is written in custom modules. Each module effectively encapsulates an independent piece of functionality. Following the Cosmos SDK convention, custom modules are stored inside the "x/" directory. By default, Ignite creates a module with a name that matches the name of the project. To create a blockchain without a default module use the "--no-module" flag. Additional modules can be added after a project is created with "ignite scaffold module" command. + +Account addresses on Cosmos SDK-based blockchains have string prefixes. For example, the Cosmos Hub blockchain uses the default "cosmos" prefix, so that addresses look like this: "cosmos12fjzdtqfrrve7zyg9sv8j25azw2ua6tvu07ypf". To use a custom address prefix use the "--address-prefix" flag. For example: + + ignite scaffold chain foo --address-prefix bar + +By default when compiling a blockchain's source code Ignite creates a cache to speed up the build process. To clear the cache when building a blockchain use the "--clear-cache" flag. It is very unlikely you will ever need to use this flag. + +The blockchain is using the Cosmos SDK modular blockchain framework. Learn more about Cosmos SDK on https://docs.cosmos.network`, + Args: cobra.ExactArgs(1), + RunE: scaffoldChainHandler, } - c.Flags().StringP(flagPath, "p", ".", "path to scaffold the chain") - c.Flags().String(flagAddressPrefix, "cosmos", "Address prefix") - c.Flags().Bool(flagNoDefaultModule, false, "Prevent scaffolding a default module in the app") + flagSetClearCache(c) + c.Flags().AddFlagSet(flagSetAccountPrefixes()) + c.Flags().StringP(flagPath, "p", ".", "Create a project in a specific path") + c.Flags().Bool(flagNoDefaultModule, false, "Create a project without a default module") return c } @@ -37,12 +61,17 @@ func scaffoldChainHandler(cmd *cobra.Command, args []string) error { var ( name = args[0] - addressPrefix, _ = cmd.Flags().GetString(flagAddressPrefix) - noDefaultModule, _ = cmd.Flags().GetBool(flagNoDefaultModule) + addressPrefix = getAddressPrefix(cmd) appPath = flagGetPath(cmd) + noDefaultModule, _ = cmd.Flags().GetBool(flagNoDefaultModule) ) - appdir, err := scaffolder.Init(placeholder.New(), appPath, name, addressPrefix, noDefaultModule) + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + + appdir, err := scaffolder.Init(cacheStorage, placeholder.New(), appPath, name, addressPrefix, noDefaultModule) if err != nil { return err } diff --git a/ignite/cmd/scaffold_list.go b/ignite/cmd/scaffold_list.go index f1bd354dc3..84df13a324 100644 --- a/ignite/cmd/scaffold_list.go +++ b/ignite/cmd/scaffold_list.go @@ -16,6 +16,7 @@ func NewScaffoldList() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().AddFlagSet(flagSetScaffoldType()) return c diff --git a/ignite/cmd/scaffold_map.go b/ignite/cmd/scaffold_map.go index e3e7de7faa..af0a6d8ec0 100644 --- a/ignite/cmd/scaffold_map.go +++ b/ignite/cmd/scaffold_map.go @@ -20,6 +20,7 @@ func NewScaffoldMap() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().AddFlagSet(flagSetScaffoldType()) c.Flags().StringSlice(FlagIndexes, []string{"index"}, "fields that index the value") diff --git a/ignite/cmd/scaffold_message.go b/ignite/cmd/scaffold_message.go index 9bbc2d4ad7..42a9521248 100644 --- a/ignite/cmd/scaffold_message.go +++ b/ignite/cmd/scaffold_message.go @@ -22,6 +22,7 @@ func NewScaffoldMessage() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().String(flagModule, "", "Module to add the message into. Default: app's main module") c.Flags().StringSliceP(flagResponse, "r", []string{}, "Response fields") c.Flags().Bool(flagNoSimulation, false, "Disable CRUD simulation scaffolding") @@ -44,6 +45,11 @@ func messageHandler(cmd *cobra.Command, args []string) error { s := clispinner.New().SetText("Scaffolding...") defer s.Stop() + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + var options []scaffolder.MessageOption // Get description @@ -66,7 +72,7 @@ func messageHandler(cmd *cobra.Command, args []string) error { return err } - sm, err := sc.AddMessage(cmd.Context(), placeholder.New(), module, args[0], args[1:], resFields, options...) + sm, err := sc.AddMessage(cmd.Context(), cacheStorage, placeholder.New(), module, args[0], args[1:], resFields, options...) if err != nil { return err } diff --git a/ignite/cmd/scaffold_module.go b/ignite/cmd/scaffold_module.go index 0be64e7942..77807d40fb 100644 --- a/ignite/cmd/scaffold_module.go +++ b/ignite/cmd/scaffold_module.go @@ -35,6 +35,7 @@ func NewScaffoldModule() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().StringSlice(flagDep, []string{}, "module dependencies (e.g. --dep account,bank)") c.Flags().Bool(flagIBC, false, "scaffold an IBC module") c.Flags().String(flagIBCOrdering, "none", "channel ordering of the IBC module [none|ordered|unordered]") @@ -71,6 +72,11 @@ func scaffoldModuleHandler(cmd *cobra.Command, args []string) error { return err } + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + options := []scaffolder.ModuleCreationOption{ scaffolder.WithParams(params), } @@ -114,7 +120,7 @@ func scaffoldModuleHandler(cmd *cobra.Command, args []string) error { return err } - sm, err := sc.CreateModule(placeholder.New(), name, options...) + sm, err := sc.CreateModule(cacheStorage, placeholder.New(), name, options...) s.Stop() if err != nil { var validationErr validation.Error diff --git a/ignite/cmd/scaffold_mwasm.go b/ignite/cmd/scaffold_mwasm.go index 7ecec30ea7..7be4d92490 100644 --- a/ignite/cmd/scaffold_mwasm.go +++ b/ignite/cmd/scaffold_mwasm.go @@ -29,12 +29,17 @@ func scaffoldWasmHandler(cmd *cobra.Command, args []string) error { s := clispinner.New().SetText("Scaffolding...") defer s.Stop() + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + sc, err := newApp(appPath) if err != nil { return err } - sm, err := sc.ImportModule(placeholder.New(), "wasm") + sm, err := sc.ImportModule(cacheStorage, placeholder.New(), "wasm") if err != nil { return err } diff --git a/ignite/cmd/scaffold_package.go b/ignite/cmd/scaffold_package.go index 1d94f3c208..03ad79991b 100644 --- a/ignite/cmd/scaffold_package.go +++ b/ignite/cmd/scaffold_package.go @@ -26,6 +26,7 @@ func NewScaffoldPacket() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().StringSlice(flagAck, []string{}, "Custom acknowledgment type (field1,field2,...)") c.Flags().String(flagModule, "", "IBC Module to add the packet into") c.Flags().String(flagSigner, "", "Label for the message signer (default: creator)") @@ -63,6 +64,11 @@ func createPacketHandler(cmd *cobra.Command, args []string) error { return err } + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + var options []scaffolder.PacketOption if noMessage { options = append(options, scaffolder.PacketWithoutMessage()) @@ -75,7 +81,7 @@ func createPacketHandler(cmd *cobra.Command, args []string) error { return err } - sm, err := sc.AddPacket(cmd.Context(), placeholder.New(), module, packet, packetFields, ackFields, options...) + sm, err := sc.AddPacket(cmd.Context(), cacheStorage, placeholder.New(), module, packet, packetFields, ackFields, options...) if err != nil { return err } diff --git a/ignite/cmd/scaffold_query.go b/ignite/cmd/scaffold_query.go index 09e81684bb..a752a8fe11 100644 --- a/ignite/cmd/scaffold_query.go +++ b/ignite/cmd/scaffold_query.go @@ -23,6 +23,7 @@ func NewScaffoldQuery() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().String(flagModule, "", "Module to add the query into. Default: app's main module") c.Flags().StringSliceP(flagResponse, "r", []string{}, "Response fields") c.Flags().StringP(flagDescription, "d", "", "Description of the command") @@ -64,12 +65,17 @@ func queryHandler(cmd *cobra.Command, args []string) error { return err } + cacheStorage, err := newCache(cmd) + if err != nil { + return err + } + sc, err := newApp(appPath) if err != nil { return err } - sm, err := sc.AddQuery(cmd.Context(), placeholder.New(), module, args[0], desc, args[1:], resFields, paginated) + sm, err := sc.AddQuery(cmd.Context(), cacheStorage, placeholder.New(), module, args[0], desc, args[1:], resFields, paginated) if err != nil { return err } diff --git a/ignite/cmd/scaffold_single.go b/ignite/cmd/scaffold_single.go index a42cbb785e..2e93b1718d 100644 --- a/ignite/cmd/scaffold_single.go +++ b/ignite/cmd/scaffold_single.go @@ -16,6 +16,7 @@ func NewScaffoldSingle() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().AddFlagSet(flagSetScaffoldType()) return c diff --git a/ignite/cmd/scaffold_type.go b/ignite/cmd/scaffold_type.go index 8d0d0a5d79..d060fd740b 100644 --- a/ignite/cmd/scaffold_type.go +++ b/ignite/cmd/scaffold_type.go @@ -16,6 +16,7 @@ func NewScaffoldType() *cobra.Command { } flagSetPath(c) + flagSetClearCache(c) c.Flags().AddFlagSet(flagSetScaffoldType()) return c diff --git a/ignite/pkg/cache/cache.go b/ignite/pkg/cache/cache.go new file mode 100644 index 0000000000..f83f7bd379 --- /dev/null +++ b/ignite/pkg/cache/cache.go @@ -0,0 +1,149 @@ +package cache + +import ( + "bytes" + "encoding/gob" + "errors" + "os" + "path/filepath" + "strings" + "time" + + bolt "go.etcd.io/bbolt" +) + +var ErrorNotFound = errors.New("no value was found with the provided key") + +// Storage is meant to be passed around and used by the New function (which provides namespacing and type-safety) +type Storage struct { + storagePath string +} + +// Cache is a namespaced and type-safe key-value store +type Cache[T any] struct { + storage Storage + namespace string +} + +// NewStorage sets up the storage needed for later cache usage +// path is the full path (including filename) to the database file to ues +// It does not need to be closed as this happens automatically in each call to the cache +func NewStorage(path string) (Storage, error) { + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return Storage{}, err + } + + return Storage{path}, nil +} + +// New creates a namespaced and typesafe key-value Cache +func New[T any](storage Storage, namespace string) Cache[T] { + return Cache[T]{ + storage: storage, + namespace: namespace, + } +} + +// Key creates a single composite key from a list of keyParts +func Key(keyParts ...string) string { + return strings.Join(keyParts, "") +} + +// Clear deletes all namespaces and cached values +func (s Storage) Clear() error { + db, err := openDb(s.storagePath) + if err != nil { + return err + } + defer db.Close() + + return db.Update(func(tx *bolt.Tx) error { + return tx.ForEach(func(name []byte, _ *bolt.Bucket) error { + return tx.DeleteBucket(name) + }) + }) +} + +// Put sets key to value within the namespace +// If the key already exists, it will be overwritten +func (c Cache[T]) Put(key string, value T) error { + db, err := openDb(c.storage.storagePath) + if err != nil { + return err + } + defer db.Close() + + var buf bytes.Buffer + encoder := gob.NewEncoder(&buf) + if err := encoder.Encode(value); err != nil { + return err + } + result := buf.Bytes() + + return db.Update(func(tx *bolt.Tx) error { + b, err := tx.CreateBucketIfNotExists([]byte(c.namespace)) + if err != nil { + return err + } + return b.Put([]byte(key), result) + }) +} + +// Get fetches the value of key within the namespace. +// If no value exists, it will return found == false +func (c Cache[T]) Get(key string) (val T, err error) { + db, err := openDb(c.storage.storagePath) + if err != nil { + return + } + defer db.Close() + + err = db.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(c.namespace)) + if b == nil { + return ErrorNotFound + } + c := b.Cursor() + if k, v := c.Seek([]byte(key)); bytes.Equal(k, []byte(key)) { + if v == nil { + return ErrorNotFound + } + + var decodedVal T + d := gob.NewDecoder(bytes.NewReader(v)) + if err := d.Decode(&decodedVal); err != nil { + return err + } + + val = decodedVal + } else { + return ErrorNotFound + } + + return nil + }) + + return val, err +} + +// Delete removes a value for key within the namespace +func (c Cache[T]) Delete(key string) error { + db, err := openDb(c.storage.storagePath) + if err != nil { + return err + } + defer db.Close() + + return db.Update(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(c.namespace)) + if b == nil { + return nil + } + + return b.Delete([]byte(key)) + }) +} + +func openDb(path string) (*bolt.DB, error) { + return bolt.Open(path, 0640, &bolt.Options{Timeout: 1 * time.Minute}) +} diff --git a/ignite/pkg/cache/cache_test.go b/ignite/pkg/cache/cache_test.go new file mode 100644 index 0000000000..e97563faa1 --- /dev/null +++ b/ignite/pkg/cache/cache_test.go @@ -0,0 +1,170 @@ +package cache_test + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ignite-hq/cli/ignite/pkg/cache" +) + +type TestStruct struct { + Num int +} + +func TestCreateStorage(t *testing.T) { + tmpDir1 := t.TempDir() + tmpDir2 := t.TempDir() + + _, err := cache.NewStorage(filepath.Join(tmpDir1, "test.db")) + require.NoError(t, err) + + _, err = cache.NewStorage(filepath.Join(tmpDir2, "test.db")) + require.NoError(t, err) +} + +func TestStoreString(t *testing.T) { + tmpDir := t.TempDir() + cacheStorage, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) + require.NoError(t, err) + + strNamespace := cache.New[string](cacheStorage, "myNameSpace") + + err = strNamespace.Put("myKey", "myValue") + require.NoError(t, err) + + val, err := strNamespace.Get("myKey") + require.NoError(t, err) + require.Equal(t, "myValue", val) + + strNamespaceAgain := cache.New[string](cacheStorage, "myNameSpace") + + valAgain, err := strNamespaceAgain.Get("myKey") + require.NoError(t, err) + require.Equal(t, "myValue", valAgain) +} + +func TestStoreObjects(t *testing.T) { + tmpDir := t.TempDir() + cacheStorage, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) + require.NoError(t, err) + + structCache := cache.New[TestStruct](cacheStorage, "mySimpleNamespace") + + err = structCache.Put("myKey", TestStruct{ + Num: 42, + }) + require.NoError(t, err) + + val, err := structCache.Get("myKey") + require.NoError(t, err) + require.Equal(t, val, TestStruct{ + Num: 42, + }) + + arrayNamespace := cache.New[[]TestStruct](cacheStorage, "myArrayNamespace") + + err = arrayNamespace.Put("myKey", []TestStruct{ + { + Num: 42, + }, + { + Num: 420, + }, + }) + require.NoError(t, err) + + val2, err := arrayNamespace.Get("myKey") + require.NoError(t, err) + require.Equal(t, 2, len(val2)) + require.Equal(t, 42, (val2)[0].Num) + require.Equal(t, 420, (val2)[1].Num) + + empty, err := arrayNamespace.Get("doesNotExists") + require.Equal(t, cache.ErrorNotFound, err) + require.Nil(t, empty) +} + +func TestConflicts(t *testing.T) { + tmpDir := t.TempDir() + tmpDir2 := t.TempDir() + cacheStorage1, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) + require.NoError(t, err) + cacheStorage2, err := cache.NewStorage(filepath.Join(tmpDir2, "testdbfile.db")) + require.NoError(t, err) + + sameStorageDifferentNamespaceCache1 := cache.New[int](cacheStorage1, "ns1") + + sameStorageDifferentNamespaceCache2 := cache.New[int](cacheStorage1, "ns2") + + differentStorageSameNamespace := cache.New[int](cacheStorage2, "ns1") + + // Put values in caches + err = sameStorageDifferentNamespaceCache1.Put("myKey", 41) + require.NoError(t, err) + + err = sameStorageDifferentNamespaceCache2.Put("myKey", 1337) + require.NoError(t, err) + + err = differentStorageSameNamespace.Put("myKey", 9001) + require.NoError(t, err) + + // Overwrite a value + err = sameStorageDifferentNamespaceCache1.Put("myKey", 42) + require.NoError(t, err) + + // Check that everything comes back as expected + val1, err := sameStorageDifferentNamespaceCache1.Get("myKey") + require.NoError(t, err) + require.Equal(t, 42, val1) + + val2, err := sameStorageDifferentNamespaceCache2.Get("myKey") + require.NoError(t, err) + require.Equal(t, 1337, val2) + + val3, err := differentStorageSameNamespace.Get("myKey") + require.NoError(t, err) + require.Equal(t, 9001, val3) +} + +func TestDeleteKey(t *testing.T) { + tmpDir := t.TempDir() + cacheStorage, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) + require.NoError(t, err) + + strNamespace := cache.New[string](cacheStorage, "myNameSpace") + err = strNamespace.Put("myKey", "someValue") + require.NoError(t, err) + + err = strNamespace.Delete("myKey") + require.NoError(t, err) + + _, err = strNamespace.Get("myKey") + require.Equal(t, cache.ErrorNotFound, err) +} + +func TestClearStorage(t *testing.T) { + tmpDir := t.TempDir() + cacheStorage, err := cache.NewStorage(filepath.Join(tmpDir, "testdbfile.db")) + require.NoError(t, err) + + strNamespace := cache.New[string](cacheStorage, "myNameSpace") + + err = strNamespace.Put("myKey", "myValue") + require.NoError(t, err) + + err = cacheStorage.Clear() + require.NoError(t, err) + + _, err = strNamespace.Get("myKey") + require.Equal(t, cache.ErrorNotFound, err) +} + +func TestKey(t *testing.T) { + singleKey := cache.Key("test1") + require.Equal(t, "test1", singleKey) + + multiKey := cache.Key("test1", "test2", "test3") + require.Equal(t, "test1test2test3", multiKey) +} diff --git a/ignite/pkg/chaincmd/runner/chain.go b/ignite/pkg/chaincmd/runner/chain.go index 72e0e0dc50..270279bafa 100644 --- a/ignite/pkg/chaincmd/runner/chain.go +++ b/ignite/pkg/chaincmd/runner/chain.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "regexp" "strings" "time" @@ -236,6 +237,12 @@ func (r Runner) WaitTx(ctx context.Context, txHash string, retryDelay time.Durat // Export exports the state of the chain into the specified file func (r Runner) Export(ctx context.Context, exportedFile string) error { + // Make sure the path exists + dir := filepath.Dir(exportedFile) + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{} if err := r.run(ctx, runOptions{stdout: stdout, stderr: stderr}, r.chainCmd.ExportCommand()); err != nil { return err diff --git a/ignite/pkg/cosmosanalysis/app/app_test.go b/ignite/pkg/cosmosanalysis/app/app_test.go index 75d0dfe8b2..e24b2466cc 100644 --- a/ignite/pkg/cosmosanalysis/app/app_test.go +++ b/ignite/pkg/cosmosanalysis/app/app_test.go @@ -144,16 +144,16 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v2/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v2/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v2/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v2/modules/core" - ibcclient "github.com/cosmos/ibc-go/v2/modules/core/02-client" - ibcclientclient "github.com/cosmos/ibc-go/v2/modules/core/02-client/client" - ibcclienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" - ibcporttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v2/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v2/modules/core/keeper" + "github.com/cosmos/ibc-go/v3/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v3/modules/core" + ibcclient "github.com/cosmos/ibc-go/v3/modules/core/02-client" + ibcclientclient "github.com/cosmos/ibc-go/v3/modules/core/02-client/client" + ibcclienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + ibcporttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" "github.com/spf13/cast" abci "github.com/tendermint/tendermint/abci/types" tmjson "github.com/tendermint/tendermint/libs/json" @@ -289,10 +289,10 @@ func TestGetRegisteredModules(t *testing.T) { "github.com/cosmos/cosmos-sdk/x/crisis", "github.com/cosmos/cosmos-sdk/x/slashing", "github.com/cosmos/cosmos-sdk/x/feegrant/module", - "github.com/cosmos/ibc-go/v2/modules/core", + "github.com/cosmos/ibc-go/v3/modules/core", "github.com/cosmos/cosmos-sdk/x/upgrade", "github.com/cosmos/cosmos-sdk/x/evidence", - "github.com/cosmos/ibc-go/v2/modules/apps/transfer", + "github.com/cosmos/ibc-go/v3/modules/apps/transfer", "github.com/cosmos/cosmos-sdk/x/auth/vesting", "github.com/tendermint/testchain/x/testchain", "github.com/tendermint/testchain/x/queryonlymod", diff --git a/ignite/pkg/cosmosclient/cosmosclient.go b/ignite/pkg/cosmosclient/cosmosclient.go index 2c7bb314db..4c32f26bf5 100644 --- a/ignite/pkg/cosmosclient/cosmosclient.go +++ b/ignite/pkg/cosmosclient/cosmosclient.go @@ -27,7 +27,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" staking "github.com/cosmos/cosmos-sdk/x/staking/types" - commitmenttypes "github.com/cosmos/ibc-go/v2/modules/core/23-commitment/types" + commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" "github.com/gogo/protobuf/proto" prototypes "github.com/gogo/protobuf/types" "github.com/pkg/errors" diff --git a/ignite/pkg/cosmosgen/cosmosgen.go b/ignite/pkg/cosmosgen/cosmosgen.go index 3abbf6188d..0437d7b140 100644 --- a/ignite/pkg/cosmosgen/cosmosgen.go +++ b/ignite/pkg/cosmosgen/cosmosgen.go @@ -6,6 +6,7 @@ import ( gomodmodule "golang.org/x/mod/module" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cosmosanalysis/module" "github.com/ignite-hq/cli/ignite/pkg/gomodulepath" ) @@ -89,6 +90,7 @@ func IncludeDirs(dirs []string) Option { // generator generates code for sdk and sdk apps. type generator struct { ctx context.Context + cacheStorage cache.Storage appPath string protoDir string o *generateOptions @@ -100,13 +102,14 @@ type generator struct { // Generate generates code from protoDir of an SDK app residing at appPath with given options. // protoDir must be relative to the projectPath. -func Generate(ctx context.Context, appPath, protoDir string, options ...Option) error { +func Generate(ctx context.Context, cacheStorage cache.Storage, appPath, protoDir string, options ...Option) error { g := &generator{ ctx: ctx, appPath: appPath, protoDir: protoDir, o: &generateOptions{}, thirdModules: make(map[string][]module.Module), + cacheStorage: cacheStorage, } for _, apply := range options { diff --git a/ignite/pkg/cosmosgen/generate.go b/ignite/pkg/cosmosgen/generate.go index 2a501b2280..1153a1107e 100644 --- a/ignite/pkg/cosmosgen/generate.go +++ b/ignite/pkg/cosmosgen/generate.go @@ -4,6 +4,7 @@ import ( "path/filepath" "strings" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner/step" "github.com/ignite-hq/cli/ignite/pkg/cosmosanalysis/module" @@ -11,7 +12,15 @@ import ( "github.com/ignite-hq/cli/ignite/pkg/protopath" ) -const defaultSdkImport = "github.com/cosmos/cosmos-sdk" +const ( + defaultSdkImport = "github.com/cosmos/cosmos-sdk" + moduleCacheNamespace = "generate.setup.module" +) + +type ModulesInPath struct { + Path string + Modules []module.Module +} func (g *generator) setup() (err error) { // Cosmos SDK hosts proto files of own x/ modules and some third party ones needed by itself and @@ -67,16 +76,34 @@ func (g *generator) setup() (err error) { // // TODO(ilgooz): we can still implement some sort of smart filtering to detect non used modules by the user's blockchain // at some point, it is a nice to have. + moduleCache := cache.New[ModulesInPath](g.cacheStorage, moduleCacheNamespace) for _, dep := range g.deps { - path, err := gomodule.LocatePath(g.ctx, g.appPath, dep) - if err != nil { + cacheKey := cache.Key(dep.Path, dep.Version) + modulesInPath, err := moduleCache.Get(cacheKey) + if err != nil && err != cache.ErrorNotFound { return err } - modules, err := g.discoverModules(path, "") - if err != nil { - return err + + if err == cache.ErrorNotFound { + path, err := gomodule.LocatePath(g.ctx, g.cacheStorage, g.appPath, dep) + if err != nil { + return err + } + modules, err := g.discoverModules(path, "") + if err != nil { + return err + } + + modulesInPath = ModulesInPath{ + Path: path, + Modules: modules, + } + if err := moduleCache.Put(cacheKey, modulesInPath); err != nil { + return err + } } - g.thirdModules[path] = append(g.thirdModules[path], modules...) + + g.thirdModules[modulesInPath.Path] = append(g.thirdModules[modulesInPath.Path], modulesInPath.Modules...) } return nil @@ -88,7 +115,7 @@ func (g *generator) resolveInclude(path string) (paths []string, err error) { paths = append(paths, filepath.Join(path, p)) } - includePaths, err := protopath.ResolveDependencyPaths(g.ctx, g.appPath, g.deps, + includePaths, err := protopath.ResolveDependencyPaths(g.ctx, g.cacheStorage, g.appPath, g.deps, protopath.NewModule(g.sdkImport, append([]string{g.protoDir}, g.o.includeDirs...)...)) if err != nil { return nil, err diff --git a/ignite/pkg/cosmosgen/generate_javascript.go b/ignite/pkg/cosmosgen/generate_javascript.go index 4cb7fbf851..a024a52c01 100644 --- a/ignite/pkg/cosmosgen/generate_javascript.go +++ b/ignite/pkg/cosmosgen/generate_javascript.go @@ -10,7 +10,9 @@ import ( "github.com/iancoleman/strcase" "golang.org/x/sync/errgroup" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cosmosanalysis/module" + "github.com/ignite-hq/cli/ignite/pkg/dirchange" "github.com/ignite-hq/cli/ignite/pkg/gomodulepath" "github.com/ignite-hq/cli/ignite/pkg/localfs" "github.com/ignite-hq/cli/ignite/pkg/nodetime/programs/sta" @@ -29,7 +31,10 @@ var ( } ) -const vuexRootMarker = "vuex-root" +const ( + vuexRootMarker = "vuex-root" + dirchangeCacheNamespace = "generate.javascript.dirchange" +) type jsGenerator struct { g *generator @@ -60,10 +65,28 @@ func (g *jsGenerator) generateModules() error { gg := &errgroup.Group{} + dirCache := cache.New[[]byte](g.g.cacheStorage, dirchangeCacheNamespace) add := func(sourcePath string, modules []module.Module) { for _, m := range modules { m := m - gg.Go(func() error { return g.generateModule(g.g.ctx, tsprotoPluginPath, sourcePath, m) }) + gg.Go(func() error { + cacheKey := m.Pkg.Path + paths := append([]string{m.Pkg.Path, g.g.o.jsOut(m)}, g.g.o.includeDirs...) + changed, err := dirchange.HasDirChecksumChanged(dirCache, cacheKey, sourcePath, paths...) + if err != nil { + return err + } + + if !changed { + return nil + } + + if err := g.generateModule(g.g.ctx, tsprotoPluginPath, sourcePath, m); err != nil { + return err + } + + return dirchange.SaveDirChecksum(dirCache, cacheKey, sourcePath, paths...) + }) } } @@ -103,6 +126,7 @@ func (g *jsGenerator) generateModule(ctx context.Context, tsprotoPluginPath, app includePaths, tsOut, protoc.Plugin(tsprotoPluginPath, "--ts_proto_opt=snakeToCamel=false"), + protoc.Env("NODE_OPTIONS="), // unset nodejs options to avoid unexpected issues with vercel "pkg" ) if err != nil { return err diff --git a/ignite/pkg/cosmosgen/generate_openapi.go b/ignite/pkg/cosmosgen/generate_openapi.go index 355a10c811..f7cd99ed7e 100644 --- a/ignite/pkg/cosmosgen/generate_openapi.go +++ b/ignite/pkg/cosmosgen/generate_openapi.go @@ -1,13 +1,16 @@ package cosmosgen import ( + "fmt" "os" "path/filepath" "sort" "github.com/iancoleman/strcase" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cosmosanalysis/module" + "github.com/ignite-hq/cli/ignite/pkg/dirchange" swaggercombine "github.com/ignite-hq/cli/ignite/pkg/nodetime/programs/swagger-combine" "github.com/ignite-hq/cli/ignite/pkg/protoc" ) @@ -16,6 +19,8 @@ var openAPIOut = []string{ "--openapiv2_out=logtostderr=true,allow_merge=true,json_names_for_fields=false,fqn_for_openapi_name=true,simple_operation_ids=true,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types:.", } +const specCacheNamespace = "generate.openapi.spec" + func generateOpenAPISpec(g *generator) error { out := filepath.Join(g.appPath, g.o.specOut) @@ -35,33 +40,63 @@ func generateOpenAPISpec(g *generator) error { } }() + specCache := cache.New[[]byte](g.cacheStorage, specCacheNamespace) + + var hasAnySpecChanged bool + // gen generates a spec for a module where it's source code resides at src. // and adds needed swaggercombine configure for it. gen := func(src string, m module.Module) (err error) { - include, err := g.resolveInclude(src) + dir, err := os.MkdirTemp("", "gen-openapi-module-spec") if err != nil { return err } + specPath := filepath.Join(dir, "apidocs.swagger.json") - dir, err := os.MkdirTemp("", "gen-openapi-module-spec") + checksumPaths := append([]string{m.Pkg.Path}, g.o.includeDirs...) + checksum, err := dirchange.ChecksumFromPaths(src, checksumPaths...) if err != nil { return err } - - err = protoc.Generate( - g.ctx, - dir, - m.Pkg.Path, - include, - openAPIOut, - ) - if err != nil { + cacheKey := fmt.Sprintf("%x", checksum) + existingSpec, err := specCache.Get(cacheKey) + if err != nil && err != cache.ErrorNotFound { return err } + if err != cache.ErrorNotFound { + if err := os.WriteFile(specPath, existingSpec, 0644); err != nil { + return err + } + } else { + hasAnySpecChanged = true + include, err := g.resolveInclude(src) + if err != nil { + return err + } + + err = protoc.Generate( + g.ctx, + dir, + m.Pkg.Path, + include, + openAPIOut, + ) + if err != nil { + return err + } + + f, err := os.ReadFile(specPath) + if err != nil { + return err + } + if err := specCache.Put(cacheKey, f); err != nil { + return err + } + } + specDirs = append(specDirs, dir) - specPath := filepath.Join(dir, "apidocs.swagger.json") return conf.AddSpec(strcase.ToCamel(m.Pkg.Name), specPath) } @@ -90,6 +125,18 @@ func generateOpenAPISpec(g *generator) error { } } + if !hasAnySpecChanged { + // In case the generated output has been changed + changed, err := dirchange.HasDirChecksumChanged(specCache, out, g.appPath, out) + if err != nil { + return err + } + + if !changed { + return nil + } + } + sort.Slice(conf.APIs, func(a, b int) bool { return conf.APIs[a].ID < conf.APIs[b].ID }) // ensure out dir exists. @@ -99,5 +146,9 @@ func generateOpenAPISpec(g *generator) error { } // combine specs into one and save to out. - return swaggercombine.Combine(g.ctx, conf, out) + if err := swaggercombine.Combine(g.ctx, conf, out); err != nil { + return err + } + + return dirchange.SaveDirChecksum(specCache, out, g.appPath, out) } diff --git a/ignite/pkg/cosmosibckeeper/expected_keeper.go b/ignite/pkg/cosmosibckeeper/expected_keeper.go index f790c12b7d..f794b6a6c1 100644 --- a/ignite/pkg/cosmosibckeeper/expected_keeper.go +++ b/ignite/pkg/cosmosibckeeper/expected_keeper.go @@ -3,8 +3,8 @@ package cosmosibckeeper import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" ) // ChannelKeeper defines the expected IBC channel keeper diff --git a/ignite/pkg/cosmosibckeeper/keeper.go b/ignite/pkg/cosmosibckeeper/keeper.go index b23185d70f..254e0e56fc 100644 --- a/ignite/pkg/cosmosibckeeper/keeper.go +++ b/ignite/pkg/cosmosibckeeper/keeper.go @@ -4,8 +4,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" ) // Keeper defines the IBC Keeper diff --git a/ignite/pkg/cosmosutil/coins.go b/ignite/pkg/cosmosutil/coins.go deleted file mode 100644 index eaa448ec2c..0000000000 --- a/ignite/pkg/cosmosutil/coins.go +++ /dev/null @@ -1,27 +0,0 @@ -package cosmosutil - -import ( - "fmt" - "regexp" - "strings" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var rePercentageRequired = regexp.MustCompile(`^[0-9]+%`) - -// ParseCoinsNormalizedWithPercentageRequired parses coins by requiring percentages. -// format: 20%foo,50%staking -func ParseCoinsNormalizedWithPercentageRequired(coins string) (sdk.Coins, error) { - trimPercentage := func(s string) string { - return strings.ReplaceAll(s, "%", "") - } - - s := strings.Split(coins, ",") - for _, ss := range s { - if len(rePercentageRequired.FindStringIndex(ss)) == 0 { - return nil, fmt.Errorf("amount for %s has to have a %% after the number", trimPercentage(ss)) - } - } - return sdk.ParseCoinsNormalized(trimPercentage(coins)) -} diff --git a/ignite/pkg/cosmosutil/coins_test.go b/ignite/pkg/cosmosutil/coins_test.go deleted file mode 100644 index c311702107..0000000000 --- a/ignite/pkg/cosmosutil/coins_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package cosmosutil_test - -import ( - "errors" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" - - "github.com/ignite-hq/cli/ignite/pkg/cosmosutil" -) - -func TestValidateCoinsStrWithPercentage(t *testing.T) { - tests := []struct { - name string - coins string - parsed sdk.Coins - err error - }{ - { - "format is OK", - "20%foo,50%staking", - sdk.NewCoins(sdk.NewInt64Coin("foo", 20), sdk.NewInt64Coin("staking", 50)), - nil, - }, - { - "wrong format", - "20nova,50baz", - sdk.NewCoins(sdk.NewInt64Coin("nova", 20), sdk.NewInt64Coin("baz", 50)), - errors.New("amount for 20nova has to have a % after the number"), - }, - { - "wrong format with percentage in the beginning", - "%20nova", - sdk.NewCoins(sdk.NewInt64Coin("nova", 20)), - errors.New("amount for 20nova has to have a % after the number"), - }, - { - "wrong format with multiple percentages", - "%20%nova", - sdk.NewCoins(sdk.NewInt64Coin("nova", 20)), - errors.New("amount for 20nova has to have a % after the number"), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - coins, err := cosmosutil.ParseCoinsNormalizedWithPercentageRequired(tt.coins) - if tt.err != nil { - require.EqualError(t, err, tt.err.Error()) - } else { - require.NoError(t, err) - require.Equal(t, tt.parsed, coins) - } - }) - } -} diff --git a/ignite/pkg/cosmosutil/genesis.go b/ignite/pkg/cosmosutil/genesis.go index 3c82ae1903..20c88bf54a 100644 --- a/ignite/pkg/cosmosutil/genesis.go +++ b/ignite/pkg/cosmosutil/genesis.go @@ -6,17 +6,28 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + "fmt" "io" "net/http" "os" + "strconv" + "strings" "time" + "github.com/buger/jsonparser" "github.com/pkg/errors" ) const ( - genesisTimeField = "genesis_time" - chainIDField = "chain_id" + FieldGenesisTime = "genesis_time" + FieldChainID = "chain_id" + FieldConsumerChainID = "app_state.monitoringp.params.consumerChainID" + FieldLastBlockHeight = "app_state.monitoringp.params.lastBlockHeight" + FieldConsensusTimestamp = "app_state.monitoringp.params.consumerConsensusState.timestamp" + FieldConsensusNextValidatorsHash = "app_state.monitoringp.params.consumerConsensusState.nextValidatorsHash" + FieldConsensusRootHash = "app_state.monitoringp.params.consumerConsensusState.root.hash" + FieldConsumerUnbondingPeriod = "app_state.monitoringp.params.consumerUnbondingPeriod" + FieldConsumerRevisionHeight = "app_state.monitoringp.params.consumerRevisionHeight" ) type ( @@ -41,6 +52,11 @@ type ( } `json:"staking"` } `json:"app_state"` } + + // fields to update from genesis + fields map[string]string + // GenesisField configures the genesis key value fields. + GenesisField func(fields) ) // HasAccount check if account exist into the genesis account @@ -53,6 +69,69 @@ func (g Genesis) HasAccount(address string) bool { return false } +// WithKeyValue sets key and value field to genesis file +func WithKeyValue(key, value string) GenesisField { + return func(f fields) { + f[key] = value + } +} + +// WithKeyValueInt sets key and int64 value field to genesis file +func WithKeyValueInt(key string, value int64) GenesisField { + return func(f fields) { + f[key] = strconv.FormatInt(value, 10) + } +} + +// WithKeyValueUint sets key and uint64 value field to genesis file +func WithKeyValueUint(key string, value uint64) GenesisField { + return func(f fields) { + f[key] = strconv.FormatUint(value, 10) + } +} + +// WithKeyValueTimestamp sets key and timestamp value field to genesis file +func WithKeyValueTimestamp(key string, value int64) GenesisField { + return func(f fields) { + f[key] = time.Unix(value, 0).UTC().Format(time.RFC3339Nano) + } +} + +// WithKeyValueBoolean sets key and boolean value field to genesis file +func WithKeyValueBoolean(key string, value bool) GenesisField { + return func(f fields) { + if value { + f[key] = "true" + } else { + f[key] = "false" + } + } +} + +func UpdateGenesis(genesisPath string, options ...GenesisField) error { + f := fields{} + for _, applyField := range options { + applyField(f) + } + + genesisBytes, err := os.ReadFile(genesisPath) + if err != nil { + return err + } + + for key, value := range f { + genesisBytes, err = jsonparser.Set( + genesisBytes, + []byte(fmt.Sprintf(`"%s"`, value)), + strings.Split(key, ".")..., + ) + if err != nil { + return err + } + } + return os.WriteFile(genesisPath, genesisBytes, 0644) +} + // ParseGenesisFromPath parse ChainGenesis object from a genesis file func ParseGenesisFromPath(genesisPath string) (Genesis, error) { genesisFile, err := os.ReadFile(genesisPath) @@ -98,51 +177,6 @@ func CheckGenesisContainsAddress(genesisPath, addr string) (bool, error) { return genesis.HasAccount(addr), nil } -// SetGenesisTime sets the genesis time inside a genesis file -func SetGenesisTime(genesisPath string, genesisTime int64) error { - // fetch and parse genesis - genesisBytes, err := os.ReadFile(genesisPath) - if err != nil { - return err - } - - var genesis map[string]interface{} - if err := json.Unmarshal(genesisBytes, &genesis); err != nil { - return err - } - - // check the genesis time with the RFC3339 standard format - formattedTime := time.Unix(genesisTime, 0).UTC().Format(time.RFC3339Nano) - - // modify and save the new genesis - genesis[genesisTimeField] = &formattedTime - genesisBytes, err = json.Marshal(genesis) - if err != nil { - return err - } - return os.WriteFile(genesisPath, genesisBytes, 0644) -} - -// TODO refactor -func SetChainID(genesisPath, chainID string) error { - genesisBytes, err := os.ReadFile(genesisPath) - if err != nil { - return err - } - - var genesis map[string]interface{} - if err := json.Unmarshal(genesisBytes, &genesis); err != nil { - return err - } - - genesis[chainIDField] = chainID - genesisBytes, err = json.Marshal(genesis) - if err != nil { - return err - } - return os.WriteFile(genesisPath, genesisBytes, 0644) -} - // GenesisAndHashFromURL fetches the genesis from the given url and returns its content along with the sha256 hash. func GenesisAndHashFromURL(ctx context.Context, url string) (genesis []byte, hash string, err error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) diff --git a/ignite/pkg/cosmosutil/genesis_test.go b/ignite/pkg/cosmosutil/genesis_test.go index 62be2ea389..03741e4e0d 100644 --- a/ignite/pkg/cosmosutil/genesis_test.go +++ b/ignite/pkg/cosmosutil/genesis_test.go @@ -1,49 +1,18 @@ package cosmosutil_test import ( - "encoding/json" + "errors" "os" "path/filepath" + "strings" "testing" + "github.com/buger/jsonparser" "github.com/stretchr/testify/require" "github.com/ignite-hq/cli/ignite/pkg/cosmosutil" ) -const ( - genesisSample = ` -{ - "foo": "bar", - "genesis_time": "foobar" -} -` - unixTime = 1600000000 - rfcTime = "2020-09-13T12:26:40Z" -) - -func TestSetGenesisTime(t *testing.T) { - tmp := t.TempDir() - tmpGenesis := filepath.Join(tmp, "genesis.json") - - // fails with no file - require.Error(t, cosmosutil.SetGenesisTime(tmpGenesis, 0)) - - require.NoError(t, os.WriteFile(tmpGenesis, []byte(genesisSample), 0644)) - require.NoError(t, cosmosutil.SetGenesisTime(tmpGenesis, unixTime)) - - // check genesis modified value - var actual struct { - Foo string `json:"foo"` - GenesisTime string `json:"genesis_time"` - } - actualBytes, err := os.ReadFile(tmpGenesis) - require.NoError(t, err) - require.NoError(t, json.Unmarshal(actualBytes, &actual)) - require.Equal(t, "bar", actual.Foo) - require.Equal(t, rfcTime, actual.GenesisTime) -} - func TestChainGenesis_HasAccount(t *testing.T) { tests := []struct { name string @@ -216,3 +185,157 @@ func TestParseGenesisFromPath(t *testing.T) { }) } } + +func TestUpdateGenesis(t *testing.T) { + genesisSample := ` +{ + "number": 33, + "foo": "bar", + "genesis_time": "foobar", + "app_state": { + "monitoring": { + "chain-id": "ignite-1" + }, + "foobar": "baz", + "debug": "false", + "height": "100", + "time": "100", + "staling": { + "params": [] + } + } +} +` + type args struct { + genesis string + options []cosmosutil.GenesisField + } + tests := []struct { + name string + args args + err error + }{ + { + name: "with key and value", + args: args{ + genesis: genesisSample, + options: []cosmosutil.GenesisField{ + cosmosutil.WithKeyValue("foo", "foobar"), + }, + }, + }, + { + name: "with key and bool value", + args: args{ + genesis: genesisSample, + options: []cosmosutil.GenesisField{ + cosmosutil.WithKeyValueBoolean("app_state.debug", true), + }, + }, + }, + { + name: "with key and int value", + args: args{ + genesis: genesisSample, + options: []cosmosutil.GenesisField{ + cosmosutil.WithKeyValueInt("app_state.height", 199), + }, + }, + }, + { + name: "with key and uint value", + args: args{ + genesis: genesisSample, + options: []cosmosutil.GenesisField{ + cosmosutil.WithKeyValueUint("app_state.height", 438), + }, + }, + }, + { + name: "with key and timestamp value", + args: args{ + genesis: genesisSample, + options: []cosmosutil.GenesisField{ + cosmosutil.WithKeyValueTimestamp("app_state.time", 3000), + }, + }, + }, + { + name: "with all key and value types", + args: args{ + genesis: genesisSample, + options: []cosmosutil.GenesisField{ + cosmosutil.WithKeyValue("foo", "baz"), + cosmosutil.WithKeyValue("app_state.monitoring.chain-id", "spn-1"), + cosmosutil.WithKeyValueBoolean("app_state.debug", false), + cosmosutil.WithKeyValueInt("app_state.height", 123), + cosmosutil.WithKeyValueUint("app_state.height", 343), + cosmosutil.WithKeyValueTimestamp("app_state.time", 999999), + }, + }, + }, + { + name: "casting key value", + args: args{ + genesis: genesisSample, + options: []cosmosutil.GenesisField{ + cosmosutil.WithKeyValue("number", "number_value"), + }, + }, + }, + { + name: "with wrong key path", + args: args{ + genesis: genesisSample, + options: []cosmosutil.GenesisField{ + cosmosutil.WithKeyValue("wrong.path", "foobar"), + cosmosutil.WithKeyValue("app_state.monitoring.wrong", "baz"), + }, + }, + }, + { + name: "with file path", + args: args{ + genesis: "", + options: []cosmosutil.GenesisField{ + cosmosutil.WithKeyValue("foo", "foobar"), + }, + }, + err: errors.New("Key path not found"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpGenesis := filepath.Join(t.TempDir(), "genesis.json") + if tt.args.genesis != "" { + require.Error(t, + cosmosutil.UpdateGenesis( + tmpGenesis, + cosmosutil.WithKeyValue("test", "test"), + ), + ) + } + require.NoError(t, os.WriteFile(tmpGenesis, []byte(tt.args.genesis), 0644)) + err := cosmosutil.UpdateGenesis(tmpGenesis, tt.args.options...) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), tt.err.Error()) + return + } + require.NoError(t, err) + + genesisBytes, err := os.ReadFile(tmpGenesis) + + f := map[string]string{} + for _, applyField := range tt.args.options { + applyField(f) + } + + for key, value := range f { + val, err := jsonparser.GetString(genesisBytes, strings.Split(key, ".")...) + require.NoError(t, err) + require.Equal(t, val, value) + } + }) + } +} diff --git a/ignite/pkg/dirchange/dirchange.go b/ignite/pkg/dirchange/dirchange.go index 4e29b3eb26..e86e4d3396 100644 --- a/ignite/pkg/dirchange/dirchange.go +++ b/ignite/pkg/dirchange/dirchange.go @@ -6,47 +6,40 @@ import ( "errors" "os" "path/filepath" + + "github.com/ignite-hq/cli/ignite/pkg/cache" ) var ErrNoFile = errors.New("no file in specified paths") -// SaveDirChecksum saves the md5 checksum of the provided paths (directories or files) in the specified directory +// SaveDirChecksum saves the md5 checksum of the provided paths (directories or files) in the provided cache // If checksumSavePath directory doesn't exist, it is created // paths are relative to workdir, if workdir is empty string paths are absolute -func SaveDirChecksum(workdir string, paths []string, checksumSavePath string, checksumName string) error { - checksum, err := checksumFromPaths(workdir, paths) +func SaveDirChecksum(checksumCache cache.Cache[[]byte], cacheKey string, workdir string, paths ...string) error { + checksum, err := ChecksumFromPaths(workdir, paths...) if err != nil { return err } - // create directory if needed - if err := os.MkdirAll(checksumSavePath, 0700); err != nil && !os.IsExist(err) { - return err - } - // save checksum - checksumFilePath := filepath.Join(checksumSavePath, checksumName) - return os.WriteFile(checksumFilePath, checksum, 0644) + return checksumCache.Put(cacheKey, checksum) } // HasDirChecksumChanged computes the md5 checksum of the provided paths (directories or files) -// and compare it with the current saved checksum -// Return true if the checksum file doesn't exist yet +// and compare it with the current cached checksum +// Return true if the checksum doesn't exist yet // paths are relative to workdir, if workdir is empty string paths are absolute -func HasDirChecksumChanged(workdir string, paths []string, checksumSavePath string, checksumName string) (bool, error) { - // create directory if needed - if err := os.MkdirAll(checksumSavePath, 0700); err != nil && !os.IsExist(err) { - return false, err - } - checksumFilePath := filepath.Join(checksumSavePath, checksumName) - if _, err := os.Stat(checksumFilePath); os.IsNotExist(err) { +func HasDirChecksumChanged(checksumCache cache.Cache[[]byte], cacheKey string, workdir string, paths ...string) (bool, error) { + savedChecksum, err := checksumCache.Get(cacheKey) + if err == cache.ErrorNotFound { return true, nil - } else if err != nil { - return false, nil + } + if err != nil { + return false, err } // Compute checksum - checksum, err := checksumFromPaths(workdir, paths) + checksum, err := ChecksumFromPaths(workdir, paths...) if errors.Is(err, ErrNoFile) { // Checksum cannot be saved with no file // Therefore if no file are found, this means these have been delete, then the directory has been changed @@ -56,10 +49,6 @@ func HasDirChecksumChanged(workdir string, paths []string, checksumSavePath stri } // Compare checksums - savedChecksum, err := os.ReadFile(checksumFilePath) - if err != nil { - return false, err - } if bytes.Equal(checksum, savedChecksum) { return false, nil } @@ -68,9 +57,9 @@ func HasDirChecksumChanged(workdir string, paths []string, checksumSavePath stri return true, nil } -// checksumFromPaths computes the md5 checksum from the provided paths +// ChecksumFromPaths computes the md5 checksum from the provided paths // paths are relative to workdir, if workdir is empty string paths are absolute -func checksumFromPaths(workdir string, paths []string) ([]byte, error) { +func ChecksumFromPaths(workdir string, paths ...string) ([]byte, error) { hash := md5.New() // Can't compute hash if no file present diff --git a/ignite/pkg/dirchange/dirchange_test.go b/ignite/pkg/dirchange/dirchange_test.go index de41a9062e..37ca36f02f 100644 --- a/ignite/pkg/dirchange/dirchange_test.go +++ b/ignite/pkg/dirchange/dirchange_test.go @@ -1,4 +1,4 @@ -package dirchange +package dirchange_test import ( "crypto/rand" @@ -7,11 +7,14 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/ignite-hq/cli/ignite/pkg/cache" + "github.com/ignite-hq/cli/ignite/pkg/dirchange" ) const ( - TmpPattern = "starport-dirchange" - ChecksumFile = "checksum.txt" + TmpPattern = "starport-dirchange" + ChecksumKey = "checksum" ) func randomBytes(n int) []byte { @@ -22,10 +25,15 @@ func randomBytes(n int) []byte { func TestHasDirChecksumChanged(t *testing.T) { tempDir := os.TempDir() + cacheDir := os.TempDir() + + cacheStorage, err := cache.NewStorage(filepath.Join(cacheDir, "testcache.db")) + require.NoError(t, err) + cache := cache.New[[]byte](cacheStorage, "testnamespace") // Create directory tree dir1 := filepath.Join(tempDir, "foo1") - err := os.MkdirAll(dir1, 0700) + err = os.MkdirAll(dir1, 0700) require.NoError(t, err) defer os.RemoveAll(dir1) dir2 := filepath.Join(tempDir, "foo2") @@ -60,7 +68,7 @@ func TestHasDirChecksumChanged(t *testing.T) { // Check checksum paths := []string{dir1, dir2, dir3} - checksum, err := checksumFromPaths("", paths) + checksum, err := dirchange.ChecksumFromPaths("", paths...) require.NoError(t, err) // md5 checksum is 16 bytes require.Len(t, checksum, 16) @@ -70,31 +78,31 @@ func TestHasDirChecksumChanged(t *testing.T) { require.NoError(t, err) err = os.WriteFile(filepath.Join(dir1, "foo"), []byte("some bytes"), 0644) require.NoError(t, err) - tmpChecksum, err := checksumFromPaths("", paths) + tmpChecksum, err := dirchange.ChecksumFromPaths("", paths...) require.NoError(t, err) require.Equal(t, checksum, tmpChecksum) // Can compute the checksum from a specific workdir pathNames := []string{"foo1", "foo2", "foo3"} - tmpChecksum, err = checksumFromPaths(tempDir, pathNames) + tmpChecksum, err = dirchange.ChecksumFromPaths(tempDir, pathNames...) require.NoError(t, err) require.Equal(t, checksum, tmpChecksum) // Ignore non existent dir pathNames = append(pathNames, "nonexistent") - tmpChecksum, err = checksumFromPaths(tempDir, pathNames) + tmpChecksum, err = dirchange.ChecksumFromPaths(tempDir, pathNames...) require.NoError(t, err) require.Equal(t, checksum, tmpChecksum) // Checksum from a subdir is different - tmpChecksum, err = checksumFromPaths("", []string{dir1, dir2}) + tmpChecksum, err = dirchange.ChecksumFromPaths("", dir1, dir2) require.NoError(t, err) require.NotEqual(t, checksum, tmpChecksum) // Checksum changes if a file is modified err = os.WriteFile(filepath.Join(dir3, "foo1"), randomBytes(10), 0644) require.NoError(t, err) - newChecksum, err := checksumFromPaths("", paths) + newChecksum, err := dirchange.ChecksumFromPaths("", paths...) require.NoError(t, err) require.NotEqual(t, checksum, newChecksum) @@ -107,46 +115,44 @@ func TestHasDirChecksumChanged(t *testing.T) { err = os.MkdirAll(empty2, 0700) require.NoError(t, err) defer os.RemoveAll(empty2) - _, err = checksumFromPaths("", []string{empty1, empty2}) + _, err = dirchange.ChecksumFromPaths("", empty1, empty2) require.Error(t, err) - // SaveDirChecksum saves the checksum in the specified dir + // SaveDirChecksum saves the checksum in the cache saveDir, err := os.MkdirTemp(tempDir, TmpPattern) require.NoError(t, err) defer os.RemoveAll(saveDir) - err = SaveDirChecksum("", paths, saveDir, ChecksumFile) + err = dirchange.SaveDirChecksum(cache, ChecksumKey, "", paths...) require.NoError(t, err) - require.FileExists(t, filepath.Join(saveDir, ChecksumFile)) - fileContent, err := os.ReadFile(filepath.Join(saveDir, ChecksumFile)) + savedChecksum, err := cache.Get(ChecksumKey) require.NoError(t, err) - require.Equal(t, newChecksum, fileContent) + require.Equal(t, newChecksum, savedChecksum) // Error if the paths contains no file - err = SaveDirChecksum("", []string{empty1, empty2}, saveDir, ChecksumFile) + err = dirchange.SaveDirChecksum(cache, ChecksumKey, "", empty1, empty2) require.Error(t, err) // HasDirChecksumChanged returns false if the directory has not changed - changed, err := HasDirChecksumChanged("", paths, saveDir, ChecksumFile) + changed, err := dirchange.HasDirChecksumChanged(cache, ChecksumKey, "", paths...) require.NoError(t, err) require.False(t, changed) - // Return true if checksum file doesn't exist - newSaveDir, err := os.MkdirTemp(tempDir, TmpPattern) + // Return true if cache entry doesn't exist + err = cache.Delete(ChecksumKey) require.NoError(t, err) - defer os.RemoveAll(newSaveDir) - changed, err = HasDirChecksumChanged("", paths, newSaveDir, ChecksumFile) + changed, err = dirchange.HasDirChecksumChanged(cache, ChecksumKey, "", paths...) require.NoError(t, err) require.True(t, changed) // Return true if the paths contains no file - changed, err = HasDirChecksumChanged("", []string{empty1, empty2}, saveDir, ChecksumFile) + changed, err = dirchange.HasDirChecksumChanged(cache, ChecksumKey, "", empty1, empty2) require.NoError(t, err) require.True(t, changed) // Return true if it has been changed err = os.WriteFile(filepath.Join(dir21, "bar"), randomBytes(20), 0644) require.NoError(t, err) - changed, err = HasDirChecksumChanged("", paths, saveDir, ChecksumFile) + changed, err = dirchange.HasDirChecksumChanged(cache, ChecksumKey, "", paths...) require.NoError(t, err) require.True(t, changed) } diff --git a/ignite/pkg/gomodule/gomodule.go b/ignite/pkg/gomodule/gomodule.go index 0bd3527780..88e133a549 100644 --- a/ignite/pkg/gomodule/gomodule.go +++ b/ignite/pkg/gomodule/gomodule.go @@ -14,10 +14,13 @@ import ( "golang.org/x/mod/modfile" "golang.org/x/mod/module" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner/step" ) +const pathCacheNamespace = "gomodule.path" + // ErrGoModNotFound returned when go.mod file cannot be found for an app. var ErrGoModNotFound = errors.New("go.mod not found") @@ -77,7 +80,7 @@ func ResolveDependencies(f *modfile.File) ([]module.Version, error) { } // LocatePath locates pkg's absolute path managed by 'go mod' on the local filesystem. -func LocatePath(ctx context.Context, src string, pkg module.Version) (path string, err error) { +func LocatePath(ctx context.Context, cacheStorage cache.Storage, src string, pkg module.Version) (path string, err error) { // can be a local package. if pkg.Version == "" { // indicates that this is a local package. if filepath.IsAbs(pkg.Path) { @@ -86,6 +89,16 @@ func LocatePath(ctx context.Context, src string, pkg module.Version) (path strin return filepath.Join(src, pkg.Path), nil } + pathCache := cache.New[string](cacheStorage, pathCacheNamespace) + cacheKey := cache.Key(pkg.Path, pkg.Version) + path, err = pathCache.Get(cacheKey) + if err != nil && err != cache.ErrorNotFound { + return "", err + } + if err != cache.ErrorNotFound { + return path, nil + } + // otherwise, it is hosted. out := &bytes.Buffer{} @@ -112,6 +125,9 @@ func LocatePath(ctx context.Context, src string, pkg module.Version) (path strin return "", err } if module.Path == pkg.Path && module.Version == pkg.Version { + if err := pathCache.Put(cacheKey, module.Dir); err != nil { + return "", err + } return module.Dir, nil } } diff --git a/ignite/pkg/localfs/watcher.go b/ignite/pkg/localfs/watcher.go index 71c69121f8..56aa549367 100644 --- a/ignite/pkg/localfs/watcher.go +++ b/ignite/pkg/localfs/watcher.go @@ -2,6 +2,8 @@ package localfs import ( "context" + "errors" + "os" "path/filepath" "strings" "sync" @@ -11,14 +13,15 @@ import ( ) type watcher struct { - wt *wt.Watcher - workdir string - ignoreHidden bool - ignoreExts []string - onChange func() - interval time.Duration - ctx context.Context - done *sync.WaitGroup + wt *wt.Watcher + workdir string + ignoreHidden bool + ignoreFolders bool + ignoreExts []string + onChange func() + interval time.Duration + ctx context.Context + done *sync.WaitGroup } // WatcherOption used to configure watcher. @@ -52,6 +55,12 @@ func WatcherIgnoreHidden() WatcherOption { } } +func WatcherIgnoreFolders() WatcherOption { + return func(w *watcher) { + w.ignoreFolders = true + } +} + // WatcherIgnoreExt ignores files with matching file extensions. func WatcherIgnoreExt(exts ...string) WatcherOption { return func(w *watcher) { @@ -62,25 +71,37 @@ func WatcherIgnoreExt(exts ...string) WatcherOption { // Watch starts watching changes on the paths. options are used to configure the // behaviour of watch operation. func Watch(ctx context.Context, paths []string, options ...WatcherOption) error { - wt := wt.New() - wt.SetMaxEvents(1) - w := &watcher{ - wt: wt, + wt: wt.New(), onChange: func() {}, interval: time.Millisecond * 300, done: &sync.WaitGroup{}, ctx: ctx, } + w.wt.SetMaxEvents(1) + for _, o := range options { o(w) } + w.wt.AddFilterHook(func(info os.FileInfo, fullPath string) error { + if info.IsDir() && w.ignoreFolders { + return wt.ErrSkip + } + if w.isFileIgnored(fullPath) { + return wt.ErrSkip + } + + return nil + }) + // ignore hidden paths. w.wt.IgnoreHiddenFiles(w.ignoreHidden) // add paths to watch - w.addPaths(paths...) + if err := w.addPaths(paths...); err != nil { + return err + } // start watching. w.done.Add(1) @@ -96,10 +117,8 @@ func (w *watcher) listen() { defer w.done.Done() for { select { - case e := <-w.wt.Event: - if !w.isFileIgnored(e.Path) { - w.onChange() - } + case <-w.wt.Event: + w.onChange() case <-w.wt.Closed: return case <-w.ctx.Done(): @@ -108,13 +127,23 @@ func (w *watcher) listen() { } } -func (w *watcher) addPaths(paths ...string) { +func (w *watcher) addPaths(paths ...string) error { for _, path := range paths { if !filepath.IsAbs(path) { path = filepath.Join(w.workdir, path) } - w.wt.AddRecursive(path) + + // Ignoring paths that don't exist + if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { + continue + } + + if err := w.wt.AddRecursive(path); err != nil { + return err + } } + + return nil } func (w *watcher) isFileIgnored(path string) bool { diff --git a/ignite/pkg/nodetime/data/nodetime-darwin-amd64.tar.gz b/ignite/pkg/nodetime/data/nodetime-darwin-amd64.tar.gz index efa4ad6d93..52912c3cec 100644 Binary files a/ignite/pkg/nodetime/data/nodetime-darwin-amd64.tar.gz and b/ignite/pkg/nodetime/data/nodetime-darwin-amd64.tar.gz differ diff --git a/ignite/pkg/nodetime/data/nodetime-darwin-arm64.tar.gz b/ignite/pkg/nodetime/data/nodetime-darwin-arm64.tar.gz index ec2bcf57e2..f0647b6cbf 100644 Binary files a/ignite/pkg/nodetime/data/nodetime-darwin-arm64.tar.gz and b/ignite/pkg/nodetime/data/nodetime-darwin-arm64.tar.gz differ diff --git a/ignite/pkg/nodetime/data/nodetime-linux-amd64.tar.gz b/ignite/pkg/nodetime/data/nodetime-linux-amd64.tar.gz index 08fb8c6aa4..c10ebdfd19 100644 Binary files a/ignite/pkg/nodetime/data/nodetime-linux-amd64.tar.gz and b/ignite/pkg/nodetime/data/nodetime-linux-amd64.tar.gz differ diff --git a/ignite/pkg/nodetime/data/nodetime-linux-arm64.tar.gz b/ignite/pkg/nodetime/data/nodetime-linux-arm64.tar.gz index acababc79a..0c886d11fa 100644 Binary files a/ignite/pkg/nodetime/data/nodetime-linux-arm64.tar.gz and b/ignite/pkg/nodetime/data/nodetime-linux-arm64.tar.gz differ diff --git a/ignite/pkg/placeholder/tracer_test.go b/ignite/pkg/placeholder/tracer_test.go index 693e61097e..54c4aa70c5 100644 --- a/ignite/pkg/placeholder/tracer_test.go +++ b/ignite/pkg/placeholder/tracer_test.go @@ -39,7 +39,6 @@ func TestReplace(t *testing.T) { missing: []string{"#one"}, }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { tr := New() content := tc.content @@ -81,7 +80,6 @@ func TestReplaceAll(t *testing.T) { missing: []string{"#one"}, }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { tr := New() content := tc.content diff --git a/ignite/pkg/protoc/protoc.go b/ignite/pkg/protoc/protoc.go index 3a51a95b92..4c888c2678 100644 --- a/ignite/pkg/protoc/protoc.go +++ b/ignite/pkg/protoc/protoc.go @@ -23,6 +23,7 @@ type configs struct { pluginPath string isGeneratedDepsEnabled bool pluginOptions []string + env []string } // Plugin configures a plugin for code generation. @@ -41,6 +42,13 @@ func GenerateDependencies() Option { } } +// Env assigns environment values during the code generation. +func Env(v ...string) Option { + return func(c *configs) { + c.env = v + } +} + type Cmd struct { Command []string Included []string @@ -119,10 +127,15 @@ func Generate(ctx context.Context, outDir, protoPath string, includePaths, proto command = append(command, files...) command = append(command, c.pluginOptions...) - if err := exec.Exec(ctx, command, + execOpts := []exec.Option{ exec.StepOption(step.Workdir(outDir)), exec.IncludeStdLogsToError(), - ); err != nil { + } + if c.env != nil { + execOpts = append(execOpts, exec.StepOption(step.Env(c.env...))) + } + + if err := exec.Exec(ctx, command, execOpts...); err != nil { return err } } diff --git a/ignite/pkg/protopath/protopath.go b/ignite/pkg/protopath/protopath.go index 17965f93c0..dc42ff47d5 100644 --- a/ignite/pkg/protopath/protopath.go +++ b/ignite/pkg/protopath/protopath.go @@ -7,6 +7,7 @@ import ( "golang.org/x/mod/module" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/gomodule" "github.com/ignite-hq/cli/ignite/pkg/xfilepath" ) @@ -39,7 +40,7 @@ func NewModule(importPath string, protoPaths ...string) Module { // r should be the list of required packages of the target go app. it is used to resolve exact versions // of the go modules that used by the target app. // global dependencies are also included to paths. -func ResolveDependencyPaths(ctx context.Context, src string, versions []module.Version, modules ...Module) (paths []string, err error) { +func ResolveDependencyPaths(ctx context.Context, cacheStorage cache.Storage, src string, versions []module.Version, modules ...Module) (paths []string, err error) { globalInclude, err := globalInclude() if err != nil { return nil, err @@ -60,7 +61,7 @@ func ResolveDependencyPaths(ctx context.Context, src string, versions []module.V } for i, v := range vs { - path, err := gomodule.LocatePath(ctx, src, v) + path, err := gomodule.LocatePath(ctx, cacheStorage, src, v) if err != nil { return nil, err } diff --git a/ignite/pkg/relayer/chain.go b/ignite/pkg/relayer/chain.go index 4f11a447fb..37824cb4bd 100644 --- a/ignite/pkg/relayer/chain.go +++ b/ignite/pkg/relayer/chain.go @@ -48,6 +48,9 @@ type Chain struct { // addressPrefix is the address prefix of the chain. addressPrefix string + // clientID is the client id of the chain for relayer connection. + clientID string + r Relayer } @@ -89,6 +92,13 @@ func WithAddressPrefix(addressPrefix string) Option { } } +// WithClientID configures the chain client id +func WithClientID(clientID string) Option { + return func(c *Chain) { + c.clientID = clientID + } +} + // NewChain creates a new chain on relayer or uses the existing matching chain. func (r Relayer) NewChain(ctx context.Context, accountName, rpcAddress string, options ...Option) ( *Chain, cosmosaccount.Account, error) { @@ -190,7 +200,7 @@ func Ordered() ChannelOption { // Connect connects dst chain to c chain and creates a path in between in offline mode. // it returns the path id on success otherwise, returns with a non-nil error. -func (c *Chain) Connect(ctx context.Context, dst *Chain, options ...ChannelOption) (id string, err error) { +func (c *Chain) Connect(dst *Chain, options ...ChannelOption) (id string, err error) { channelOptions := newChannelOptions() for _, apply := range options { @@ -210,7 +220,7 @@ func (c *Chain) Connect(ctx context.Context, dst *Chain, options ...ChannelOptio i := 2 for { guess := pathID + suffix - if _, err := conf.PathByID(guess); err != nil { // guess is inique. + if _, err := conf.PathByID(guess); err != nil { // guess is unique. pathID = guess break } @@ -261,6 +271,7 @@ func (c *Chain) ensureChainSetup(ctx context.Context) error { RPCAddress: c.rpcAddress, GasPrice: c.gasPrice, GasLimit: c.gasLimit, + ClientID: c.clientID, } conf, err := relayerconfig.Get() diff --git a/ignite/pkg/relayer/config/config.go b/ignite/pkg/relayer/config/config.go index 44c32858e1..7b30b8e63f 100644 --- a/ignite/pkg/relayer/config/config.go +++ b/ignite/pkg/relayer/config/config.go @@ -58,6 +58,7 @@ type Chain struct { RPCAddress string `json:"rpc_address" yaml:"rpc_address"` GasPrice string `json:"gas_price" yaml:"gas_price,omitempty"` GasLimit int64 `json:"gas_limit" yaml:"gas_limit,omitempty"` + ClientID string `json:"client_id" yaml:"client_id,omitempty"` } type Path struct { diff --git a/ignite/pkg/relayer/relayer.go b/ignite/pkg/relayer/relayer.go index 3334cbd4a3..561b15e463 100644 --- a/ignite/pkg/relayer/relayer.go +++ b/ignite/pkg/relayer/relayer.go @@ -31,11 +31,9 @@ type Relayer struct { // New creates a new IBC relayer and uses ca to access accounts. func New(ca cosmosaccount.Registry) Relayer { - r := Relayer{ + return Relayer{ ca: ca, } - - return r } // Link links all chains that has a path to each other. @@ -119,7 +117,7 @@ func (r Relayer) Start(ctx context.Context, pathIDs ...string) error { } func (r Relayer) call(ctx context.Context, conf relayerconf.Config, path relayerconf.Path, action string) ( - relayerconf.Path, error) { + reply relayerconf.Path, err error) { srcChain, srcKey, err := r.prepare(ctx, conf, path.Src.ChainID) if err != nil { return relayerconf.Path{}, err @@ -130,17 +128,14 @@ func (r Relayer) call(ctx context.Context, conf relayerconf.Config, path relayer return relayerconf.Path{}, err } - var reply relayerconf.Path - - err = tsrelayer.Call(ctx, action, []interface{}{ + args := []interface{}{ path, srcChain, dstChain, srcKey, dstKey, - }, &reply) - - return reply, err + } + return reply, tsrelayer.Call(ctx, action, args, &reply) } func (r Relayer) prepare(ctx context.Context, conf relayerconf.Config, chainID string) ( diff --git a/ignite/services/chain/build.go b/ignite/services/chain/build.go index d102b1d3b8..240946e8dc 100644 --- a/ignite/services/chain/build.go +++ b/ignite/services/chain/build.go @@ -11,34 +11,38 @@ import ( "github.com/docker/docker/pkg/archive" "github.com/pkg/errors" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/checksum" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner/exec" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner/step" + "github.com/ignite-hq/cli/ignite/pkg/dirchange" "github.com/ignite-hq/cli/ignite/pkg/goanalysis" "github.com/ignite-hq/cli/ignite/pkg/gocmd" "github.com/ignite-hq/cli/ignite/pkg/xstrings" ) const ( - releaseDir = "release" - checksumTxt = "checksum.txt" + releaseDir = "release" + releaseChecksumKey = "release_checksum" + modChecksumKey = "go_mod_checksum" + buildDirchangeCacheNamespace = "build.dirchange" ) // Build builds and installs app binaries. -func (c *Chain) Build(ctx context.Context, output string) (binaryName string, err error) { +func (c *Chain) Build(ctx context.Context, cacheStorage cache.Storage, output string) (binaryName string, err error) { if err := c.setup(); err != nil { return "", err } - if err := c.build(ctx, output); err != nil { + if err := c.build(ctx, cacheStorage, output); err != nil { return "", err } return c.Binary() } -func (c *Chain) build(ctx context.Context, output string) (err error) { +func (c *Chain) build(ctx context.Context, cacheStorage cache.Storage, output string) (err error) { defer func() { var exitErr *exec.ExitError @@ -47,11 +51,11 @@ func (c *Chain) build(ctx context.Context, output string) (err error) { } }() - if err := c.generateAll(ctx); err != nil { + if err := c.generateAll(ctx, cacheStorage); err != nil { return err } - buildFlags, err := c.preBuild(ctx) + buildFlags, err := c.preBuild(ctx, cacheStorage) if err != nil { return err } @@ -72,7 +76,7 @@ func (c *Chain) build(ctx context.Context, output string) (err error) { // BuildRelease builds binaries for a release. targets is a list // of GOOS:GOARCH when provided. It defaults to your system when no targets provided. // prefix is used as prefix to tarballs containing each target. -func (c *Chain) BuildRelease(ctx context.Context, output, prefix string, targets ...string) (releasePath string, err error) { +func (c *Chain) BuildRelease(ctx context.Context, cacheStorage cache.Storage, output, prefix string, targets ...string) (releasePath string, err error) { if prefix == "" { prefix = c.app.Name } @@ -85,7 +89,7 @@ func (c *Chain) BuildRelease(ctx context.Context, output, prefix string, targets return "", err } - buildFlags, err := c.preBuild(ctx) + buildFlags, err := c.preBuild(ctx, cacheStorage) if err != nil { return "", err } @@ -157,13 +161,13 @@ func (c *Chain) BuildRelease(ctx context.Context, output, prefix string, targets tarf.Close() } - checksumPath := filepath.Join(releasePath, checksumTxt) + checksumPath := filepath.Join(releasePath, releaseChecksumKey) // create a checksum.txt and return with the path to release dir. return releasePath, checksum.Sum(releasePath, checksumPath) } -func (c *Chain) preBuild(ctx context.Context) (buildFlags []string, err error) { +func (c *Chain) preBuild(ctx context.Context, cacheStorage cache.Storage) (buildFlags []string, err error) { config, err := c.Config() if err != nil { return nil, err @@ -189,13 +193,28 @@ func (c *Chain) preBuild(ctx context.Context) (buildFlags []string, err error) { fmt.Fprintln(c.stdLog().out, "📦 Installing dependencies...") + // We do mod tidy before checking for checksum changes, because go.mod gets modified often + // and the mod verify command is the expensive one anyway if err := gocmd.ModTidy(ctx, c.app.Path); err != nil { return nil, err } - if err := gocmd.ModVerify(ctx, c.app.Path); err != nil { + + dirCache := cache.New[[]byte](cacheStorage, buildDirchangeCacheNamespace) + modChanged, err := dirchange.HasDirChecksumChanged(dirCache, modChecksumKey, c.app.Path, "go.mod") + if err != nil { return nil, err } + if modChanged { + if err := gocmd.ModVerify(ctx, c.app.Path); err != nil { + return nil, err + } + + if err := dirchange.SaveDirChecksum(dirCache, modChecksumKey, c.app.Path, "go.mod"); err != nil { + return nil, err + } + } + fmt.Fprintln(c.stdLog().out, "🛠️ Building the blockchain...") return buildFlags, nil diff --git a/ignite/services/chain/generate.go b/ignite/services/chain/generate.go index 7514674046..a0c799b5b9 100644 --- a/ignite/services/chain/generate.go +++ b/ignite/services/chain/generate.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cosmosanalysis/module" "github.com/ignite-hq/cli/ignite/pkg/cosmosgen" ) @@ -54,7 +55,7 @@ func GenerateOpenAPI() GenerateTarget { } } -func (c *Chain) generateAll(ctx context.Context) error { +func (c *Chain) generateAll(ctx context.Context, cacheStorage cache.Storage) error { conf, err := c.Config() if err != nil { return err @@ -74,12 +75,13 @@ func (c *Chain) generateAll(ctx context.Context) error { additionalTargets = append(additionalTargets, GenerateOpenAPI()) } - return c.Generate(ctx, GenerateGo(), additionalTargets...) + return c.Generate(ctx, cacheStorage, GenerateGo(), additionalTargets...) } // Generate makes code generation from proto files for given target and additionalTargets. func (c *Chain) Generate( ctx context.Context, + cacheStorage cache.Storage, target GenerateTarget, additionalTargets ...GenerateTarget, ) error { @@ -164,7 +166,7 @@ func (c *Chain) Generate( options = append(options, cosmosgen.WithOpenAPIGeneration(openAPIPath)) } - if err := cosmosgen.Generate(ctx, c.app.Path, conf.Build.Proto.Path, options...); err != nil { + if err := cosmosgen.Generate(ctx, cacheStorage, c.app.Path, conf.Build.Proto.Path, options...); err != nil { return &CannotBuildAppError{err} } diff --git a/ignite/services/chain/plugin-stargate.go b/ignite/services/chain/plugin-stargate.go index eafcb0da34..7423f7225b 100644 --- a/ignite/services/chain/plugin-stargate.go +++ b/ignite/services/chain/plugin-stargate.go @@ -6,9 +6,9 @@ import ( "os" "path/filepath" + sdktypes "github.com/cosmos/cosmos-sdk/types" "github.com/pelletier/go-toml" - sdktypes "github.com/cosmos/cosmos-sdk/types" "github.com/ignite-hq/cli/ignite/chainconfig" "github.com/ignite-hq/cli/ignite/pkg/chaincmd" chaincmdrunner "github.com/ignite-hq/cli/ignite/pkg/chaincmd/runner" diff --git a/ignite/services/chain/serve.go b/ignite/services/chain/serve.go index 55a589e87a..7d4b351c83 100644 --- a/ignite/services/chain/serve.go +++ b/ignite/services/chain/serve.go @@ -15,6 +15,7 @@ import ( "golang.org/x/sync/errgroup" "github.com/ignite-hq/cli/ignite/chainconfig" + "github.com/ignite-hq/cli/ignite/pkg/cache" chaincmdrunner "github.com/ignite-hq/cli/ignite/pkg/chaincmd/runner" "github.com/ignite-hq/cli/ignite/pkg/cosmosfaucet" "github.com/ignite-hq/cli/ignite/pkg/dirchange" @@ -29,14 +30,17 @@ const ( // exportedGenesis is the name of the exported genesis file for a chain exportedGenesis = "exported_genesis.json" - // sourceChecksum is the file containing the checksum to detect source modification - sourceChecksum = "source_checksum.txt" + // sourceChecksumKey is the cache key for the checksum to detect source modification + sourceChecksumKey = "source_checksum" - // binaryChecksum is the file containing the checksum to detect binary modification - binaryChecksum = "binary_checksum.txt" + // binaryChecksumKey is the cache key for the checksum to detect binary modification + binaryChecksumKey = "binary_checksum" - // configChecksum is the file containing the checksum to detect config modification - configChecksum = "config_checksum.txt" + // configChecksumKey is the cache key for containing the checksum to detect config modification + configChecksumKey = "config_checksum" + + // serveDirchangeCacheNamespace is the name of the cache namespace for detecting changes in directories + serveDirchangeCacheNamespace = "serve.dirchange" ) var ( @@ -80,7 +84,7 @@ func ServeResetOnce() ServeOption { } // Serve serves an app. -func (c *Chain) Serve(ctx context.Context, options ...ServeOption) error { +func (c *Chain) Serve(ctx context.Context, cacheStorage cache.Storage, options ...ServeOption) error { serveOptions := newServeOption() // apply the options @@ -134,7 +138,7 @@ func (c *Chain) Serve(ctx context.Context, options ...ServeOption) error { shouldReset := serveOptions.forceReset || serveOptions.resetOnce // serve the app. - err = c.serve(serveCtx, shouldReset) + err = c.serve(serveCtx, cacheStorage, shouldReset) serveOptions.resetOnce = false switch { @@ -235,6 +239,7 @@ func (c *Chain) watchAppBackend(ctx context.Context) error { localfs.WatcherWorkdir(c.app.Path), localfs.WatcherOnChange(c.refreshServe), localfs.WatcherIgnoreHidden(), + localfs.WatcherIgnoreFolders(), localfs.WatcherIgnoreExt(ignoredExts...), ) } @@ -242,7 +247,7 @@ func (c *Chain) watchAppBackend(ctx context.Context) error { // serve performs the operations to serve the blockchain: build, init and start // if the chain is already initialized and the file didn't changed, the app is directly started // if the files changed, the state is imported -func (c *Chain) serve(ctx context.Context, forceReset bool) error { +func (c *Chain) serve(ctx context.Context, cacheStorage cache.Storage, forceReset bool) error { conf, err := c.Config() if err != nil { return &CannotBuildAppError{err} @@ -253,14 +258,11 @@ func (c *Chain) serve(ctx context.Context, forceReset bool) error { return err } - saveDir, err := c.chainSavePath() - if err != nil { - return err - } - // isInit determines if the app is initialized var isInit bool + dirCache := cache.New[[]byte](cacheStorage, serveDirchangeCacheNamespace) + // determine if the app must reset the state // if the state must be reset, then we consider the chain as being not initialized isInit, err = c.IsInitialized() @@ -270,7 +272,7 @@ func (c *Chain) serve(ctx context.Context, forceReset bool) error { if isInit { configModified := false if c.ConfigPath() != "" { - configModified, err = dirchange.HasDirChecksumChanged(c.app.Path, []string{c.ConfigPath()}, saveDir, configChecksum) + configModified, err = dirchange.HasDirChecksumChanged(dirCache, configChecksumKey, c.app.Path, c.ConfigPath()) if err != nil { return err } @@ -285,7 +287,7 @@ func (c *Chain) serve(ctx context.Context, forceReset bool) error { // check if source has been modified since last serve // if the state must not be reset but the source has changed, we rebuild the chain and import the exported state - sourceModified, err := dirchange.HasDirChecksumChanged(c.app.Path, appBackendSourceWatchPaths, saveDir, sourceChecksum) + sourceModified, err := dirchange.HasDirChecksumChanged(dirCache, sourceChecksumKey, c.app.Path, appBackendSourceWatchPaths...) if err != nil { return err } @@ -303,7 +305,7 @@ func (c *Chain) serve(ctx context.Context, forceReset bool) error { } binaryModified = true } else { - binaryModified, err = dirchange.HasDirChecksumChanged("", []string{binaryPath}, saveDir, binaryChecksum) + binaryModified, err = dirchange.HasDirChecksumChanged(dirCache, binaryChecksumKey, "", binaryPath) if err != nil { return err } @@ -326,7 +328,7 @@ func (c *Chain) serve(ctx context.Context, forceReset bool) error { // build phase if !isInit || appModified { // build the blockchain app - if err := c.build(ctx, ""); err != nil { + if err := c.build(ctx, cacheStorage, ""); err != nil { return err } } @@ -357,18 +359,18 @@ func (c *Chain) serve(ctx context.Context, forceReset bool) error { // save checksums if c.ConfigPath() != "" { - if err := dirchange.SaveDirChecksum(c.app.Path, []string{c.ConfigPath()}, saveDir, configChecksum); err != nil { + if err := dirchange.SaveDirChecksum(dirCache, configChecksumKey, c.app.Path, c.ConfigPath()); err != nil { return err } } - if err := dirchange.SaveDirChecksum(c.app.Path, appBackendSourceWatchPaths, saveDir, sourceChecksum); err != nil { + if err := dirchange.SaveDirChecksum(dirCache, sourceChecksumKey, c.app.Path, appBackendSourceWatchPaths...); err != nil { return err } binaryPath, err = exec.LookPath(binaryName) if err != nil { return err } - if err := dirchange.SaveDirChecksum("", []string{binaryPath}, saveDir, binaryChecksum); err != nil { + if err := dirchange.SaveDirChecksum(dirCache, binaryChecksumKey, "", binaryPath); err != nil { return err } diff --git a/ignite/services/network/client.go b/ignite/services/network/client.go index 7f1d2847bb..25e36a8565 100644 --- a/ignite/services/network/client.go +++ b/ignite/services/network/client.go @@ -8,15 +8,16 @@ import ( func (n Network) CreateClient( launchID uint64, - ibcInfo IBCInfo, + unbondingTime int64, + rewardsInfo networktypes.Reward, ) (string, error) { msgCreateClient := monitoringctypes.NewMsgCreateClient( n.account.Address(networktypes.SPN), launchID, - ibcInfo.ConsensusState, - ibcInfo.ValidatorSet, - ibcInfo.UnbondingTime, - ibcInfo.Height, + rewardsInfo.ConsensusState, + rewardsInfo.ValidatorSet, + unbondingTime, + rewardsInfo.RevisionHeight, ) res, err := n.cosmos.BroadcastTx(n.account.Name, msgCreateClient) diff --git a/ignite/services/network/join.go b/ignite/services/network/join.go index 4c094f43da..47e15bcb87 100644 --- a/ignite/services/network/join.go +++ b/ignite/services/network/join.go @@ -104,7 +104,7 @@ func (n Network) Join( } if !o.accountAmount.IsZero() { - if err := n.sendAccountRequest( + if err := n.ensureAccount( ctx, genesisPath, isCustomGentx, @@ -119,8 +119,8 @@ func (n Network) Join( return n.sendValidatorRequest(ctx, launchID, peer, accountAddress, gentx, gentxInfo) } -// sendAccountRequest creates an add AddAccount request message. -func (n Network) sendAccountRequest( +// ensureAccount creates an add AddAccount request message. +func (n Network) ensureAccount( ctx context.Context, genesisPath string, isCustomGentx bool, @@ -150,33 +150,7 @@ func (n Network) sendAccountRequest( return fmt.Errorf("account %s already exist", address) } - msg := launchtypes.NewMsgRequestAddAccount( - n.account.Address(networktypes.SPN), - launchID, - address, - amount, - ) - - n.ev.Send(events.New(events.StatusOngoing, "Broadcasting account transactions")) - res, err := n.cosmos.BroadcastTx(n.account.Name, msg) - if err != nil { - return err - } - - var requestRes launchtypes.MsgRequestAddAccountResponse - if err := res.Decode(&requestRes); err != nil { - return err - } - - if requestRes.AutoApproved { - n.ev.Send(events.New(events.StatusDone, "Account added to the network by the coordinator!")) - } else { - n.ev.Send(events.New(events.StatusDone, - fmt.Sprintf("Request %d to add account to the network has been submitted!", - requestRes.RequestID), - )) - } - return nil + return n.sendAccountRequest(launchID, address, amount) } // sendValidatorRequest creates the RequestAddValidator message into the SPN diff --git a/ignite/services/network/mocks/account_info.go b/ignite/services/network/mocks/account_info.go index ddb063d1fd..d411c7da13 100644 --- a/ignite/services/network/mocks/account_info.go +++ b/ignite/services/network/mocks/account_info.go @@ -1,10 +1,8 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.12.3. DO NOT EDIT. package mocks import ( - "testing" - "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -114,8 +112,13 @@ func (_m *AccountInfo) GetType() keyring.KeyType { return r0 } -// NewAccountInfo creates a new instance of AccountInfo. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewAccountInfo(t testing.TB) *AccountInfo { +type NewAccountInfoT interface { + mock.TestingT + Cleanup(func()) +} + +// 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. +func NewAccountInfo(t NewAccountInfoT) *AccountInfo { mock := &AccountInfo{} mock.Mock.Test(t) diff --git a/ignite/services/network/mocks/campaign_client.go b/ignite/services/network/mocks/campaign_client.go index a482fe88f4..21ffada677 100644 --- a/ignite/services/network/mocks/campaign_client.go +++ b/ignite/services/network/mocks/campaign_client.go @@ -1,10 +1,9 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.12.3. DO NOT EDIT. package mocks import ( "context" - "testing" "github.com/stretchr/testify/mock" "github.com/tendermint/spn/x/campaign/types" @@ -256,6 +255,66 @@ func (_m *CampaignClient) MainnetAccountAll(ctx context.Context, in *types.Query return r0, r1 } +// MainnetAccountBalance provides a mock function with given fields: ctx, in, opts +func (_m *CampaignClient) MainnetAccountBalance(ctx context.Context, in *types.QueryGetMainnetAccountBalanceRequest, opts ...grpc.CallOption) (*types.QueryGetMainnetAccountBalanceResponse, 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...) + + var r0 *types.QueryGetMainnetAccountBalanceResponse + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryGetMainnetAccountBalanceRequest, ...grpc.CallOption) *types.QueryGetMainnetAccountBalanceResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryGetMainnetAccountBalanceResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryGetMainnetAccountBalanceRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MainnetAccountBalanceAll provides a mock function with given fields: ctx, in, opts +func (_m *CampaignClient) MainnetAccountBalanceAll(ctx context.Context, in *types.QueryAllMainnetAccountBalanceRequest, opts ...grpc.CallOption) (*types.QueryAllMainnetAccountBalanceResponse, 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...) + + var r0 *types.QueryAllMainnetAccountBalanceResponse + if rf, ok := ret.Get(0).(func(context.Context, *types.QueryAllMainnetAccountBalanceRequest, ...grpc.CallOption) *types.QueryAllMainnetAccountBalanceResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.QueryAllMainnetAccountBalanceResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *types.QueryAllMainnetAccountBalanceRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // MainnetVestingAccount provides a mock function with given fields: ctx, in, opts func (_m *CampaignClient) MainnetVestingAccount(ctx context.Context, in *types.QueryGetMainnetVestingAccountRequest, opts ...grpc.CallOption) (*types.QueryGetMainnetVestingAccountResponse, error) { _va := make([]interface{}, len(opts)) @@ -346,6 +405,36 @@ func (_m *CampaignClient) Params(ctx context.Context, in *types.QueryParamsReque return r0, r1 } +// SpecialAllocationsBalance provides a mock function with given fields: ctx, in, opts +func (_m *CampaignClient) 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...) + + var r0 *types.QuerySpecialAllocationsBalanceResponse + 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) + } + } + + var r1 error + 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 +} + // TotalShares provides a mock function with given fields: ctx, in, opts func (_m *CampaignClient) TotalShares(ctx context.Context, in *types.QueryTotalSharesRequest, opts ...grpc.CallOption) (*types.QueryTotalSharesResponse, error) { _va := make([]interface{}, len(opts)) @@ -376,8 +465,13 @@ func (_m *CampaignClient) TotalShares(ctx context.Context, in *types.QueryTotalS return r0, r1 } -// NewCampaignClient creates a new instance of CampaignClient. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewCampaignClient(t testing.TB) *CampaignClient { +type NewCampaignClientT interface { + mock.TestingT + Cleanup(func()) +} + +// NewCampaignClient creates a new instance of CampaignClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewCampaignClient(t NewCampaignClientT) *CampaignClient { mock := &CampaignClient{} mock.Mock.Test(t) diff --git a/ignite/services/network/mocks/launch_client.go b/ignite/services/network/mocks/launch_client.go index cc9a174f8e..847d9bf83d 100644 --- a/ignite/services/network/mocks/launch_client.go +++ b/ignite/services/network/mocks/launch_client.go @@ -1,10 +1,9 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.12.3. DO NOT EDIT. package mocks import ( "context" - "testing" "github.com/stretchr/testify/mock" "github.com/tendermint/spn/x/launch/types" @@ -346,8 +345,13 @@ func (_m *LaunchClient) VestingAccountAll(ctx context.Context, in *types.QueryAl return r0, r1 } -// NewLaunchClient creates a new instance of LaunchClient. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewLaunchClient(t testing.TB) *LaunchClient { +type NewLaunchClientT interface { + mock.TestingT + Cleanup(func()) +} + +// 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. +func NewLaunchClient(t NewLaunchClientT) *LaunchClient { mock := &LaunchClient{} mock.Mock.Test(t) diff --git a/ignite/services/network/mocks/profile_client.go b/ignite/services/network/mocks/profile_client.go index b2b3eb96c1..b61ea09818 100644 --- a/ignite/services/network/mocks/profile_client.go +++ b/ignite/services/network/mocks/profile_client.go @@ -1,10 +1,9 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.12.3. DO NOT EDIT. package mocks import ( "context" - "testing" "github.com/stretchr/testify/mock" "github.com/tendermint/spn/x/profile/types" @@ -196,8 +195,13 @@ func (_m *ProfileClient) ValidatorByOperatorAddress(ctx context.Context, in *typ return r0, r1 } -// NewProfileClient creates a new instance of ProfileClient. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewProfileClient(t testing.TB) *ProfileClient { +type NewProfileClientT interface { + mock.TestingT + Cleanup(func()) +} + +// 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. +func NewProfileClient(t NewProfileClientT) *ProfileClient { mock := &ProfileClient{} mock.Mock.Test(t) diff --git a/ignite/services/network/mocks/reward_client.go b/ignite/services/network/mocks/reward_client.go index 1169d355cd..193fc96453 100644 --- a/ignite/services/network/mocks/reward_client.go +++ b/ignite/services/network/mocks/reward_client.go @@ -1,10 +1,9 @@ -// Code generated by mockery v2.12.2. DO NOT EDIT. +// Code generated by mockery v2.12.3. DO NOT EDIT. package mocks import ( "context" - "testing" "github.com/stretchr/testify/mock" "github.com/tendermint/spn/x/reward/types" @@ -106,8 +105,13 @@ func (_m *RewardClient) RewardPoolAll(ctx context.Context, in *types.QueryAllRew return r0, r1 } -// NewRewardClient creates a new instance of RewardClient. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. -func NewRewardClient(t testing.TB) *RewardClient { +type NewRewardClientT interface { + mock.TestingT + Cleanup(func()) +} + +// 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. +func NewRewardClient(t NewRewardClientT) *RewardClient { mock := &RewardClient{} mock.Mock.Test(t) diff --git a/ignite/services/network/network.go b/ignite/services/network/network.go index db2b11e2df..ad17598739 100644 --- a/ignite/services/network/network.go +++ b/ignite/services/network/network.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" sdktypes "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/pkg/errors" campaigntypes "github.com/tendermint/spn/x/campaign/types" launchtypes "github.com/tendermint/spn/x/launch/types" @@ -38,6 +39,7 @@ type Network struct { launchQuery launchtypes.QueryClient profileQuery profiletypes.QueryClient rewardQuery rewardtypes.QueryClient + stakingQuery stakingtypes.QueryClient } //go:generate mockery --name Chain --case underscore @@ -83,6 +85,12 @@ func WithRewardQueryClient(client rewardtypes.QueryClient) Option { } } +func WithStakingQueryClient(client stakingtypes.QueryClient) Option { + return func(n *Network) { + n.stakingQuery = client + } +} + // CollectEvents collects events from the network builder. func CollectEvents(ev events.Bus) Option { return func(n *Network) { @@ -99,6 +107,7 @@ func New(cosmos CosmosClient, account cosmosaccount.Account, options ...Option) launchQuery: launchtypes.NewQueryClient(cosmos.Context()), profileQuery: profiletypes.NewQueryClient(cosmos.Context()), rewardQuery: rewardtypes.NewQueryClient(cosmos.Context()), + stakingQuery: stakingtypes.NewQueryClient(cosmos.Context()), } for _, opt := range options { opt(&n) diff --git a/ignite/services/network/network_test.go b/ignite/services/network/network_test.go index 04b03a3108..74c7a0e883 100644 --- a/ignite/services/network/network_test.go +++ b/ignite/services/network/network_test.go @@ -19,6 +19,7 @@ func newSuite(account cosmosaccount.Account) (testutil.Suite, Network) { WithLaunchQueryClient(suite.LaunchQueryMock), WithProfileQueryClient(suite.ProfileQueryMock), WithRewardQueryClient(suite.RewardClient), + WithStakingQueryClient(suite.StakingClient), ) } @@ -63,3 +64,9 @@ func TestParseID(t *testing.T) { }) } } + +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/ignite/services/network/networkchain/init.go b/ignite/services/network/networkchain/init.go index 82d895029f..36a648107d 100644 --- a/ignite/services/network/networkchain/init.go +++ b/ignite/services/network/networkchain/init.go @@ -5,13 +5,14 @@ import ( "fmt" "os" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cosmosutil" "github.com/ignite-hq/cli/ignite/pkg/events" ) // Init initializes blockchain by building the binaries and running the init command and // create the initial genesis of the chain, and set up a validator key -func (c *Chain) Init(ctx context.Context) error { +func (c *Chain) Init(ctx context.Context, cacheStorage cache.Storage) error { chainHome, err := c.chain.Home() if err != nil { return err @@ -23,7 +24,7 @@ func (c *Chain) Init(ctx context.Context) error { } // build the chain and initialize it with a new validator key - if _, err := c.Build(ctx); err != nil { + if _, err := c.Build(ctx, cacheStorage); err != nil { return err } diff --git a/ignite/services/network/networkchain/networkchain.go b/ignite/services/network/networkchain/networkchain.go index 29ea288162..c45930695e 100644 --- a/ignite/services/network/networkchain/networkchain.go +++ b/ignite/services/network/networkchain/networkchain.go @@ -10,6 +10,7 @@ import ( "github.com/go-git/go-git/v5/plumbing" sperrors "github.com/ignite-hq/cli/ignite/errors" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/chaincmd" "github.com/ignite-hq/cli/ignite/pkg/checksum" "github.com/ignite-hq/cli/ignite/pkg/cosmosaccount" @@ -253,7 +254,7 @@ func (c Chain) NodeID(ctx context.Context) (string, error) { } // Build builds chain sources, also checks if source was already built -func (c *Chain) Build(ctx context.Context) (binaryName string, err error) { +func (c *Chain) Build(ctx context.Context, cacheStorage cache.Storage) (binaryName string, err error) { // if chain was already published and has launch id check binary cache if c.launchID != 0 { if binaryName, err = c.chain.Binary(); err != nil { @@ -275,7 +276,7 @@ func (c *Chain) Build(ctx context.Context) (binaryName string, err error) { c.ev.Send(events.New(events.StatusOngoing, "Building the chain's binary")) // build binary - if binaryName, err = c.chain.Build(ctx, ""); err != nil { + if binaryName, err = c.chain.Build(ctx, cacheStorage, ""); err != nil { return "", err } diff --git a/ignite/services/network/networkchain/prepare.go b/ignite/services/network/networkchain/prepare.go index 2730afbed9..97072abe27 100644 --- a/ignite/services/network/networkchain/prepare.go +++ b/ignite/services/network/networkchain/prepare.go @@ -13,6 +13,7 @@ import ( "github.com/pkg/errors" launchtypes "github.com/tendermint/spn/x/launch/types" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cosmosutil" "github.com/ignite-hq/cli/ignite/pkg/events" "github.com/ignite-hq/cli/ignite/services/network/networktypes" @@ -25,14 +26,26 @@ func (c Chain) ResetGenesisTime() error { if err != nil { return errors.Wrap(err, "genesis of the blockchain can't be read") } - if err := cosmosutil.SetGenesisTime(genesisPath, 0); err != nil { + + if err := cosmosutil.UpdateGenesis( + genesisPath, + cosmosutil.WithKeyValueTimestamp(cosmosutil.FieldGenesisTime, 0), + ); err != nil { return errors.Wrap(err, "genesis time can't be set") } return nil } // Prepare prepares the chain to be launched from genesis information -func (c Chain) Prepare(ctx context.Context, gi networktypes.GenesisInformation) error { +func (c Chain) Prepare( + ctx context.Context, + cacheStorage cache.Storage, + gi networktypes.GenesisInformation, + rewardsInfo networktypes.Reward, + chainID string, + lastBlockHeight, + unbondingTime int64, +) error { // chain initialization genesisPath, err := c.chain.GenesisPath() if err != nil { @@ -44,14 +57,14 @@ func (c Chain) Prepare(ctx context.Context, gi networktypes.GenesisInformation) 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); err != nil { + 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); err != nil { + if _, err := c.Build(ctx, cacheStorage); err != nil { return err } @@ -60,7 +73,14 @@ func (c Chain) Prepare(ctx context.Context, gi networktypes.GenesisInformation) } } - if err := c.buildGenesis(ctx, gi); err != nil { + if err := c.buildGenesis( + ctx, + gi, + rewardsInfo, + chainID, + lastBlockHeight, + unbondingTime, + ); err != nil { return err } @@ -83,7 +103,14 @@ func (c Chain) Prepare(ctx context.Context, gi networktypes.GenesisInformation) } // buildGenesis builds the genesis for the chain from the launch approved requests -func (c Chain) buildGenesis(ctx context.Context, gi networktypes.GenesisInformation) error { +func (c Chain) buildGenesis( + ctx context.Context, + gi networktypes.GenesisInformation, + rewardsInfo networktypes.Reward, + spnChainID string, + lastBlockHeight, + unbondingTime int64, +) error { c.ev.Send(events.New(events.StatusOngoing, "Building the genesis")) addressPrefix, err := c.detectPrefix(ctx) @@ -107,12 +134,21 @@ func (c Chain) buildGenesis(ctx context.Context, gi networktypes.GenesisInformat return errors.Wrap(err, "genesis of the blockchain can't be read") } - // set chain id - if err := cosmosutil.SetChainID(genesisPath, c.id); err != nil { - return errors.Wrap(err, "chain id cannot be set") - } - // set the genesis time for the chain - if err := cosmosutil.SetGenesisTime(genesisPath, c.launchTime); err != nil { + // update genesis + if err := cosmosutil.UpdateGenesis( + genesisPath, + // set genesis time and chain id + cosmosutil.WithKeyValue(cosmosutil.FieldChainID, c.id), + cosmosutil.WithKeyValueTimestamp(cosmosutil.FieldGenesisTime, c.launchTime), + // set the network consensus parameters + cosmosutil.WithKeyValue(cosmosutil.FieldConsumerChainID, spnChainID), + cosmosutil.WithKeyValueInt(cosmosutil.FieldLastBlockHeight, lastBlockHeight), + cosmosutil.WithKeyValue(cosmosutil.FieldConsensusTimestamp, rewardsInfo.ConsensusState.Timestamp), + cosmosutil.WithKeyValue(cosmosutil.FieldConsensusNextValidatorsHash, rewardsInfo.ConsensusState.NextValidatorsHash), + cosmosutil.WithKeyValue(cosmosutil.FieldConsensusRootHash, rewardsInfo.ConsensusState.Root.Hash), + cosmosutil.WithKeyValueInt(cosmosutil.FieldConsumerUnbondingPeriod, unbondingTime), + cosmosutil.WithKeyValueUint(cosmosutil.FieldConsumerRevisionHeight, rewardsInfo.RevisionHeight), + ); err != nil { return errors.Wrap(err, "genesis time can't be set") } diff --git a/ignite/services/network/networkchain/simulate.go b/ignite/services/network/networkchain/simulate.go index b9f4b2d932..41edd438e0 100644 --- a/ignite/services/network/networkchain/simulate.go +++ b/ignite/services/network/networkchain/simulate.go @@ -12,6 +12,7 @@ import ( "github.com/pkg/errors" "github.com/ignite-hq/cli/ignite/pkg/availableport" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/events" "github.com/ignite-hq/cli/ignite/pkg/httpstatuschecker" "github.com/ignite-hq/cli/ignite/pkg/xurl" @@ -24,7 +25,12 @@ const ( ) // SimulateRequests simulates the genesis creation and the start of the network from the provided requests -func (c Chain) SimulateRequests(ctx context.Context, gi networktypes.GenesisInformation, reqs []networktypes.Request) (err error) { +func (c Chain) SimulateRequests( + ctx context.Context, + cacheStorage cache.Storage, + gi networktypes.GenesisInformation, + reqs []networktypes.Request, +) (err error) { c.ev.Send(events.New(events.StatusOngoing, "Verifying requests format")) for _, req := range reqs { // static verification of the request @@ -41,7 +47,15 @@ func (c Chain) SimulateRequests(ctx context.Context, gi networktypes.GenesisInfo c.ev.Send(events.New(events.StatusDone, "Requests format verified")) // prepare the chain with the requests - if err := c.Prepare(ctx, gi); err != nil { + if err := c.Prepare( + ctx, + cacheStorage, + gi, + networktypes.Reward{RevisionHeight: 1}, + networktypes.SPNChainID, + 1, + 2, + ); err != nil { return err } diff --git a/ignite/services/network/networktypes/ibc.go b/ignite/services/network/networktypes/ibc.go new file mode 100644 index 0000000000..379c34a266 --- /dev/null +++ b/ignite/services/network/networktypes/ibc.go @@ -0,0 +1,12 @@ +package networktypes + +import ( + spntypes "github.com/tendermint/spn/pkg/types" +) + +// Reward is node reward info. +type Reward struct { + ConsensusState spntypes.ConsensusState + ValidatorSet spntypes.ValidatorSet + RevisionHeight uint64 +} diff --git a/ignite/services/network/networktypes/networktypes.go b/ignite/services/network/networktypes/networktypes.go index bf43726ce4..19187885d8 100644 --- a/ignite/services/network/networktypes/networktypes.go +++ b/ignite/services/network/networktypes/networktypes.go @@ -1,6 +1,9 @@ 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" diff --git a/ignite/services/network/node.go b/ignite/services/network/node.go index 87ca822b00..f249461906 100644 --- a/ignite/services/network/node.go +++ b/ignite/services/network/node.go @@ -6,6 +6,8 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" spntypes "github.com/tendermint/spn/pkg/types" + + "github.com/ignite-hq/cli/ignite/services/network/networktypes" ) // Node is node builder. @@ -14,14 +16,6 @@ type Node struct { stakingQuery stakingtypes.QueryClient } -// IBCInfo is node client info. -type IBCInfo struct { - ConsensusState spntypes.ConsensusState - ValidatorSet spntypes.ValidatorSet - UnbondingTime int64 - Height uint64 -} - func NewNodeClient(cosmos CosmosClient) (Node, error) { return Node{ cosmos: cosmos, @@ -29,19 +23,13 @@ func NewNodeClient(cosmos CosmosClient) (Node, error) { }, nil } -// IBCInfo Fetches the consensus state, validator set and the staking parameters -func (n Node) IBCInfo(ctx context.Context) (IBCInfo, error) { - status, err := n.cosmos.Status(ctx) +// RewardsInfo Fetches the consensus state with the validator set +func RewardsInfo(ctx context.Context, client CosmosClient, height int64) (networktypes.Reward, error) { + consensusState, err := client.ConsensusInfo(ctx, height) if err != nil { - return IBCInfo{}, err + return networktypes.Reward{}, err } - lastBlockHeight := status.SyncInfo.LatestBlockHeight - - consensusState, err := n.cosmos.ConsensusInfo(ctx, lastBlockHeight) - if err != nil { - return IBCInfo{}, err - } - spnConsensusStatue := spntypes.NewConsensusState( + spnConsensusState := spntypes.NewConsensusState( consensusState.Timestamp, consensusState.NextValidatorsHash, consensusState.Root, @@ -56,16 +44,10 @@ func (n Node) IBCInfo(ctx context.Context) (IBCInfo, error) { ) } - stakingParams, err := n.StakingParams(ctx) - if err != nil { - return IBCInfo{}, err - } - - return IBCInfo{ - ConsensusState: spnConsensusStatue, + return networktypes.Reward{ + ConsensusState: spnConsensusState, ValidatorSet: spntypes.NewValidatorSet(validators...), - UnbondingTime: int64(stakingParams.UnbondingTime.Seconds()), - Height: uint64(lastBlockHeight), + RevisionHeight: uint64(height), }, nil } @@ -77,3 +59,23 @@ func (n Node) StakingParams(ctx context.Context) (stakingtypes.Params, error) { } return res.Params, nil } + +// RewardsInfo Fetches the consensus state with the validator set and the unbounding time +func (n Node) RewardsInfo(ctx context.Context) (networktypes.Reward, int64, error) { + status, err := n.cosmos.Status(ctx) + if err != nil { + return networktypes.Reward{}, 0, err + } + lastBlockHeight := status.SyncInfo.LatestBlockHeight + + info, err := RewardsInfo(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, int64(stakingParams.UnbondingTime.Seconds()), nil +} diff --git a/ignite/services/network/publish.go b/ignite/services/network/publish.go index 926bc56e7f..345cec8f83 100644 --- a/ignite/services/network/publish.go +++ b/ignite/services/network/publish.go @@ -2,6 +2,7 @@ package network import ( "context" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" campaigntypes "github.com/tendermint/spn/x/campaign/types" @@ -16,14 +17,14 @@ import ( // publishOptions holds info about how to create a chain. type publishOptions struct { - genesisURL string - chainID string - campaignID uint64 - noCheck bool - metadata string - totalSupply sdk.Coins - shares campaigntypes.Shares - mainnet bool + genesisURL string + chainID string + campaignID uint64 + noCheck bool + metadata string + totalSupply sdk.Coins + sharePercentages SharePercents + mainnet bool } // PublishOption configures chain creation. @@ -71,10 +72,10 @@ func WithTotalSupply(totalSupply sdk.Coins) PublishOption { } } -// WithShares enables minting vouchers for shares. -func WithShares(shares campaigntypes.Shares) PublishOption { +// WithPercentageShares enables minting vouchers for shares. +func WithPercentageShares(sharePercentages []SharePercent) PublishOption { return func(c *publishOptions) { - c.shares = shares + c.sharePercentages = sharePercentages } } @@ -86,7 +87,7 @@ func Mainnet() PublishOption { } // Publish submits Genesis to SPN to announce a new network. -func (n Network) Publish(ctx context.Context, c Chain, options ...PublishOption) (launchID, campaignID, mainnetID uint64, err error) { +func (n Network) Publish(ctx context.Context, c Chain, options ...PublishOption) (launchID, campaignID uint64, err error) { o := publishOptions{} for _, apply := range options { apply(&o) @@ -102,11 +103,11 @@ func (n Network) Publish(ctx context.Context, c Chain, options ...PublishOption) if o.genesisURL != "" { genesisFile, genesisHash, err = cosmosutil.GenesisAndHashFromURL(ctx, o.genesisURL) if err != nil { - return 0, 0, 0, err + return 0, 0, err } genesis, err = cosmosutil.ParseChainGenesis(genesisFile) if err != nil { - return 0, 0, 0, err + return 0, 0, err } } @@ -119,7 +120,7 @@ func (n Network) Publish(ctx context.Context, c Chain, options ...PublishOption) if chainID == "" { chainID, err = c.ChainID() if err != nil { - return 0, 0, 0, err + return 0, 0, err } } @@ -140,10 +141,10 @@ func (n Network) Publish(ctx context.Context, c Chain, options ...PublishOption) "", ) if _, err := n.cosmos.BroadcastTx(n.account.Name, msgCreateCoordinator); err != nil { - return 0, 0, 0, err + return 0, 0, err } } else if err != nil { - return 0, 0, 0, err + return 0, 0, err } if campaignID != 0 { @@ -152,61 +153,114 @@ func (n Network) Publish(ctx context.Context, c Chain, options ...PublishOption) CampaignID: o.campaignID, }) if err != nil { - return 0, 0, 0, err + return 0, 0, err } } else { campaignID, err = n.CreateCampaign(c.Name(), o.metadata, o.totalSupply) if err != nil { - return 0, 0, 0, err + return 0, 0, err } } - msgCreateChain := launchtypes.NewMsgCreateChain( - n.account.Address(networktypes.SPN), - chainID, - c.SourceURL(), - c.SourceHash(), - o.genesisURL, - genesisHash, - true, - campaignID, - nil, - ) - - msgs := []sdk.Msg{msgCreateChain} + // mint vouchers + if !o.sharePercentages.Empty() { + totalSharesResp, err := n.campaignQuery.TotalShares(ctx, &campaigntypes.QueryTotalSharesRequest{}) + if err != nil { + return 0, 0, err + } - if !o.shares.Empty() { + 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 UpdateCampaign, 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. msgMintVouchers := campaigntypes.NewMsgMintVouchers( n.account.Address(networktypes.SPN), campaignID, - o.shares, + campaigntypes.NewSharesFromCoins(sdk.NewCoins(coins...)), ) - msgs = append(msgs, msgMintVouchers) + _, err = n.cosmos.BroadcastTx(n.account.Name, msgMintVouchers) + if err != nil { + return 0, 0, err + } } - res, err := n.cosmos.BroadcastTx(n.account.Name, msgs...) - if err != nil { - return 0, 0, 0, err + // depending on mainnet flag initialize mainnet or testnet + if o.mainnet { + launchID, err = n.InitializeMainnet(campaignID, c.SourceURL(), c.SourceHash(), chainID) + if err != nil { + return 0, 0, err + } + } else { + msgCreateChain := launchtypes.NewMsgCreateChain( + n.account.Address(networktypes.SPN), + chainID, + c.SourceURL(), + c.SourceHash(), + o.genesisURL, + genesisHash, + true, + campaignID, + nil, + ) + res, err := n.cosmos.BroadcastTx(n.account.Name, 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 } - - var createChainRes launchtypes.MsgCreateChainResponse - if err := res.Decode(&createChainRes); err != nil { - return 0, 0, 0, err + if err := c.CacheBinary(launchID); err != nil { + return 0, 0, err } - if err := c.CacheBinary(createChainRes.LaunchID); err != nil { - return 0, 0, 0, err + return launchID, campaignID, nil +} + +func (n Network) SendAccountRequestForCoordinator(launchID uint64, amount sdk.Coins) error { + return n.sendAccountRequest(launchID, n.account.Address(networktypes.SPN), amount) +} + +// SendAccountRequest creates an add AddAccount request message. +func (n Network) sendAccountRequest( + launchID uint64, + address string, + amount sdk.Coins, +) error { + msg := launchtypes.NewMsgRequestAddAccount( + n.account.Address(networktypes.SPN), + launchID, + address, + amount, + ) + + n.ev.Send(events.New(events.StatusOngoing, "Broadcasting account transactions")) + res, err := n.cosmos.BroadcastTx(n.account.Name, msg) + if err != nil { + return err + } + var requestRes launchtypes.MsgRequestAddAccountResponse + if err := res.Decode(&requestRes); err != nil { + return err } - if o.mainnet { - mainnetID, err = n.InitializeMainnet(campaignID, c.SourceURL(), c.SourceHash(), chainID) - if err != nil { - return 0, 0, 0, err - } + if requestRes.AutoApproved { + n.ev.Send(events.New(events.StatusDone, "Account added to the network by the coordinator!")) + } else { + n.ev.Send(events.New(events.StatusDone, + fmt.Sprintf("Request %d to add account to the network has been submitted!", + requestRes.RequestID), + )) } - return createChainRes.LaunchID, campaignID, mainnetID, nil + return nil } diff --git a/ignite/services/network/publish_test.go b/ignite/services/network/publish_test.go index 58bffae1b2..d2536ed869 100644 --- a/ignite/services/network/publish_test.go +++ b/ignite/services/network/publish_test.go @@ -8,6 +8,7 @@ import ( "net/http/httptest" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" campaigntypes "github.com/tendermint/spn/x/campaign/types" @@ -89,7 +90,7 @@ func TestPublish(t *testing.T) { suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() - launchID, campaignID, _, publishError := network.Publish(context.Background(), suite.ChainMock) + launchID, campaignID, publishError := network.Publish(context.Background(), suite.ChainMock) require.NoError(t, publishError) require.Equal(t, testutil.LaunchID, launchID) require.Equal(t, testutil.CampaignID, campaignID) @@ -101,8 +102,6 @@ func TestPublish(t *testing.T) { account = testutil.NewTestAccount(t, testutil.TestAccountName) suite, network = newSuite(account) ) - shares, err := campaigntypes.NewShares("20foo,50staking") - require.NoError(t, err) suite.ProfileQueryMock. On( @@ -114,6 +113,28 @@ func TestPublish(t *testing.T) { ). Return(nil, nil). Once() + suite.CampaignQueryMock. + On( + "TotalShares", + context.Background(), + &campaigntypes.QueryTotalSharesRequest{}, + ). + Return(&campaigntypes.QueryTotalSharesResponse{ + TotalShares: 100000, + }, nil). + Once() + suite.CosmosClientMock. + On( + "BroadcastTx", + account.Name, + campaigntypes.NewMsgMintVouchers( + account.Address(networktypes.SPN), + testutil.CampaignID, + campaigntypes.NewSharesFromCoins(sdk.NewCoins(sdk.NewInt64Coin("foo", 2000), sdk.NewInt64Coin("staking", 50000))), + ), + ). + Return(testutil.NewResponse(&campaigntypes.MsgMintVouchersResponse{}), nil). + Once() suite.CosmosClientMock. On( "BroadcastTx", @@ -128,11 +149,6 @@ func TestPublish(t *testing.T) { HasCampaign: true, CampaignID: testutil.CampaignID, }, - campaigntypes.NewMsgMintVouchers( - account.Address(networktypes.SPN), - testutil.CampaignID, - shares, - ), ). Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ LaunchID: testutil.LaunchID, @@ -158,8 +174,11 @@ func TestPublish(t *testing.T) { suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() - launchID, campaignID, _, publishError := network.Publish(context.Background(), suite.ChainMock, - WithShares(shares), + launchID, campaignID, publishError := network.Publish(context.Background(), suite.ChainMock, + WithPercentageShares([]SharePercent{ + SampleSharePercent(t, "foo", 2, 100), + SampleSharePercent(t, "staking", 50, 100), + }), ) require.NoError(t, publishError) require.Equal(t, testutil.LaunchID, launchID) @@ -217,7 +236,7 @@ func TestPublish(t *testing.T) { suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() - launchID, campaignID, _, publishError := network.Publish(context.Background(), suite.ChainMock, WithCampaign(testutil.CampaignID)) + launchID, campaignID, publishError := network.Publish(context.Background(), suite.ChainMock, WithCampaign(testutil.CampaignID)) require.NoError(t, publishError) require.Equal(t, testutil.LaunchID, launchID) require.Equal(t, testutil.CampaignID, campaignID) @@ -282,7 +301,7 @@ func TestPublish(t *testing.T) { suite.ChainMock.On("Name").Return(testutil.ChainName).Once() suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() - launchID, campaignID, _, publishError := network.Publish(context.Background(), suite.ChainMock, WithCustomGenesis(gts.URL)) + launchID, campaignID, publishError := network.Publish(context.Background(), suite.ChainMock, WithCustomGenesis(gts.URL)) require.NoError(t, publishError) require.Equal(t, testutil.LaunchID, launchID) require.Equal(t, testutil.CampaignID, campaignID) @@ -343,7 +362,7 @@ func TestPublish(t *testing.T) { suite.ChainMock.On("Name").Return(testutil.ChainName).Once() suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() - launchID, campaignID, _, publishError := network.Publish(context.Background(), suite.ChainMock, WithChainID(testutil.ChainID)) + launchID, campaignID, publishError := network.Publish(context.Background(), suite.ChainMock, WithChainID(testutil.ChainID)) require.NoError(t, publishError) require.Equal(t, testutil.LaunchID, launchID) require.Equal(t, testutil.CampaignID, campaignID) @@ -369,25 +388,6 @@ func TestPublish(t *testing.T) { ). Return(nil, nil). Once() - suite.CosmosClientMock. - On( - "BroadcastTx", - account.Name, - &launchtypes.MsgCreateChain{ - Coordinator: account.Address(networktypes.SPN), - GenesisChainID: testutil.ChainID, - SourceURL: testutil.ChainSourceURL, - SourceHash: testutil.ChainSourceHash, - GenesisURL: "", - GenesisHash: "", - HasCampaign: true, - CampaignID: testutil.CampaignID, - }, - ). - Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ - LaunchID: testutil.LaunchID, - }), nil). - Once() suite.CosmosClientMock. On( "BroadcastTx", @@ -418,17 +418,16 @@ func TestPublish(t *testing.T) { MainnetID: testutil.MainnetID, }), nil). Once() - suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Times(2) - suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Times(2) + 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, campaignID, mainnetID, publishError := network.Publish(context.Background(), suite.ChainMock, Mainnet()) + launchID, campaignID, publishError := network.Publish(context.Background(), suite.ChainMock, Mainnet()) require.NoError(t, publishError) require.Equal(t, testutil.LaunchID, launchID) require.Equal(t, testutil.CampaignID, campaignID) - require.Equal(t, testutil.MainnetID, mainnetID) suite.AssertAllMocks(t) }) @@ -449,25 +448,6 @@ func TestPublish(t *testing.T) { ). Return(nil, nil). Once() - suite.CosmosClientMock. - On( - "BroadcastTx", - account.Name, - &launchtypes.MsgCreateChain{ - Coordinator: account.Address(networktypes.SPN), - GenesisChainID: testutil.ChainID, - SourceURL: testutil.ChainSourceURL, - SourceHash: testutil.ChainSourceHash, - GenesisURL: "", - GenesisHash: "", - HasCampaign: true, - CampaignID: testutil.CampaignID, - }, - ). - Return(testutil.NewResponse(&launchtypes.MsgCreateChainResponse{ - LaunchID: testutil.LaunchID, - }), nil). - Once() suite.CosmosClientMock. On( "BroadcastTx", @@ -498,13 +478,12 @@ func TestPublish(t *testing.T) { MainnetID: testutil.MainnetID, }), expectedError). Once() - suite.ChainMock.On("SourceHash").Return(testutil.ChainSourceHash).Times(2) - suite.ChainMock.On("SourceURL").Return(testutil.ChainSourceURL).Times(2) + 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() - _, _, _, publishError := network.Publish(context.Background(), suite.ChainMock, Mainnet()) + _, _, publishError := network.Publish(context.Background(), suite.ChainMock, Mainnet()) require.Error(t, publishError) require.Equal(t, expectedError, publishError) suite.AssertAllMocks(t) @@ -519,7 +498,7 @@ func TestPublish(t *testing.T) { ) defer gts.Close() - _, _, _, publishError := network.Publish(context.Background(), suite.ChainMock, WithCustomGenesis(gts.URL)) + _, _, publishError := network.Publish(context.Background(), suite.ChainMock, WithCustomGenesis(gts.URL)) require.Error(t, publishError) require.Equal(t, expectedError.Error(), publishError.Error()) suite.AssertAllMocks(t) @@ -586,7 +565,7 @@ func TestPublish(t *testing.T) { suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() suite.ChainMock.On("CacheBinary", testutil.LaunchID).Return(nil).Once() - launchID, campaignID, _, publishError := network.Publish(context.Background(), suite.ChainMock) + launchID, campaignID, publishError := network.Publish(context.Background(), suite.ChainMock) require.NoError(t, publishError) require.Equal(t, testutil.LaunchID, launchID) require.Equal(t, testutil.CampaignID, campaignID) @@ -608,7 +587,7 @@ func TestPublish(t *testing.T) { Once() suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() - _, _, _, publishError := network.Publish(context.Background(), suite.ChainMock) + _, _, publishError := network.Publish(context.Background(), suite.ChainMock) require.Error(t, publishError) require.Equal(t, expectedError, publishError) suite.AssertAllMocks(t) @@ -626,7 +605,7 @@ func TestPublish(t *testing.T) { Return("", expectedError). Once() - _, _, _, publishError := network.Publish(context.Background(), suite.ChainMock) + _, _, publishError := network.Publish(context.Background(), suite.ChainMock) require.Error(t, publishError) require.Equal(t, expectedError, publishError) suite.AssertAllMocks(t) @@ -656,7 +635,7 @@ func TestPublish(t *testing.T) { Once() suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() - _, _, _, publishError := network.Publish(context.Background(), suite.ChainMock, WithCampaign(testutil.CampaignID)) + _, _, publishError := network.Publish(context.Background(), suite.ChainMock, WithCampaign(testutil.CampaignID)) require.Error(t, publishError) require.Equal(t, cosmoserror.ErrNotFound, publishError) suite.AssertAllMocks(t) @@ -696,7 +675,7 @@ func TestPublish(t *testing.T) { suite.ChainMock.On("Name").Return(testutil.ChainName).Once() suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() - _, _, _, publishError := network.Publish(context.Background(), suite.ChainMock) + _, _, publishError := network.Publish(context.Background(), suite.ChainMock) require.Error(t, publishError) require.Equal(t, expectedError, publishError) suite.AssertAllMocks(t) @@ -757,7 +736,7 @@ func TestPublish(t *testing.T) { suite.ChainMock.On("Name").Return(testutil.ChainName).Once() suite.ChainMock.On("ChainID").Return(testutil.ChainID, nil).Once() - _, _, _, publishError := network.Publish(context.Background(), suite.ChainMock) + _, _, publishError := network.Publish(context.Background(), suite.ChainMock) require.Error(t, publishError) require.Equal(t, expectedError, publishError) suite.AssertAllMocks(t) @@ -822,7 +801,7 @@ func TestPublish(t *testing.T) { Return(expectedError). Once() - _, _, _, publishError := network.Publish(context.Background(), suite.ChainMock) + _, _, publishError := network.Publish(context.Background(), suite.ChainMock) require.Error(t, publishError) require.Equal(t, expectedError, publishError) suite.AssertAllMocks(t) diff --git a/ignite/services/network/queries.go b/ignite/services/network/queries.go index 1adb4f4e4e..5b010f9398 100644 --- a/ignite/services/network/queries.go +++ b/ignite/services/network/queries.go @@ -5,6 +5,7 @@ import ( "sort" "sync" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/pkg/errors" campaigntypes "github.com/tendermint/spn/x/campaign/types" launchtypes "github.com/tendermint/spn/x/launch/types" @@ -220,3 +221,55 @@ func (n Network) ChainReward(ctx context.Context, launchID uint64) (rewardtypes. } return res.RewardPool, nil } + +// stakingParams fetches the staking module params +func (n Network) 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 +} + +// 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 = RewardsInfo(ctx, n.cosmos, height) + if err != nil { + return rewardsInfo, 0, 0, err + } + + stakingParams, err := n.stakingParams(ctx) + if err != nil { + return rewardsInfo, 0, 0, err + } + unboundingTime = int64(stakingParams.UnbondingTime.Seconds()) + + chainReward, err := n.ChainReward(ctx, launchID) + if err == ErrObjectNotFound { + return rewardsInfo, 1, unboundingTime, nil + } else if err != nil { + return rewardsInfo, 0, 0, err + } + lastRewardHeight = chainReward.LastRewardHeight + + return +} + +// 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/ignite/services/network/share_percent.go b/ignite/services/network/share_percent.go new file mode 100644 index 0000000000..4e01c8a962 --- /dev/null +++ b/ignite/services/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 { + var 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/ignite/services/network/share_percent_test.go b/ignite/services/network/share_percent_test.go new file mode 100644 index 0000000000..56b87dcc7e --- /dev/null +++ b/ignite/services/network/share_percent_test.go @@ -0,0 +1,134 @@ +package network_test + +import ( + "errors" + "testing" + + "github.com/ignite-hq/cli/ignite/services/network" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +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/ignite/services/network/testutil/suite.go b/ignite/services/network/testutil/suite.go index 8726a71d01..44c73cfb79 100644 --- a/ignite/services/network/testutil/suite.go +++ b/ignite/services/network/testutil/suite.go @@ -16,6 +16,7 @@ type Suite struct { CampaignQueryMock *mocks.CampaignClient ProfileQueryMock *mocks.ProfileClient RewardClient *mocks.RewardClient + StakingClient *mocks.StakingClient } // AssertAllMocks asserts all suite mocks expectations @@ -26,6 +27,7 @@ func (s *Suite) AssertAllMocks(t *testing.T) { s.CosmosClientMock.AssertExpectations(t) s.CampaignQueryMock.AssertExpectations(t) s.RewardClient.AssertExpectations(t) + s.StakingClient.AssertExpectations(t) } // NewSuite creates new suite with mocks @@ -39,5 +41,6 @@ func NewSuite() Suite { CampaignQueryMock: new(mocks.CampaignClient), ProfileQueryMock: new(mocks.ProfileClient), RewardClient: new(mocks.RewardClient), + StakingClient: new(mocks.StakingClient), } } diff --git a/ignite/services/scaffolder/init.go b/ignite/services/scaffolder/init.go index c18c93c44e..706f0bc5b7 100644 --- a/ignite/services/scaffolder/init.go +++ b/ignite/services/scaffolder/init.go @@ -13,6 +13,7 @@ import ( "github.com/tendermint/flutter/v2" "github.com/tendermint/vue" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/gomodulepath" "github.com/ignite-hq/cli/ignite/pkg/localfs" "github.com/ignite-hq/cli/ignite/pkg/placeholder" @@ -30,7 +31,7 @@ var ( ) // Init initializes a new app with name and given options. -func Init(tracer *placeholder.Tracer, root, name, addressPrefix string, noDefaultModule bool) (path string, err error) { +func Init(cacheStorage cache.Storage, tracer *placeholder.Tracer, root, name, addressPrefix string, noDefaultModule bool) (path string, err error) { if root, err = filepath.Abs(root); err != nil { return "", err } @@ -47,7 +48,7 @@ func Init(tracer *placeholder.Tracer, root, name, addressPrefix string, noDefaul return "", err } - if err := finish(path, pathInfo.RawPath); err != nil { + if err := finish(cacheStorage, path, pathInfo.RawPath); err != nil { return "", err } diff --git a/ignite/services/scaffolder/message.go b/ignite/services/scaffolder/message.go index b717bcfa4f..bd1d2f3115 100644 --- a/ignite/services/scaffolder/message.go +++ b/ignite/services/scaffolder/message.go @@ -6,6 +6,7 @@ import ( "github.com/gobuffalo/genny" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/multiformatname" "github.com/ignite-hq/cli/ignite/pkg/placeholder" "github.com/ignite-hq/cli/ignite/pkg/xgenny" @@ -57,6 +58,7 @@ func WithoutSimulation() MessageOption { // AddMessage adds a new message to scaffolded app func (s Scaffolder) AddMessage( ctx context.Context, + cacheStorage cache.Storage, tracer *placeholder.Tracer, moduleName, msgName string, @@ -165,7 +167,7 @@ func (s Scaffolder) AddMessage( if err != nil { return sm, err } - return sm, finish(opts.AppPath, s.modpath.RawPath) + return sm, finish(cacheStorage, opts.AppPath, s.modpath.RawPath) } // checkForbiddenMessageField returns true if the name is forbidden as a message name diff --git a/ignite/services/scaffolder/module.go b/ignite/services/scaffolder/module.go index 1b1cff56d0..0bab777d95 100644 --- a/ignite/services/scaffolder/module.go +++ b/ignite/services/scaffolder/module.go @@ -12,6 +12,7 @@ import ( "github.com/gobuffalo/genny" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner/step" appanalysis "github.com/ignite-hq/cli/ignite/pkg/cosmosanalysis/app" @@ -145,6 +146,7 @@ func WithDependencies(dependencies []modulecreate.Dependency) ModuleCreationOpti // CreateModule creates a new empty module in the scaffolded app func (s Scaffolder) CreateModule( + cacheStorage cache.Storage, tracer *placeholder.Tracer, moduleName string, options ...ModuleCreationOption, @@ -225,11 +227,11 @@ func (s Scaffolder) CreateModule( return sm, runErr } - return sm, finish(opts.AppPath, s.modpath.RawPath) + return sm, finish(cacheStorage, opts.AppPath, s.modpath.RawPath) } // ImportModule imports specified module with name to the scaffolded app. -func (s Scaffolder) ImportModule(tracer *placeholder.Tracer, name string) (sm xgenny.SourceModification, err error) { +func (s Scaffolder) ImportModule(cacheStorage cache.Storage, tracer *placeholder.Tracer, name string) (sm xgenny.SourceModification, err error) { // Only wasm is currently supported if name != "wasm" { return sm, errors.New("module cannot be imported. Supported module: wasm") @@ -270,7 +272,7 @@ func (s Scaffolder) ImportModule(tracer *placeholder.Tracer, name string) (sm xg return sm, err } - return sm, finish(s.path, s.modpath.RawPath) + return sm, finish(cacheStorage, s.path, s.modpath.RawPath) } // moduleExists checks if the module exists in the app diff --git a/ignite/services/scaffolder/oracle.go b/ignite/services/scaffolder/oracle.go index ee8d4b7fa2..4f73c20867 100644 --- a/ignite/services/scaffolder/oracle.go +++ b/ignite/services/scaffolder/oracle.go @@ -6,6 +6,7 @@ import ( "github.com/gobuffalo/genny" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner/step" "github.com/ignite-hq/cli/ignite/pkg/gocmd" @@ -43,6 +44,7 @@ func OracleWithSigner(signer string) OracleOption { // AddOracle adds a new BandChain oracle envtest. func (s *Scaffolder) AddOracle( + cacheStorage cache.Storage, tracer *placeholder.Tracer, moduleName, queryName string, @@ -106,7 +108,7 @@ func (s *Scaffolder) AddOracle( if err != nil { return sm, err } - return sm, finish(opts.AppPath, s.modpath.RawPath) + return sm, finish(cacheStorage, opts.AppPath, s.modpath.RawPath) } func (s Scaffolder) installBandPacket() error { diff --git a/ignite/services/scaffolder/packet.go b/ignite/services/scaffolder/packet.go index 34212f5e6a..c721371ce5 100644 --- a/ignite/services/scaffolder/packet.go +++ b/ignite/services/scaffolder/packet.go @@ -8,6 +8,7 @@ import ( "github.com/gobuffalo/genny" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/multiformatname" "github.com/ignite-hq/cli/ignite/pkg/placeholder" "github.com/ignite-hq/cli/ignite/pkg/xgenny" @@ -53,6 +54,7 @@ func PacketWithSigner(signer string) PacketOption { // AddPacket adds a new type stype to scaffolded app by using optional type fields. func (s Scaffolder) AddPacket( ctx context.Context, + cacheStorage cache.Storage, tracer *placeholder.Tracer, moduleName, packetName string, @@ -141,7 +143,7 @@ func (s Scaffolder) AddPacket( if err != nil { return sm, err } - return sm, finish(opts.AppPath, s.modpath.RawPath) + return sm, finish(cacheStorage, opts.AppPath, s.modpath.RawPath) } // isIBCModule returns true if the provided module implements the IBC module interface diff --git a/ignite/services/scaffolder/query.go b/ignite/services/scaffolder/query.go index 8bd604b208..0100fd1c62 100644 --- a/ignite/services/scaffolder/query.go +++ b/ignite/services/scaffolder/query.go @@ -6,6 +6,7 @@ import ( "github.com/gobuffalo/genny" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/multiformatname" "github.com/ignite-hq/cli/ignite/pkg/placeholder" "github.com/ignite-hq/cli/ignite/pkg/xgenny" @@ -16,6 +17,7 @@ import ( // AddQuery adds a new query to scaffolded app func (s Scaffolder) AddQuery( ctx context.Context, + cacheStorage cache.Storage, tracer *placeholder.Tracer, moduleName, queryName, @@ -85,5 +87,5 @@ func (s Scaffolder) AddQuery( if err != nil { return sm, err } - return sm, finish(opts.AppPath, s.modpath.RawPath) + return sm, finish(cacheStorage, opts.AppPath, s.modpath.RawPath) } diff --git a/ignite/services/scaffolder/scaffolder.go b/ignite/services/scaffolder/scaffolder.go index c91e463f71..465d5a3bca 100644 --- a/ignite/services/scaffolder/scaffolder.go +++ b/ignite/services/scaffolder/scaffolder.go @@ -9,6 +9,7 @@ import ( "github.com/ignite-hq/cli/ignite/chainconfig" sperrors "github.com/ignite-hq/cli/ignite/errors" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner" "github.com/ignite-hq/cli/ignite/pkg/cmdrunner/step" "github.com/ignite-hq/cli/ignite/pkg/cosmosanalysis" @@ -21,14 +22,14 @@ import ( // Scaffolder is Ignite CLI app scaffolder. type Scaffolder struct { + // Version of the chain + Version cosmosver.Version + // path of the app. path string // modpath represents the go module path of the app. modpath gomodulepath.Path - - // Version of the chain - Version cosmosver.Version } // App creates a new scaffolder for an existent app. @@ -60,16 +61,16 @@ func App(path string) (Scaffolder, error) { } s := Scaffolder{ + Version: version, path: path, modpath: modpath, - Version: version, } return s, nil } -func finish(path, gomodPath string) error { - if err := protoc(path, gomodPath); err != nil { +func finish(cacheStorage cache.Storage, path, gomodPath string) error { + if err := protoc(cacheStorage, path, gomodPath); err != nil { return err } if err := tidy(path); err != nil { @@ -78,7 +79,7 @@ func finish(path, gomodPath string) error { return fmtProject(path) } -func protoc(projectPath, gomodPath string) error { +func protoc(cacheStorage cache.Storage, projectPath, gomodPath string) error { if err := cosmosgen.InstallDependencies(context.Background(), projectPath); err != nil { return err } @@ -113,7 +114,7 @@ func protoc(projectPath, gomodPath string) error { options = append(options, cosmosgen.WithOpenAPIGeneration(conf.Client.OpenAPI.Path)) } - return cosmosgen.Generate(context.Background(), projectPath, conf.Build.Proto.Path, options...) + return cosmosgen.Generate(context.Background(), cacheStorage, projectPath, conf.Build.Proto.Path, options...) } func tidy(path string) error { diff --git a/ignite/services/scaffolder/type.go b/ignite/services/scaffolder/type.go index c2d613467a..b0c4396081 100644 --- a/ignite/services/scaffolder/type.go +++ b/ignite/services/scaffolder/type.go @@ -7,6 +7,7 @@ import ( "github.com/gobuffalo/genny" + "github.com/ignite-hq/cli/ignite/pkg/cache" "github.com/ignite-hq/cli/ignite/pkg/multiformatname" "github.com/ignite-hq/cli/ignite/pkg/placeholder" "github.com/ignite-hq/cli/ignite/pkg/xgenny" @@ -118,6 +119,7 @@ func TypeWithSigner(signer string) AddTypeOption { // if no module is given, the type will be scaffolded inside the app's default module. func (s Scaffolder) AddType( ctx context.Context, + cacheStorage cache.Storage, typeName string, tracer *placeholder.Tracer, kind AddTypeKind, @@ -243,7 +245,7 @@ func (s Scaffolder) AddType( return sm, err } - return sm, finish(opts.AppPath, s.modpath.RawPath) + return sm, finish(cacheStorage, opts.AppPath, s.modpath.RawPath) } // checkForbiddenTypeIndex returns true if the name is forbidden as a field name diff --git a/ignite/templates/app/stargate/app/app.go.plush b/ignite/templates/app/stargate/app/app.go.plush index 9b26480840..6e726f82c9 100644 --- a/ignite/templates/app/stargate/app/app.go.plush +++ b/ignite/templates/app/stargate/app/app.go.plush @@ -74,16 +74,16 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v2/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v2/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v2/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v2/modules/core" - ibcclient "github.com/cosmos/ibc-go/v2/modules/core/02-client" - ibcclientclient "github.com/cosmos/ibc-go/v2/modules/core/02-client/client" - ibcclienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" - ibcporttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v2/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v2/modules/core/keeper" + "github.com/cosmos/ibc-go/v3/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v3/modules/core" + ibcclient "github.com/cosmos/ibc-go/v3/modules/core/02-client" + ibcclientclient "github.com/cosmos/ibc-go/v3/modules/core/02-client/client" + ibcclienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + ibcporttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" "github.com/spf13/cast" abci "github.com/tendermint/tendermint/abci/types" tmjson "github.com/tendermint/tendermint/libs/json" @@ -348,10 +348,13 @@ func New( // Create Transfer Keepers app.TransferKeeper = ibctransferkeeper.NewKeeper( appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, ) - transferModule := transfer.NewAppModule(app.TransferKeeper) + var ( + transferModule = transfer.NewAppModule(app.TransferKeeper) + transferIBCModule = transfer.NewIBCModule(app.TransferKeeper) + ) // Create evidence Keeper for to register the IBC light client misbehaviour evidence route evidenceKeeper := evidencekeeper.NewKeeper( @@ -384,7 +387,7 @@ func New( // Create static IBC router, add transfer route, then set and seal it ibcRouter := ibcporttypes.NewRouter() - ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) + ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferIBCModule) ibcRouter.AddRoute(monitoringptypes.ModuleName, monitoringModule) // this line is used by starport scaffolding # ibc/app/router app.IBCKeeper.SetRouter(ibcRouter) diff --git a/ignite/templates/app/stargate/go.mod.plush b/ignite/templates/app/stargate/go.mod.plush index a8df22af8a..36cb8c70b6 100644 --- a/ignite/templates/app/stargate/go.mod.plush +++ b/ignite/templates/app/stargate/go.mod.plush @@ -4,20 +4,20 @@ go 1.16 require ( github.com/cosmos/cosmos-sdk v0.45.4 - github.com/cosmos/ibc-go/v2 v2.0.3 + github.com/cosmos/ibc-go/v3 v3.0.0 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/ignite-hq/cli v0.20.3 + github.com/ignite-hq/cli v0.22.0 github.com/spf13/cast v1.4.1 github.com/spf13/cobra v1.4.0 github.com/stretchr/testify v1.7.1 - github.com/tendermint/spn v0.2.1-0.20220511154430-aeab7a5b2bc0 + github.com/tendermint/spn v0.2.1-0.20220609194312-7833ecf4454a github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.7 - google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e - google.golang.org/grpc v1.45.0 + google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd + google.golang.org/grpc v1.46.2 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/ignite/templates/app/stargate/go.sum b/ignite/templates/app/stargate/go.sum index f7eb5292ee..937bf07d2a 100644 --- a/ignite/templates/app/stargate/go.sum +++ b/ignite/templates/app/stargate/go.sum @@ -6,6 +6,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -19,6 +20,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= @@ -52,6 +54,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-beta.2 h1:/BZRNzm8N4K4eWfK28dL4yescorxtO7YG1yun8fy+pI= @@ -272,6 +275,7 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +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/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= @@ -484,8 +488,9 @@ github.com/cosmos/iavl v0.17.3/go.mod h1:prJoErZFABYZGDHka1R6Oay4z9PrNeFFiMKHDAM github.com/cosmos/ibc-go v1.2.2 h1:bs6TZ8Es1kycIu2AHlRZ9dzJ+mveqlLN/0sjWtRH88o= github.com/cosmos/ibc-go v1.2.2/go.mod h1:XmYjsRFOs6Q9Cz+CSsX21icNoH27vQKb3squgnCOCbs= github.com/cosmos/ibc-go/v2 v2.0.2/go.mod h1:XUmW7wmubCRhIEAGtMGS+5IjiSSmcAwihoN/yPGd6Kk= -github.com/cosmos/ibc-go/v2 v2.0.3 h1:kZ6SAj7hyxoixsLEUBx431bVGiBW22PCHwkWHafWhXs= github.com/cosmos/ibc-go/v2 v2.0.3/go.mod h1:XUmW7wmubCRhIEAGtMGS+5IjiSSmcAwihoN/yPGd6Kk= +github.com/cosmos/ibc-go/v3 v3.0.0 h1:XUNplHVS51Q2gMnTFsFsH9QJ7flsovMamnltKbEgPQ4= +github.com/cosmos/ibc-go/v3 v3.0.0/go.mod h1:Mb+1NXiPOLd+CPFlOC6BKeAUaxXlhuWenMmRiUiSmwY= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= @@ -758,6 +763,7 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2V github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -827,8 +833,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/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.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/go-github/v37 v37.0.0/go.mod h1:LM7in3NmXDrX58GbEHy7FtNLbI2JijX93RnMKvWG3m4= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -855,6 +862,7 @@ github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -874,6 +882,7 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= @@ -925,6 +934,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqC github.com/grpc-ecosystem/grpc-gateway v1.14.7/go.mod h1:oYZKL012gGh6LMyg/xA7Q2yq6j8bu0wa+9w14EEthWU= 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/grpc-ecosystem/grpc-gateway/v2 v2.10.0/go.mod h1:XnLCLFp3tjoZJszVKjfpyAK6J8sYIcQXWQxmqLWF21I= 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/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= @@ -998,9 +1008,6 @@ github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHL github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ignite-hq/cli v0.20.0/go.mod h1:kOs9GoMwvbIkbgIZP/LWE/qpw1eaqwPchWtNBIUSElY= -github.com/ignite-hq/cli v0.20.3 h1:MFmClpkLyIN+LUR6GEIqyVvILku4aTl/FWOSWSN3Y7Q= -github.com/ignite-hq/cli v0.20.3/go.mod h1:kOs9GoMwvbIkbgIZP/LWE/qpw1eaqwPchWtNBIUSElY= github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -1420,6 +1427,7 @@ 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/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -1519,8 +1527,10 @@ github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.23.0 h1:UskrK+saS9P9Y789yNNulYKdARjPZuS35B8gJF2x60g= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.23.0/go.mod h1:6c7hFfxPOy7TacJc4Fcdi24/J0NKYGzjG8FWRI916Qo= +github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= +github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= 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= @@ -1583,8 +1593,9 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60= +github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= @@ -1661,6 +1672,7 @@ github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrn github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tendermint/flutter/v2 v2.0.3/go.mod h1:hnaVhWhzv2Od1LqZFWrRKwiOHeMonsB9EIWP0AGMPw0= +github.com/tendermint/flutter/v2 v2.0.4/go.mod h1:hnaVhWhzv2Od1LqZFWrRKwiOHeMonsB9EIWP0AGMPw0= github.com/tendermint/fundraising v0.2.0/go.mod h1:AoOF/njoU8FZMZTngspweCClg+3ANI0aRswe0FaUQsE= github.com/tendermint/fundraising v0.3.0 h1:VtHfmVlAS93MUDlt6Em21l3taw6s9kLY/w8Cd1FB9fM= github.com/tendermint/fundraising v0.3.0/go.mod h1:oJFZUZ/GsACtkYeWScKpHLdqMUThNWpMAi/G47LJUi4= @@ -1669,8 +1681,9 @@ github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM github.com/tendermint/spm v0.1.8/go.mod h1:iHgfQ5YOI6ONc9E7ugGQolVdfSMHpeXfZ/OpXuN/42Q= github.com/tendermint/spn v0.1.1-0.20211210094128-4ca78a240c57/go.mod h1:p4BO8YC6kOKSKqMfySqaLHfwBmuPE/QcLwnnVhh7H9M= github.com/tendermint/spn v0.1.1-0.20220407154406-5cfd1bf28150/go.mod h1:B+KuhkB4Sms4yh0UN1HGsVbbMa3vCypai22QXLudQ3o= -github.com/tendermint/spn v0.2.1-0.20220511154430-aeab7a5b2bc0 h1:kIjnfHO472W2WSzul3ek3p07yKVYxSFUNng4YJmVex4= -github.com/tendermint/spn v0.2.1-0.20220511154430-aeab7a5b2bc0/go.mod h1:xNtBc/jmB1pvb+EJYQtyJdcTZM9dOhJeW3C4Qj9n7tg= +github.com/tendermint/spn v0.2.1-0.20220427143342-de7398284030/go.mod h1:9wXyogMDn9fK85s+bSADy+wvZ27DjLEByByMM+0O6NU= +github.com/tendermint/spn v0.2.1-0.20220609194312-7833ecf4454a h1:+xo1H4r/dLkUcx89/jP88TbVQiA40Rcn7yQyPozIj5k= +github.com/tendermint/spn v0.2.1-0.20220609194312-7833ecf4454a/go.mod h1:5w8qNkgtJM24CcMjqTsVOKnSbz+U2fke7bEGzRlcdHA= github.com/tendermint/starport v0.19.5/go.mod h1:XdbMpJ5R6QzP1+yrfsoCk44fnp9/52raponbkvjIMQA= github.com/tendermint/tendermint v0.34.0-rc4/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxmPUrT4hNuOQWX9XUwB4= github.com/tendermint/tendermint v0.34.0-rc6/go.mod h1:ugzyZO5foutZImv0Iyx/gOFCX6mjJTgbLHTwi17VDVg= @@ -1726,6 +1739,7 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/vektra/mockery/v2 v2.11.0/go.mod h1:8vf4KDDUptfkyypzdHLuE7OE2xA7Gdt60WgIS8PgD+U= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= @@ -1760,6 +1774,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= @@ -1874,11 +1890,16 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 h1:3erb+vDS8lU1sxfDHF4/hhWyaXnhIaO+7RgL4fDZORA= golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI= +golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1921,8 +1942,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1987,15 +2009,19 @@ golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2014,6 +2040,7 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 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= @@ -2124,6 +2151,7 @@ golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2152,14 +2180,16 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/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-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/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-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/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-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2288,12 +2318,15 @@ golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= 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= @@ -2401,8 +2434,10 @@ google.golang.org/genproto v0.0.0-20201119123407-9b1e624d6bc4/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -2432,8 +2467,9 @@ google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e h1:fNKDNuUyC4WH+inqDMpfXDdfvwfYILbsX+oskGZ8hxg= google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -2450,8 +2486,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/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 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 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= @@ -2472,8 +2509,9 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.3 h1:jRskFVxYaMGAMUbN0UZ7niA9gzL9B49DOqE78vg0k3w= +gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= @@ -2500,8 +2538,9 @@ 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-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 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 v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= @@ -2578,4 +2617,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/ignite/templates/ibc/oracle/x/{{moduleName}}/keeper/msg_{{queryName}}.go.plush b/ignite/templates/ibc/oracle/x/{{moduleName}}/keeper/msg_{{queryName}}.go.plush index aa017490a3..579c664abf 100644 --- a/ignite/templates/ibc/oracle/x/{{moduleName}}/keeper/msg_{{queryName}}.go.plush +++ b/ignite/templates/ibc/oracle/x/{{moduleName}}/keeper/msg_{{queryName}}.go.plush @@ -8,9 +8,9 @@ import ( "github.com/bandprotocol/bandchain-packet/packet" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" "<%= ModulePath %>/x/<%= moduleName %>/types" ) diff --git a/ignite/templates/ibc/oracle/x/{{moduleName}}/oracle.go.plush b/ignite/templates/ibc/oracle/x/{{moduleName}}/oracle.go.plush index cccccae64d..0a8906bf59 100644 --- a/ignite/templates/ibc/oracle/x/{{moduleName}}/oracle.go.plush +++ b/ignite/templates/ibc/oracle/x/{{moduleName}}/oracle.go.plush @@ -5,7 +5,7 @@ import ( "github.com/bandprotocol/bandchain-packet/packet" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" "<%= ModulePath %>/x/<%= moduleName %>/types" ) diff --git a/ignite/templates/ibc/packet/component/x/{{moduleName}}/keeper/{{packetName}}.go.plush b/ignite/templates/ibc/packet/component/x/{{moduleName}}/keeper/{{packetName}}.go.plush index a1d212b2a1..8f0a9d9626 100644 --- a/ignite/templates/ibc/packet/component/x/{{moduleName}}/keeper/{{packetName}}.go.plush +++ b/ignite/templates/ibc/packet/component/x/{{moduleName}}/keeper/{{packetName}}.go.plush @@ -6,9 +6,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "<%= ModulePath %>/x/<%= moduleName %>/types" - clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" ) // Transmit<%= packetName.UpperCamel %>Packet transmits the packet over IBC with the specified source port and source channel diff --git a/ignite/templates/ibc/packet/messages/x/{{moduleName}}/client/cli/tx_{{packetName}}.go.plush b/ignite/templates/ibc/packet/messages/x/{{moduleName}}/client/cli/tx_{{packetName}}.go.plush index 3bdaa19920..e4b588f158 100644 --- a/ignite/templates/ibc/packet/messages/x/{{moduleName}}/client/cli/tx_{{packetName}}.go.plush +++ b/ignite/templates/ibc/packet/messages/x/{{moduleName}}/client/cli/tx_{{packetName}}.go.plush @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" "<%= ModulePath %>/x/<%= moduleName %>/types" - channelutils "github.com/cosmos/ibc-go/v2/modules/core/04-channel/client/utils" + channelutils "github.com/cosmos/ibc-go/v3/modules/core/04-channel/client/utils" ) var _ = strconv.Itoa(0) diff --git a/ignite/templates/ibc/packet/messages/x/{{moduleName}}/keeper/msg_server_{{packetName}}.go.plush b/ignite/templates/ibc/packet/messages/x/{{moduleName}}/keeper/msg_server_{{packetName}}.go.plush index 0757302ee0..7cdef1d931 100644 --- a/ignite/templates/ibc/packet/messages/x/{{moduleName}}/keeper/msg_server_{{packetName}}.go.plush +++ b/ignite/templates/ibc/packet/messages/x/{{moduleName}}/keeper/msg_server_{{packetName}}.go.plush @@ -5,7 +5,7 @@ import ( "<%= ModulePath %>/x/<%= moduleName %>/types" sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v2/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" ) diff --git a/ignite/templates/module/create/ibc.go b/ignite/templates/module/create/ibc.go index 8efbb01026..517716ac0f 100644 --- a/ignite/templates/module/create/ibc.go +++ b/ignite/templates/module/create/ibc.go @@ -93,7 +93,7 @@ func genesisTypesModify(replacer placeholder.Replacer, opts *CreateOptions) genn } // Import - templateImport := `host "github.com/cosmos/ibc-go/v2/modules/core/24-host" + templateImport := `host "github.com/cosmos/ibc-go/v3/modules/core/24-host" %s` replacementImport := fmt.Sprintf(templateImport, typed.PlaceholderGenesisTypesImport) content := replacer.Replace(f.String(), typed.PlaceholderGenesisTypesImport, replacementImport) diff --git a/ignite/templates/module/create/ibc/testutil/keeper/{{moduleName}}.go.plush b/ignite/templates/module/create/ibc/testutil/keeper/{{moduleName}}.go.plush index 3559df1972..c9ab31f657 100644 --- a/ignite/templates/module/create/ibc/testutil/keeper/{{moduleName}}.go.plush +++ b/ignite/templates/module/create/ibc/testutil/keeper/{{moduleName}}.go.plush @@ -11,7 +11,7 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" - ibckeeper "github.com/cosmos/ibc-go/v2/modules/core/keeper" + ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" typesparams "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" diff --git a/ignite/templates/module/create/ibc/x/{{moduleName}}/module_ibc.go.plush b/ignite/templates/module/create/ibc/x/{{moduleName}}/module_ibc.go.plush index adb000a11d..de8e0cd775 100644 --- a/ignite/templates/module/create/ibc/x/{{moduleName}}/module_ibc.go.plush +++ b/ignite/templates/module/create/ibc/x/{{moduleName}}/module_ibc.go.plush @@ -6,10 +6,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v2/modules/core/24-host" - ibcexported "github.com/cosmos/ibc-go/v2/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" "<%= modulePath %>/x/<%= moduleName %>/types" ) diff --git a/ignite/templates/module/create/stargate/x/{{moduleName}}/module.go.plush b/ignite/templates/module/create/stargate/x/{{moduleName}}/module.go.plush index 67c2add1db..ecc079ba94 100644 --- a/ignite/templates/module/create/stargate/x/{{moduleName}}/module.go.plush +++ b/ignite/templates/module/create/stargate/x/{{moduleName}}/module.go.plush @@ -19,7 +19,7 @@ import ( "<%= modulePath %>/x/<%= moduleName %>/keeper" "<%= modulePath %>/x/<%= moduleName %>/types" "<%= modulePath %>/x/<%= moduleName %>/client/cli" - <%= if (isIBC) { %>porttypes "github.com/cosmos/ibc-go/v2/modules/core/05-port/types"<% } %> + <%= if (isIBC) { %>porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types"<% } %> ) var ( diff --git a/ignite/templates/typed/list/stargate/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush b/ignite/templates/typed/list/stargate/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush index 61f7c60227..a22e44ec9d 100644 --- a/ignite/templates/typed/list/stargate/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush +++ b/ignite/templates/typed/list/stargate/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush @@ -36,7 +36,6 @@ func TestCreate<%= TypeName.UpperCamel %>(t *testing.T) { }, }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { args := []string{} args = append(args, fields...) @@ -92,7 +91,6 @@ func TestUpdate<%= TypeName.UpperCamel %>(t *testing.T) { code: sdkerrors.ErrKeyNotFound.ABCICode(), }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { args := []string{tc.id} args = append(args, fields...) @@ -148,7 +146,6 @@ func TestDelete<%= TypeName.UpperCamel %>(t *testing.T) { code: sdkerrors.ErrKeyNotFound.ABCICode(), }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdDelete<%= TypeName.UpperCamel %>(), append([]string{tc.id}, tc.args...)) if tc.err != nil { diff --git a/ignite/templates/typed/map/stargate/tests/component/x/{{moduleName}}/client/cli/query_{{typeName}}_test.go.plush b/ignite/templates/typed/map/stargate/tests/component/x/{{moduleName}}/client/cli/query_{{typeName}}_test.go.plush index ce8757b767..b939ed200a 100644 --- a/ignite/templates/typed/map/stargate/tests/component/x/{{moduleName}}/client/cli/query_{{typeName}}_test.go.plush +++ b/ignite/templates/typed/map/stargate/tests/component/x/{{moduleName}}/client/cli/query_{{typeName}}_test.go.plush @@ -71,7 +71,6 @@ func TestShow<%= TypeName.UpperCamel %>(t *testing.T) { err: status.Error(codes.NotFound, "not found"), }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { args := []string{ <%= for (i, index) in Indexes { %><%= index.ToString("tc.id" + index.Name.UpperCamel) %>, diff --git a/ignite/templates/typed/map/stargate/tests/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush b/ignite/templates/typed/map/stargate/tests/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush index 0a3ceb1021..c6861ae624 100644 --- a/ignite/templates/typed/map/stargate/tests/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush +++ b/ignite/templates/typed/map/stargate/tests/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush @@ -44,7 +44,6 @@ func TestCreate<%= TypeName.UpperCamel %>(t *testing.T) { }, }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { args := []string{ <%= for (i, index) in Indexes { %><%= index.ToString("tc.id" + index.Name.UpperCamel) %>, @@ -108,7 +107,6 @@ func TestUpdate<%= TypeName.UpperCamel %>(t *testing.T) { code: sdkerrors.ErrKeyNotFound.ABCICode(), }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { args := []string{ <%= for (i, index) in Indexes { %><%= index.ToString("tc.id" + index.Name.UpperCamel) %>, @@ -173,7 +171,6 @@ func TestDelete<%= TypeName.UpperCamel %>(t *testing.T) { code: sdkerrors.ErrKeyNotFound.ABCICode(), }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { args := []string{ <%= for (i, index) in Indexes { %><%= index.ToString("tc.id" + index.Name.UpperCamel) %>, diff --git a/ignite/templates/typed/singleton/stargate/component/x/{{moduleName}}/client/cli/query_{{typeName}}_test.go.plush b/ignite/templates/typed/singleton/stargate/component/x/{{moduleName}}/client/cli/query_{{typeName}}_test.go.plush index ddf064e542..6cf09834a0 100644 --- a/ignite/templates/typed/singleton/stargate/component/x/{{moduleName}}/client/cli/query_{{typeName}}_test.go.plush +++ b/ignite/templates/typed/singleton/stargate/component/x/{{moduleName}}/client/cli/query_{{typeName}}_test.go.plush @@ -49,7 +49,6 @@ func TestShow<%= TypeName.UpperCamel %>(t *testing.T) { obj: obj, }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { var args []string args = append(args, tc.args...) diff --git a/ignite/templates/typed/singleton/stargate/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush b/ignite/templates/typed/singleton/stargate/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush index 2e1efd80d5..516b7fa514 100644 --- a/ignite/templates/typed/singleton/stargate/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush +++ b/ignite/templates/typed/singleton/stargate/messages/x/{{moduleName}}/client/cli/tx_{{typeName}}_test.go.plush @@ -35,7 +35,6 @@ func TestCreate<%= TypeName.UpperCamel %>(t *testing.T) { }, }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { var args []string args = append(args, fields...) @@ -82,7 +81,6 @@ func TestUpdate<%= TypeName.UpperCamel %>(t *testing.T) { args: common, }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { var args []string args = append(args, fields...) @@ -130,7 +128,6 @@ func TestDelete<%= TypeName.UpperCamel %>(t *testing.T) { args: common, }, } { - tc := tc t.Run(tc.desc, func(t *testing.T) { out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdDelete<%= TypeName.UpperCamel %>(), append([]string{}, tc.args...)) if tc.err != nil { diff --git a/integration/app/cache_test.go b/integration/app/cache_test.go new file mode 100644 index 0000000000..d91f65a19e --- /dev/null +++ b/integration/app/cache_test.go @@ -0,0 +1,114 @@ +package app_test + +import ( + "context" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ignite-hq/cli/ignite/pkg/cmdrunner/step" + envtest "github.com/ignite-hq/cli/integration" +) + +func TestCliWithCaching(t *testing.T) { + var ( + env = envtest.New(t) + path = env.Scaffold("github.com/test/cacheblog") + vueGenerated = filepath.Join(path, "vue/src/store/generated") + openapiGenerated = filepath.Join(path, "docs/static/openapi.yml") + typesDir = filepath.Join(path, "x/cacheblog/types") + servers = env.RandomizeServerPorts(path, "") + ctx, cancel = context.WithTimeout(env.Ctx(), envtest.ServeTimeout) + isBackendAliveErr error + ) + + env.Must(env.Exec("create a message", + step.NewSteps(step.New( + step.Exec( + envtest.IgniteApp, + "s", + "message", + "mymessage", + "myfield1", + "myfield2:bool", + "--yes", + ), + step.Workdir(path), + )), + )) + + env.Must(env.Exec("create a query", + step.NewSteps(step.New( + step.Exec( + envtest.IgniteApp, + "s", + "query", + "myQuery", + "mytypefield", + "--yes", + ), + step.Workdir(path), + )), + )) + + env.Must(env.Exec("build", + step.NewSteps(step.New( + step.Exec( + envtest.IgniteApp, + "c", + "build", + "--proto-all-modules", + ), + step.Workdir(path), + )), + )) + + env.EnsureAppIsSteady(path) + + deleteCachedFiles(t, vueGenerated, openapiGenerated, typesDir) + + env.Must(env.Exec("build", + step.NewSteps(step.New( + step.Exec( + envtest.IgniteApp, + "c", + "build", + "--proto-all-modules", + ), + step.Workdir(path), + )), + )) + + env.EnsureAppIsSteady(path) + + deleteCachedFiles(t, vueGenerated, openapiGenerated, typesDir) + + go func() { + defer cancel() + isBackendAliveErr = env.IsAppServed(ctx, servers) + }() + env.Must(env.Serve("should serve with Stargate version", path, "", "", envtest.ExecCtx(ctx))) + + require.NoError(t, isBackendAliveErr, "app cannot get online in time") +} + +func deleteCachedFiles(t *testing.T, vueGenerated, openapiGenerated, typesDir string) { + require.NoError(t, os.RemoveAll(vueGenerated)) + require.NoError(t, os.Remove(openapiGenerated)) + + typesDirEntries, err := os.ReadDir(typesDir) + require.NoError(t, err) + + for _, v := range typesDirEntries { + if v.IsDir() { + continue + } + + if strings.Contains(v.Name(), ".pb") { + require.NoError(t, os.Remove(filepath.Join(typesDir, v.Name()))) + } + } +} diff --git a/integration/env.go b/integration/env.go index 5e3183a103..f7c259d3f6 100644 --- a/integration/env.go +++ b/integration/env.go @@ -184,7 +184,7 @@ func (e Env) Scaffold(name string, flags ...string) (appPath string) { appDir := path.Base(name) - // Cleanup the home directory of the app + // Cleanup the home directory and cache of the app e.t.Cleanup(func() { os.RemoveAll(filepath.Join(e.Home(), fmt.Sprintf(".%s", appDir))) }) diff --git a/readme.md b/readme.md index f982c6373e..518a219807 100644 --- a/readme.md +++ b/readme.md @@ -6,10 +6,12 @@ ## Quick start -Open Ignite CLI [in your web browser](https://gitpod.io/#https://github.com/ignite-hq/cli/tree/master) (or open [nightly version](https://gitpod.io/#https://github.com/ignite-hq/cli/)), or [install latest release](https://docs.ignite.com/guide/install.html). Create and start a blockchain: +Open Ignite CLI [in your web browser](https://gitpod.io/#https://github.com/ignite-hq/cli/tree/master) (or open [nightly version](https://gitpod.io/#https://github.com/ignite-hq/cli/)), or [install the latest release](https://docs.ignite.com/guide/install.html). + +To create and start a blockchain: ```bash -ignite scaffold chain github.com/username/mars +ignite scaffold chain mars cd mars @@ -22,13 +24,13 @@ To learn how to use Ignite CLI, check out the [Ignite CLI docs](https://docs.ign To install Ignite CLI locally on GNU, Linux, or macOS, see [Install Ignite CLI](https://docs.ignite.com/guide/install.html). -To learn more about building a JavaScript frontend for your Cosmos SDK blockchain, see [ignite-hq/vue](https://github.com/ignite-hq/vue). +To learn more about building a JavaScript frontend for your Cosmos SDK blockchain, see [ignite-hq/web](https://github.com/ignite-hq/web). ## Questions For questions and support, join the official [Ignite Discord](https://discord.gg/ignite) server. The issue list in this repo is exclusively for bug reports and feature requests. -## Cosmos SDK Compatibility +## Cosmos SDK compatibility Blockchains created with Ignite CLI use the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/) framework. To ensure the best possible experience, use the version of Ignite CLI that corresponds to the version of Cosmos SDK that your blockchain is built with. Unless noted otherwise, a row refers to a minor version and all associated patch versions. @@ -47,7 +49,7 @@ We welcome contributions from everyone. The `develop` branch contains the develo Our [Ignite CLI bounty program](docs/bounty/index.md) provides incentives for your participation and pays rewards. Track new, in-progress, and completed bounties on the [Bounty board](https://github.com/ignite-hq/cli/projects/5) in GitHub. -**Important** Before you start implementing a new Ignite CLI feature, the first step is to create an issue on Github that describes the proposed changes. +**Important** Before you start implementing a new Ignite CLI feature, the first step is to create an issue on GitHub that describes the proposed changes. If you're not sure where to start, check out [contributing.md](contributing.md) for our guidelines and policies for how we develop Ignite CLI. Thank you to everyone who has contributed to Ignite CLI! @@ -59,6 +61,6 @@ Ignite CLI is a free and open source product maintained by [Ignite](https://igni - [@ignite_dev on Twitter](https://twitter.com/ignite_dev) - [ignite.com/blog](https://ignite.com/blog/) - [Ignite Discord](https://discord.com/invite/ignite) -- [Ignite YouTube](https://www.youtube.com/channel/ignitehq) +- [Ignite YouTube](https://www.youtube.com/ignitehq) - [Ignite docs](https://docs.ignite.com/) - [Ignite jobs](https://ignite.com/careers) diff --git a/scripts/data/gen-nodetime/src/relayer/jsonrpc.ts b/scripts/data/gen-nodetime/src/relayer/jsonrpc.ts index 6972112bf5..44708ea2ad 100644 --- a/scripts/data/gen-nodetime/src/relayer/jsonrpc.ts +++ b/scripts/data/gen-nodetime/src/relayer/jsonrpc.ts @@ -9,21 +9,22 @@ export default async function run(handlers: Handler[]) { const server = new JSONRPCServer(); // attach methods to the rpc server. - for (var [name, func] of handlers) { + for (const [name, func] of handlers) { server.addMethod(name, func); } // read the rpc call, invoke it and send a response. - let jsonreq: string = ""; + let jsonRequest: string = ""; stdin.setEncoding("utf8"); for await (const chunk of stdin) { - jsonreq += chunk; + jsonRequest += chunk; } - const jsonres = await server.receiveJSON(jsonreq); - const res = JSON.stringify(jsonres); + const jsonResponse = await server.receiveJSON(jsonRequest); + const response = JSON.stringify(jsonResponse); - console.log(res); + console.log(response); } + diff --git a/scripts/data/gen-nodetime/src/relayer/lib/logger.ts b/scripts/data/gen-nodetime/src/relayer/lib/logger.ts index f45307b175..8f19bf92f7 100644 --- a/scripts/data/gen-nodetime/src/relayer/lib/logger.ts +++ b/scripts/data/gen-nodetime/src/relayer/lib/logger.ts @@ -16,22 +16,22 @@ export default class ConsoleLogger { public readonly debug: LogMethod; constructor() { - this.error = (msg) => { + this.error = () => { return this; }; - this.warn = (msg) => { + this.warn = () => { return this; }; this.info = (msg) => { - if (msg.indexOf("Relay") == 0 && msg.indexOf("Relay 0") == -1) { + if (msg.indexOf('Relay') == 0 && msg.indexOf('Relay 0') == -1) { console.log(msg); } return this; }; - this.verbose = (msg) => { + this.verbose = () => { return this; }; - this.debug = (msg) => { + this.debug = () => { return this; }; } diff --git a/scripts/data/gen-nodetime/src/relayer/lib/relayer.ts b/scripts/data/gen-nodetime/src/relayer/lib/relayer.ts index 54119eb3ae..7a8720e691 100644 --- a/scripts/data/gen-nodetime/src/relayer/lib/relayer.ts +++ b/scripts/data/gen-nodetime/src/relayer/lib/relayer.ts @@ -1,141 +1,213 @@ // cosmosjs related imports. -import { fromHex } from "@cosmjs/encoding"; -import { DirectSecp256k1Wallet } from "@cosmjs/proto-signing"; -import { GasPrice } from "@cosmjs/stargate"; +import {fromHex} from "@cosmjs/encoding"; +import {DirectSecp256k1Wallet} from "@cosmjs/proto-signing"; +import {GasPrice} from "@cosmjs/stargate"; -import { Link, IbcClient } from "@confio/relayer/build"; -import { orderFromJSON } from "@confio/relayer/build/codec/ibc/core/channel/v1/channel"; +import {Endpoint, IbcClient, Link} from "@confio/relayer/build"; +import {buildCreateClientArgs, prepareConnectionHandshake} from "@confio/relayer/build/lib/ibcclient"; +import {orderFromJSON} from "@confio/relayer/build/codec/ibc/core/channel/v1/channel"; // local imports. -import ConsoleLogger from "./logger"; +import ConsoleLogger from './logger'; const calcGasLimits = (limit: number) => ({ - initClient: 150000, - updateClient: 600000, - initConnection: 150000, - connectionHandshake: limit, - initChannel: 150000, - channelHandshake: limit, - receivePacket: limit, - ackPacket: limit, - timeoutPacket: limit, - transfer: 180000, + initClient: 150000, + updateClient: 600000, + initConnection: 150000, + connectionHandshake: limit, + initChannel: 150000, + channelHandshake: limit, + receivePacket: limit, + ackPacket: limit, + timeoutPacket: limit, + transfer: 180000 }); type Chain = { - id: string; - account: string, - address_prefix: string; - rpc_address: string; - gas_price: string; - gas_limit: number; + id: string; + account: string, + address_prefix: string; + rpc_address: string; + gas_price: string; + gas_limit: number; + client_id: string; }; type Path = { - id: string; - ordering: string; - src: PathEnd; - dst: PathEnd; + id: string; + ordering: string; + src: PathEnd; + dst: PathEnd; }; type PathEnd = { - chain_id: string; - connection_id: string; - channel_id: string; - port_id: string; - version: string; - packet_height: number; - ack_height: number; + chain_id: string; + connection_id: string; + channel_id: string; + port_id: string; + version: string; + packet_height?: number; + ack_height?: number; }; export default class Relayer { - private defaultMaxAge: number = 86400; - - public async link([ - path, - srcChain, - dstChain, - srcKey, - dstKey, - ]: [ Path, Chain, Chain, string, string ]): Promise { - const srcClient = await this.getIBCClient(srcChain, srcKey); - const dstClient = await this.getIBCClient(dstChain, dstKey); - - const link = await Link.createWithNewConnections(srcClient, dstClient); - - const channels = await link.createChannel( - "A", - path.src.port_id, - path.dst.port_id, - orderFromJSON(path.ordering), - path.dst.version, - ); - - path.src.channel_id = channels.src.channelId; - path.dst.channel_id = channels.dest.channelId; - path.src.connection_id = link.endA.connectionID; - path.dst.connection_id = link.endB.connectionID; - - return path; - } - - public async start([ - path, - srcChain, - dstChain, - srcKey, - dstKey, - ]: [ Path, Chain, Chain, string, string ]): Promise { - const srcClient = await this.getIBCClient(srcChain, srcKey); - const dstClient = await this.getIBCClient(dstChain, dstKey); - - const link = await Link.createWithExistingConnections( - srcClient, - dstClient, - path.src.connection_id, - path.dst.connection_id, - new ConsoleLogger(), - ); - - const heights = await link.checkAndRelayPacketsAndAcks( - { - packetHeightA: path.src.packet_height, - packetHeightB: path.dst.packet_height, - ackHeightA: path.src.ack_height, - ackHeightB: path.dst.ack_height, - } ?? {}, - 2, - 6 - ); - - await link.updateClientIfStale("A", this.defaultMaxAge); - await link.updateClientIfStale("B", this.defaultMaxAge); - - path.src.packet_height = heights.packetHeightA; - path.dst.packet_height = heights.packetHeightB; - path.src.ack_height = heights.ackHeightA; - path.dst.ack_height = heights.ackHeightB; - - return path; - } - - private async getIBCClient(chain: Chain, key: string): Promise { - let chainGP = GasPrice.fromString(chain.gas_price); - let signer = await DirectSecp256k1Wallet.fromKey(fromHex(key), chain.address_prefix); - - const [account] = await signer.getAccounts(); - - const client = await IbcClient.connectWithSigner( - chain.rpc_address, - signer, - account.address, - { - prefix: chain.address_prefix, - gasPrice: chainGP, - gasLimits: calcGasLimits(chain.gas_limit), - } - ); - - return client; - } + private defaultMaxAge = 86400; + + public async link([ + path, + srcChain, + dstChain, + srcKey, + dstKey, + ]: [Path, Chain, Chain, string, string]): Promise { + const srcClient = await Relayer.getIBCClient(srcChain, srcKey); + const dstClient = await Relayer.getIBCClient(dstChain, dstKey); + const link = await this.create(srcClient, dstClient, srcChain.client_id, dstChain.client_id); + + const channels = await link.createChannel( + 'A', + path.src.port_id, + path.dst.port_id, + orderFromJSON(path.ordering), + path.dst.version + ); + + path.src.channel_id = channels.src.channelId; + path.dst.channel_id = channels.dest.channelId; + path.src.connection_id = link.endA.connectionID; + path.dst.connection_id = link.endB.connectionID; + + return path; + } + + public async start([ + path, + srcChain, + dstChain, + srcKey, + dstKey + ]: [Path, Chain, Chain, string, string]): Promise { + const srcClient = await Relayer.getIBCClient(srcChain, srcKey); + const dstClient = await Relayer.getIBCClient(dstChain, dstKey); + + const link = await Link.createWithExistingConnections( + srcClient, + dstClient, + path.src.connection_id, + path.dst.connection_id, + new ConsoleLogger() + ); + + const heights = await link.checkAndRelayPacketsAndAcks( + { + packetHeightA: path.src.packet_height, + packetHeightB: path.dst.packet_height, + ackHeightA: path.src.ack_height, + ackHeightB: path.dst.ack_height + } ?? {}, + 2, + 6 + ); + + await link.updateClientIfStale('A', this.defaultMaxAge); + await link.updateClientIfStale('B', this.defaultMaxAge); + + path.src.packet_height = heights.packetHeightA; + path.dst.packet_height = heights.packetHeightB; + path.src.ack_height = heights.ackHeightA; + path.dst.ack_height = heights.ackHeightB; + + return path; + } + + private static async getIBCClient(chain: Chain, key: string): Promise { + const chainGP = GasPrice.fromString(chain.gas_price); + const signer = await DirectSecp256k1Wallet.fromKey(fromHex(key), chain.address_prefix); + + const [account] = await signer.getAccounts(); + + return await IbcClient.connectWithSigner( + chain.rpc_address, + signer, + account.address, + { + prefix: chain.address_prefix, + gasPrice: chainGP, + gasLimits: calcGasLimits(chain.gas_limit) + } + ); + } + + public async create( + nodeA: IbcClient, + nodeB: IbcClient, + clientA: string, + clientB: string + ): Promise { + let dstClientID = clientB; + if (!clientB) { + const args = await buildCreateClientArgs(nodeA); + const {clientId: clientId} = await nodeB.createTendermintClient( + args.clientState, + args.consensusState + ); + dstClientID = clientId; + } + + let srcClientID = clientA; + if (!clientA) { + // client on A pointing to B + const args2 = await buildCreateClientArgs(nodeB); + const {clientId: clientId} = await nodeA.createTendermintClient( + args2.clientState, + args2.consensusState + ); + srcClientID = clientId; + } + + // wait a block to ensure we have proper proofs for creating a connection (this has failed on CI before) + await Promise.all([nodeA.waitOneBlock(), nodeB.waitOneBlock()]); + + // connectionInit on nodeA + const {connectionId: connIdA} = await nodeA.connOpenInit( + srcClientID, + dstClientID + ); + + // connectionTry on nodeB + const proof = await prepareConnectionHandshake( + nodeA, + nodeB, + srcClientID, + dstClientID, + connIdA + ); + + const {connectionId: connIdB} = await nodeB.connOpenTry(dstClientID, proof); + + // connectionAck on nodeA + const proofAck = await prepareConnectionHandshake( + nodeB, + nodeA, + dstClientID, + srcClientID, + connIdB + ); + await nodeA.connOpenAck(connIdA, proofAck); + + // connectionConfirm on dest + const proofConfirm = await prepareConnectionHandshake( + nodeA, + nodeB, + srcClientID, + dstClientID, + connIdA + ); + await nodeB.connOpenConfirm(connIdB, proofConfirm); + + const endA = new Endpoint(nodeA, srcClientID, connIdA); + const endB = new Endpoint(nodeB, dstClientID, connIdB); + + return new Link(endA, endB, new ConsoleLogger()); + } }