diff --git a/.codecov.yml b/.codecov.yml index 7321557bc1..758acd488e 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,4 +1,3 @@ - # # This codecov.yml is the default configuration for # all repositories on Codecov. You may adjust the settings @@ -10,17 +9,25 @@ coverage: range: 70...100 status: - # Learn more at https://codecov.io/docs#yaml_default_commit_status - project: + # Learn more at https://docs.codecov.io/docs/commit-status + project: default: threshold: 1% # allow this much decrease on project + app: + target: 80% + paths: "app/" + changes: false comment: - layout: "header, diff" - behavior: default # update if exists else create new + layout: "reach, diff, files" + behavior: default # update if exists else create new + require_changes: true ignore: - - "docs" - "*.md" - "*.rst" + - "cmd/" + - "contrib/" + - "docs/" + - "networks/" diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 94301cbac0..6a78563ab0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,17 +4,19 @@ v Before smashing the submit button please review the checkboxes. v If a checkbox is n/a - please still include it but + a little note why ☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > --> -- Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmwasm/wasmd/blob/master/CONTRIBUTING.md#pr-targeting)) +- Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/gaia/blob/master/CONTRIBUTING.md#pr-targeting)) -- [ ] Linked to github-issue with discussion and accepted design OR link to spec that describes this work. +- [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Wrote tests - [ ] Updated relevant documentation (`docs/`) +- [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` -- [ ] Reviewed `Files changed` in the github PR explorer +- [ ] Re-reviewed `Files changed` in the Github PR explorer ______ -For Admin Use: -- Added appropriate labels to PR (ex. wip, ready-for-review, docs) -- Reviewers Assigned -- Squashed all commits, uses message "Merge PR #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)) +For admin use: + +- [ ] Added appropriate labels to PR (ex. `WIP`, `R4R`, `docs`, etc) +- [ ] Reviewers assigned +- [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)) \ No newline at end of file diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000..435cfeaafd --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,45 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 10 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 4 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - blocked + - pinned + - security + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: true + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: true + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +only: pulls + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +pulls: + daysUntilStale: 30 + markComment: > + This pull request has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. diff --git a/.github/workflows/linkchecker.yml b/.github/workflows/linkchecker.yml new file mode 100644 index 0000000000..c78daa396f --- /dev/null +++ b/.github/workflows/linkchecker.yml @@ -0,0 +1,11 @@ +name: Check links +on: [pull_request] +jobs: + link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Link Checker + uses: peter-evans/link-checker@v1 + with: + args: -v -r * \ No newline at end of file diff --git a/.gitignore b/.gitignore index e28bc13c55..d16c4a23aa 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ docs/_build docs/tutorial dist tools-stamp +docs/node_modules # Data - ideally these don't exist baseapp/data/* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3e508a749a..25db57d23e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,11 +53,12 @@ overall information on repository workflow and standards. Note, we use `make tools` for installing the linting tools. Other notes: - - Looking for a good place to start contributing? How about checking out some - [good first issues](https://github.com/cosmwasm/wasmd/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) - - Please make sure to use `gofmt` before every commit - the easiest way to do - this is have your editor run it for you upon saving a file. Additionally - please ensure that your code is lint compliant by running `make lint` + +- Looking for a good place to start contributing? How about checking out some + [good first issues](https://github.com/cosmwasm/wasmd/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) +- Please make sure to use `gofmt` before every commit - the easiest way to do + this is have your editor run it for you upon saving a file. Additionally + please ensure that your code is lint compliant by running `make lint` ## Pull Requests @@ -84,7 +85,7 @@ All PRs require two Reviews before merge (except docs changes, or variable name- If you open a PR in Gaia, it is mandatory to update the relevant documentation in /docs. -* If your changes relate specifically to the gaia application, please modify the docs/ folder. +- If your changes relate specifically to the gaia application, please modify the docs/ folder. ## Forking @@ -96,10 +97,10 @@ Instead, we use `git remote` to add the fork as a new remote for the original re For instance, to create a fork and work on a branch of it, I would: - - Create the fork on github, using the fork button. - - Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/cosmwasm/wasmd`) - - `git remote rename origin upstream` - - `git remote add origin git@github.com:rigeyrigerige/gaia.git` +- Create the fork on github, using the fork button. +- Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/cosmwasm/wasmd`) +- `git remote rename origin upstream` +- `git remote add origin git@github.com:rigeyrigerige/gaia.git` Now `origin` refers to my fork and `upstream` refers to the Gaia version. So I can `git push -u origin master` to update my fork, and make pull requests to Gaia from there. @@ -107,8 +108,8 @@ Of course, replace `rigeyrigerige` with your git handle. To pull in updates from the origin repo, run - - `git fetch upstream` - - `git rebase upstream/master` (or whatever branch you want) +- `git fetch upstream` +- `git rebase upstream/master` (or whatever branch you want) Please don't make Pull Requests to `master`. @@ -152,13 +153,13 @@ for tcIndex, tc := range cases { for i := 0; i < tc.numTxsToTest; i++ { - require.Equal(t, expectedTx[:32], calculatedTx[:32], - "First 32 bytes of the txs differed. tc #%d, i #%d", tcIndex, i) + require.Equal(t, expectedTx[:32], calculatedTx[:32], + "First 32 bytes of the txs differed. tc #%d, i #%d", tcIndex, i) ``` ## Branching Model and Release -User-facing repos should adhere to the trunk based development branching model: https://trunkbaseddevelopment.com/. +User-facing repos should adhere to the [trunk based development branching model](https://trunkbaseddevelopment.com/). Libraries need not follow the model strictly, but would be wise to. @@ -173,17 +174,19 @@ should be targeted against the release candidate branch. Release candidate branc only pull requests targeted directly against master. ### Development Procedure - - the latest state of development is on `master` - - `master` must never fail `make test` or `make test_cli` - - `master` should not fail `make lint` - - no `--force` onto `master` (except when reverting a broken commit, which should seldom happen) - - create a development branch either on github.com/cosmwasm/wasmd, or your fork (using `git remote add origin`) - - before submitting a pull request, begin `git rebase` on top of `master` + +- the latest state of development is on `master` +- `master` must never fail `make test` or `make test_cli` +- `master` should not fail `make lint` +- no `--force` onto `master` (except when reverting a broken commit, which should seldom happen) +- create a development branch either on github.com/cosmwasm/wasmd, or your fork (using `git remote add origin`) +- before submitting a pull request, begin `git rebase` on top of `master` ### Pull Merge Procedure - - ensure pull branch is rebased on `master` - - run `make test` and `make test_cli` to ensure that all tests pass - - merge pull request + +- ensure pull branch is rebased on `master` +- run `make test` and `make test_cli` to ensure that all tests pass +- merge pull request ### Release Procedure @@ -206,15 +209,15 @@ only pull requests targeted directly against master. At the moment, only a single major release will be supported, so all point releases will be based off of that release. - - start on `vX.XX.X` - - checkout a new branch `pre-rc/vX.X.X` - - cherry pick the desired changes from `master` - - these changes should be small and NON-BREAKING (both API and state machine) - - add entries to CHANGELOG.md and remove corresponding pending log entries - - checkout a new branch `rc/vX.X.X` based off of `vX.XX.X` - - create a PR merging `pre-rc/vX.X.X` into `rc/vX.X.X` - - run tests and simulations (noted in [Release Procedure](#release-procedure)) - - after tests and simulation have successfully completed, create the release branch `release/vX.XX.X` from the `RC` branch - - delete the `pre-rc/vX.X.X` and `RC` branches - - create a PR into `master` containing ONLY the CHANGELOG.md updates - - tag and release `release/vX.XX.X` +- start on `vX.XX.X` +- checkout a new branch `pre-rc/vX.X.X` +- cherry pick the desired changes from `master` + - these changes should be small and NON-BREAKING (both API and state machine) +- add entries to CHANGELOG.md and remove corresponding pending log entries +- checkout a new branch `rc/vX.X.X` based off of `vX.XX.X` +- create a PR merging `pre-rc/vX.X.X` into `rc/vX.X.X` +- run tests and simulations (noted in [Release Procedure](#release-procedure)) +- after tests and simulation have successfully completed, create the release branch `release/vX.XX.X` from the `RC` branch +- delete the `pre-rc/vX.X.X` and `RC` branches +- create a PR into `master` containing ONLY the CHANGELOG.md updates +- tag and release `release/vX.XX.X` \ No newline at end of file diff --git a/Makefile b/Makefile index a43bb838ea..1b046d51eb 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,6 @@ LEDGER_ENABLED ?= true SDK_PACK := $(shell go list -m github.com/cosmos/cosmos-sdk | sed 's/ /\@/g') export GO111MODULE = on -export COSMOS_SDK_TEST_KEYRING = y # process build tags @@ -61,7 +60,7 @@ endif ldflags += $(LDFLAGS) ldflags := $(strip $(ldflags)) -BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)' +BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)' -trimpath # The below include contains the tools target. include contrib/devtools/Makefile @@ -91,6 +90,27 @@ install: go.sum go install -mod=readonly $(BUILD_FLAGS) ./cmd/wasmd go install -mod=readonly $(BUILD_FLAGS) ./cmd/wasmcli + +######################################## +### Documentation + +build-docs: + @cd docs && \ + while read p; do \ + (git checkout $${p} && npm install && VUEPRESS_BASE="/$${p}/" npm run build) ; \ + mkdir -p ~/output/$${p} ; \ + cp -r .vuepress/dist/* ~/output/$${p}/ ; \ + cp ~/output/$${p}/index.html ~/output ; \ + done < versions ; + +sync-docs: + cd ~/output && \ + echo "role_arn = ${DEPLOYMENT_ROLE_ARN}" >> /root/.aws/config ; \ + echo "CI job = ${CIRCLE_BUILD_URL}" >> version.html ; \ + aws s3 sync . s3://${WEBSITE_BUCKET} --profile terraform --delete ; \ + aws cloudfront create-invalidation --distribution-id ${CF_DISTRIBUTION_ID} --profile terraform --path "/*" ; +.PHONY: sync-docs + ######################################## ### Tools & dependencies @@ -155,7 +175,7 @@ build-docker-wasmdnode: # Run a 4-node testnet locally localnet-start: build-linux localnet-stop - @if ! [ -f build/node0/wasmd/config/genesis.json ]; then docker run -e COSMOS_SDK_TEST_KEYRING=y --rm -v $(CURDIR)/build:/wasmd:Z tendermint/wasmdnode testnet --v 4 -o . --starting-ip-address 192.168.10.2 ; fi + @if ! [ -f build/node0/wasmd/config/genesis.json ]; then docker run --rm -v $(CURDIR)/build:/wasmd:Z tendermint/wasmdnode testnet --v 4 -o . --starting-ip-address 192.168.10.2 ; fi docker-compose up -d # Stop testnet diff --git a/README.md b/README.md index 65e8b731a9..e4e862b78b 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This code was forked from the `cosmos/gaia` repository and the majority of the c **Note**: Requires [Go 1.13+](https://golang.org/dl/) -**Compatibility**: Last merge from `cosmos/gaia` was `d6dfa141e2ae38a1ff9f53fca8078c0822671b95` +**Compatibility**: Last merge from `cosmos/gaia` was `090c545347b03e59415a18107a0a279c703c8f40` (Jan 23, 2020) ## Quick Start diff --git a/app/app.go b/app/app.go index 8477acb3d7..52286b5116 100644 --- a/app/app.go +++ b/app/app.go @@ -1,7 +1,6 @@ package app import ( - "fmt" "io" "os" "path/filepath" @@ -10,8 +9,8 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/cli" - cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" + tmos "github.com/tendermint/tendermint/libs/os" dbm "github.com/tendermint/tm-db" bam "github.com/cosmos/cosmos-sdk/baseapp" @@ -34,6 +33,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/cosmos/cosmos-sdk/x/upgrade" + upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" "github.com/cosmwasm/wasmd/x/wasm" ) @@ -57,12 +58,13 @@ var ( staking.AppModuleBasic{}, mint.AppModuleBasic{}, distr.AppModuleBasic{}, - gov.NewAppModuleBasic(paramsclient.ProposalHandler, distr.ProposalHandler), + gov.NewAppModuleBasic(paramsclient.ProposalHandler, distr.ProposalHandler, upgradeclient.ProposalHandler), params.AppModuleBasic{}, wasm.AppModuleBasic{}, crisis.AppModuleBasic{}, slashing.AppModuleBasic{}, supply.AppModuleBasic{}, + upgrade.AppModuleBasic{}, evidence.AppModuleBasic{}, ) @@ -91,6 +93,9 @@ func MakeCodec() *codec.Codec { return cdc.Seal() } +// Verify app interface at compile time +var _ simapp.App = (*WasmApp)(nil) + // WasmApp extended ABCI application type WasmApp struct { *bam.BaseApp @@ -102,6 +107,9 @@ type WasmApp struct { keys map[string]*sdk.KVStoreKey tKeys map[string]*sdk.TransientStoreKey + // subspaces + subspaces map[string]params.Subspace + // keepers accountKeeper auth.AccountKeeper bankKeeper bank.Keeper @@ -114,6 +122,7 @@ type WasmApp struct { crisisKeeper crisis.Keeper paramsKeeper params.Keeper evidenceKeeper *evidence.Keeper + upgradeKeeper upgrade.Keeper wasmKeeper wasm.Keeper // the module manager @@ -132,7 +141,7 @@ type WasmWrapper struct { // NewWasmApp returns a reference to an initialized WasmApp. func NewWasmApp( logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, - invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp), + invCheckPeriod uint, skipUpgradeHeights map[int64]bool, baseAppOptions ...func(*bam.BaseApp), ) *WasmApp { cdc := MakeCodec() @@ -142,9 +151,10 @@ func NewWasmApp( bApp.SetAppVersion(version.Version) keys := sdk.NewKVStoreKeys( - bam.MainStoreKey, auth.StoreKey, staking.StoreKey, supply.StoreKey, - mint.StoreKey, distr.StoreKey, slashing.StoreKey, gov.StoreKey, - params.StoreKey, evidence.StoreKey, wasm.StoreKey, + bam.MainStoreKey, auth.StoreKey, staking.StoreKey, + supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, + gov.StoreKey, params.StoreKey, evidence.StoreKey, upgrade.StoreKey, + wasm.StoreKey, ) tKeys := sdk.NewTransientStoreKeys(staking.TStoreKey, params.TStoreKey) @@ -154,34 +164,49 @@ func NewWasmApp( invCheckPeriod: invCheckPeriod, keys: keys, tKeys: tKeys, + subspaces: make(map[string]params.Subspace), } // init params keeper and subspaces - app.paramsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tKeys[params.TStoreKey], params.DefaultCodespace) - authSubspace := app.paramsKeeper.Subspace(auth.DefaultParamspace) - bankSubspace := app.paramsKeeper.Subspace(bank.DefaultParamspace) - stakingSubspace := app.paramsKeeper.Subspace(staking.DefaultParamspace) - mintSubspace := app.paramsKeeper.Subspace(mint.DefaultParamspace) - distrSubspace := app.paramsKeeper.Subspace(distr.DefaultParamspace) - slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace) - govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable()) - crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace) - evidenceSubspace := app.paramsKeeper.Subspace(evidence.DefaultParamspace) + app.paramsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tKeys[params.TStoreKey]) + app.subspaces[auth.ModuleName] = app.paramsKeeper.Subspace(auth.DefaultParamspace) + app.subspaces[bank.ModuleName] = app.paramsKeeper.Subspace(bank.DefaultParamspace) + app.subspaces[staking.ModuleName] = app.paramsKeeper.Subspace(staking.DefaultParamspace) + app.subspaces[mint.ModuleName] = app.paramsKeeper.Subspace(mint.DefaultParamspace) + app.subspaces[distr.ModuleName] = app.paramsKeeper.Subspace(distr.DefaultParamspace) + app.subspaces[slashing.ModuleName] = app.paramsKeeper.Subspace(slashing.DefaultParamspace) + app.subspaces[gov.ModuleName] = app.paramsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable()) + app.subspaces[crisis.ModuleName] = app.paramsKeeper.Subspace(crisis.DefaultParamspace) + app.subspaces[evidence.ModuleName] = app.paramsKeeper.Subspace(evidence.DefaultParamspace) // add keepers - app.accountKeeper = auth.NewAccountKeeper(app.cdc, keys[auth.StoreKey], authSubspace, auth.ProtoBaseAccount) - app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, bankSubspace, bank.DefaultCodespace, app.ModuleAccountAddrs()) - app.supplyKeeper = supply.NewKeeper(app.cdc, keys[supply.StoreKey], app.accountKeeper, app.bankKeeper, maccPerms) + app.accountKeeper = auth.NewAccountKeeper( + app.cdc, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount, + ) + app.bankKeeper = bank.NewBaseKeeper( + app.accountKeeper, app.subspaces[bank.ModuleName], app.ModuleAccountAddrs(), + ) + app.supplyKeeper = supply.NewKeeper( + app.cdc, keys[supply.StoreKey], app.accountKeeper, app.bankKeeper, maccPerms, + ) stakingKeeper := staking.NewKeeper( - app.cdc, keys[staking.StoreKey], app.supplyKeeper, stakingSubspace, staking.DefaultCodespace, + app.cdc, keys[staking.StoreKey], app.supplyKeeper, app.subspaces[staking.ModuleName], + ) + app.mintKeeper = mint.NewKeeper( + app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, + app.supplyKeeper, auth.FeeCollectorName, + ) + app.distrKeeper = distr.NewKeeper( + app.cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], &stakingKeeper, + app.supplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs(), ) - app.mintKeeper = mint.NewKeeper(app.cdc, keys[mint.StoreKey], mintSubspace, &stakingKeeper, app.supplyKeeper, auth.FeeCollectorName) - app.distrKeeper = distr.NewKeeper(app.cdc, keys[distr.StoreKey], distrSubspace, &stakingKeeper, - app.supplyKeeper, distr.DefaultCodespace, auth.FeeCollectorName, app.ModuleAccountAddrs()) app.slashingKeeper = slashing.NewKeeper( - app.cdc, keys[slashing.StoreKey], &stakingKeeper, slashingSubspace, slashing.DefaultCodespace, + app.cdc, keys[slashing.StoreKey], &stakingKeeper, app.subspaces[slashing.ModuleName], + ) + app.crisisKeeper = crisis.NewKeeper( + app.subspaces[crisis.ModuleName], invCheckPeriod, app.supplyKeeper, auth.FeeCollectorName, ) - app.crisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.supplyKeeper, auth.FeeCollectorName) + app.upgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], app.cdc) // just re-use the full router - do we want to limit this more? var wasmRouter = bApp.Router() @@ -192,28 +217,32 @@ func NewWasmApp( wasmWrap := WasmWrapper{Wasm: wasm.DefaultWasmConfig()} err := viper.Unmarshal(&wasmWrap) if err != nil { - fmt.Println("error while reading wasm config:", err.Error()) + panic("error while reading wasm config: " + err.Error()) } wasmConfig := wasmWrap.Wasm app.wasmKeeper = wasm.NewKeeper(app.cdc, keys[wasm.StoreKey], app.accountKeeper, app.bankKeeper, wasmRouter, wasmDir, wasmConfig) // create evidence keeper with evidence router - app.evidenceKeeper = evidence.NewKeeper( - app.cdc, keys[evidence.StoreKey], evidenceSubspace, evidence.DefaultCodespace, + evidenceKeeper := evidence.NewKeeper( + app.cdc, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &stakingKeeper, app.slashingKeeper, ) evidenceRouter := evidence.NewRouter() - // TODO: Register evidence routes. - app.evidenceKeeper.SetRouter(evidenceRouter) + + // TODO: register evidence routes + evidenceKeeper.SetRouter(evidenceRouter) + + app.evidenceKeeper = evidenceKeeper // register the proposal types govRouter := gov.NewRouter() govRouter.AddRoute(gov.RouterKey, gov.ProposalHandler). AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper)). - AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper)) + AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper)). + AddRoute(upgrade.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.upgradeKeeper)) app.govKeeper = gov.NewKeeper( - app.cdc, keys[gov.StoreKey], govSubspace, - app.supplyKeeper, &stakingKeeper, gov.DefaultCodespace, govRouter, + app.cdc, keys[gov.StoreKey], app.subspaces[gov.ModuleName], + app.supplyKeeper, &stakingKeeper, govRouter, ) // register the staking hooks @@ -230,20 +259,21 @@ func NewWasmApp( bank.NewAppModule(app.bankKeeper, app.accountKeeper), crisis.NewAppModule(&app.crisisKeeper), supply.NewAppModule(app.supplyKeeper, app.accountKeeper), - distr.NewAppModule(app.distrKeeper, app.supplyKeeper), - gov.NewAppModule(app.govKeeper, app.supplyKeeper), + gov.NewAppModule(app.govKeeper, app.accountKeeper, app.supplyKeeper), mint.NewAppModule(app.mintKeeper), - slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper), + slashing.NewAppModule(app.slashingKeeper, app.accountKeeper, app.stakingKeeper), + distr.NewAppModule(app.distrKeeper, app.accountKeeper, app.supplyKeeper, app.stakingKeeper), staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper), evidence.NewAppModule(*app.evidenceKeeper), wasm.NewAppModule(app.wasmKeeper), + upgrade.NewAppModule(app.upgradeKeeper), + evidence.NewAppModule(*app.evidenceKeeper), ) - // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. - app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName) + app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName) app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName) // NOTE: The genutils module must occur after staking so that pools are @@ -265,11 +295,11 @@ func NewWasmApp( auth.NewAppModule(app.accountKeeper), bank.NewAppModule(app.bankKeeper, app.accountKeeper), supply.NewAppModule(app.supplyKeeper, app.accountKeeper), - gov.NewAppModule(app.govKeeper, app.supplyKeeper), + gov.NewAppModule(app.govKeeper, app.accountKeeper, app.supplyKeeper), mint.NewAppModule(app.mintKeeper), - distr.NewAppModule(app.distrKeeper, app.supplyKeeper), + distr.NewAppModule(app.distrKeeper, app.accountKeeper, app.supplyKeeper, app.stakingKeeper), staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper), - slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper), + slashing.NewAppModule(app.slashingKeeper, app.accountKeeper, app.stakingKeeper), ) app.sm.RegisterStoreDecoders() @@ -287,24 +317,27 @@ func NewWasmApp( if loadLatest { err := app.LoadLatestVersion(app.keys[bam.MainStoreKey]) if err != nil { - cmn.Exit(err.Error()) + tmos.Exit(err.Error()) } } return app } +// Name returns the name of the App +func (app *WasmApp) Name() string { return app.BaseApp.Name() } + // application updates every begin block func (app *WasmApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { return app.mm.BeginBlock(ctx, req) } -// application updates every end block +// EndBlocker application updates every end block func (app *WasmApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { return app.mm.EndBlock(ctx, req) } -// application update at chain initialization +// InitChainer application update at chain initialization func (app *WasmApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { var genesisState simapp.GenesisState app.cdc.MustUnmarshalJSON(req.AppStateBytes, &genesisState) @@ -312,7 +345,7 @@ func (app *WasmApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci return app.mm.InitGenesis(ctx, genesisState) } -// load a particular height +// LoadHeight loads a particular height func (app *WasmApp) LoadHeight(height int64) error { return app.LoadVersion(height, app.keys[bam.MainStoreKey]) } @@ -332,6 +365,11 @@ func (app *WasmApp) Codec() *codec.Codec { return app.cdc } +// SimulationManager implements the SimulationApp interface +func (app *WasmApp) SimulationManager() *module.SimulationManager { + return app.sm +} + // GetMaccPerms returns a mapping of the application's module account permissions. func GetMaccPerms() map[string][]string { modAccPerms := make(map[string][]string) diff --git a/app/app_test.go b/app/app_test.go index dd1fb0696c..9e894bd2dc 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -16,12 +16,12 @@ import ( func TestWasmdExport(t *testing.T) { db := db.NewMemDB() - gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0, map[int64]bool{}) err := setGenesis(gapp) require.NoError(t, err) // Making a new app object with the db, so that initchain hasn't been called - newGapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + newGapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0, map[int64]bool{}) _, _, err = newGapp.ExportAppStateAndValidators(false, []string{}) require.NoError(t, err, "ExportAppStateAndValidators should not have an error") } @@ -29,7 +29,7 @@ func TestWasmdExport(t *testing.T) { // ensure that black listed addresses are properly set in bank keeper func TestBlackListedAddrs(t *testing.T) { db := db.NewMemDB() - gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0, map[int64]bool{}) for acc := range maccPerms { require.True(t, gapp.bankKeeper.BlacklistedAddr(gapp.supplyKeeper.GetModuleAddress(acc))) @@ -38,7 +38,7 @@ func TestBlackListedAddrs(t *testing.T) { func setGenesis(gapp *WasmApp) error { genesisState := simapp.NewDefaultGenesisState() - stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState) + stateBytes, err := codec.MarshalJSONIndent(gapp.Codec(), genesisState) if err != nil { return err } diff --git a/app/export.go b/app/export.go index 40b21603a7..21ffe0f94d 100644 --- a/app/export.go +++ b/app/export.go @@ -92,7 +92,7 @@ func (app *WasmApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st // donate any unwithdrawn outstanding reward fraction tokens to the community pool scraps := app.distrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator()) feePool := app.distrKeeper.GetFeePool(ctx) - feePool.CommunityPool = feePool.CommunityPool.Add(scraps) + feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) app.distrKeeper.SetFeePool(ctx, feePool) app.distrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) diff --git a/app/integration/common_test.go b/app/integration/common_test.go index f3739bdd32..4fdc522acd 100644 --- a/app/integration/common_test.go +++ b/app/integration/common_test.go @@ -31,7 +31,7 @@ const ( // Setup initializes a new wasmd.WasmApp. A Nop logger is set in WasmApp. func Setup(isCheckTx bool) *wasmd.WasmApp { db := dbm.NewMemDB() - app := wasmd.NewWasmApp(log.NewNopLogger(), db, nil, true, 0) + app := wasmd.NewWasmApp(log.NewNopLogger(), db, nil, true, 0, nil) // app := wasmd.NewWasmApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0) if !isCheckTx { // init chain must be called to stop deliverState from being nil @@ -57,7 +57,7 @@ func Setup(isCheckTx bool) *wasmd.WasmApp { // genesis accounts. func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount) *wasmd.WasmApp { db := dbm.NewMemDB() - app := wasmd.NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + app := wasmd.NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0, nil) // app := wasmd.NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0) // initialize the chain with the passed in genesis accounts @@ -94,8 +94,7 @@ func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount) *wasmd.Wasm func SignAndDeliver( t *testing.T, app *wasmd.WasmApp, msgs []sdk.Msg, accNums, seq []uint64, expPass bool, priv ...crypto.PrivKey, -) sdk.Result { - // ) (sdk.GasInfo, *sdk.Result, error) { +) (sdk.GasInfo, *sdk.Result, error) { tx := GenTx( msgs, @@ -110,26 +109,19 @@ func SignAndDeliver( // Simulate a sending a transaction and committing a block app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: app.LastBlockHeight() + 1, ChainID: SimAppChainID}}) - res := app.Deliver(tx) + gasInfo, res, err := app.Deliver(tx) if expPass { - require.True(t, res.IsOK(), res) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.False(t, res.IsOK(), res) + require.Error(t, err) + require.Nil(t, res) } - // gInfo, res, err := app.Deliver(tx) - // if expPass { - // require.NoError(t, err) - // require.NotNil(t, res) - // } else { - // require.Error(t, err) - // require.Nil(t, res) - // } - app.EndBlock(abci.RequestEndBlock{}) app.Commit() - return res + return gasInfo, res, err } // GenTx generates a signed mock transaction. diff --git a/app/integration/integration_test.go b/app/integration/integration_test.go index ae2e34b139..64314f884d 100644 --- a/app/integration/integration_test.go +++ b/app/integration/integration_test.go @@ -49,9 +49,11 @@ func TestSendWithApp(t *testing.T) { _ = sign(t, wasm, msg, &keys[0], true) } -func sign(t *testing.T, wasm *app.WasmApp, msg sdk.Msg, signer *signer, expectPass bool) sdk.Result { - res := SignAndDeliver(t, wasm, []sdk.Msg{msg}, []uint64{signer.acctNum}, []uint64{signer.seq}, expectPass, signer.priv) - signer.seq++ +func sign(t *testing.T, wasm *app.WasmApp, msg sdk.Msg, signer *signer, expectPass bool) *sdk.Result { + _, res, _ := SignAndDeliver(t, wasm, []sdk.Msg{msg}, []uint64{signer.acctNum}, []uint64{signer.seq}, expectPass, signer.priv) + if expectPass { + signer.seq++ + } return res } diff --git a/app/sim_bench_test.go b/app/sim_bench_test.go new file mode 100644 index 0000000000..c7a887614b --- /dev/null +++ b/app/sim_bench_test.go @@ -0,0 +1,108 @@ +package app + +import ( + "fmt" + "os" + "testing" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// Profile with: +// /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/simapp -bench ^BenchmarkFullAppSimulation$ -Commit=true -cpuprofile cpu.out +func BenchmarkFullAppSimulation(b *testing.B) { + config, db, dir, logger, _, err := simapp.SetupSimulation("goleveldb-app-sim", "Simulation") + if err != nil { + b.Fatalf("simulation setup failed: %s", err.Error()) + } + + defer func() { + db.Close() + err = os.RemoveAll(dir) + if err != nil { + b.Fatal(err) + } + }() + + app := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, map[int64]bool{}, interBlockCacheOpt()) + + // run randomized simulation + _, simParams, simErr := simulation.SimulateFromSeed( + b, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()), + simapp.SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, + ) + + // export state and simParams before the simulation error is checked + if err = simapp.CheckExportSimulation(app, config, simParams); err != nil { + b.Fatal(err) + } + + if simErr != nil { + b.Fatal(simErr) + } + + if config.Commit { + simapp.PrintStats(db) + } +} + +func BenchmarkInvariants(b *testing.B) { + config, db, dir, logger, _, err := simapp.SetupSimulation("leveldb-app-invariant-bench", "Simulation") + if err != nil { + b.Fatalf("simulation setup failed: %s", err.Error()) + } + + config.AllInvariants = false + + defer func() { + db.Close() + err = os.RemoveAll(dir) + if err != nil { + b.Fatal(err) + } + }() + + app := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, map[int64]bool{}, interBlockCacheOpt()) + + // run randomized simulation + _, simParams, simErr := simulation.SimulateFromSeed( + b, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()), + simapp.SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, + ) + + // export state and simParams before the simulation error is checked + if err = simapp.CheckExportSimulation(app, config, simParams); err != nil { + b.Fatal(err) + } + + if simErr != nil { + b.Fatal(simErr) + } + + if config.Commit { + simapp.PrintStats(db) + } + + ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight() + 1}) + + // 3. Benchmark each invariant separately + // + // NOTE: We use the crisis keeper as it has all the invariants registered with + // their respective metadata which makes it useful for testing/benchmarking. + for _, cr := range app.crisisKeeper.Routes() { + cr := cr + b.Run(fmt.Sprintf("%s/%s", cr.ModuleName, cr.Route), func(b *testing.B) { + if res, stop := cr.Invar(ctx); stop { + b.Fatalf( + "broken invariant at block %d of %d\n%s", + ctx.BlockHeight()-1, config.NumBlocks, res, + ) + } + }) + } +} diff --git a/app/sim_test.go b/app/sim_test.go index a180cfeebe..83f2b5a321 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -3,7 +3,6 @@ package app import ( "encoding/json" "fmt" - "io/ioutil" "math/rand" "os" "testing" @@ -15,22 +14,17 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/simapp/helpers" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation" distr "github.com/cosmos/cosmos-sdk/x/distribution" - distrsim "github.com/cosmos/cosmos-sdk/x/distribution/simulation" "github.com/cosmos/cosmos-sdk/x/gov" - govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation" "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/params" - paramsim "github.com/cosmos/cosmos-sdk/x/params/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/slashing" - slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation" "github.com/cosmos/cosmos-sdk/x/staking" - stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation" "github.com/cosmos/cosmos-sdk/x/supply" ) @@ -38,199 +32,10 @@ func init() { simapp.GetSimulatorFlags() } -func testAndRunTxs(app *WasmApp, config simulation.Config) []simulation.WeightedOperation { - ap := make(simulation.AppParams) - - paramChanges := app.sm.GenerateParamChanges(config.Seed) - - if config.ParamsFile != "" { - bz, err := ioutil.ReadFile(config.ParamsFile) - if err != nil { - panic(err) - } - - app.cdc.MustUnmarshalJSON(bz, &ap) - } - - // nolint: govet - return []simulation.WeightedOperation{ - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgSend, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - banksim.SimulateMsgSend(app.accountKeeper, app.bankKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgMultiSend, &v, nil, - func(_ *rand.Rand) { - v = 40 - }) - return v - }(nil), - banksim.SimulateMsgMultiSend(app.accountKeeper, app.bankKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgSetWithdrawAddress, &v, nil, - func(_ *rand.Rand) { - v = 50 - }) - return v - }(nil), - distrsim.SimulateMsgSetWithdrawAddress(app.accountKeeper, app.distrKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgWithdrawDelegationReward, &v, nil, - func(_ *rand.Rand) { - v = 50 - }) - return v - }(nil), - distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper, app.stakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgWithdrawValidatorCommission, &v, nil, - func(_ *rand.Rand) { - v = 50 - }) - return v - }(nil), - distrsim.SimulateMsgWithdrawValidatorCommission(app.accountKeeper, app.distrKeeper, app.stakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightSubmitTextProposal, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - govsim.SimulateSubmitProposal(app.accountKeeper, app.govKeeper, govsim.SimulateTextProposalContent), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightSubmitCommunitySpendProposal, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - govsim.SimulateSubmitProposal(app.accountKeeper, app.govKeeper, distrsim.SimulateCommunityPoolSpendProposalContent(app.distrKeeper)), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightSubmitParamChangeProposal, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - govsim.SimulateSubmitProposal(app.accountKeeper, app.govKeeper, paramsim.SimulateParamChangeProposalContent(paramChanges)), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgDeposit, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - govsim.SimulateMsgDeposit(app.accountKeeper, app.govKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgVote, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - govsim.SimulateMsgVote(app.accountKeeper, app.govKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgCreateValidator, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgCreateValidator(app.accountKeeper, app.stakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgEditValidator, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - stakingsim.SimulateMsgEditValidator(app.accountKeeper, app.stakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgDelegate, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgDelegate(app.accountKeeper, app.stakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgUndelegate, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgUndelegate(app.accountKeeper, app.stakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgBeginRedelegate, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgBeginRedelegate(app.accountKeeper, app.stakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgUnjail, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - slashingsim.SimulateMsgUnjail(app.accountKeeper, app.slashingKeeper, app.stakingKeeper), - }, - } +type StoreKeysPrefixes struct { + A sdk.StoreKey + B sdk.StoreKey + Prefixes [][]byte } // fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of @@ -245,209 +50,96 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) { return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager()) } -// Profile with: -// /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/WasmApp -bench ^BenchmarkFullAppSimulation$ -Commit=true -cpuprofile cpu.out -func BenchmarkFullAppSimulation(b *testing.B) { - logger := log.NewNopLogger() - config := simapp.NewConfigFromFlags() - - var db dbm.DB - dir, err := ioutil.TempDir("", "goleveldb-app-sim") - if err != nil { - fmt.Println(err) - b.Fail() - } - db, err = sdk.NewLevelDB("Simulation", dir) - if err != nil { - fmt.Println(err) - b.Fail() - } - defer func() { - db.Close() - _ = os.RemoveAll(dir) - }() - - gapp := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, interBlockCacheOpt()) - - // Run randomized simulation - // TODO: parameterize numbers, save for a later PR - _, simParams, simErr := simulation.SimulateFromSeed( - b, os.Stdout, gapp.BaseApp, simapp.AppStateFn(gapp.Codec(), gapp.sm), - testAndRunTxs(gapp, config), gapp.ModuleAccountAddrs(), config, - ) - - // export state and params before the simulation error is checked - if config.ExportStatePath != "" { - if err := ExportStateToJSON(gapp, config.ExportStatePath); err != nil { - fmt.Println(err) - b.Fail() - } - } - - if config.ExportParamsPath != "" { - if err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath); err != nil { - fmt.Println(err) - b.Fail() - } - } - - if simErr != nil { - fmt.Println(simErr) - b.FailNow() - } - - if config.Commit { - fmt.Println("\nGoLevelDB Stats") - fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) - } -} - func TestFullAppSimulation(t *testing.T) { - if !simapp.FlagEnabledValue { + config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation") + if skip { t.Skip("skipping application simulation") } - - var logger log.Logger - config := simapp.NewConfigFromFlags() - - if simapp.FlagVerboseValue { - logger = log.TestingLogger() - } else { - logger = log.NewNopLogger() - } - - var db dbm.DB - dir, err := ioutil.TempDir("", "goleveldb-app-sim") - require.NoError(t, err) - db, err = sdk.NewLevelDB("Simulation", dir) - require.NoError(t, err) + require.NoError(t, err, "simulation setup failed") defer func() { db.Close() - _ = os.RemoveAll(dir) + require.NoError(t, os.RemoveAll(dir)) }() - gapp := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt) - require.Equal(t, "WasmApp", gapp.Name()) + app := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, map[int64]bool{}, fauxMerkleModeOpt) + require.Equal(t, appName, app.Name()) - // Run randomized simulation + // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - t, os.Stdout, gapp.BaseApp, simapp.AppStateFn(gapp.Codec(), gapp.sm), - testAndRunTxs(gapp, config), gapp.ModuleAccountAddrs(), config, + t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()), + simapp.SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) - // export state and params before the simulation error is checked - if config.ExportStatePath != "" { - err := ExportStateToJSON(gapp, config.ExportStatePath) - require.NoError(t, err) - } - - if config.ExportParamsPath != "" { - err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath) - require.NoError(t, err) - } - + // export state and simParams before the simulation error is checked + err = simapp.CheckExportSimulation(app, config, simParams) + require.NoError(t, err) require.NoError(t, simErr) if config.Commit { - // for memdb: - // fmt.Println("Database Size", db.Stats()["database.size"]) - fmt.Println("\nGoLevelDB Stats") - fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) + simapp.PrintStats(db) } } func TestAppImportExport(t *testing.T) { - if !simapp.FlagEnabledValue { + config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation") + if skip { t.Skip("skipping application import/export simulation") } - - var logger log.Logger - config := simapp.NewConfigFromFlags() - - if simapp.FlagVerboseValue { - logger = log.TestingLogger() - } else { - logger = log.NewNopLogger() - } - - var db dbm.DB - dir, err := ioutil.TempDir("", "goleveldb-app-sim") - require.NoError(t, err) - db, err = sdk.NewLevelDB("Simulation", dir) - require.NoError(t, err) + require.NoError(t, err, "simulation setup failed") defer func() { db.Close() - _ = os.RemoveAll(dir) + require.NoError(t, os.RemoveAll(dir)) }() - app := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt) - require.Equal(t, "SimApp", app.Name()) + app := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, map[int64]bool{}, fauxMerkleModeOpt) + require.Equal(t, appName, app.Name()) // Run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()), + simapp.SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and simParams before the simulation error is checked - if config.ExportStatePath != "" { - err := ExportStateToJSON(app, config.ExportStatePath) - require.NoError(t, err) - } - - if config.ExportParamsPath != "" { - err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath) - require.NoError(t, err) - } - + err = simapp.CheckExportSimulation(app, config, simParams) + require.NoError(t, err) require.NoError(t, simErr) if config.Commit { - // for memdb: - // fmt.Println("Database Size", db.Stats()["database.size"]) - fmt.Println("\nGoLevelDB Stats") - fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) + simapp.PrintStats(db) } fmt.Printf("exporting genesis...\n") appState, _, err := app.ExportAppStateAndValidators(false, []string{}) require.NoError(t, err) + fmt.Printf("importing genesis...\n") - newDir, err := ioutil.TempDir("", "goleveldb-app-sim-2") - require.NoError(t, err) - newDB, err := sdk.NewLevelDB("Simulation-2", dir) - require.NoError(t, err) + _, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2") + require.NoError(t, err, "simulation setup failed") defer func() { newDB.Close() - _ = os.RemoveAll(newDir) + require.NoError(t, os.RemoveAll(newDir)) }() - newApp := NewWasmApp(log.NewNopLogger(), newDB, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt) - require.Equal(t, "SimApp", newApp.Name()) + newApp := NewWasmApp(log.NewNopLogger(), newDB, nil, true, simapp.FlagPeriodValue, map[int64]bool{}, fauxMerkleModeOpt) + require.Equal(t, appName, newApp.Name()) - var genesisState simapp.GenesisState - err = app.cdc.UnmarshalJSON(appState, &genesisState) + var genesisState GenesisState + err = app.Codec().UnmarshalJSON(appState, &genesisState) require.NoError(t, err) + ctxA := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) ctxB := newApp.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) newApp.mm.InitGenesis(ctxB, genesisState) fmt.Printf("comparing stores...\n") - ctxA := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) - - type StoreKeysPrefixes struct { - A sdk.StoreKey - B sdk.StoreKey - Prefixes [][]byte - } storeKeysPrefixes := []StoreKeysPrefixes{ {app.keys[baseapp.MainStoreKey], newApp.keys[baseapp.MainStoreKey], [][]byte{}}, @@ -464,120 +156,84 @@ func TestAppImportExport(t *testing.T) { {app.keys[gov.StoreKey], newApp.keys[gov.StoreKey], [][]byte{}}, } - for _, storeKeysPrefix := range storeKeysPrefixes { - storeKeyA := storeKeysPrefix.A - storeKeyB := storeKeysPrefix.B - prefixes := storeKeysPrefix.Prefixes + for _, skp := range storeKeysPrefixes { + storeA := ctxA.KVStore(skp.A) + storeB := ctxB.KVStore(skp.B) - storeA := ctxA.KVStore(storeKeyA) - storeB := ctxB.KVStore(storeKeyB) - - failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, prefixes) + failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes) require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare") - fmt.Printf("compared %d key/value pairs between %s and %s\n", len(failedKVAs), storeKeyA, storeKeyB) - require.Len(t, failedKVAs, 0, simapp.GetSimulationLog(storeKeyA.Name(), app.sm.StoreDecoders, app.cdc, failedKVAs, failedKVBs)) + fmt.Printf("compared %d key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B) + require.Equal(t, len(failedKVAs), 0, simapp.GetSimulationLog(skp.A.Name(), app.SimulationManager().StoreDecoders, app.Codec(), failedKVAs, failedKVBs)) } } func TestAppSimulationAfterImport(t *testing.T) { - if !simapp.FlagEnabledValue { + config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation") + if skip { t.Skip("skipping application simulation after import") } - - var logger log.Logger - config := simapp.NewConfigFromFlags() - - if simapp.FlagVerboseValue { - logger = log.TestingLogger() - } else { - logger = log.NewNopLogger() - } - - dir, err := ioutil.TempDir("", "goleveldb-app-sim") - require.NoError(t, err) - db, err := sdk.NewLevelDB("Simulation", dir) - require.NoError(t, err) + require.NoError(t, err, "simulation setup failed") defer func() { db.Close() - _ = os.RemoveAll(dir) + require.NoError(t, os.RemoveAll(dir)) }() - gapp := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt) - require.Equal(t, "WasmApp", gapp.Name()) + app := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, map[int64]bool{}, fauxMerkleModeOpt) + require.Equal(t, appName, app.Name()) - // Run randomized simulation // Run randomized simulation stopEarly, simParams, simErr := simulation.SimulateFromSeed( - t, os.Stdout, gapp.BaseApp, simapp.AppStateFn(gapp.Codec(), gapp.sm), - testAndRunTxs(gapp, config), gapp.ModuleAccountAddrs(), config, + t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()), + simapp.SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) - // export state and params before the simulation error is checked - if config.ExportStatePath != "" { - err := ExportStateToJSON(gapp, config.ExportStatePath) - require.NoError(t, err) - } - - if config.ExportParamsPath != "" { - err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath) - require.NoError(t, err) - } - + // export state and simParams before the simulation error is checked + err = simapp.CheckExportSimulation(app, config, simParams) + require.NoError(t, err) require.NoError(t, simErr) if config.Commit { - // for memdb: - // fmt.Println("Database Size", db.Stats()["database.size"]) - fmt.Println("\nGoLevelDB Stats") - fmt.Println(db.Stats()["leveldb.stats"]) - fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) + simapp.PrintStats(db) } if stopEarly { - // we can't export or import a zero-validator genesis - fmt.Printf("We can't export or import a zero-validator genesis, exiting test...\n") + fmt.Println("can't export or import a zero-validator genesis, exiting test...") return } - fmt.Printf("Exporting genesis...\n") + fmt.Printf("exporting genesis...\n") - appState, _, err := gapp.ExportAppStateAndValidators(true, []string{}) - if err != nil { - panic(err) - } + appState, _, err := app.ExportAppStateAndValidators(true, []string{}) + require.NoError(t, err) - fmt.Printf("Importing genesis...\n") + fmt.Printf("importing genesis...\n") - newDir, err := ioutil.TempDir("", "goleveldb-app-sim-2") - require.NoError(t, err) - newDB, err := sdk.NewLevelDB("Simulation-2", dir) - require.NoError(t, err) + _, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2") + require.NoError(t, err, "simulation setup failed") defer func() { newDB.Close() - _ = os.RemoveAll(newDir) + require.NoError(t, os.RemoveAll(newDir)) }() - newApp := NewWasmApp(log.NewNopLogger(), newDB, nil, true, 0, fauxMerkleModeOpt) - require.Equal(t, "WasmApp", newApp.Name()) + newApp := NewWasmApp(log.NewNopLogger(), newDB, nil, true, simapp.FlagPeriodValue, map[int64]bool{}, fauxMerkleModeOpt) + require.Equal(t, appName, newApp.Name()) newApp.InitChain(abci.RequestInitChain{ AppStateBytes: appState, }) - // Run randomized simulation on imported app _, _, err = simulation.SimulateFromSeed( - t, os.Stdout, newApp.BaseApp, simapp.AppStateFn(gapp.Codec(), gapp.sm), - testAndRunTxs(newApp, config), newApp.ModuleAccountAddrs(), config, + t, os.Stdout, newApp.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()), + simapp.SimulationOperations(newApp, newApp.Codec(), config), + newApp.ModuleAccountAddrs(), config, ) - require.NoError(t, err) } -// TODO: Make another test for the fuzzer itself, which just has noOp txs -// and doesn't depend on the application. func TestAppStateDeterminism(t *testing.T) { if !simapp.FlagEnabledValue { t.Skip("skipping application simulation") @@ -588,6 +244,7 @@ func TestAppStateDeterminism(t *testing.T) { config.ExportParamsPath = "" config.OnOperation = false config.AllInvariants = false + config.ChainID = helpers.SimAppChainID numSeeds := 3 numTimesToRunPerSeed := 5 @@ -597,9 +254,16 @@ func TestAppStateDeterminism(t *testing.T) { config.Seed = rand.Int63() for j := 0; j < numTimesToRunPerSeed; j++ { - logger := log.NewNopLogger() + var logger log.Logger + if simapp.FlagVerboseValue { + logger = log.TestingLogger() + } else { + logger = log.NewNopLogger() + } + db := dbm.NewMemDB() - app := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, interBlockCacheOpt()) + + app := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, map[int64]bool{}, interBlockCacheOpt()) fmt.Printf( "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", @@ -607,11 +271,16 @@ func TestAppStateDeterminism(t *testing.T) { ) _, _, err := simulation.SimulateFromSeed( - t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()), + simapp.SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) require.NoError(t, err) + if config.Commit { + simapp.PrintStats(db) + } + appHash := app.LastCommitID().Hash appHashList[j] = appHash @@ -624,70 +293,3 @@ func TestAppStateDeterminism(t *testing.T) { } } } - -func BenchmarkInvariants(b *testing.B) { - logger := log.NewNopLogger() - - config := simapp.NewConfigFromFlags() - config.AllInvariants = false - - dir, err := ioutil.TempDir("", "goleveldb-app-invariant-bench") - if err != nil { - fmt.Println(err) - b.Fail() - } - db, err := sdk.NewLevelDB("simulation", dir) - if err != nil { - fmt.Println(err) - b.Fail() - } - - defer func() { - db.Close() - os.RemoveAll(dir) - }() - - gapp := NewWasmApp(logger, db, nil, true, simapp.FlagPeriodValue, interBlockCacheOpt()) - - // 2. Run parameterized simulation (w/o invariants) - _, simParams, simErr := simulation.SimulateFromSeed( - b, ioutil.Discard, gapp.BaseApp, simapp.AppStateFn(gapp.Codec(), gapp.sm), - testAndRunTxs(gapp, config), gapp.ModuleAccountAddrs(), config, - ) - - // export state and params before the simulation error is checked - if config.ExportStatePath != "" { - if err := ExportStateToJSON(gapp, config.ExportStatePath); err != nil { - fmt.Println(err) - b.Fail() - } - } - - if config.ExportParamsPath != "" { - if err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath); err != nil { - fmt.Println(err) - b.Fail() - } - } - - if simErr != nil { - fmt.Println(simErr) - b.FailNow() - } - - ctx := gapp.NewContext(true, abci.Header{Height: gapp.LastBlockHeight() + 1}) - - // 3. Benchmark each invariant separately - // - // NOTE: We use the crisis keeper as it has all the invariants registered with - // their respective metadata which makes it useful for testing/benchmarking. - for _, cr := range gapp.crisisKeeper.Routes() { - cr := cr - b.Run(fmt.Sprintf("%s/%s", cr.ModuleName, cr.Route), func(b *testing.B) { - if res, stop := cr.Invar(ctx); stop { - fmt.Printf("broken invariant at block %d of %d\n%s", ctx.BlockHeight()-1, config.NumBlocks, res) - b.FailNow() - } - }) - } -} diff --git a/app/utils.go b/app/utils.go deleted file mode 100644 index dc55116537..0000000000 --- a/app/utils.go +++ /dev/null @@ -1,38 +0,0 @@ -//nolint -package app - -import ( - "fmt" - "io" - "io/ioutil" - - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/cosmos-sdk/baseapp" - bam "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking" -) - -// ExportStateToJSON util function to export the app state to JSON -func ExportStateToJSON(app *WasmApp, path string) error { - fmt.Println("exporting app state...") - appState, _, err := app.ExportAppStateAndValidators(false, nil) - if err != nil { - return err - } - - return ioutil.WriteFile(path, []byte(appState), 0644) -} - -// NewWasmAppUNSAFE is used for debugging purposes only. -// -// NOTE: to not use this function with non-test code -func NewWasmAppUNSAFE(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, - invCheckPeriod uint, baseAppOptions ...func(*baseapp.BaseApp), -) (gapp *WasmApp, keyMain, keyStaking *sdk.KVStoreKey, stakingKeeper staking.Keeper) { - - gapp = NewWasmApp(logger, db, traceStore, loadLatest, invCheckPeriod, baseAppOptions...) - return gapp, gapp.keys[bam.MainStoreKey], gapp.keys[staking.StoreKey], gapp.stakingKeeper -} diff --git a/cli_test/cli_test.go b/cli_test/cli_test.go index 1f0fc429f1..0fdb46b51e 100644 --- a/cli_test/cli_test.go +++ b/cli_test/cli_test.go @@ -12,16 +12,15 @@ import ( "path/filepath" "strings" "testing" - "time" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" tmtypes "github.com/tendermint/tendermint/types" - "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmwasm/wasmd/app" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -352,7 +351,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { barAddr := f.KeyAddress(keyBar) barVal := sdk.ValAddress(barAddr) - consPubKey := sdk.MustBech32ifyConsPub(ed25519.GenPrivKey().PubKey()) + consPubKey := sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, ed25519.GenPrivKey().PubKey()) sendTokens := sdk.TokensFromConsensusPower(10) f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "-y") @@ -420,12 +419,12 @@ func TestGaiaCLIQueryRewards(t *testing.T) { cdc := app.MakeCodec() genesisState := f.GenesisState() - inflationMin := sdk.MustNewDecFromStr("10000.0") + inflationMin := sdk.MustNewDecFromStr("1.0") var mintData mint.GenesisState cdc.UnmarshalJSON(genesisState[mint.ModuleName], &mintData) mintData.Minter.Inflation = inflationMin mintData.Params.InflationMin = inflationMin - mintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0") + mintData.Params.InflationMax = sdk.MustNewDecFromStr("1.0") mintDataBz, err := cdc.MarshalJSON(mintData) require.NoError(t, err) genesisState[mint.ModuleName] = mintDataBz @@ -504,8 +503,8 @@ func TestGaiaCLISubmitProposal(t *testing.T) { f.TxGovSubmitProposal(keyFoo, "Text", "Test", "test", sdk.NewCoin(denom, proposalTokens), "-y") tests.WaitForNextNBlocksTM(1, f.Port) - // Ensure transaction tags can be queried - searchResult := f.QueryTxs(1, 50, "message.action:submit_proposal", fmt.Sprintf("message.sender:%s", fooAddr)) + // Ensure transaction events can be queried + searchResult := f.QueryTxs(1, 50, "message.action=submit_proposal", fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, searchResult.Txs, 1) // Ensure deposit was deducted @@ -548,8 +547,8 @@ func TestGaiaCLISubmitProposal(t *testing.T) { deposit = f.QueryGovDeposit(1, fooAddr) require.Equal(t, proposalTokens.Add(depositTokens), deposit.Amount.AmountOf(denom)) - // Ensure tags are set on the transaction - searchResult = f.QueryTxs(1, 50, "message.action:deposit", fmt.Sprintf("message.sender:%s", fooAddr)) + // Ensure events are set on the transaction + searchResult = f.QueryTxs(1, 50, "message.action=deposit", fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, searchResult.Txs, 1) // Ensure account has expected amount of funds @@ -585,8 +584,8 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.Equal(t, uint64(1), votes[0].ProposalID) require.Equal(t, gov.OptionYes, votes[0].Option) - // Ensure tags are applied to voting transaction properly - searchResult = f.QueryTxs(1, 50, "message.action:vote", fmt.Sprintf("message.sender:%s", fooAddr)) + // Ensure events are applied to voting transaction properly + searchResult = f.QueryTxs(1, 50, "message.action=vote", fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, searchResult.Txs, 1) // Ensure no proposals in deposit period @@ -648,8 +647,8 @@ func TestGaiaCLISubmitParamChangeProposal(t *testing.T) { f.TxGovSubmitParamChangeProposal(keyFoo, proposalFile.Name(), sdk.NewCoin(denom, proposalTokens), "-y") tests.WaitForNextNBlocksTM(1, f.Port) - // ensure transaction tags can be queried - txsPage := f.QueryTxs(1, 50, "message.action:submit_proposal", fmt.Sprintf("message.sender:%s", fooAddr)) + // ensure transaction events can be queried + txsPage := f.QueryTxs(1, 50, "message.action=submit_proposal", fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, txsPage.Txs, 1) // ensure deposit was deducted @@ -680,12 +679,12 @@ func TestGaiaCLISubmitCommunityPoolSpendProposal(t *testing.T) { // create some inflation cdc := app.MakeCodec() genesisState := f.GenesisState() - inflationMin := sdk.MustNewDecFromStr("10000.0") + inflationMin := sdk.MustNewDecFromStr("1.0") var mintData mint.GenesisState cdc.UnmarshalJSON(genesisState[mint.ModuleName], &mintData) mintData.Minter.Inflation = inflationMin mintData.Params.InflationMin = inflationMin - mintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0") + mintData.Params.InflationMax = sdk.MustNewDecFromStr("1.0") mintDataBz, err := cdc.MarshalJSON(mintData) require.NoError(t, err) genesisState[mint.ModuleName] = mintDataBz @@ -732,8 +731,8 @@ func TestGaiaCLISubmitCommunityPoolSpendProposal(t *testing.T) { f.TxGovSubmitCommunityPoolSpendProposal(keyFoo, proposalFile.Name(), sdk.NewCoin(denom, proposalTokens), "-y") tests.WaitForNextNBlocksTM(1, f.Port) - // ensure transaction tags can be queried - txsPage := f.QueryTxs(1, 50, "message.action:submit_proposal", fmt.Sprintf("message.sender:%s", fooAddr)) + // ensure transaction events can be queried + txsPage := f.QueryTxs(1, 50, "message.action=submit_proposal", fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, txsPage.Txs, 1) // ensure deposit was deducted @@ -778,30 +777,30 @@ func TestGaiaCLIQueryTxPagination(t *testing.T) { } // perPage = 15, 2 pages - txsPage1 := f.QueryTxs(1, 15, fmt.Sprintf("message.sender:%s", fooAddr)) + txsPage1 := f.QueryTxs(1, 15, fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, txsPage1.Txs, 15) require.Equal(t, txsPage1.Count, 15) - txsPage2 := f.QueryTxs(2, 15, fmt.Sprintf("message.sender:%s", fooAddr)) + txsPage2 := f.QueryTxs(2, 15, fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, txsPage2.Txs, 15) require.NotEqual(t, txsPage1.Txs, txsPage2.Txs) // perPage = 16, 2 pages - txsPage1 = f.QueryTxs(1, 16, fmt.Sprintf("message.sender:%s", fooAddr)) + txsPage1 = f.QueryTxs(1, 16, fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, txsPage1.Txs, 16) - txsPage2 = f.QueryTxs(2, 16, fmt.Sprintf("message.sender:%s", fooAddr)) + txsPage2 = f.QueryTxs(2, 16, fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, txsPage2.Txs, 14) require.NotEqual(t, txsPage1.Txs, txsPage2.Txs) // perPage = 50 - txsPageFull := f.QueryTxs(1, 50, fmt.Sprintf("message.sender:%s", fooAddr)) + txsPageFull := f.QueryTxs(1, 50, fmt.Sprintf("message.sender=%s", fooAddr)) require.Len(t, txsPageFull.Txs, 30) require.Equal(t, txsPageFull.Txs, append(txsPage1.Txs, txsPage2.Txs...)) // perPage = 0 - f.QueryTxsInvalid(errors.New("ERROR: page must greater than 0"), 0, 50, fmt.Sprintf("message.sender:%s", fooAddr)) + f.QueryTxsInvalid(errors.New("ERROR: page must greater than 0"), 0, 50, fmt.Sprintf("message.sender=%s", fooAddr)) // limit = 0 - f.QueryTxsInvalid(errors.New("ERROR: limit must greater than 0"), 1, 0, fmt.Sprintf("message.sender:%s", fooAddr)) + f.QueryTxsInvalid(errors.New("ERROR: limit must greater than 0"), 1, 0, fmt.Sprintf("message.sender=%s", fooAddr)) // Cleanup testing directories f.Cleanup() @@ -873,7 +872,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { require.True(t, success) require.Empty(t, stderr) msg := unmarshalStdTx(t, stdout) - require.Equal(t, msg.Fee.Gas, uint64(client.DefaultGasLimit)) + require.Equal(t, msg.Fee.Gas, uint64(flags.DefaultGasLimit)) require.Equal(t, len(msg.Msgs), 1) require.Equal(t, 0, len(msg.GetSignatures())) @@ -1175,12 +1174,14 @@ func TestGaiaCLIConfig(t *testing.T) { f.CLIConfig("chain-id", f.ChainID) f.CLIConfig("trace", "false") f.CLIConfig("indent", "true") + f.CLIConfig("keyring-backend", "test") config, err := ioutil.ReadFile(path.Join(f.GaiacliHome, "config", "config.toml")) require.NoError(t, err) expectedConfig := fmt.Sprintf(`broadcast-mode = "block" chain-id = "%s" indent = true +keyring-backend = "test" node = "%s" output = "text" trace = false @@ -1291,7 +1292,6 @@ func TestSlashingGetParams(t *testing.T) { defer proc.Stop(false) params := f.QuerySlashingParams() - require.Equal(t, time.Duration(120000000000), params.MaxEvidenceAge) require.Equal(t, int64(100), params.SignedBlocksWindow) require.Equal(t, sdk.NewDecWithPrec(5, 1), params.MinSignedPerWindow) diff --git a/cli_test/test_helpers.go b/cli_test/test_helpers.go index 05617c5955..d9d1e50116 100644 --- a/cli_test/test_helpers.go +++ b/cli_test/test_helpers.go @@ -10,10 +10,7 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/client" - "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmwasm/wasmd/app" @@ -138,6 +135,8 @@ func InitFixtures(t *testing.T) (f *Fixtures) { // reset test state f.UnsafeResetAll() + f.CLIConfig("keyring-backend", "test") + // ensure keystore has foo and bar keys f.KeysDelete(keyFoo) f.KeysDelete(keyBar) @@ -203,7 +202,7 @@ func (f *Fixtures) UnsafeResetAll(flags ...string) { // NOTE: GDInit sets the ChainID for the Fixtures instance func (f *Fixtures) GDInit(moniker string, flags ...string) { cmd := fmt.Sprintf("%s init -o --home=%s %s", f.GaiadBinary, f.GaiadHome, moniker) - _, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + _, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) var chainID string var initRes map[string]json.RawMessage @@ -219,13 +218,13 @@ func (f *Fixtures) GDInit(moniker string, flags ...string) { // AddGenesisAccount is wasmd add-genesis-account func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, flags ...string) { - cmd := fmt.Sprintf("%s add-genesis-account %s %s --home=%s", f.GaiadBinary, address, coins, f.GaiadHome) + cmd := fmt.Sprintf("%s add-genesis-account %s %s --home=%s --keyring-backend=test", f.GaiadBinary, address, coins, f.GaiadHome) executeWriteCheckErr(f.T, addFlags(cmd, flags)) } // GenTx is wasmd gentx func (f *Fixtures) GenTx(name string, flags ...string) { - cmd := fmt.Sprintf("%s gentx --name=%s --home=%s --home-client=%s", f.GaiadBinary, name, f.GaiadHome, f.GaiacliHome) + cmd := fmt.Sprintf("%s gentx --name=%s --home=%s --home-client=%s --keyring-backend=test", f.GaiadBinary, name, f.GaiadHome, f.GaiacliHome) executeWriteCheckErr(f.T, addFlags(cmd, flags)) } @@ -264,31 +263,36 @@ func (f *Fixtures) ValidateGenesis() { // KeysDelete is wasmcli keys delete func (f *Fixtures) KeysDelete(name string, flags ...string) { - cmd := fmt.Sprintf("%s keys delete --home=%s %s", f.GaiacliBinary, f.GaiacliHome, name) + cmd := fmt.Sprintf("%s keys delete --keyring-backend=test --home=%s %s", f.GaiacliBinary, + f.GaiacliHome, name) executeWrite(f.T, addFlags(cmd, append(append(flags, "-y"), "-f"))) } // KeysAdd is wasmcli keys add func (f *Fixtures) KeysAdd(name string, flags ...string) { - cmd := fmt.Sprintf("%s keys add --home=%s %s", f.GaiacliBinary, f.GaiacliHome, name) + cmd := fmt.Sprintf("%s keys add --keyring-backend=test --home=%s %s", f.GaiacliBinary, + f.GaiacliHome, name) executeWriteCheckErr(f.T, addFlags(cmd, flags)) } // KeysAddRecover prepares wasmcli keys add --recover func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) (exitSuccess bool, stdout, stderr string) { - cmd := fmt.Sprintf("%s keys add --home=%s --recover %s", f.GaiacliBinary, f.GaiacliHome, name) + cmd := fmt.Sprintf("%s keys add --keyring-backend=test --home=%s --recover %s", + f.GaiacliBinary, f.GaiacliHome, name) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), mnemonic) } // KeysAddRecoverHDPath prepares wasmcli keys add --recover --account --index func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) { - cmd := fmt.Sprintf("%s keys add --home=%s --recover %s --account %d --index %d", f.GaiacliBinary, f.GaiacliHome, name, account, index) + cmd := fmt.Sprintf("%s keys add --keyring-backend=test --home=%s --recover %s --account %d"+ + " --index %d", f.GaiacliBinary, f.GaiacliHome, name, account, index) executeWriteCheckErr(f.T, addFlags(cmd, flags), mnemonic) } // KeysShow is wasmcli keys show func (f *Fixtures) KeysShow(name string, flags ...string) keys.KeyOutput { - cmd := fmt.Sprintf("%s keys show --home=%s %s", f.GaiacliBinary, f.GaiacliHome, name) + cmd := fmt.Sprintf("%s keys show --keyring-backend=test --home=%s %s", f.GaiacliBinary, + f.GaiacliHome, name) out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") var ko keys.KeyOutput err := clientkeys.UnmarshalJSON([]byte(out), &ko) @@ -318,33 +322,35 @@ func (f *Fixtures) CLIConfig(key, value string, flags ...string) { // TxSend is wasmcli tx send func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx send %s %s %s %v", f.GaiacliBinary, from, to, amount, f.Flags()) - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + cmd := fmt.Sprintf("%s tx send --keyring-backend=test %s %s %s %v", f.GaiacliBinary, from, + to, amount, f.Flags()) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } // TxSign is wasmcli tx sign func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx sign %v --from=%s %v", f.GaiacliBinary, f.Flags(), signer, fileName) - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + cmd := fmt.Sprintf("%s tx sign %v --keyring-backend=test --from=%s %v", f.GaiacliBinary, + f.Flags(), signer, fileName) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } // TxBroadcast is wasmcli tx broadcast func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) { cmd := fmt.Sprintf("%s tx broadcast %v %v", f.GaiacliBinary, f.Flags(), fileName) - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } // TxEncode is wasmcli tx encode func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) { cmd := fmt.Sprintf("%s tx encode %v %v", f.GaiacliBinary, f.Flags(), fileName) - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } // TxMultisign is wasmcli tx multisign func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx multisign %v %s %s %s", f.GaiacliBinary, f.Flags(), + cmd := fmt.Sprintf("%s tx multisign --keyring-backend=test %v %s %s %s", f.GaiacliBinary, f.Flags(), fileName, name, strings.Join(signaturesFiles, " "), ) return executeWriteRetStdStreams(f.T, cmd) @@ -355,17 +361,19 @@ func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string, // TxStakingCreateValidator is wasmcli tx staking create-validator func (f *Fixtures) TxStakingCreateValidator(from, consPubKey string, amount sdk.Coin, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx staking create-validator %v --from=%s --pubkey=%s", f.GaiacliBinary, f.Flags(), from, consPubKey) + cmd := fmt.Sprintf("%s tx staking create-validator %v --keyring-backend=test --from=%s"+ + " --pubkey=%s", f.GaiacliBinary, f.Flags(), from, consPubKey) cmd += fmt.Sprintf(" --amount=%v --moniker=%v --commission-rate=%v", amount, from, "0.05") cmd += fmt.Sprintf(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10") cmd += fmt.Sprintf(" --min-self-delegation=%v", "1") - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } // TxStakingUnbond is wasmcli tx staking unbond func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress, flags ...string) bool { - cmd := fmt.Sprintf("%s tx staking unbond %s %v --from=%s %v", f.GaiacliBinary, validator, shares, from, f.Flags()) - return executeWrite(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + cmd := fmt.Sprintf("%s tx staking unbond --keyring-backend=test %s %v --from=%s %v", + f.GaiacliBinary, validator, shares, from, f.Flags()) + return executeWrite(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } //___________________________________________________________________________________ @@ -373,21 +381,24 @@ func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress // TxGovSubmitProposal is wasmcli tx gov submit-proposal func (f *Fixtures) TxGovSubmitProposal(from, typ, title, description string, deposit sdk.Coin, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx gov submit-proposal %v --from=%s --type=%s", f.GaiacliBinary, f.Flags(), from, typ) + cmd := fmt.Sprintf("%s tx gov submit-proposal %v --keyring-backend=test --from=%s --type=%s", + f.GaiacliBinary, f.Flags(), from, typ) cmd += fmt.Sprintf(" --title=%s --description=%s --deposit=%s", title, description, deposit) - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } // TxGovDeposit is wasmcli tx gov deposit func (f *Fixtures) TxGovDeposit(proposalID int, from string, amount sdk.Coin, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx gov deposit %d %s --from=%s %v", f.GaiacliBinary, proposalID, amount, from, f.Flags()) - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + cmd := fmt.Sprintf("%s tx gov deposit %d %s --keyring-backend=test --from=%s %v", + f.GaiacliBinary, proposalID, amount, from, f.Flags()) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } // TxGovVote is wasmcli tx gov vote func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx gov vote %d %s --from=%s %v", f.GaiacliBinary, proposalID, option, from, f.Flags()) - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + cmd := fmt.Sprintf("%s tx gov vote %d %s --keyring-backend=test --from=%s %v", + f.GaiacliBinary, proposalID, option, from, f.Flags()) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } // TxGovSubmitParamChangeProposal executes a CLI parameter change proposal @@ -397,11 +408,11 @@ func (f *Fixtures) TxGovSubmitParamChangeProposal( ) (bool, string, string) { cmd := fmt.Sprintf( - "%s tx gov submit-proposal param-change %s --from=%s %v", + "%s tx gov submit-proposal param-change %s --keyring-backend=test --from=%s %v", f.GaiacliBinary, proposalPath, from, f.Flags(), ) - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } // TxGovSubmitCommunityPoolSpendProposal executes a CLI community pool spend proposal @@ -411,11 +422,11 @@ func (f *Fixtures) TxGovSubmitCommunityPoolSpendProposal( ) (bool, string, string) { cmd := fmt.Sprintf( - "%s tx gov submit-proposal community-pool-spend %s --from=%s %v", + "%s tx gov submit-proposal community-pool-spend %s --keyring-backend=test --from=%s %v", f.GaiacliBinary, proposalPath, from, f.Flags(), ) - return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) + return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass) } //___________________________________________________________________________________ @@ -441,8 +452,8 @@ func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.Ba // wasmcli query txs // QueryTxs is wasmcli query txs -func (f *Fixtures) QueryTxs(page, limit int, tags ...string) *sdk.SearchTxsResult { - cmd := fmt.Sprintf("%s query txs --page=%d --limit=%d --tags='%s' %v", f.GaiacliBinary, page, limit, queryTags(tags), f.Flags()) +func (f *Fixtures) QueryTxs(page, limit int, events ...string) *sdk.SearchTxsResult { + cmd := fmt.Sprintf("%s query txs --page=%d --limit=%d --events='%s' %v", f.GaiacliBinary, page, limit, queryEvents(events), f.Flags()) out, _ := tests.ExecuteT(f.T, cmd, "") var result sdk.SearchTxsResult cdc := app.MakeCodec() @@ -452,8 +463,8 @@ func (f *Fixtures) QueryTxs(page, limit int, tags ...string) *sdk.SearchTxsResul } // QueryTxsInvalid query txs with wrong parameters and compare expected error -func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, tags ...string) { - cmd := fmt.Sprintf("%s query txs --page=%d --limit=%d --tags='%s' %v", f.GaiacliBinary, page, limit, queryTags(tags), f.Flags()) +func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, events ...string) { + cmd := fmt.Sprintf("%s query txs --page=%d --limit=%d --events='%s' %v", f.GaiacliBinary, page, limit, queryEvents(events), f.Flags()) _, err := tests.ExecuteT(f.T, cmd, "") require.EqualError(f.T, expectedErr, err) } @@ -742,9 +753,9 @@ func addFlags(cmd string, flags []string) string { return strings.TrimSpace(cmd) } -func queryTags(tags []string) (out string) { - for _, tag := range tags { - out += tag + "&" +func queryEvents(events []string) (out string) { + for _, event := range events { + out += event + "&" } return strings.TrimSuffix(out, "&") } diff --git a/cmd/wasmcli/main.go b/cmd/wasmcli/main.go index fd3b9ce378..a24bff4640 100644 --- a/cmd/wasmcli/main.go +++ b/cmd/wasmcli/main.go @@ -6,6 +6,7 @@ import ( "path" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/lcd" "github.com/cosmos/cosmos-sdk/client/rpc" @@ -51,7 +52,7 @@ func main() { } // Add --chain-id to persistent flags and mark it required - rootCmd.PersistentFlags().String(client.FlagChainID, "", "Chain ID of tendermint node") + rootCmd.PersistentFlags().String(flags.FlagChainID, "", "Chain ID of tendermint node") rootCmd.PersistentPreRunE = func(_ *cobra.Command, _ []string) error { return initConfig(rootCmd) } @@ -62,13 +63,13 @@ func main() { client.ConfigCmd(app.DefaultCLIHome), queryCmd(cdc), txCmd(cdc), - client.LineBreak, + flags.LineBreak, lcd.ServeCommand(cdc, registerRoutes), - client.LineBreak, + flags.LineBreak, keys.Commands(), - client.LineBreak, + flags.LineBreak, version.Cmd, - client.NewCompletionCmd(rootCmd, true), + flags.NewCompletionCmd(rootCmd, true), ) // Add flags and prefix all env exposed with WM @@ -90,12 +91,12 @@ func queryCmd(cdc *amino.Codec) *cobra.Command { queryCmd.AddCommand( authcmd.GetAccountCmd(cdc), - client.LineBreak, + flags.LineBreak, rpc.ValidatorCommand(cdc), rpc.BlockCommand(), authcmd.QueryTxsByEventsCmd(cdc), authcmd.QueryTxCmd(cdc), - client.LineBreak, + flags.LineBreak, ) // add modules' query commands @@ -112,15 +113,16 @@ func txCmd(cdc *amino.Codec) *cobra.Command { txCmd.AddCommand( bankcmd.SendTxCmd(cdc), - client.LineBreak, + flags.LineBreak, authcmd.GetSignCommand(cdc), authcmd.GetMultiSignCommand(cdc), - client.LineBreak, + flags.LineBreak, authcmd.GetBroadcastCommand(cdc), authcmd.GetEncodeCommand(cdc), authcmd.GetDecodeCommand(cdc), - authcmd.GetDecodeTxCmd(cdc), - client.LineBreak, + // TODO: I think it is safe to remove + // authcmd.GetDecodeTxCmd(cdc), + flags.LineBreak, ) // add modules' tx commands @@ -163,7 +165,7 @@ func initConfig(cmd *cobra.Command) error { return err } } - if err := viper.BindPFlag(client.FlagChainID, cmd.PersistentFlags().Lookup(client.FlagChainID)); err != nil { + if err := viper.BindPFlag(flags.FlagChainID, cmd.PersistentFlags().Lookup(flags.FlagChainID)); err != nil { return err } if err := viper.BindPFlag(cli.EncodingFlag, cmd.PersistentFlags().Lookup(cli.EncodingFlag)); err != nil { diff --git a/cmd/wasmd/genaccounts.go b/cmd/wasmd/genaccounts.go index 92c5c3b8f6..0d912791b2 100644 --- a/cmd/wasmd/genaccounts.go +++ b/cmd/wasmd/genaccounts.go @@ -10,8 +10,9 @@ import ( "github.com/tendermint/tendermint/libs/cli" - "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -49,7 +50,12 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa inBuf := bufio.NewReader(cmd.InOrStdin()) if err != nil { // attempt to lookup address from Keybase if no address was provided - kb, err := keys.NewKeyringFromDir(viper.GetString(flagClientHome), inBuf) + kb, err := keys.NewKeyring( + sdk.GetConfig().GetKeyringServiceName(), + viper.GetString(flags.FlagKeyringBackend), + viper.GetString(flagClientHome), + inBuf, + ) if err != nil { return err } @@ -137,6 +143,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa } cmd.Flags().String(cli.HomeFlag, defaultNodeHome, "node's home directory") + cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") cmd.Flags().String(flagClientHome, defaultClientHome, "client's home directory") cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts") cmd.Flags().Uint64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts") diff --git a/cmd/wasmd/main.go b/cmd/wasmd/main.go index d37ad4ca8c..549eda306a 100644 --- a/cmd/wasmd/main.go +++ b/cmd/wasmd/main.go @@ -16,8 +16,8 @@ import ( "github.com/cosmwasm/wasmd/app" "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/debug" + "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" @@ -59,7 +59,7 @@ func main() { ) rootCmd.AddCommand(genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics)) rootCmd.AddCommand(AddGenesisAccountCmd(ctx, cdc, app.DefaultNodeHome, app.DefaultCLIHome)) - rootCmd.AddCommand(client.NewCompletionCmd(rootCmd, true)) + rootCmd.AddCommand(flags.NewCompletionCmd(rootCmd, true)) // rootCmd.AddCommand(testnetCmd(ctx, cdc, app.ModuleBasics, auth.GenesisAccountIterator{})) rootCmd.AddCommand(replayCmd()) rootCmd.AddCommand(debug.Cmd(cdc)) @@ -83,8 +83,13 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application cache = store.NewCommitKVStoreCacheManager() } + skipUpgradeHeights := make(map[int64]bool) + for _, h := range viper.GetIntSlice(server.FlagUnsafeSkipUpgrades) { + skipUpgradeHeights[int64(h)] = true + } + return app.NewWasmApp( - logger, db, traceStore, true, invCheckPeriod, + logger, db, traceStore, true, invCheckPeriod, skipUpgradeHeights, baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))), baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)), baseapp.SetHaltHeight(viper.GetUint64(server.FlagHaltHeight)), @@ -98,7 +103,7 @@ func exportAppStateAndTMValidators( ) (json.RawMessage, []tmtypes.GenesisValidator, error) { if height != -1 { - gapp := app.NewWasmApp(logger, db, traceStore, false, uint(1)) + gapp := app.NewWasmApp(logger, db, traceStore, false, uint(1), nil) err := gapp.LoadHeight(height) if err != nil { return nil, nil, err @@ -106,6 +111,6 @@ func exportAppStateAndTMValidators( return gapp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) } - gapp := app.NewWasmApp(logger, db, traceStore, true, uint(1)) + gapp := app.NewWasmApp(logger, db, traceStore, true, uint(1), nil) return gapp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) } diff --git a/cmd/wasmd/replay.go b/cmd/wasmd/replay.go index 76f844165f..4798613056 100644 --- a/cmd/wasmd/replay.go +++ b/cmd/wasmd/replay.go @@ -11,7 +11,7 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" "github.com/tendermint/tendermint/proxy" tmsm "github.com/tendermint/tendermint/state" tmstore "github.com/tendermint/tendermint/store" @@ -43,8 +43,8 @@ func replayTxs(rootDir string) error { fmt.Fprintln(os.Stderr, "Copying rootdir over") oldRootDir := rootDir rootDir = oldRootDir + "_replay" - if cmn.FileExists(rootDir) { - cmn.Exit(fmt.Sprintf("temporary copy dir %v already exists", rootDir)) + if tmos.FileExists(rootDir) { + tmos.Exit(fmt.Sprintf("temporary copy dir %v already exists", rootDir)) } if err := cpm.Copy(oldRootDir, rootDir); err != nil { return err @@ -93,7 +93,8 @@ func replayTxs(rootDir string) error { // Application fmt.Fprintln(os.Stderr, "Creating application") gapp := app.NewWasmApp( - ctx.Logger, appDB, traceStoreWriter, true, uint(1), + // TODO: do we want to set skipUpgradeHieghts here? + ctx.Logger, appDB, traceStoreWriter, true, uint(1), nil, baseapp.SetPruning(store.PruneEverything), // nothing ) diff --git a/cmd/wasmd/testnet.go b/cmd/wasmd/testnet.go index 997ab2e0eb..a4295c8225 100644 --- a/cmd/wasmd/testnet.go +++ b/cmd/wasmd/testnet.go @@ -14,13 +14,15 @@ import ( "github.com/spf13/viper" tmconfig "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" - cmn "github.com/tendermint/tendermint/libs/common" + tmos "github.com/tendermint/tendermint/libs/os" + tmrand "github.com/tendermint/tendermint/libs/rand" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/client/flags" + clientkeys "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/server" srvconfig "github.com/cosmos/cosmos-sdk/server/config" sdk "github.com/cosmos/cosmos-sdk/types" @@ -61,7 +63,7 @@ Example: config := ctx.Config outputDir := viper.GetString(flagOutputDir) - chainID := viper.GetString(client.FlagChainID) + chainID := viper.GetString(flags.FlagChainID) minGasPrices := viper.GetString(server.FlagMinGasPrices) nodeDirPrefix := viper.GetString(flagNodeDirPrefix) nodeDaemonHome := viper.GetString(flagNodeDaemonHome) @@ -87,10 +89,11 @@ Example: cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)") cmd.Flags().String( - client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") + flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") cmd.Flags().String( server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)") + cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") return cmd } @@ -103,7 +106,7 @@ func InitTestnet(cmd *cobra.Command, config *tmconfig.Config, cdc *codec.Codec, nodeCLIHome, startingIPAddress string, numValidators int) error { if chainID == "" { - chainID = "chain-" + cmn.RandStr(6) + chainID = "chain-" + tmrand.Str(6) } monikers := make([]string, numValidators) @@ -158,12 +161,17 @@ func InitTestnet(cmd *cobra.Command, config *tmconfig.Config, cdc *codec.Codec, memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip) genFiles = append(genFiles, config.GenesisFile()) - kb, err := keys.NewKeyringFromDir(clientDir, inBuf) + kb, err := keys.NewKeyring( + sdk.GetConfig().GetKeyringServiceName(), + viper.GetString(flags.FlagKeyringBackend), + viper.GetString(flagClientHome), + inBuf, + ) if err != nil { return err } - keyPass := client.DefaultKeyPass + keyPass := clientkeys.DefaultKeyPass addr, secret, err := server.GenerateSaveCoinKey(kb, nodeDirName, keyPass, true) if err != nil { _ = os.RemoveAll(outputDir) @@ -203,7 +211,7 @@ func InitTestnet(cmd *cobra.Command, config *tmconfig.Config, cdc *codec.Codec, tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithChainID(chainID).WithMemo(memo).WithKeybase(kb) - signedTx, err := txBldr.SignStdTx(nodeDirName, client.DefaultKeyPass, tx, false) + signedTx, err := txBldr.SignStdTx(nodeDirName, clientkeys.DefaultKeyPass, tx, false) if err != nil { _ = os.RemoveAll(outputDir) return err @@ -352,12 +360,12 @@ func writeFile(name string, dir string, contents []byte) error { writePath := filepath.Join(dir) file := filepath.Join(writePath, name) - err := cmn.EnsureDir(writePath, 0700) + err := tmos.EnsureDir(writePath, 0700) if err != nil { return err } - err = cmn.WriteFile(file, contents, 0600) + err = tmos.WriteFile(file, contents, 0600) if err != nil { return err } diff --git a/docs/.vuepress/components/home.vue b/docs/.vuepress/components/home.vue new file mode 100644 index 0000000000..b49c06157d --- /dev/null +++ b/docs/.vuepress/components/home.vue @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js new file mode 100644 index 0000000000..2c160dc11b --- /dev/null +++ b/docs/.vuepress/config.js @@ -0,0 +1,160 @@ +module.exports = { + theme: "cosmos", + title: "Cosmos Hub", + head: [ + [ + "link", + { + rel: "stylesheet", + type: "text/css", + href: "https://cloud.typography.com/6138116/7255612/css/fonts.css" + } + ], + ], + base: process.env.VUEPRESS_BASE || "/", + themeConfig: { + docsRepo: "cosmos/gaia", + docsDir: "docs", + editLinks: true, + label: "hub", + sidebar: [ + { + title: "Resources", + children: [ + { + title: "Tutorials", + path: "https://tutorials.cosmos.network" + }, + { + title: "SDK API Reference", + path: "https://godoc.org/github.com/cosmos/cosmos-sdk" + }, + { + title: "REST API Spec", + path: "https://cosmos.network/rpc/" + } + ] + } + ], + gutter: { + title: "Help & Support", + editLink: true, + chat: { + title: "Riot Chat", + text: "Chat with Cosmos developers on Riot Chat.", + url: "https://riot.im/app/#/room/#cosmos-sdk:matrix.org", + bg: "linear-gradient(225.11deg, #2E3148 0%, #161931 95.68%)" + }, + forum: { + title: "Cosmos SDK Forum", + text: "Join the SDK Developer Forum to learn more.", + url: "https://forum.cosmos.network/", + bg: "linear-gradient(225deg, #46509F -1.08%, #2F3564 95.88%)", + logo: "cosmos" + }, + github: { + title: "Found an Issue?", + text: "Help us improve this page by suggesting edits on GitHub." + } + }, + footer: { + logo: "/logo-bw.svg", + textLink: { + text: "cosmos.network", + url: "/" + }, + services: [ + { + service: "medium", + url: "https://blog.cosmos.network/" + }, + { + service: "twitter", + url: "https://twitter.com/cosmos" + }, + { + service: "linkedin", + url: "https://www.linkedin.com/company/tendermint/" + }, + { + service: "reddit", + url: "https://reddit.com/r/cosmosnetwork" + }, + { + service: "telegram", + url: "https://t.me/cosmosproject" + }, + { + service: "youtube", + url: "https://www.youtube.com/c/CosmosProject" + } + ], + smallprint: + "This website is maintained by Tendermint Inc. The contents and opinions of this website are those of Tendermint Inc.", + links: [ + { + title: "Documentation", + children: [ + { + title: "Cosmos SDK", + url: "https://docs.cosmos.network" + }, + { + title: "Cosmos Hub", + url: "https://hub.cosmos.network/" + }, + { + title: "Tendermint Core", + url: "https://docs.tendermint.com/" + } + ] + }, + { + title: "Community", + children: [ + { + title: "Cosmos blog", + url: "https://blog.cosmos.network/" + }, + { + title: "Forum", + url: "https://forum.cosmos.network/" + }, + { + title: "Chat", + url: "https://riot.im/app/#/room/#cosmos-sdk:matrix.org" + } + ] + }, + { + title: "Contributing", + children: [ + { + title: "Contributing to the docs", + url: + "https://github.com/cosmos/cosmos-sdk/blob/master/docs/DOCS_README.md" + }, + { + title: "Source code on GitHub", + url: "https://github.com/cosmos/cosmos-sdk/" + } + ] + } + ] + } + }, + plugins: [ + // [ + // "@vuepress/google-analytics", + // { + // ga: "UA-51029217-12" + // } + // ], + [ + "sitemap", + { + hostname: "https://hub.cosmos.network" + } + ] + ] +}; diff --git a/docs/.vuepress/public/logo-bw.svg b/docs/.vuepress/public/logo-bw.svg new file mode 100644 index 0000000000..f2575260a7 --- /dev/null +++ b/docs/.vuepress/public/logo-bw.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docs/.vuepress/public/logo.svg b/docs/.vuepress/public/logo.svg new file mode 100644 index 0000000000..95ca6d30da --- /dev/null +++ b/docs/.vuepress/public/logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/docs/.vuepress/styles/index.styl b/docs/.vuepress/styles/index.styl new file mode 100644 index 0000000000..e50a4efbac --- /dev/null +++ b/docs/.vuepress/styles/index.styl @@ -0,0 +1,3 @@ +:root + --accent-color #ba3ed9 + --background #161931 \ No newline at end of file diff --git a/docs/DOCS_README.md b/docs/DOCS_README.md index bf049bed43..cca06e665f 100644 --- a/docs/DOCS_README.md +++ b/docs/DOCS_README.md @@ -1,20 +1,24 @@ + + # Updating the docs -If you want to open a PR on Gaia to update the documentation, please follow the guidelines in the [`CONTRIBUTING.md`](https://github.com/cosmwasm/wasmd/tree/master/CONTRIBUTING.md) +If you want to open a PR on Gaia to update the documentation, please follow the guidelines in the [`CONTRIBUTING.md`](https://github.com/cosmos/gaia/tree/master/CONTRIBUTING.md) ## Docs Build Workflow The documentation for Gaia is hosted at: -- https://hub.cosmos.network/docs/ - -built from the files in this (`/docs`) directory for [master](https://github.com/cosmwasm/wasmd/tree/master/docs) +- https://hub.cosmos.network/docs/ +built from the files in this (`/docs`) directory for [master](https://github.com/cosmos/gaia/tree/master/docs) ### How It Works There is a CircleCI job listening for changes in the `/docs` directory, on both -the `master` and `develop` branches. Any updates to files in this directory +the `master` and `develop` branches. Any updates to files in this directory on those branches will automatically trigger a website deployment. Under the hood, the private website repository has a `make build-docs` target consumed by a CircleCI job in that repo. @@ -24,13 +28,6 @@ The [README.md](./README.md) is also the landing page for the documentation on the website. During the Jenkins build, the current commit is added to the bottom of the README. -## Config.js - -The [config.js](./.vuepress/config.js) generates the sidebar and Table of Contents -on the website docs. Note the use of relative links and the omission of -file extensions. Additional features are available to improve the look -of the sidebar. - ## Links **NOTE:** Strongly consider the existing links - both within this directory @@ -90,14 +87,6 @@ python -m SimpleHTTPServer 8080 then navigate to localhost:8080 in your browser. -## Build RPC Docs - -First, run `make tools` from the root of repo, to install the swagger-ui tool. - -Then, edit the `swagger.yaml` manually; it is found [here](https://github.com/cosmwasm/wasmd/blob/master/cmd/wasmcli/swagger-ui/swagger.yaml) - -Finally, run `make update-gaia-lite-docs` from the root of the repo. - ## Search We are using [Algolia](https://www.algolia.com) to power full-text search. This uses a public API search-only key in the `config.js` as well as a [cosmos_network.json](https://github.com/algolia/docsearch-configs/blob/master/configs/cosmos_network.json) configuration file that we can update with PRs. @@ -105,19 +94,19 @@ We are using [Algolia](https://www.algolia.com) to power full-text search. This ## Consistency Because the build processes are identical (as is the information contained herein), this file should be kept in sync as -much as possible with its [counterpart in the Tendermint Core repo](https://github.com/tendermint/tendermint/blob/develop/docs/DOCS_README.md). +much as possible with its [counterpart in the Tendermint Core repo](https://github.com/tendermint/tendermint/blob/master/docs/DOCS_README.md). ### Update and Build the RPC docs 1. Execute the following command at the root directory to install the swagger-ui generate tool. - ```bash - make tools - ``` + ```bash + make tools + ``` 2. Edit API docs - 1. Directly Edit API docs manually: `cmd/wasmcli/swagger-ui/swagger.yaml`. - 2. Edit API docs within the [Swagger Editor](https://editor.swagger.io/). Please refer to this [document](https://swagger.io/docs/specification/2-0/basic-structure/) for the correct structure in `.yaml`. -3. Download `swagger.yaml` and replace the old `swagger.yaml` under fold `cmd/wasmcli/swagger-ui`. -4. Compile wasmcli - ```bash - make install - ``` + 1. Directly Edit API docs manually: `cmd/gaiacli/swagger-ui/swagger.yaml`. + 2. Edit API docs within the [Swagger Editor](https://editor.swagger.io/). Please refer to this [document](https://swagger.io/docs/specification/2-0/basic-structure/) for the correct structure in `.yaml`. +3. Download `swagger.yaml` and replace the old `swagger.yaml` under fold `cmd/gaiacli/swagger-ui`. +4. Compile gaiacli + ```bash + make install + ``` diff --git a/docs/README.md b/docs/README.md index e69e25ffef..4701aac986 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,37 +1,43 @@ + + # Cosmos Hub Documentation Welcome to the documentation of the **Cosmos Hub application: `gaia`**. ## What is Gaia? -- [Gaia](./what-is-gaia.md) +- [Intro to the `gaia` software](./gaia-tutorials/what-is-gaia.md) ## Join the Cosmos Hub Mainnet -- [Install the `gaia` application](./installation.md) -- [Set up a full node and join the mainnet](./join-mainnet.md) +- [Install the `gaia` application](./gaia-tutorials/installation.md) +- [Set up a full node and join the mainnet](./gaia-tutorials/join-mainnet.md) - [Upgrade to a validator node](./validators/validator-setup.md) ## Join the Cosmos Hub Public Testnet -- [Join the testnet](./join-testnet.md) +- [Join the testnet](./gaia-tutorials/join-testnet.md) ## Setup Your Own `gaia` Testnet -- [Setup your own `gaia` testnet](./deploy-testnet.md) +- [Setup your own `gaia` testnet](./gaia-tutorials/deploy-testnet.md) ## Additional Resources -- [Intro to validators](./validators/overview.md) -- [Validator FAQ](./validators/validator-faq.md) -- [Validator security considerations](./validators/security.md) -- [Reproducible builds](./reproducible-builds.md) +- [Validator Resources](./validators/README.md): Contains documentation for `gaia` validators. +- [Delegator Resources](./delegators/README.md): Contains documentation for delegators. +- [Other Resources](./resources/README.md): Contains documentation on `gaiacli`, genesis file, service providers, ledger wallets, ... +- [Cosmos Hub Archives](./resources/archives.md): State archives of past iteration of the Cosmos Hub. # Contribute -See [this file](https://github.com/cosmwasm/wasmd/blob/master/docs/DOCS_README.md) for details of the build process and +See [this file](./DOCS_README.md) for details of the build process and considerations when making changes. # Version - This documentation is built from the following commit: +This documentation is built from the following commit: diff --git a/docs/delegators/README.md b/docs/delegators/README.md new file mode 100644 index 0000000000..3ccd423976 --- /dev/null +++ b/docs/delegators/README.md @@ -0,0 +1,13 @@ +--- +order: false +parent: + order: 2 +--- + +# Delegators + +This folder contains documentation relevant to delegators of the Cosmos Hub and other `gaia` blockchains. + +- [Delegator CLI Guide](./delegator-guide-cli.md) +- [Delegators FAQ](./delegator-faq.md) +- [Delegator Security Notice](./delegator-security.md) \ No newline at end of file diff --git a/docs/delegators/delegator-faq.md b/docs/delegators/delegator-faq.md new file mode 100644 index 0000000000..9617824a0b --- /dev/null +++ b/docs/delegators/delegator-faq.md @@ -0,0 +1,71 @@ + + +# Delegator FAQ + +## What is a delegator? + +People that cannot or do not want to operate [validator nodes](..//validators/overview.md) can still participate in the staking process as delegators. Indeed, validators are not chosen based on their self-delegated stake but based on their total stake, which is the sum of their self-delegated stake and of the stake that is delegated to them. This is an important property, as it makes delegators a safeguard against validators that exhibit bad behavior. If a validator misbehaves, their delegators will move their Atoms away from them, thereby reducing their stake. Eventually, if a validator's stake falls under the top 100 addresses with highest stake, they will exit the validator set. + +**Delegators share the revenue of their validators, but they also share the risks.** In terms of revenue, validators and delegators differ in that validators can apply a commission on the revenue that goes to their delegator before it is distributed. This commission is known to delegators beforehand and can only change according to predefined constraints (see [section](#choosing-a-validator) below). In terms of risk, delegators' Atoms can be slashed if their validator misbehaves. For more, see [Risks](#risks) section. + +To become delegators, Atom holders need to send a ["Delegate transaction"](./delegator-guide-cli.md#sending-transactions) where they specify how many Atoms they want to bond and to which validator. A list of validator candidates will be displayed in Cosmos Hub explorers. Later, if a delegator wants to unbond part or all of their stake, they needs to send an "Unbond transaction". From there, the delegator will have to wait 3 weeks to retrieve their Atoms. Delegators can also send a "Rebond Transaction" to switch from one validator to another, without having to go through the 3 weeks waiting period. + +For a practical guide on how to become a delegator, click [here](./delegator-guide-cli.md). + +## Choosing a validator + +In order to choose their validators, delegators have access to a range of information directly in [Lunie](https://lunie.io) or other Cosmos block explorers. + +- **Validator's moniker**: Name of the validator candidate. +- **Validator's description**: Description provided by the validator operator. +- **Validator's website**: Link to the validator's website. +- **Initial commission rate**: The commission rate on revenue charged to any delegator by the validator (see below for more detail). +- **Commission max change rate:** The maximum daily increase of the validator's commission. This parameter cannot be changed by the validator operator. +- **Maximum commission:** The maximum commission rate this validator candidate can charge. This parameter cannot be changed by the validator operator. +- **Minimum self-bond amount**: Minimum amount of Atoms the validator candidate need to have bonded at all time. If the validator's self-bonded stake falls below this limit, their entire staking pool (i.e. all its delegators) will unbond. This parameter exists as a safeguard for delegators. Indeed, when a validator misbehaves, part of their total stake gets slashed. This included the validator's self-delegateds stake as well as their delegators' stake. Thus, a validator with a high amount of self-delegated Atoms has more skin-in-the-game than a validator with a low amount. The minimum self-bond amount parameter guarantees to delegators that a validator will never fall below a certain amount of self-bonded stake, thereby ensuring a minimum level of skin-in-the-game. This parameter can only be increased by the validator operator. + +## Directives of delegators + +Being a delegator is not a passive task. Here are the main directives of a delegator: + +- **Perform careful due diligence on validators before delegating.** If a validator misbehaves, part of their total stake, which includes the stake of their delegators, can be slashed. Delegators should therefore carefully select validators they think will behave correctly. +- **Actively monitor their validator after having delegated.** Delegators should ensure that the validators they delegate to behave correctly, meaning that they have good uptime, do not double sign or get compromised, and participate in governance. They should also monitor the commission rate that is applied. If a delegator is not satisfied with its validator, they can unbond or switch to another validator (Note: Delegators do not have to wait for the unbonding period to switch validators. Rebonding takes effect immediately). +- **Participate in governance.** Delegators can and are expected to actively participate in governance. A delegator's voting power is proportional to the size of their bonded stake. If a delegator does not vote, they will inherit the vote of their validator(s). If they do vote, they override the vote of their validator(s). Delegators therefore act as a counterbalance to their validators. + +## Revenue + +Validators and delegators earn revenue in exchange for their services. This revenue is given in three forms: + +- **Block provisions (Atoms):** They are paid in newly created Atoms. Block provisions exist to incentivize Atom holders to stake. The yearly inflation rate is calculated to target 2/3 bonded stake. If the total bonded stake in the network is less than 2/3 of the total Atom supply, inflation increases until it reaches 20%. If the total bonded stake is more than 2/3 of the Atom supply, inflation decreases until it reaches 7%. This means that if total bonded stake stays less than 2/3 of the total Atom supply for a prolonged period of time, unbonded Atom holders can expect their Atom value to deflate by 20% (compounded) per year. +- **Transaction fees (various tokens):** Each transfer on the Cosmos Hub comes with transactions fees. These fees can be paid in any currency that is whitelisted by the Hub's governance. Fees are distributed to bonded Atom holders in proportion to their stake. The first whitelisted token at launch is the ATOM. + +## Validator Commission + +Each validator receives revenue based on their total stake. Before this revenue is distributed to delegators, the validator can apply a commission. In other words, delegators have to pay a commission to their validators on the revenue they earn. Let us look at a concrete example: + +We consider a validator whose stake (i.e. self-delegated stake + delegated stake) is 10% of the total stake of all validators. This validator has 20% self-delegated stake and applies a commission of 10%. Now let us consider a block with the following revenue: + +- 990 Atoms in block provisions +- 10 Atoms in transaction fees. + +This amounts to a total of 1000 Atoms and 100 Photons to be distributed among all staking pools. + +Our validator's staking pool represents 10% of the total stake, which means the pool obtains 100 Atoms and 10 Photons. Now let us look at the internal distribution of revenue: + +- Commission = `10% * 80% * 100` Atoms = 8 Atoms +- Validator's revenue = `20% * 100` Atoms + Commission = 28 Atoms +- Delegators' total revenue = `80% * 100` Atoms - Commission = 72 Atoms + +Then, each delegator in the staking pool can claim their portion of the delegators' total revenue. + +## Risks + +Staking Atoms is not free of risk. First, staked Atoms are locked up, and retrieving them requires a 3 week waiting period called unbonding period. Additionally, if a validator misbehaves, a portion of their total stake can be slashed (i.e. destroyed). This includes the stake of their delegators. + +There is one main slashing condition: + +- **Double signing:** If someone reports on that a validator signed two different blocks with the same chain ID at the same height, this validator will get slashed. + +This is why Atom holders should perform careful due diligence on validators before delegating. It is also important that delegators actively monitor the activity of their validators. If a validator behaves suspiciously or is too often offline, delegators can choose to unbond from them or switch to another validator. **Delegators can also mitigate risk by distributing their stake across multiple validators.**s \ No newline at end of file diff --git a/docs/delegator-guide-cli.md b/docs/delegators/delegator-guide-cli.md similarity index 90% rename from docs/delegator-guide-cli.md rename to docs/delegators/delegator-guide-cli.md index 766bf04044..dd8345025b 100644 --- a/docs/delegator-guide-cli.md +++ b/docs/delegators/delegator-guide-cli.md @@ -1,3 +1,7 @@ + + # Delegator Guide (CLI) This document contains all the necessary information for delegators to interact with the Cosmos Hub through the Command-Line Interface (CLI). @@ -29,14 +33,14 @@ Please exercise extreme caution! ## Table of Contents -- [Installing `wasmcli`](#installing-wasmcli) +- [Installing `gaiacli`](#installing-gaiacli) - [Cosmos Accounts](#cosmos-accounts) + [Restoring an Account from the Fundraiser](#restoring-an-account-from-the-fundraiser) + [Creating an Account](#creating-an-account) - [Accessing the Cosmos Hub Network](#accessing-the-cosmos-hub-network) + [Running Your Own Full-Node](#running-your-own-full-node) + [Connecting to a Remote Full-Node](#connecting-to-a-remote-full-node) -- [Setting Up `wasmcli`](#setting-up-wasmcli) +- [Setting Up `gaiacli`](#setting-up-gaiacli) - [Querying the State](#querying-the-state) - [Sending Transactions](#sending-transactions) + [A Note on Gas and Fees](#a-note-on-gas-and-fees) @@ -44,21 +48,21 @@ Please exercise extreme caution! + [Participating in Governance](#participating-in-governance) + [Signing Transactions from an Offline Computer](#signing-transactions-from-an-offline-computer) -## Installing `wasmcli` +## Installing `gaiacli` -`wasmcli`: This is the command-line interface to interact with a `wasmd` full-node. +`gaiacli`: This is the command-line interface to interact with a `gaiad` full-node. ::: warning -**Please check that you download the latest stable release of `wasmcli` that is available** +**Please check that you download the latest stable release of `gaiacli` that is available** ::: [**Download the binaries**] Not available yet. -[**Install from source**](https://cosmos.network/docs/cosmos-hub/installation.html) +[**Install from source**](../gaia-tutorials/installation.md) ::: tip -`wasmcli` is used from a terminal. To open the terminal, follow these steps: +`gaiacli` is used from a terminal. To open the terminal, follow these steps: - **Windows**: `Start` > `All Programs` > `Accessories` > `Command Prompt` - **MacOS**: `Finder` > `Applications` > `Utilities` > `Terminal` - **Linux**: `Ctrl` + `Alt` + `T` @@ -147,7 +151,7 @@ Next, click [here](#using-a-ledger-device) to learn how to generate an account. To restore an account using a fundraiser mnemonic and store the associated encrypted private key on a computer, use the following command: ```bash -wasmcli keys add --recover +gaiacli keys add --recover ``` - `` is the name of the account. It is a reference to the account number used to derive the key pair from the mnemonic. You will use this name to identify your account when you want to send a transaction. @@ -166,7 +170,7 @@ store security policies please refer to your operating system manual.** ### Creating an Account -To create an account, you just need to have `wasmcli` installed. Before creating it, you need to know where you intend to store and interact with your private keys. The best options are to store them in an offline dedicated computer or a ledger device. Storing them on your regular online computer involves more risk, since anyone who infiltrates your computer through the internet could exfiltrate your private keys and steal your funds. +To create an account, you just need to have `gaiacli` installed. Before creating it, you need to know where you intend to store and interact with your private keys. The best options are to store them in an offline dedicated computer or a ledger device. Storing them on your regular online computer involves more risk, since anyone who infiltrates your computer through the internet could exfiltrate your private keys and steal your funds. #### Using a Ledger Device @@ -174,7 +178,7 @@ To create an account, you just need to have `wasmcli` installed. Before creating **Only use Ledger devices that you bought factory new or trust fully** ::: -When you initialize your ledger, a 24-word mnemonic is generated and stored in the device. This mnemonic is compatible with Cosmos and Cosmos accounts can be derived from it. Therefore, all you have to do is make your ledger compatible with `wasmcli`. To do so, you need to go through the following steps: +When you initialize your ledger, a 24-word mnemonic is generated and stored in the device. This mnemonic is compatible with Cosmos and Cosmos accounts can be derived from it. Therefore, all you have to do is make your ledger compatible with `gaiacli`. To do so, you need to go through the following steps: 1. Download the Ledger Live app [here](https://www.ledger.com/pages/ledger-live). 2. Connect your ledger via USB and update to the latest firmware @@ -184,7 +188,7 @@ When you initialize your ledger, a 24-word mnemonic is generated and stored in t Then, to create an account, use the following command: ```bash -wasmcli keys add --ledger +gaiacli keys add --ledger ``` ::: warning @@ -203,7 +207,7 @@ wasmcli keys add --ledger To generate an account, just use the following command: ```bash -wasmcli keys add +gaiacli keys add ``` The command will generate a 24-words mnemonic and save the private and public keys for account `0` @@ -238,7 +242,7 @@ rm ~/.bash_history You can generate more accounts from the same mnemonic using the following command: ```bash -wasmcli keys add --recover --account 1 +gaiacli keys add --recover --account 1 ``` This command will prompt you to input a passphrase as well as your mnemonic. Change the account number to generate a different account. @@ -256,30 +260,30 @@ In order to query the state and send transactions, you need a way to access the This is the most secure option, but comes with relatively high resource requirements. In order to run your own full-node, you need good bandwidth and at least 1TB of disk space. -You will find the tutorial on how to install `wasmd` [here](https://cosmos.network/docs/cosmos-hub/installation.html), and the guide to run a full-node [here](https://cosmos.network/docs/cosmos-hub/join-mainnet.html). +You will find the tutorial on how to install `gaiad` [here](https://cosmos.network/docs/cosmos-hub/installation.html), and the guide to run a full-node [here](https://cosmos.network/docs/cosmos-hub/join-mainnet.html). ### Connecting to a Remote Full-Node If you do not want or cannot run your own node, you can connect to someone else's full-node. You should pick an operator you trust, because a malicious operator could return incorrect query results or censor your transactions. However, they will never be able to steal your funds, as your private keys are stored locally on your computer or ledger device. Possible options of full-node operators include validators, wallet providers or exchanges. -In order to connect to the full-node, you will need an address of the following form: `https://77.87.106.33:26657` (*Note: This is a placeholder*). This address has to be communicated by the full-node operator you choose to trust. You will use this address in the [following section](#setting-up-wasmcli). +In order to connect to the full-node, you will need an address of the following form: `https://77.87.106.33:26657` (*Note: This is a placeholder*). This address has to be communicated by the full-node operator you choose to trust. You will use this address in the [following section](#setting-up-gaiacli). -## Setting Up `wasmcli` +## Setting Up `gaiacli` ::: tip -**Before setting up `wasmcli`, make sure you have set up a way to [access the Cosmos Hub network](#accessing-the-cosmos-hub-network)** +**Before setting up `gaiacli`, make sure you have set up a way to [access the Cosmos Hub network](#accessing-the-cosmos-hub-network)** ::: ::: warning -**Please check that you are always using the latest stable release of `wasmcli`** +**Please check that you are always using the latest stable release of `gaiacli`** ::: -`wasmcli` is the tool that enables you to interact with the node that runs on the Cosmos Hub network, whether you run it yourself or not. Let us set it up properly. +`gaiacli` is the tool that enables you to interact with the node that runs on the Cosmos Hub network, whether you run it yourself or not. Let us set it up properly. -In order to set up `wasmcli`, use the following command: +In order to set up `gaiacli`, use the following command: ```bash -wasmcli config +gaiacli config ``` It allows you to set a default value for each given flag. @@ -287,9 +291,9 @@ It allows you to set a default value for each given flag. First, set up the address of the full-node you want to connect to: ```bash -wasmcli config node :: +gaiacli query account // query the list of validators -wasmcli query staking validators +gaiacli query staking validators // query the information of a validator given their address (e.g. cosmosvaloper1n5pepvmgsfd3p2tqqgvt505jvymmstf6s9gw27) -wasmcli query staking validator +gaiacli query staking validator // query all delegations made from a delegator given their address (e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg) -wasmcli query staking delegations +gaiacli query staking delegations // query a specific delegation made from a delegator (e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg) to a validator (e.g. cosmosvaloper1n5pepvmgsfd3p2tqqgvt505jvymmstf6s9gw27) given their addresses -wasmcli query staking delegation +gaiacli query staking delegation // query the rewards of a delegator given a delegator address (e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg) -wasmcli query distribution rewards +gaiacli query distribution rewards // query all proposals currently open for depositing -wasmcli query gov proposals --status deposit_period +gaiacli query gov proposals --status deposit_period // query all proposals currently open for voting -wasmcli query gov proposals --status voting_period +gaiacli query gov proposals --status voting_period // query a proposal given its proposalID -wasmcli query gov proposal +gaiacli query gov proposal ``` For more commands, just type: ```bash -wasmcli query +gaiacli query ``` For each command, you can use the `-h` or `--help` flag to get more information. @@ -380,7 +384,7 @@ For mainnet, the recommended `gas-prices` is `0.025uatom`. ### Sending Tokens ::: tip -**Before you can bond atoms and withdraw rewards, you need to [set up `wasmcli`](#setting-up-wasmcli) and [create an account](#creating-an-account)** +**Before you can bond atoms and withdraw rewards, you need to [set up `gaiacli`](#setting-up-gaiacli) and [create an account](#creating-an-account)** ::: ::: warning @@ -392,13 +396,13 @@ For mainnet, the recommended `gas-prices` is `0.025uatom`. // Ex value for parameters (do not actually use these values in your tx!!): =cosmos16m93fezfiezhvnjajzrfyszml8qm92a0w67ntjhd3d0 =1000000uatom // Ex value for flags: =0.025uatom -wasmcli tx send --from --gas auto --gas-adjustment 1.5 --gas-prices +gaiacli tx send --from --gas auto --gas-adjustment 1.5 --gas-prices ``` ### Bonding Atoms and Withdrawing Rewards ::: tip -**Before you can bond atoms and withdraw rewards, you need to [set up `wasmcli`](#setting-up-wasmcli) and [create an account](#creating-an-account)** +**Before you can bond atoms and withdraw rewards, you need to [set up `gaiacli`](#setting-up-gaiacli) and [create an account](#creating-an-account)** ::: ::: warning @@ -413,7 +417,7 @@ wasmcli tx send --from --gas auto --gas-adju // Bond a certain amount of Atoms to a given validator // ex value for flags: =cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, =10000000uatom, =0.025uatom -wasmcli tx staking delegate --from --gas auto --gas-adjustment 1.5 --gas-prices +gaiacli tx staking delegate --from --gas auto --gas-adjustment 1.5 --gas-prices // Redelegate a certain amount of Atoms from a validator to another @@ -422,19 +426,19 @@ wasmcli tx staking delegate --from =cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, =100000000uatom, =0.025uatom -wasmcli tx staking redelegate --from --gas auto --gas-adjustment 1.5 --gas-prices +gaiacli tx staking redelegate --from --gas auto --gas-adjustment 1.5 --gas-prices // Withdraw all rewards // ex value for flag: =0.025uatom -wasmcli tx distribution withdraw-all-rewards --from --gas auto --gas-adjustment 1.5 --gas-prices +gaiacli tx distribution withdraw-all-rewards --from --gas auto --gas-adjustment 1.5 --gas-prices // Unbond a certain amount of Atoms from a given validator // You will have to wait 3 weeks before your Atoms are fully unbonded and transferrable // ex value for flags: =cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, =10000000uatom, =0.025uatom -wasmcli tx staking unbond --from --gas auto --gas-adjustment 1.5 --gas-prices +gaiacli tx staking unbond --from --gas auto --gas-adjustment 1.5 --gas-prices ``` ::: warning @@ -445,14 +449,14 @@ To confirm that your transaction went through, you can use the following queries ```bash // your balance should change after you bond Atoms or withdraw rewards -wasmcli query account +gaiacli query account // you should have delegations after you bond Atom -wasmcli query staking delegations +gaiacli query staking delegations // this returns your tx if it has been included // use the tx hash that was displayed when you created the tx -wasmcli query tx +gaiacli query tx ``` @@ -489,19 +493,19 @@ At the end of the voting period, the proposal is accepted if there are more than // =text/parameter_change/software_upgrade // ex value for flag: =0.025uatom -wasmcli tx gov submit-proposal --title "Test Proposal" --description "My awesome proposal" --type --deposit=10000000uatom --gas auto --gas-adjustment 1.5 --gas-prices --from +gaiacli tx gov submit-proposal --title "Test Proposal" --description "My awesome proposal" --type --deposit=10000000uatom --gas auto --gas-adjustment 1.5 --gas-prices --from // Increase deposit of a proposal -// Retrieve proposalID from $wasmcli query gov proposals --status deposit_period +// Retrieve proposalID from $gaiacli query gov proposals --status deposit_period // ex value for parameter: =10000000uatom -wasmcli tx gov deposit --gas auto --gas-adjustment 1.5 --gas-prices --from +gaiacli tx gov deposit --gas auto --gas-adjustment 1.5 --gas-prices --from // Vote on a proposal -// Retrieve proposalID from $wasmcli query gov proposals --status voting_period +// Retrieve proposalID from $gaiacli query gov proposals --status voting_period //