diff --git a/.github/workflows/release-sims.yml b/.github/workflows/release-sims.yml index b7faa1a00e7..db2886e988e 100644 --- a/.github/workflows/release-sims.yml +++ b/.github/workflows/release-sims.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/setup-go@v2.1.5 with: - go-version: 1.16 + go-version: 1.17 - name: Install runsim run: export GO111MODULE="on" && go get github.com/cosmos/tools/cmd/runsim@v1.0.0 - uses: actions/cache@v2.1.7 diff --git a/.github/workflows/sims.yml b/.github/workflows/sims.yml index ff99e469210..132ab4e2982 100644 --- a/.github/workflows/sims.yml +++ b/.github/workflows/sims.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/setup-go@v2.1.5 with: - go-version: 1.16 + go-version: 1.17 - name: Install runsim run: export GO111MODULE="on" && go get github.com/cosmos/tools/cmd/runsim@v1.0.0 - uses: actions/cache@v2.1.7 @@ -33,7 +33,7 @@ jobs: # - uses: actions/checkout@v2.4.0 # - uses: actions/setup-go@v2.1.5 # with: -# go-version: 1.16 +# go-version: 1.17 # - uses: technote-space/get-diff-action@v5.0.2 # with: # PATTERNS: | @@ -63,7 +63,7 @@ jobs: - uses: actions/checkout@v2.4.0 - uses: actions/setup-go@v2.1.5 with: - go-version: 1.16 + go-version: 1.17 - uses: actions/cache@v2.1.7 with: path: ~/go/bin @@ -80,7 +80,7 @@ jobs: steps: - uses: actions/setup-go@v2.1.5 with: - go-version: 1.16 + go-version: 1.17 - uses: actions/checkout@v2.4.0 - uses: technote-space/get-diff-action@v5.0.2 with: @@ -105,7 +105,7 @@ jobs: - uses: actions/checkout@v2.4.0 - uses: actions/setup-go@v2.1.5 with: - go-version: 1.16 + go-version: 1.17 - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | @@ -130,7 +130,7 @@ jobs: - uses: actions/checkout@v2.4.0 - uses: actions/setup-go@v2.1.5 with: - go-version: 1.16 + go-version: 1.17 - uses: technote-space/get-diff-action@v5.0.2 with: PATTERNS: | @@ -144,4 +144,4 @@ jobs: - name: test liveness run: | ./contrib/localnet-blocks-test.sh 100 5 50 localhost - if: "env.GIT_DIFF != ''" \ No newline at end of file + if: "env.GIT_DIFF != ''" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index effb9d2ac54..98eafad45b5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/setup-go@v2.1.5 with: - go-version: 1.16 + go-version: 1.17 - uses: actions/checkout@v2.4.0 - uses: technote-space/get-diff-action@v5.0.2 with: @@ -31,7 +31,7 @@ jobs: make build - name: test & coverage report creation run: | - go test ./... -mod=readonly -timeout 12m -race -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' + make test-unit-cover if: "env.GIT_DIFF != ''" - name: filter out DONTCOVER run: | @@ -48,4 +48,27 @@ jobs: with: file: ./coverage.txt # optional fail_ci_if_error: true - if: "env.GIT_DIFF != ''" \ No newline at end of file + if: "env.GIT_DIFF != ''" + + test-e2e: + runs-on: ubuntu-latest + timeout-minutes: 25 + steps: + - uses: actions/setup-go@v2.2.0 + with: + go-version: 1.17 + - uses: actions/checkout@v2 + - uses: technote-space/get-diff-action@v6.0.1 + with: + PATTERNS: | + **/**.go + go.mod + go.sum + - name: Build Docker Image + run: | + make docker-build-debug + if: env.GIT_DIFF + - name: Test E2E + run: | + make test-e2e + if: env.GIT_DIFF diff --git a/.golangci.yml b/.golangci.yml index 540a47632ca..03eff284ce6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,7 @@ run: tests: false -# # timeout for analysis, e.g. 30s, 5m, default is 1m -# timeout: 5m + skip-dirs: + - tests/e2e linters: disable-all: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 47cf18563d8..96402f387da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,11 +36,11 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] -## [7.0.0-rc0] - 2022-03-16 +## [v7.0.0] - 2022-03-24 - (gaia) bump [cosmos-sdk](https://github.com/cosmos/cosmos-sdk) to [v0.45.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.45.1). See [CHANGELOG.md](https://github.com/cosmos/cosmos-sdk/blob/v0.45.1/CHANGELOG.md#v0451---2022-02-03) for details. - (gaia) bump [ibc-go](https://github.com/cosmos/ibc-go) module to [v3.0.0](https://github.com/cosmos/ibc-go/releases/tag/v3.0.0). See [CHANGELOG.md](https://github.com/cosmos/ibc-go/blob/v3.0.0/CHANGELOG.md#v300---2022-03-15) for details. -- (gaia) add [interhcian account](https://github.com/cosmos/ibc-go/tree/main/modules/apps/27-interchain-accounts) module (interhchain-account module is part of ibc-go module). -- (gaia) bump [liquidity](github.com/gravity-devs/liquidity/x/liquidity) module to [v1.5.0](https://github.com/Gravity-Devs/liquidity/releases/tag/v1.5.0). See [CHANGELOG.md](https://github.com/Gravity-Devs/liquidity/blob/v1.5.0/CHANGELOG.md#v150---20220223) for details. +- (gaia) add [interchain account](https://github.com/cosmos/ibc-go/tree/main/modules/apps/27-interchain-accounts) module (interhchain-account module is part of ibc-go module). +- (gaia) bump [liquidity](https://github.com/gravity-devs/liquidity) module to [v1.5.0](https://github.com/Gravity-Devs/liquidity/releases/tag/v1.5.0). See [CHANGELOG.md](https://github.com/Gravity-Devs/liquidity/blob/v1.5.0/CHANGELOG.md#v150---20220223) for details. - (gaia) bump [packet-forward-middleware](https://github.com/strangelove-ventures/packet-forward-middleware) module to [v2.1.1](https://github.com/strangelove-ventures/packet-forward-middleware/releases/tag/v2.1.1). - (gaia) add migration logs for upgrade process. @@ -78,6 +78,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (gaia) This release includes a new AnteHandler that rejects redundant IBC transactions to save relayers fees. +## [v5.0.8] - 2021-10-14 + +* (gaia) This release includes a new AnteHandler that rejects redundant IBC transactions to save relayers fees. + ## [v5.0.7] - 2021-09-30 * (gaia) Bump Cosmos SDK to 0.42.10 @@ -411,8 +415,8 @@ See the [Tendermint v0.34.7 SDK changelog](https://github.com/tendermint/tenderm -[Unreleased]: https://github.com/cosmos/gaia/compare/v7.0.0-rc1...HEAD -[7.0.0-rc0]: https://github.com/cosmos/gaia/releases/tag/v7.0.0-rc0 +[Unreleased]: https://github.com/cosmos/gaia/compare/v7.0.1...HEAD +[v7.0.0]: https://github.com/cosmos/gaia/releases/tag/v7.0.0 [v6.0.4]: https://github.com/cosmos/gaia/releases/tag/v6.0.4 [v6.0.3]: https://github.com/cosmos/gaia/releases/tag/v6.0.3 [v6.0.2]: https://github.com/cosmos/gaia/releases/tag/v6.0.2 diff --git a/Makefile b/Makefile index cf7b0a434d0..9b7d5f7df8a 100644 --- a/Makefile +++ b/Makefile @@ -170,22 +170,39 @@ sync-docs: include sims.mk -test: test-unit test-build - -test-all: check test-race test-cover - -test-unit: - @VERSION=$(VERSION) go test -mod=readonly -tags='ledger test_ledger_mock' ./... - -test-race: - @VERSION=$(VERSION) go test -mod=readonly -race -tags='ledger test_ledger_mock' ./... +PACKAGES_UNIT=$(shell go list ./... | grep -v -e '/tests/e2e') +PACKAGES_E2E=$(shell go list ./... | grep '/e2e') +TEST_PACKAGES=./... +TEST_TARGETS := test-unit test-unit-cover test-race test-e2e + +test-unit: ARGS=-timeout=5m -tags='norace' +test-unit: TEST_PACKAGES=$(PACKAGES_UNIT) +test-unit-cover: ARGS=-timeout=5m -tags='norace' -coverprofile=coverage.txt -covermode=atomic +test-unit-cover: TEST_PACKAGES=$(PACKAGES_UNIT) +test-race: ARGS=-timeout=5m -race +test-race: TEST_PACKAGES=$(PACKAGES_UNIT) +test-e2e: ARGS=-timeout=25m -v +test-e2e: TEST_PACKAGES=$(PACKAGES_E2E) +$(TEST_TARGETS): run-tests + +run-tests: +ifneq (,$(shell which tparse 2>/dev/null)) + @echo "--> Running tests" + @go test -mod=readonly -json $(ARGS) $(TEST_PACKAGES) | tparse +else + @echo "--> Running tests" + @go test -mod=readonly $(ARGS) $(TEST_PACKAGES) +endif -test-cover: - @go test -mod=readonly -timeout 30m -race -coverprofile=coverage.txt -covermode=atomic -tags='ledger test_ledger_mock' ./... +.PHONY: run-tests $(TEST_TARGETS) -benchmark: - @go test -mod=readonly -bench=. ./... +docker-build-debug: + @docker build -t cosmos/gaiad-e2e --build-arg IMG_TAG=debug -f e2e.Dockerfile . +# TODO: Push this to the Cosmos Dockerhub so we don't have to keep building it +# in CI. +docker-build-hermes: + @cd tests/e2e/docker; docker build -t cosmos/hermes-e2e:latest -f hermes.Dockerfile . ############################################################################### ### Linting ### @@ -229,7 +246,6 @@ test-docker-push: test-docker .PHONY: all build-linux install format lint \ go-mod-cache draw-deps clean build \ setup-transactions setup-contract-tests-data start-gaia run-lcd-contract-tests contract-tests \ - test test-all test-build test-cover test-unit test-race \ benchmark \ build-docker-gaiadnode localnet-start localnet-stop \ - docker-single-node + docker-single-node docker-build-debug docker-build-hermes diff --git a/app/app.go b/app/app.go index 4dd2484c113..31d7534c499 100644 --- a/app/app.go +++ b/app/app.go @@ -113,9 +113,6 @@ import ( _ "github.com/cosmos/cosmos-sdk/client/docs/statik" ) -const appName = "GaiaApp" -const upgradeName = "v7-Theta" - var ( // DefaultNodeHome default home directories for the application daemon DefaultNodeHome string @@ -637,32 +634,32 @@ func NewGaiaApp( hostParams := icahosttypes.Params{ HostEnabled: true, AllowMessages: []string{ - "/cosmos.authz.v1beta1.MsgExec", - "/cosmos.authz.v1beta1.MsgGrant", - "/cosmos.authz.v1beta1.MsgRevoke", - "/cosmos.bank.v1beta1.MsgSend", - "/cosmos.bank.v1beta1.MsgMultiSend", - "/cosmos.distribution.v1beta1.MsgSetWithdrawAddress", - "/cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission", - "/cosmos.distribution.v1beta1.MsgFundCommunityPool", - "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", - "/cosmos.feegrant.v1beta1.MsgGrantAllowance", - "/cosmos.feegrant.v1beta1.MsgRevokeAllowance", - "/cosmos.gov.v1beta1.MsgVoteWeighted", - "/cosmos.gov.v1beta1.MsgSubmitProposal", - "/cosmos.gov.v1beta1.MsgDeposit", - "/cosmos.gov.v1beta1.MsgVote", - "/cosmos.staking.v1beta1.MsgEditValidator", - "/cosmos.staking.v1beta1.MsgDelegate", - "/cosmos.staking.v1beta1.MsgUndelegate", - "/cosmos.staking.v1beta1.MsgBeginRedelegate", - "/cosmos.staking.v1beta1.MsgCreateValidator", - "/cosmos.vesting.v1beta1.MsgCreateVestingAccount", - "/ibc.applications.transfer.v1.MsgTransfer", - "/tendermint.liquidity.v1beta1.MsgCreatePool", - "/tendermint.liquidity.v1beta1.MsgSwapWithinBatch", - "/tendermint.liquidity.v1beta1.MsgDepositWithinBatch", - "/tendermint.liquidity.v1beta1.MsgWithdrawWithinBatch", + authzMsgExec, + authzMsgGrant, + authzMsgRevoke, + bankMsgSend, + bankMsgMultiSend, + distrMsgSetWithdrawAddr, + distrMsgWithdrawValidatorCommission, + distrMsgFundCommunityPool, + distrMsgWithdrawDelegatorReward, + feegrantMsgGrantAllowance, + feegrantMsgRevokeAllowance, + govMsgVoteWeighted, + govMsgSubmitProposal, + govMsgDeposit, + govMsgVote, + stakingMsgEditValidator, + stakingMsgDelegate, + stakingMsgUndelegate, + stakingMsgBeginRedelegate, + stakingMsgCreateValidator, + vestingMsgCreateVestingAccount, + transferMsgTransfer, + liquidityMsgCreatePool, + liquidityMsgSwapWithinBatch, + liquidityMsgDepositWithinBatch, + liquidityMsgWithdrawWithinBatch, }, } diff --git a/app/const.go b/app/const.go new file mode 100644 index 00000000000..81a6dc046e3 --- /dev/null +++ b/app/const.go @@ -0,0 +1,33 @@ +package gaia + +const ( + appName = "GaiaApp" + upgradeName = "v7-Theta" + + authzMsgExec = "/cosmos.authz.v1beta1.MsgExec" + authzMsgGrant = "/cosmos.authz.v1beta1.MsgGrant" + authzMsgRevoke = "/cosmos.authz.v1beta1.MsgRevoke" + bankMsgSend = "/cosmos.bank.v1beta1.MsgSend" + bankMsgMultiSend = "/cosmos.bank.v1beta1.MsgMultiSend" + distrMsgSetWithdrawAddr = "/cosmos.distribution.v1beta1.MsgSetWithdrawAddress" + distrMsgWithdrawValidatorCommission = "/cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission" + distrMsgFundCommunityPool = "/cosmos.distribution.v1beta1.MsgFundCommunityPool" + distrMsgWithdrawDelegatorReward = "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward" + feegrantMsgGrantAllowance = "/cosmos.feegrant.v1beta1.MsgGrantAllowance" + feegrantMsgRevokeAllowance = "/cosmos.feegrant.v1beta1.MsgRevokeAllowance" + govMsgVoteWeighted = "/cosmos.gov.v1beta1.MsgVoteWeighted" + govMsgSubmitProposal = "/cosmos.gov.v1beta1.MsgSubmitProposal" + govMsgDeposit = "/cosmos.gov.v1beta1.MsgDeposit" + govMsgVote = "/cosmos.gov.v1beta1.MsgVote" + stakingMsgEditValidator = "/cosmos.staking.v1beta1.MsgEditValidator" + stakingMsgDelegate = "/cosmos.staking.v1beta1.MsgDelegate" + stakingMsgUndelegate = "/cosmos.staking.v1beta1.MsgUndelegate" + stakingMsgBeginRedelegate = "/cosmos.staking.v1beta1.MsgBeginRedelegate" + stakingMsgCreateValidator = "/cosmos.staking.v1beta1.MsgCreateValidator" + vestingMsgCreateVestingAccount = "/cosmos.vesting.v1beta1.MsgCreateVestingAccount" + transferMsgTransfer = "/ibc.applications.transfer.v1.MsgTransfer" + liquidityMsgCreatePool = "/tendermint.liquidity.v1beta1.MsgCreatePool" + liquidityMsgSwapWithinBatch = "/tendermint.liquidity.v1beta1.MsgSwapWithinBatch" + liquidityMsgDepositWithinBatch = "/tendermint.liquidity.v1beta1.MsgDepositWithinBatch" + liquidityMsgWithdrawWithinBatch = "/tendermint.liquidity.v1beta1.MsgWithdrawWithinBatch" +) diff --git a/docs/hub-tutorials/join-testnet.md b/docs/hub-tutorials/join-testnet.md index d045e21c44f..f7d57a8fe25 100644 --- a/docs/hub-tutorials/join-testnet.md +++ b/docs/hub-tutorials/join-testnet.md @@ -4,17 +4,113 @@ order: 4 # Join the Public Testnet -::: tip Current Testnet -See the [testnet repo](https://github.com/cosmos/testnets) for -information on the latest testnet, including the correct version -of Gaia to use and details about the genesis file. -::: +| Current Upgrade | Chain Id | Upgrade Block Height | Upgrade Date | +| --------------- | -------------- | -------------------- | ---------------- | +| Theta | `theta-testnet-001` | TBD | March 17 2021 | + + +## Background +The current Cosmos Hub Testnet is running to prepare for the [Theta Upgrade](https://interchain-io.medium.com/preparing-for-the-cosmos-hub-v7-theta-upgrade-2fc41ce34787). Visit the [testnet explorer](https://explorer.theta-testnet.polypore.xyz/) to view all on chain activity. + +For those who just need instructions on performing the upgrade, see the [Upgrade](#upgrading) section. + +## Releases +If syncing before the Theta update, checkout [`v6.0.0`](https://github.com/cosmos/gaia/tree/v6.0.0). Until a release is cut for the upgrade, feel free to track the [`theta-prepare` branch](https://github.com/cosmos/gaia/tree/theta-prepare). + +## Prerequisites + +**Hardware** + +It's recommended that public testnet nodes are running on machines with at least `16GB` of RAM. + +**Make sure Go & Gaia are [properly installed](../getting-started/installation.md). The most recent Gaia version for the Theta Testnet is [`v6.0.0`](https://github.com/cosmos/gaia/tree/v6.0.0).** + + +This tutorial will provide all necessary instructions for joining the current public testnet. If you're interested in more advanced configuration and synchronization options, see [Join Mainnet](./join-mainnet.md) for a detailed walkthrough. + +## Sync Options +There are two ways to sync a testnet node, Blocksync and State Sync. [Blocksync](https://docs.tendermint.com/v0.35/tendermint-core/block-sync/) syncs the chain from genesis by downloading blocks in paralell and then verifying them. [State Sync](https://docs.tendermint.com/master/tendermint-core/state-sync/#) will look for snapshots from peers at a trusted height and then verifying a minimal set of snapshot chunks against the network. + +State Sync is far faster and more efficient than Blocksync, but Blocksync offers higher data integrity and more robust history. For those who are concerned about storage and costs, State Sync can be the better option as it minimizes storage usage when rebuilding initial state. + +### Configuration & Setup + +To get started, you'll need to install and configure the Gaia binary using the script below. **For Blocksync, it is important to checkout Gaia `release/v6.0.0`. For State Sync checkout the most recent [testnet release](https://github.com/cosmos/gaia/tree/v6.0.0) until the upgrade is performed** + +This example is using the Theta testnet genesis. For up to date values like `seeds`, visit the [testnet repository](https://github.com/cosmos/testnets). + +> **Note**: Cosmos Hub recommends running `gaiad` or `cosmovisor` with the `--x-crisis-skip-assert-invariants` flag. If checking for invariants, operators are likely to see `rounding error withdrawing rewards from validator`. These are expected. For more information see [Verify Mainnet](./join-mainnet.md#verify-mainnet) + +``` +# Build gaiad binary and initialize chain +cd $HOME +git clone -b release/ https://github.com/cosmos/gaia +cd gaia +make install +gaiad init + +# Prepare genesis file +wget https://github.com/hyphacoop/testnets/raw/add-theta-testnet/v7-theta/public-testnet/genesis.json.gz +gzip -d genesis.json.gz +mv genesis.json $HOME/.gaia/config/genesis.json + +# Set minimum gas price & peers +cd $HOME/.gaia/config +sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0.001uatom"/' app.toml +sed -i 's/persistent_peers = ""/persistent_peers = ","/' config.toml +``` + +### State Sync ::: warning -**You need to [install gaia](./getting-started/installation.md) before you go further** +State Sync requires Gaia version [`v6.0.0`](https://github.com/cosmos/gaia/tree/v6.0.0) until the upgrade is performed. ::: -## Starting a New Node +**Check out the [quickstart script](https://github.com/cosmos/testnets/tree/master/v7-theta/public-testnet#quickstart-on-a-fresh-machine-eg-on-digital-ocean-droplet) to bootstrap a Theta testnet node and configure as needed** + +There will need to be additional configuration to enable State Sync on the testnet. State Sync requires setting an initial list of `persistent_peers` to fetch snapshots from. This will change and eventually move to the p2p layer when the Cosmos Hub upgrades to [Tendermint `v0.35`](https://github.com/tendermint/tendermint/issues/6491). For the sake of simplicity, this step is already done in the [Configuration & Setup](#configuration-amp=-setup) section. + +Visit a [testnet explorer](https://explorer.theta-testnet.polypore.xyz/) to get a recent block height and corresponding hash. A node operator can choose any height/hash in the current bonding period, but as the recommended snapshot period is 1000 blocks, it is advised to choose something close to current height - 1000. Set these parameters in the code snippet below `` and `` + +For up to date values like `rpc_servers`, visit the current [testnet repository](https://github.com/cosmos/testnets). + +``` +cd $HOME/.gaia/config +sed -i 's/enable = false/enable = true/' config.toml +sed -i 's/trust_height = 0/trust_height = /' config.toml +sed -i 's/trust_hash = ""/trust_hash = ""/' config.toml +sed -i 's/rpc_servers = ""/rpc_servers = ":26657,:26657"/' config.toml +``` + +Now run `gaiad start --x-crisis-skip-assert-invariants` or if using [Cosmovisor](#using-cosmovisor), `cosmovisor start --x-crisis-skip-assert-invariants`. Once a snapshot is found and verified, the chain will start syncing via regular consensus within minutes. + +### Using Cosmovisor + +Cosmovisor is a process manager that monitors the governance module for incoming chain upgrade proposals. When a proposal is approved, Cosmovisor can automatically download the new binary, stop the chain when it hits the upgrade height, switch to the new binary, and restart the daemon. This tutorial will provide instructions for the most efficient way to sync via Cosmovisor. For more information on configuration, check out the Cosmos SDK's [Cosmovisor repository documentation](https://github.com/cosmos/cosmos-sdk/tree/master/cosmovisor#auto-download). + +Cosmovisor can be used when syncing with Blocksync or State Sync. Make sure to follow the Cosmovisor setup below, and then run `cosmovisor start` in place of `gaiad start`. + +Cosmovisor requires the creation the following directory structure: +```shell +. +├── current -> genesis or upgrades/ +├── genesis +│ └── bin +│ └── gaiad +└── upgrades + └── v7-Theta + ├── bin + │ └── gaiad + └── upgrade-info.json +``` + +It is possible to enable autodownload for the new binary, but for the purpose of this tutorial, the setup instructions will include how to do this manually. For more information on autodownload with Cosmovisor, see the full docs on [setting up Cosmosvisor](https://github.com/cosmos/cosmos-sdk/blob/master/cosmovisor/README.md). + +The following script installs, configures and starts Cosmovisor: + +``` +# Install Cosmovisor +go get github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor > NOTE: If you ran a full node on a previous testnet, please skip to [Upgrading From Previous Testnet](#upgrading-from-previous-testnet). @@ -29,31 +125,35 @@ The only difference is the SDK version and genesis file. See the [testnet repo]( These instructions are for full nodes that have ran on previous versions of and would like to upgrade to the latest testnet. -### Reset Data +When the chain reaches the upgrade block height, the chain will halt and you will have to download the new binary and move it to the correct folder. For the `Theta` upgrade, this would look like: +``` +# Prepare Theta upgrade directory +mkdir -p ~/.gaia/cosmovisor/upgrades/Theta/bin -First, remove the outdated files and reset the data. +# Download and install the new binary version. +cd $HOME/gaia +git pull +git checkout +make install -```bash -rm $HOME/.gaia/config/addrbook.json $HOME/.gaia/config/genesis.json -gaiad unsafe-reset-all +# Move the new binary to the Theta upgrade directory +cp $GOPATH/bin/gaiad ~/.gaia/cosmovisor/upgrades/Theta/bin ``` Your node is now in a pristine state while keeping the original `priv_validator.json` and `config.toml`. If you had any sentry nodes or full nodes setup before, your node will still try to connect to them, but may fail if they haven't also been upgraded. -::: danger Warning -Make sure that every node has a unique `priv_validator.json`. Do not copy the `priv_validator.json` from an old node to multiple new nodes. Running two nodes with the same `priv_validator.json` will cause you to double sign. -::: +### Blocksync +Blocksync will require navigating the Theta upgrade either via [Cosmovisor](#using-cosmovisor) or manually. -### Software Upgrade +Manually updating `gaiad` will require stopping the chain and installing the new binary once it halts at the expected block height (some time on March 17, TBA). -Now it is time to upgrade the software: +Logs will show `ERR UPGRADE "Theta" NEEDED at height: XXXX`. Stop `gaiad` and run the following: -```bash -git clone https://github.com/cosmos/gaia.git -cd gaia -git fetch --all && git checkout master +``` +cd $HOME/gaia +git checkout make install ``` @@ -64,4 +164,4 @@ _NOTE_: If you have issues at this step, please check that you have the latest s Note we use `master` here since it contains the latest stable release. See the [testnet repo](https://github.com/cosmos/testnets) for details on which version is needed for which testnet, and the [Gaia release page](https://github.com/cosmos/gaia/releases) for details on each release. -Your full node has been cleanly upgraded! +Once the new binary is installed, restart the Gaia daemon. Logs will show `INF applying upgrade "Theta" at height: XXXXX`. After a few minutes, the node will start syncing blocks. diff --git a/docs/roadmap/cosmos-hub-roadmap-2.0.md b/docs/roadmap/cosmos-hub-roadmap-2.0.md index 869fa486b70..aa56264fd8d 100644 --- a/docs/roadmap/cosmos-hub-roadmap-2.0.md +++ b/docs/roadmap/cosmos-hub-roadmap-2.0.md @@ -62,9 +62,15 @@ The upgrades aim to add features such as liquidity, economic security, usability - Liquid Staking - Frees secure and low-risk delegations for use in other parts of the Cosmos ecosystem - Features include enabling transfer of rewards and voting rights -- Governance permissioned CosmWASM instance on the hub -- Budget Module +- Wasmd + - Governance permissioned CosmWASM instance on the hub +- Budget Module (stretch-goal) - Inflation funding directed to arbitrary module and account addresses +- Global Fee Module (stretch-goal) + - Allows denoms and min-fees to be governance parameters so gas can be paid in various denoms. + - Visible on [tgrade](https://github.com/confio/tgrade/tree/main/x/globalfee) already and enabled in [ante.go](https://github.com/confio/tgrade/blob/main/app/ante.go#L72-L92) +- Bech32 Prefix forwarding (stretch-goal) + - https://github.com/osmosis-labs/bech32-ibc ## v9-Lambda Upgrade (expected Q3 2022) - Gaia v9.0.x diff --git a/docs/validators/validator-setup.md b/docs/validators/validator-setup.md index 4d180d3d1fc..c862a64a0c8 100644 --- a/docs/validators/validator-setup.md +++ b/docs/validators/validator-setup.md @@ -136,7 +136,7 @@ When attempting to perform routine maintenance or planning for an upcoming coord the block. ## Advanced configuration -You can find more advanced information about running a node or a validator on the [Tendermint Core documentation](https://docs.tendermint.com/master/nodes/). +You can find more advanced information about running a node or a validator on the [Tendermint Core documentation](https://docs.tendermint.com/v0.35/nodes/). ## Common Problems @@ -181,4 +181,4 @@ LimitNOFILE=4096 [Install] WantedBy=multi-user.target -``` \ No newline at end of file +``` diff --git a/e2e.Dockerfile b/e2e.Dockerfile new file mode 100644 index 00000000000..52011341380 --- /dev/null +++ b/e2e.Dockerfile @@ -0,0 +1,19 @@ +ARG IMG_TAG=latest + +# Compile the gaiad binary +FROM golang:1.17-alpine AS gaiad-builder +WORKDIR /src/app/ +COPY go.mod go.sum* ./ +RUN go mod download +COPY . . +ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3 +RUN apk add --no-cache $PACKAGES +RUN CGO_ENABLED=0 make install + +# Add to a distroless container +FROM gcr.io/distroless/cc:$IMG_TAG +ARG IMG_TAG +COPY --from=gaiad-builder /go/bin/gaiad /usr/local/bin/ +EXPOSE 26656 26657 1317 9090 + +ENTRYPOINT ["gaiad", "start"] diff --git a/go.mod b/go.mod index 68f04093868..2ec9fe4285a 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,15 @@ go 1.17 require ( github.com/cosmos/cosmos-sdk v0.45.1 + github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/ibc-go/v3 v3.0.0 github.com/gorilla/mux v1.8.0 github.com/gravity-devs/liquidity v1.5.0 + github.com/ory/dockertest/v3 v3.8.1 github.com/rakyll/statik v0.1.7 github.com/spf13/cast v1.4.1 github.com/spf13/cobra v1.3.0 + github.com/spf13/viper v1.10.1 github.com/strangelove-ventures/packet-forward-middleware/v2 v2.1.1 github.com/stretchr/testify v1.7.0 github.com/tendermint/tendermint v0.34.14 @@ -19,20 +22,23 @@ require ( require ( filippo.io/edwards25519 v1.0.0-beta.2 // indirect github.com/99designs/keyring v1.1.6 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/DataDog/zstd v1.4.5 // indirect + github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/Workiva/go-datastructures v1.0.52 // indirect github.com/armon/go-metrics v0.3.10 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect + github.com/cenkalti/backoff/v4 v4.1.2 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/coinbase/rosetta-sdk-go v0.7.0 // indirect github.com/confio/ics23/go v0.7.0 // indirect github.com/containerd/continuity v0.1.0 // indirect github.com/cosmos/btcutil v1.0.4 // indirect - github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/iavl v0.17.3 // indirect github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect github.com/cosmos/ledger-go v0.9.2 // indirect @@ -42,6 +48,10 @@ require ( github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/docker/cli v20.10.11+incompatible // indirect + github.com/docker/docker v20.10.7+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect github.com/felixge/httpsnoop v1.0.1 // indirect @@ -56,6 +66,7 @@ require ( github.com/golang/snappy v0.0.3 // indirect github.com/google/btree v1.0.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -68,6 +79,7 @@ require ( github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 // indirect + github.com/imdario/mergo v0.3.12 // indirect github.com/improbable-eng/grpc-web v0.14.1 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect @@ -82,8 +94,11 @@ require ( github.com/minio/highwayhash v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/opencontainers/runc v1.0.3 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -97,16 +112,19 @@ require ( github.com/rs/cors v1.7.0 // indirect github.com/rs/zerolog v1.23.0 // indirect github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect + github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/afero v1.6.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.10.1 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/btcd v0.1.1 // indirect github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect github.com/tendermint/go-amino v0.16.0 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/zondax/hid v0.9.0 // indirect go.etcd.io/bbolt v1.3.6 // indirect golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect diff --git a/go.sum b/go.sum index 7bbc19fa68d..54c4599b52a 100644 --- a/go.sum +++ b/go.sum @@ -77,8 +77,9 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= @@ -152,6 +153,8 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= @@ -219,6 +222,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= @@ -241,7 +246,11 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docker/cli v20.10.11+incompatible h1:tXU1ezXcruZQRrMP8RN2z9N91h+6egZTS1gsPsKantc= +github.com/docker/cli v20.10.11+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ= +github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= @@ -414,6 +423,8 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -515,6 +526,8 @@ github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3 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/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/improbable-eng/grpc-web v0.14.1 h1:NrN4PY71A6tAz2sKDvC5JCauENWp0ykG8Oq1H3cpFvw= github.com/improbable-eng/grpc-web v0.14.1/go.mod h1:zEjGHa8DAlkoOXmswrNvhUGEYQA9UI7DhrGeHR1DMGU= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -570,6 +583,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 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 v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -628,6 +642,8 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -700,6 +716,8 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.8.1 h1:vU/8d1We4qIad2YM0kOwRVtnyue7ExvacPiw1yDm17g= +github.com/ory/dockertest/v3 v3.8.1/go.mod h1:wSRQ3wmkz+uSARYMk7kVJFDBGm8x5gSxIhI7NDc+BAQ= github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -908,6 +926,12 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI= github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= @@ -1155,6 +1179,7 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1221,6 +1246,7 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1443,7 +1469,11 @@ 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= +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= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/tests/e2e/chain.go b/tests/e2e/chain.go new file mode 100644 index 00000000000..a16c69dabf3 --- /dev/null +++ b/tests/e2e/chain.go @@ -0,0 +1,126 @@ +package e2e + +import ( + "fmt" + "io/ioutil" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + tmrand "github.com/tendermint/tendermint/libs/rand" + + gaia "github.com/cosmos/gaia/v7/app" + "github.com/cosmos/gaia/v7/app/params" +) + +const ( + keyringPassphrase = "testpassphrase" + keyringAppName = "testnet" +) + +var ( + encodingConfig params.EncodingConfig + cdc codec.Codec +) + +func init() { + encodingConfig = gaia.MakeEncodingConfig() + + encodingConfig.InterfaceRegistry.RegisterImplementations( + (*sdk.Msg)(nil), + &stakingtypes.MsgCreateValidator{}, + ) + encodingConfig.InterfaceRegistry.RegisterImplementations( + (*cryptotypes.PubKey)(nil), + &secp256k1.PubKey{}, + &ed25519.PubKey{}, + ) + + cdc = encodingConfig.Marshaler +} + +type chain struct { + dataDir string + id string + validators []*validator +} + +func newChain() (*chain, error) { + tmpDir, err := ioutil.TempDir("", "gaia-e2e-testnet-") + if err != nil { + return nil, err + } + + return &chain{ + id: "chain-" + tmrand.NewRand().Str(6), + dataDir: tmpDir, + }, nil +} + +func (c *chain) configDir() string { + return fmt.Sprintf("%s/%s", c.dataDir, c.id) +} + +func (c *chain) createAndInitValidators(count int) error { + for i := 0; i < count; i++ { + node := c.createValidator(i) + + // generate genesis files + if err := node.init(); err != nil { + return err + } + + c.validators = append(c.validators, node) + + // create keys + if err := node.createKey("val"); err != nil { + return err + } + if err := node.createNodeKey(); err != nil { + return err + } + if err := node.createConsensusKey(); err != nil { + return err + } + } + + return nil +} + +func (c *chain) createAndInitValidatorsWithMnemonics(count int, mnemonics []string) error { + for i := 0; i < count; i++ { + // create node + node := c.createValidator(i) + + // generate genesis files + if err := node.init(); err != nil { + return err + } + + c.validators = append(c.validators, node) + + // create keys + if err := node.createKeyFromMnemonic("val", mnemonics[i]); err != nil { + return err + } + if err := node.createNodeKey(); err != nil { + return err + } + if err := node.createConsensusKey(); err != nil { + return err + } + } + + return nil +} + +func (c *chain) createValidator(index int) *validator { + return &validator{ + chain: c, + index: index, + moniker: fmt.Sprintf("%s-gaia-%d", c.id, index), + } +} diff --git a/tests/e2e/doc.go b/tests/e2e/doc.go new file mode 100644 index 00000000000..698fb496dde --- /dev/null +++ b/tests/e2e/doc.go @@ -0,0 +1,14 @@ +// package e2e defines an integration testing suite used for full end-to-end +// testing functionality. +// +// The file e2e_suite_test.go defines the testing suite and contains the core +// bootrapping logic that creates a testing environment via Docker containers. +// A testing network is created dynamically and contains multiple Docker +// containers: +// +// 1. Two independent Gaia networks +// 3. A hermes relayer connecting the two Gaia networks over IBC +// +// The file e2e_test.go contains the actual end-to-end integration tests that +// utilize the testing suite. +package e2e diff --git a/tests/e2e/docker/hermes.Dockerfile b/tests/e2e/docker/hermes.Dockerfile new file mode 100644 index 00000000000..432e444e102 --- /dev/null +++ b/tests/e2e/docker/hermes.Dockerfile @@ -0,0 +1,12 @@ +FROM informalsystems/hermes:0.12.0 AS hermes-builder + +FROM debian:buster-slim +USER root + +COPY --chown=0:0 --from=hermes-builder /usr/lib/x86_64-linux-gnu/libssl.so.1.1 /usr/lib/x86_64-linux-gnu/libssl.so.1.1 +COPY --chown=0:0 --from=hermes-builder /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 +COPY --from=hermes-builder /usr/bin/hermes /usr/local/bin/ +RUN chmod +x /usr/local/bin/hermes + +EXPOSE 3031 +ENTRYPOINT ["hermes", "start"] diff --git a/tests/e2e/e2e_setup_test.go b/tests/e2e/e2e_setup_test.go new file mode 100644 index 00000000000..e7db4f57d02 --- /dev/null +++ b/tests/e2e/e2e_setup_test.go @@ -0,0 +1,421 @@ +package e2e + +import ( + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "path" + "path/filepath" + "strconv" + "strings" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/server" + srvconfig "github.com/cosmos/cosmos-sdk/server/config" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" + "github.com/spf13/viper" + "github.com/stretchr/testify/suite" + tmconfig "github.com/tendermint/tendermint/config" + tmjson "github.com/tendermint/tendermint/libs/json" + rpchttp "github.com/tendermint/tendermint/rpc/client/http" +) + +const ( + photonDenom = "photon" + initBalanceStr = "110000000000stake,100000000000photon" + minGasPrice = "0.00001" +) + +var ( + stakeAmount, _ = sdk.NewIntFromString("100000000000") + stakeAmountCoin = sdk.NewCoin("stake", stakeAmount) +) + +type IntegrationTestSuite struct { + suite.Suite + + tmpDirs []string + chainA *chain + chainB *chain + dkrPool *dockertest.Pool + dkrNet *dockertest.Network + hermesResource *dockertest.Resource + valResources map[string][]*dockertest.Resource +} + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up e2e integration test suite...") + + var err error + s.chainA, err = newChain() + s.Require().NoError(err) + + s.chainB, err = newChain() + s.Require().NoError(err) + + s.dkrPool, err = dockertest.NewPool("") + s.Require().NoError(err) + + s.dkrNet, err = s.dkrPool.CreateNetwork(fmt.Sprintf("%s-%s-testnet", s.chainA.id, s.chainB.id)) + s.Require().NoError(err) + + s.valResources = make(map[string][]*dockertest.Resource) + + // The boostrapping phase is as follows: + // + // 1. Initialize Gaia validator nodes. + // 2. Create and initialize Gaia validator genesis files (both chains) + // 3. Start both networks. + // 4. Create and run IBC relayer (Hermes) containers. + + s.T().Logf("starting e2e infrastructure for chain A; chain-id: %s; datadir: %s", s.chainA.id, s.chainA.dataDir) + s.initNodes(s.chainA) + s.initGenesis(s.chainA) + s.initValidatorConfigs(s.chainA) + s.runValidators(s.chainA, 0) + + s.T().Logf("starting e2e infrastructure for chain B; chain-id: %s; datadir: %s", s.chainB.id, s.chainB.dataDir) + s.initNodes(s.chainB) + s.initGenesis(s.chainB) + s.initValidatorConfigs(s.chainB) + s.runValidators(s.chainB, 10) + + s.runIBCRelayer() +} + +func (s *IntegrationTestSuite) TearDownSuite() { + if str := os.Getenv("GAIA_E2E_SKIP_CLEANUP"); len(str) > 0 { + skipCleanup, err := strconv.ParseBool(str) + s.Require().NoError(err) + + if skipCleanup { + return + } + } + + s.T().Log("tearing down e2e integration test suite...") + + s.Require().NoError(s.dkrPool.Purge(s.hermesResource)) + + for _, vr := range s.valResources { + for _, r := range vr { + s.Require().NoError(s.dkrPool.Purge(r)) + } + } + + s.Require().NoError(s.dkrPool.RemoveNetwork(s.dkrNet)) + + os.RemoveAll(s.chainA.dataDir) + os.RemoveAll(s.chainB.dataDir) + + for _, td := range s.tmpDirs { + os.RemoveAll(td) + } +} + +func (s *IntegrationTestSuite) initNodes(c *chain) { + s.Require().NoError(c.createAndInitValidators(2)) + + // initialize a genesis file for the first validator + val0ConfigDir := c.validators[0].configDir() + for _, val := range c.validators { + s.Require().NoError( + addGenesisAccount(val0ConfigDir, "", initBalanceStr, val.keyInfo.GetAddress()), + ) + } + + // copy the genesis file to the remaining validators + for _, val := range c.validators[1:] { + _, err := copyFile( + filepath.Join(val0ConfigDir, "config", "genesis.json"), + filepath.Join(val.configDir(), "config", "genesis.json"), + ) + s.Require().NoError(err) + } +} + +func (s *IntegrationTestSuite) initGenesis(c *chain) { + serverCtx := server.NewDefaultContext() + config := serverCtx.Config + + config.SetRoot(c.validators[0].configDir()) + config.Moniker = c.validators[0].moniker + + genFilePath := config.GenesisFile() + appGenState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFilePath) + s.Require().NoError(err) + + var bankGenState banktypes.GenesisState + s.Require().NoError(cdc.UnmarshalJSON(appGenState[banktypes.ModuleName], &bankGenState)) + + bankGenState.DenomMetadata = append(bankGenState.DenomMetadata, banktypes.Metadata{ + Description: "An example stable token", + Display: photonDenom, + Base: photonDenom, + Symbol: photonDenom, + Name: photonDenom, + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: photonDenom, + Exponent: 0, + }, + }, + }) + + bz, err := cdc.MarshalJSON(&bankGenState) + s.Require().NoError(err) + appGenState[banktypes.ModuleName] = bz + + var genUtilGenState genutiltypes.GenesisState + s.Require().NoError(cdc.UnmarshalJSON(appGenState[genutiltypes.ModuleName], &genUtilGenState)) + + // generate genesis txs + genTxs := make([]json.RawMessage, len(c.validators)) + for i, val := range c.validators { + createValmsg, err := val.buildCreateValidatorMsg(stakeAmountCoin) + s.Require().NoError(err) + + signedTx, err := val.signMsg(createValmsg) + s.Require().NoError(err) + + txRaw, err := cdc.MarshalJSON(signedTx) + s.Require().NoError(err) + + genTxs[i] = txRaw + } + + genUtilGenState.GenTxs = genTxs + + bz, err = cdc.MarshalJSON(&genUtilGenState) + s.Require().NoError(err) + appGenState[genutiltypes.ModuleName] = bz + + bz, err = json.MarshalIndent(appGenState, "", " ") + s.Require().NoError(err) + + genDoc.AppState = bz + + bz, err = tmjson.MarshalIndent(genDoc, "", " ") + s.Require().NoError(err) + + // write the updated genesis file to each validator + for _, val := range c.validators { + writeFile(filepath.Join(val.configDir(), "config", "genesis.json"), bz) + } +} + +func (s *IntegrationTestSuite) initValidatorConfigs(c *chain) { + for i, val := range c.validators { + tmCfgPath := filepath.Join(val.configDir(), "config", "config.toml") + + vpr := viper.New() + vpr.SetConfigFile(tmCfgPath) + s.Require().NoError(vpr.ReadInConfig()) + + valConfig := &tmconfig.Config{} + s.Require().NoError(vpr.Unmarshal(valConfig)) + + valConfig.P2P.ListenAddress = "tcp://0.0.0.0:26656" + valConfig.P2P.AddrBookStrict = false + valConfig.P2P.ExternalAddress = fmt.Sprintf("%s:%d", val.instanceName(), 26656) + valConfig.RPC.ListenAddress = "tcp://0.0.0.0:26657" + valConfig.StateSync.Enable = false + valConfig.LogLevel = "info" + + var peers []string + + for j := 0; j < len(c.validators); j++ { + if i == j { + continue + } + + peer := c.validators[j] + peerID := fmt.Sprintf("%s@%s%d:26656", peer.nodeKey.ID(), peer.moniker, j) + peers = append(peers, peerID) + } + + valConfig.P2P.PersistentPeers = strings.Join(peers, ",") + + tmconfig.WriteConfigFile(tmCfgPath, valConfig) + + // set application configuration + appCfgPath := filepath.Join(val.configDir(), "config", "app.toml") + + appConfig := srvconfig.DefaultConfig() + appConfig.API.Enable = true + appConfig.MinGasPrices = fmt.Sprintf("%s%s", minGasPrice, photonDenom) + + srvconfig.WriteConfigFile(appCfgPath, appConfig) + } +} + +func (s *IntegrationTestSuite) runValidators(c *chain, portOffset int) { + s.T().Logf("starting Gaia %s validator containers...", c.id) + + s.valResources[c.id] = make([]*dockertest.Resource, len(c.validators)) + for i, val := range c.validators { + runOpts := &dockertest.RunOptions{ + Name: val.instanceName(), + NetworkID: s.dkrNet.Network.ID, + Mounts: []string{ + fmt.Sprintf("%s/:/root/.gaia", val.configDir()), + }, + Repository: "cosmos/gaiad-e2e", + } + + // expose the first validator for debugging and communication + if val.index == 0 { + runOpts.PortBindings = map[docker.Port][]docker.PortBinding{ + "1317/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 1317+portOffset)}}, + "6060/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 6060+portOffset)}}, + "6061/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 6061+portOffset)}}, + "6062/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 6062+portOffset)}}, + "6063/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 6063+portOffset)}}, + "6064/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 6064+portOffset)}}, + "6065/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 6065+portOffset)}}, + "9090/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 9090+portOffset)}}, + "26656/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 26656+portOffset)}}, + "26657/tcp": {{HostIP: "", HostPort: fmt.Sprintf("%d", 26657+portOffset)}}, + } + } + + resource, err := s.dkrPool.RunWithOptions(runOpts, noRestart) + s.Require().NoError(err) + + s.valResources[c.id][i] = resource + s.T().Logf("started Gaia %s validator container: %s", c.id, resource.Container.ID) + } + + rpcClient, err := rpchttp.New("tcp://localhost:26657", "/websocket") + s.Require().NoError(err) + + s.Require().Eventually( + func() bool { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + + status, err := rpcClient.Status(ctx) + if err != nil { + return false + } + + // let the node produce a few blocks + if status.SyncInfo.CatchingUp || status.SyncInfo.LatestBlockHeight < 3 { + return false + } + + return true + }, + 5*time.Minute, + time.Second, + "Gaia node failed to produce blocks", + ) +} + +func (s *IntegrationTestSuite) runIBCRelayer() { + s.T().Log("starting Hermes relayer container...") + + tmpDir, err := ioutil.TempDir("", "gaia-e2e-testnet-hermes-") + s.Require().NoError(err) + s.tmpDirs = append(s.tmpDirs, tmpDir) + + gaiaAVal := s.chainA.validators[0] + gaiaBVal := s.chainB.validators[0] + hermesCfgPath := path.Join(tmpDir, "hermes") + + s.Require().NoError(os.MkdirAll(hermesCfgPath, 0755)) + _, err = copyFile( + filepath.Join("./scripts/", "hermes_bootstrap.sh"), + filepath.Join(hermesCfgPath, "hermes_bootstrap.sh"), + ) + s.Require().NoError(err) + + s.hermesResource, err = s.dkrPool.RunWithOptions( + &dockertest.RunOptions{ + Name: fmt.Sprintf("%s-%s-relayer", s.chainA.id, s.chainB.id), + Repository: "ghcr.io/cosmos/hermes-e2e", + Tag: "latest", + NetworkID: s.dkrNet.Network.ID, + Mounts: []string{ + fmt.Sprintf("%s/:/root/hermes", hermesCfgPath), + }, + PortBindings: map[docker.Port][]docker.PortBinding{ + "3031/tcp": {{HostIP: "", HostPort: "3031"}}, + }, + Env: []string{ + fmt.Sprintf("GAIA_A_E2E_CHAIN_ID=%s", s.chainA.id), + fmt.Sprintf("GAIA_B_E2E_CHAIN_ID=%s", s.chainB.id), + fmt.Sprintf("GAIA_A_E2E_VAL_MNEMONIC=%s", gaiaAVal.mnemonic), + fmt.Sprintf("GAIA_B_E2E_VAL_MNEMONIC=%s", gaiaBVal.mnemonic), + fmt.Sprintf("GAIA_A_E2E_VAL_HOST=%s", s.valResources[s.chainA.id][0].Container.Name[1:]), + fmt.Sprintf("GAIA_B_E2E_VAL_HOST=%s", s.valResources[s.chainB.id][0].Container.Name[1:]), + }, + Entrypoint: []string{ + "sh", + "-c", + "chmod +x /root/hermes/hermes_bootstrap.sh && /root/hermes/hermes_bootstrap.sh", + }, + }, + noRestart, + ) + s.Require().NoError(err) + + endpoint := fmt.Sprintf("http://%s/state", s.hermesResource.GetHostPort("3031/tcp")) + s.Require().Eventually( + func() bool { + resp, err := http.Get(endpoint) + if err != nil { + return false + } + + defer resp.Body.Close() + + bz, err := io.ReadAll(resp.Body) + if err != nil { + return false + } + + var respBody map[string]interface{} + if err := json.Unmarshal(bz, &respBody); err != nil { + return false + } + + status := respBody["status"].(string) + result := respBody["result"].(map[string]interface{}) + + return status == "success" && len(result["chains"].([]interface{})) == 2 + }, + 5*time.Minute, + time.Second, + "hermes relayer not healthy", + ) + + s.T().Logf("started Hermes relayer container: %s", s.hermesResource.Container.ID) + + // XXX: Give time to both networks to start, otherwise we might see gRPC + // transport errors. + time.Sleep(10 * time.Second) + + // create the client, connection and channel between the two Gaia chains + s.connectIBCChains() +} + +func noRestart(config *docker.HostConfig) { + // in this case we don't want the nodes to restart on failure + config.RestartPolicy = docker.RestartPolicy{ + Name: "no", + } +} diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go new file mode 100644 index 00000000000..58dbb110b94 --- /dev/null +++ b/tests/e2e/e2e_test.go @@ -0,0 +1,47 @@ +package e2e + +import ( + "fmt" + "strings" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (s *IntegrationTestSuite) TestIBCTokenTransfer() { + var ibcStakeDenom string + + s.Run("send_photon_to_chainB", func() { + recipient := s.chainB.validators[0].keyInfo.GetAddress().String() + token := sdk.NewInt64Coin(photonDenom, 3300000000) // 3,300photon + s.sendIBC(s.chainA.id, s.chainB.id, recipient, token) + + chainBAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainB.id][0].GetHostPort("1317/tcp")) + + // require the recipient account receives the IBC tokens (IBC packets ACKd) + var ( + balances sdk.Coins + err error + ) + s.Require().Eventually( + func() bool { + balances, err = queryGaiaAllBalances(chainBAPIEndpoint, recipient) + s.Require().NoError(err) + + return balances.Len() == 3 + }, + time.Minute, + 5*time.Second, + ) + + for _, c := range balances { + if strings.Contains(c.Denom, "ibc/") { + ibcStakeDenom = c.Denom + s.Require().Equal(token.Amount.Int64(), c.Amount.Int64()) + break + } + } + + s.Require().NotEmpty(ibcStakeDenom) + }) +} diff --git a/tests/e2e/e2e_util_test.go b/tests/e2e/e2e_util_test.go new file mode 100644 index 00000000000..ab6e8371e8c --- /dev/null +++ b/tests/e2e/e2e_util_test.go @@ -0,0 +1,185 @@ +package e2e + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ory/dockertest/v3/docker" +) + +func (s *IntegrationTestSuite) connectIBCChains() { + s.T().Logf("connecting %s and %s chains via IBC", s.chainA.id, s.chainB.id) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + exec, err := s.dkrPool.Client.CreateExec(docker.CreateExecOptions{ + Context: ctx, + AttachStdout: true, + AttachStderr: true, + Container: s.hermesResource.Container.ID, + User: "root", + Cmd: []string{ + "hermes", + "create", + "channel", + s.chainA.id, + s.chainB.id, + "--port-a=transfer", + "--port-b=transfer", + }, + }) + s.Require().NoError(err) + + var ( + outBuf bytes.Buffer + errBuf bytes.Buffer + ) + + err = s.dkrPool.Client.StartExec(exec.ID, docker.StartExecOptions{ + Context: ctx, + Detach: false, + OutputStream: &outBuf, + ErrorStream: &errBuf, + }) + s.Require().NoErrorf( + err, + "failed connect chains; stdout: %s, stderr: %s", outBuf.String(), errBuf.String(), + ) + + s.Require().Containsf( + errBuf.String(), + "successfully opened init channel", + "failed to connect chains via IBC: %s", errBuf.String(), + ) + + s.T().Logf("connected %s and %s chains via IBC", s.chainA.id, s.chainB.id) +} + +func (s *IntegrationTestSuite) sendIBC(srcChainID, dstChainID, recipient string, token sdk.Coin) { + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + s.T().Logf("sending %s from %s to %s (%s)", token, srcChainID, dstChainID, recipient) + + exec, err := s.dkrPool.Client.CreateExec(docker.CreateExecOptions{ + Context: ctx, + AttachStdout: true, + AttachStderr: true, + Container: s.hermesResource.Container.ID, + User: "root", + Cmd: []string{ + "hermes", + "tx", + "raw", + "ft-transfer", + dstChainID, + srcChainID, + "transfer", // source chain port ID + "channel-0", // since only one connection/channel exists, assume 0 + token.Amount.String(), + fmt.Sprintf("--denom=%s", token.Denom), + fmt.Sprintf("--receiver=%s", recipient), + "--timeout-height-offset=1000", + }, + }) + s.Require().NoError(err) + + var ( + outBuf bytes.Buffer + errBuf bytes.Buffer + ) + + err = s.dkrPool.Client.StartExec(exec.ID, docker.StartExecOptions{ + Context: ctx, + Detach: false, + OutputStream: &outBuf, + ErrorStream: &errBuf, + }) + s.Require().NoErrorf( + err, + "failed to send IBC tokens; stdout: %s, stderr: %s", outBuf.String(), errBuf.String(), + ) + + s.T().Log("successfully sent IBC tokens") +} + +func queryGaiaTx(endpoint, txHash string) error { + resp, err := http.Get(fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", endpoint, txHash)) + if err != nil { + return fmt.Errorf("failed to execute HTTP request: %w", err) + } + + defer resp.Body.Close() + + if resp.StatusCode != 200 { + return fmt.Errorf("tx query returned non-200 status: %d", resp.StatusCode) + } + + var result map[string]interface{} + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return fmt.Errorf("failed to read response body: %w", err) + } + + txResp := result["tx_response"].(map[string]interface{}) + if v := txResp["code"]; v.(float64) != 0 { + return fmt.Errorf("tx %s failed with status code %v", txHash, v) + } + + return nil +} + +func queryGaiaAllBalances(endpoint, addr string) (sdk.Coins, error) { + resp, err := http.Get(fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", endpoint, addr)) + if err != nil { + return nil, fmt.Errorf("failed to execute HTTP request: %w", err) + } + + defer resp.Body.Close() + + bz, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var balancesResp banktypes.QueryAllBalancesResponse + if err := cdc.UnmarshalJSON(bz, &balancesResp); err != nil { + return nil, err + } + + return balancesResp.Balances, nil +} + +func queryGaiaDenomBalance(endpoint, addr, denom string) (sdk.Coin, error) { + var zeroCoin sdk.Coin + + path := fmt.Sprintf( + "%s/cosmos/bank/v1beta1/balances/%s/by_denom?denom=%s", + endpoint, addr, denom, + ) + resp, err := http.Get(path) + if err != nil { + return zeroCoin, fmt.Errorf("failed to execute HTTP request: %w", err) + } + + defer resp.Body.Close() + + bz, err := io.ReadAll(resp.Body) + if err != nil { + return zeroCoin, err + } + + var balanceResp banktypes.QueryBalanceResponse + if err := cdc.UnmarshalJSON(bz, &balanceResp); err != nil { + return zeroCoin, err + } + + return *balanceResp.Balance, nil +} diff --git a/tests/e2e/genesis.go b/tests/e2e/genesis.go new file mode 100644 index 00000000000..8ef24b81173 --- /dev/null +++ b/tests/e2e/genesis.go @@ -0,0 +1,110 @@ +package e2e + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + tmtypes "github.com/tendermint/tendermint/types" +) + +func getGenDoc(path string) (*tmtypes.GenesisDoc, error) { + serverCtx := server.NewDefaultContext() + config := serverCtx.Config + config.SetRoot(path) + + genFile := config.GenesisFile() + doc := &tmtypes.GenesisDoc{} + + if _, err := os.Stat(genFile); err != nil { + if !os.IsNotExist(err) { + return nil, err + } + } else { + var err error + + doc, err = tmtypes.GenesisDocFromFile(genFile) + if err != nil { + return nil, fmt.Errorf("failed to read genesis doc from file: %w", err) + } + } + + return doc, nil +} + +func addGenesisAccount(path, moniker, amountStr string, accAddr sdk.AccAddress) error { + serverCtx := server.NewDefaultContext() + config := serverCtx.Config + + config.SetRoot(path) + config.Moniker = moniker + + coins, err := sdk.ParseCoinsNormalized(amountStr) + if err != nil { + return fmt.Errorf("failed to parse coins: %w", err) + } + + balances := banktypes.Balance{Address: accAddr.String(), Coins: coins.Sort()} + genAccount := authtypes.NewBaseAccount(accAddr, nil, 0, 0) + + genFile := config.GenesisFile() + appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) + if err != nil { + return fmt.Errorf("failed to unmarshal genesis state: %w", err) + } + + authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState) + + accs, err := authtypes.UnpackAccounts(authGenState.Accounts) + if err != nil { + return fmt.Errorf("failed to get accounts from any: %w", err) + } + + if accs.Contains(accAddr) { + return fmt.Errorf("failed to add account to genesis state; account already exists: %s", accAddr) + } + + // Add the new account to the set of genesis accounts and sanitize the + // accounts afterwards. + accs = append(accs, genAccount) + accs = authtypes.SanitizeGenesisAccounts(accs) + + genAccs, err := authtypes.PackAccounts(accs) + if err != nil { + return fmt.Errorf("failed to convert accounts into any's: %w", err) + } + + authGenState.Accounts = genAccs + + authGenStateBz, err := cdc.MarshalJSON(&authGenState) + if err != nil { + return fmt.Errorf("failed to marshal auth genesis state: %w", err) + } + + appState[authtypes.ModuleName] = authGenStateBz + + bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState) + bankGenState.Balances = append(bankGenState.Balances, balances) + bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) + + bankGenStateBz, err := cdc.MarshalJSON(bankGenState) + if err != nil { + return fmt.Errorf("failed to marshal bank genesis state: %w", err) + } + + appState[banktypes.ModuleName] = bankGenStateBz + + appStateJSON, err := json.Marshal(appState) + if err != nil { + return fmt.Errorf("failed to marshal application genesis state: %w", err) + } + + genDoc.AppState = appStateJSON + return genutil.ExportGenesisFile(genDoc, genFile) +} diff --git a/tests/e2e/io.go b/tests/e2e/io.go new file mode 100644 index 00000000000..97bfac75dce --- /dev/null +++ b/tests/e2e/io.go @@ -0,0 +1,43 @@ +package e2e + +import ( + "fmt" + "io" + "io/ioutil" + "os" +) + +func copyFile(src, dst string) (int64, error) { + sourceFileStat, err := os.Stat(src) + if err != nil { + return 0, err + } + + if !sourceFileStat.Mode().IsRegular() { + return 0, fmt.Errorf("%s is not a regular file", src) + } + + source, err := os.Open(src) + if err != nil { + return 0, err + } + defer source.Close() + + destination, err := os.Create(dst) + if err != nil { + return 0, err + } + defer destination.Close() + + nBytes, err := io.Copy(destination, source) + return nBytes, err +} + +func writeFile(path string, body []byte) error { + _, err := os.Create(path) + if err != nil { + return err + } + + return ioutil.WriteFile(path, body, 0600) +} diff --git a/tests/e2e/keys.go b/tests/e2e/keys.go new file mode 100644 index 00000000000..55074ef30b6 --- /dev/null +++ b/tests/e2e/keys.go @@ -0,0 +1,56 @@ +package e2e + +import ( + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/go-bip39" +) + +func createMnemonic() (string, error) { + entropySeed, err := bip39.NewEntropy(256) + if err != nil { + return "", err + } + + mnemonic, err := bip39.NewMnemonic(entropySeed) + if err != nil { + return "", err + } + + return mnemonic, nil +} + +func createMemoryKey() (mnemonic string, info *keyring.Info, err error) { + mnemonic, err = createMnemonic() + if err != nil { + return "", nil, err + } + + account, err := createMemoryKeyFromMnemonic(mnemonic) + if err != nil { + return "", nil, err + } + + return mnemonic, account, nil +} + +func createMemoryKeyFromMnemonic(mnemonic string) (*keyring.Info, error) { + kb, err := keyring.New("testnet", keyring.BackendMemory, "", nil) + if err != nil { + return nil, err + } + + keyringAlgos, _ := kb.SupportedAlgorithms() + algo, err := keyring.NewSigningAlgoFromString(string(hd.Secp256k1Type), keyringAlgos) + if err != nil { + return nil, err + } + + account, err := kb.NewAccount("", mnemonic, "", sdk.FullFundraiserPath, algo) + if err != nil { + return nil, err + } + + return &account, nil +} diff --git a/tests/e2e/scripts/hermes_bootstrap.sh b/tests/e2e/scripts/hermes_bootstrap.sh new file mode 100755 index 00000000000..c8ca1bfb58a --- /dev/null +++ b/tests/e2e/scripts/hermes_bootstrap.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +set -ex + +# initialize Hermes relayer configuration +mkdir -p /root/.hermes/ +touch /root/.hermes/config.toml + +# setup Hermes relayer configuration +tee /root/.hermes/config.toml <