Merge pull request #3349 from cosmos/release/v0.30.0

Release 0.30.0
This commit is contained in:
Jae Kwon 2019-01-24 13:50:02 -08:00 committed by GitHub
commit e003c5ebe0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
415 changed files with 14492 additions and 15034 deletions

View File

@ -1,12 +1,37 @@
version: 2
defaults: &defaults
defaults: &linux_defaults
working_directory: /go/src/github.com/cosmos/cosmos-sdk
docker:
- image: circleci/golang:1.11.1
- image: circleci/golang:1.11.4
environment:
GOBIN: /tmp/workspace/bin
############
#
# Configure macos integration tests
macos_config: &macos_defaults
macos:
xcode: "10.1.0"
working_directory: /Users/distiller/project/src/github.com/cosmos/cosmos-sdk
environment:
GO_VERSION: "1.11.4"
set_macos_env: &macos_env
run:
name: Set environment
command: |
echo 'export PATH=$PATH:$HOME/go/bin' >> $BASH_ENV
echo 'export GOPATH=$HOME/project' >> $BASH_ENV
echo 'export GOBIN=$GOPATH/bin' >> $BASH_ENV
echo 'export PATH=$PATH:$HOME/go/bin:$GOBIN' >> $BASH_ENV
############
#
# Configure docs deployment
docs_update: &docs_deploy
working_directory: ~/repo
docker:
@ -14,33 +39,31 @@ docs_update: &docs_deploy
environment:
AWS_REGION: us-east-1
jobs:
deps: &dependencies
run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make vendor-deps
jobs:
setup_dependencies:
<<: *defaults
<<: *linux_defaults
steps:
- run: mkdir -p /tmp/workspace/bin
- run: mkdir -p /tmp/workspace/profiles
- checkout
- restore_cache:
keys:
- v1-pkg-cache
- run:
name: tools
command: |
export PATH="$GOBIN:$PATH"
make get_tools
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
make tools
- *dependencies
- run:
name: binaries
command: |
export PATH="$GOBIN:$PATH"
make install
make install_examples
- persist_to_workspace:
root: /tmp/workspace
paths:
@ -48,23 +71,18 @@ jobs:
- profiles
lint:
<<: *defaults
<<: *linux_defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- *dependencies
- run:
name: Get metalinter
command: |
export PATH="$GOBIN:$PATH"
make get_tools
make get_dev_tools
make devtools
- run:
name: Lint source
command: |
@ -72,36 +90,27 @@ jobs:
make test_lint
integration_tests:
<<: *defaults
<<: *linux_defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- *dependencies
- run:
name: Test cli
command: |
export PATH="$GOBIN:$PATH"
make test_cli
make test_examples
test_sim_gaia_nondeterminism:
<<: *defaults
<<: *linux_defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- *dependencies
- run:
name: Test individual module simulations
command: |
@ -109,17 +118,13 @@ jobs:
make test_sim_gaia_nondeterminism
test_sim_gaia_fast:
<<: *defaults
<<: *linux_defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- *dependencies
- run:
name: Test full Gaia simulation
command: |
@ -127,17 +132,13 @@ jobs:
make test_sim_gaia_fast
test_sim_gaia_import_export:
<<: *defaults
<<: *linux_defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- *dependencies
- run:
name: Test Gaia import/export simulation
command: |
@ -145,53 +146,55 @@ jobs:
make test_sim_gaia_import_export
test_sim_gaia_simulation_after_import:
<<: *defaults
<<: *linux_defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- *dependencies
- run:
name: Test Gaia import/export simulation
command: |
export PATH="$GOBIN:$PATH"
make test_sim_gaia_simulation_after_import
test_sim_gaia_multi_seed:
<<: *defaults
test_sim_gaia_multi_seed_long:
<<: *linux_defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- *dependencies
- run:
name: dependencies
name: Test multi-seed Gaia simulation long
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
scripts/multisim.sh 800 50 TestFullGaiaSimulation
test_sim_gaia_multi_seed:
<<: *linux_defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- *dependencies
- run:
name: Test multi-seed Gaia simulation
name: Test multi-seed Gaia simulation short
command: |
export PATH="$GOBIN:$PATH"
scripts/multisim.sh 25 TestFullGaiaSimulation
scripts/multisim.sh 50 10 TestFullGaiaSimulation
test_cover:
<<: *defaults
<<: *linux_defaults
parallelism: 4
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- *dependencies
- run: mkdir -p /tmp/logs
- run:
name: Run tests
@ -211,17 +214,13 @@ jobs:
path: /tmp/logs
upload_coverage:
<<: *defaults
<<: *linux_defaults
parallelism: 1
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- run:
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make get_vendor_deps
- *dependencies
- run:
name: gather
command: |
@ -244,6 +243,7 @@ jobs:
GOPATH: /home/circleci/.go_workspace/
GOOS: linux
GOARCH: amd64
GO_VERSION: "1.11.4"
parallelism: 1
steps:
- checkout
@ -251,17 +251,18 @@ jobs:
name: run localnet and exit on failure
command: |
pushd /tmp
wget https://dl.google.com/go/go1.11.linux-amd64.tar.gz
sudo tar -xvf go1.11.linux-amd64.tar.gz
wget https://dl.google.com/go/go$GO_VERSION.linux-amd64.tar.gz
sudo tar -xvf go$GO_VERSION.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo mv go /usr/local
popd
set -x
make get_tools
make get_vendor_deps
make tools
make vendor-deps
make build-linux
make localnet-start
./scripts/localnet-blocks-test.sh 40 5 10 localhost
deploy_docs:
<<: *docs_deploy
steps:
@ -271,10 +272,75 @@ jobs:
command: |
chamber exec cosmos-sdk -- start_website_build
macos_ci:
<<: *macos_defaults
steps:
- *macos_env
- run:
name: Install go
command: |
source $BASH_ENV
curl -L -O https://dl.google.com/go/go$GO_VERSION.darwin-amd64.tar.gz
tar -C $HOME -xzf go$GO_VERSION.darwin-amd64.tar.gz
rm go$GO_VERSION.darwin-amd64.tar.gz
go version
- checkout
- run:
name: Install SDK
command: |
source $BASH_ENV
make tools
make vendor-deps
make install
- run:
name: Integration tests
command:
source $BASH_ENV
make test_cli
- run:
name: Test full gaia simulation
command: |
source $BASH_ENV
make test_sim_gaia_fast
docker_image:
<<: *linux_defaults
steps:
- attach_workspace:
at: /tmp/workspace
- checkout
- setup_remote_docker:
docker_layer_caching: true
- run: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
GAIAD_VERSION="stable"
elif [ "${CIRCLE_BRANCH}" == "develop" ]; then
GAIAD_VERSION="develop"
else
GAIAD_VERSION=`/tmp/workspace/bin/gaiad version`
fi
docker build -t tendermint/gaia:$GAIAD_VERSION .
docker login -u $DOCKER_USER -p $DOCKER_PASS
docker push tendermint/gaia:$GAIAD_VERSION
workflows:
version: 2
test-suite:
jobs:
- docker_image:
filters:
branches:
only:
- master
- develop
requires:
- setup_dependencies
- macos_ci:
filters:
branches:
only:
- master
- develop
- deploy_docs:
filters:
branches:
@ -303,6 +369,14 @@ workflows:
- test_sim_gaia_multi_seed:
requires:
- setup_dependencies
- test_sim_gaia_multi_seed_long:
requires:
- setup_dependencies
filters:
branches:
only:
- master
- develop
- test_cover:
requires:
- setup_dependencies

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
client/lcd/swagger-ui/* linguist-vendored

5
.gitignore vendored
View File

@ -10,14 +10,17 @@
# Build
vendor
vendor-deps
.vendor-new
build
tools/bin/*
examples/build/*
docs/_build
docs/tutorial
dist
devtools-stamp
# Data - ideally these don't exist
examples/basecoin/app/data
baseapp/data/*
client/lcd/keys/*
client/lcd/statik/statik.go

View File

@ -1,5 +1,153 @@
# Changelog
## 0.30.0
BREAKING CHANGES
* Gaia REST API (`gaiacli advanced rest-server`)
* [gaia-lite] [\#2182] Renamed and merged all redelegations endpoints into `/staking/redelegations`
* [\#3176](https://github.com/cosmos/cosmos-sdk/issues/3176) `tx/sign` endpoint now expects `BaseReq` fields as nested object.
* [\#2222] all endpoints renamed from `/stake` -> `/staking`
* [\#1268] `LooseTokens` -> `NotBondedTokens`
* [\#3289] misc renames:
* `Validator.UnbondingMinTime` -> `Validator.UnbondingCompletionTime`
* `Delegation` -> `Value` in `MsgCreateValidator` and `MsgDelegate`
* `MsgBeginUnbonding` -> `MsgUndelegate`
* Gaia CLI (`gaiacli`)
* [\#810](https://github.com/cosmos/cosmos-sdk/issues/810) Don't fallback to any default values for chain ID.
* Users need to supply chain ID either via config file or the `--chain-id` flag.
* Change `chain_id` and `trust_node` in `gaiacli` configuration to `chain-id` and `trust-node` respectively.
* [\#3069](https://github.com/cosmos/cosmos-sdk/pull/3069) `--fee` flag renamed to `--fees` to support multiple coins
* [\#3156](https://github.com/cosmos/cosmos-sdk/pull/3156) Remove unimplemented `gaiacli init` command
* [\#2222] `gaiacli tx stake` -> `gaiacli tx staking`, `gaiacli query stake` -> `gaiacli query staking`
* [\#1894](https://github.com/cosmos/cosmos-sdk/issues/1894) `version` command now shows latest commit, vendor dir hash, and build machine info.
* [\#3320](https://github.com/cosmos/cosmos-sdk/pull/3320) Ensure all `gaiacli query` commands respect the `--output` and `--indent` flags
* Gaia
* https://github.com/cosmos/cosmos-sdk/issues/2838 - Move store keys to constants
* [\#3162](https://github.com/cosmos/cosmos-sdk/issues/3162) The `--gas` flag now takes `auto` instead of `simulate`
in order to trigger a simulation of the tx before the actual execution.
* [\#3285](https://github.com/cosmos/cosmos-sdk/pull/3285) New `gaiad tendermint version` to print libs versions
* [\#1894](https://github.com/cosmos/cosmos-sdk/pull/1894) `version` command now shows latest commit, vendor dir hash, and build machine info.
* [\#3249\(https://github.com/cosmos/cosmos-sdk/issues/3249) `tendermint`'s `show-validator` and `show-address` `--json` flags removed in favor of `--output-format=json`.
* SDK
* [distribution] [\#3359](https://github.com/cosmos/cosmos-sdk/issues/3359) Always round down when calculating rewards-to-be-withdrawn in F1 fee distribution
* [#3336](https://github.com/cosmos/cosmos-sdk/issues/3336) Ensure all SDK
messages have their signature bytes contain canonical fields `value` and `type`.
* [\#3333](https://github.com/cosmos/cosmos-sdk/issues/3333) - F1 storage efficiency improvements - automatic withdrawals when unbonded, historical reward reference counting
* [staking] [\#2513](https://github.com/cosmos/cosmos-sdk/issues/2513) Validator power type from Dec -> Int
* [staking] [\#3233](https://github.com/cosmos/cosmos-sdk/issues/3233) key and value now contain duplicate fields to simplify code
* [\#3064](https://github.com/cosmos/cosmos-sdk/issues/3064) Sanitize `sdk.Coin` denom. Coins denoms are now case insensitive, i.e. 100fooToken equals to 100FOOTOKEN.
* [\#3195](https://github.com/cosmos/cosmos-sdk/issues/3195) Allows custom configuration for syncable strategy
* [\#3242](https://github.com/cosmos/cosmos-sdk/issues/3242) Fix infinite gas
meter utilization during aborted ante handler executions.
* [x/distribution] [\#3292](https://github.com/cosmos/cosmos-sdk/issues/3292) Enable or disable withdraw addresses with a parameter in the param store
* [staking] [\#2222](https://github.com/cosmos/cosmos-sdk/issues/2222) `/stake` -> `/staking` module rename
* [staking] [\#1268](https://github.com/cosmos/cosmos-sdk/issues/1268) `LooseTokens` -> `NotBondedTokens`
* [staking] [\#1402](https://github.com/cosmos/cosmos-sdk/issues/1402) Redelegation and unbonding-delegation structs changed to include multiple an array of entries
* [staking] [\#3289](https://github.com/cosmos/cosmos-sdk/issues/3289) misc renames:
* `Validator.UnbondingMinTime` -> `Validator.UnbondingCompletionTime`
* `Delegation` -> `Value` in `MsgCreateValidator` and `MsgDelegate`
* `MsgBeginUnbonding` -> `MsgUndelegate`
* [\#3315] Increase decimal precision to 18
* [\#3323](https://github.com/cosmos/cosmos-sdk/issues/3323) Update to Tendermint 0.29.0
* [\#3328](https://github.com/cosmos/cosmos-sdk/issues/3328) [x/gov] Remove redundant action tag
* Tendermint
* [\#3298](https://github.com/cosmos/cosmos-sdk/issues/3298) Upgrade to Tendermint 0.28.0
FEATURES
* Gaia REST API (`gaiacli advanced rest-server`)
* [\#3067](https://github.com/cosmos/cosmos-sdk/issues/3067) Add support for fees on transactions
* [\#3069](https://github.com/cosmos/cosmos-sdk/pull/3069) Add a custom memo on transactions
* [\#3027](https://github.com/cosmos/cosmos-sdk/issues/3027) Implement
`/gov/proposals/{proposalID}/proposer` to query for a proposal's proposer.
* Gaia CLI (`gaiacli`)
* [\#2399](https://github.com/cosmos/cosmos-sdk/issues/2399) Implement `params` command to query slashing parameters.
* [\#2730](https://github.com/cosmos/cosmos-sdk/issues/2730) Add tx search pagination parameter
* [\#3027](https://github.com/cosmos/cosmos-sdk/issues/3027) Implement
`query gov proposer [proposal-id]` to query for a proposal's proposer.
* [\#3198](https://github.com/cosmos/cosmos-sdk/issues/3198) New `keys add --multisig` flag to store multisig keys locally.
* [\#3198](https://github.com/cosmos/cosmos-sdk/issues/3198) New `multisign` command to generate multisig signatures.
* [\#3198](https://github.com/cosmos/cosmos-sdk/issues/3198) New `sign --multisig` flag to enable multisig mode.
* [\#2715](https://github.com/cosmos/cosmos-sdk/issues/2715) Reintroduce gaia server's insecure mode.
* [\#3334](https://github.com/cosmos/cosmos-sdk/pull/3334) New `gaiad completion` and `gaiacli completion` to generate Bash/Zsh completion scripts.
* [\#2607](https://github.com/cosmos/cosmos-sdk/issues/2607) Make `gaiacli config` handle the boolean `indent` flag to beautify commands JSON output.
* Gaia
* [\#2182] [x/staking] Added querier for querying a single redelegation
* [\#3305](https://github.com/cosmos/cosmos-sdk/issues/3305) Add support for
vesting accounts at genesis.
* [\#3198](https://github.com/cosmos/cosmos-sdk/issues/3198) [x/auth] Add multisig transactions support
* [\#3198](https://github.com/cosmos/cosmos-sdk/issues/3198) `add-genesis-account` can take both account addresses and key names
* SDK
- [\#3099](https://github.com/cosmos/cosmos-sdk/issues/3099) Implement F1 fee distribution
- [\#2926](https://github.com/cosmos/cosmos-sdk/issues/2926) Add TxEncoder to client TxBuilder.
* [\#2694](https://github.com/cosmos/cosmos-sdk/issues/2694) Vesting account implementation.
* [\#2996](https://github.com/cosmos/cosmos-sdk/issues/2996) Update the `AccountKeeper` to contain params used in the context of
the ante handler.
* [\#3179](https://github.com/cosmos/cosmos-sdk/pull/3179) New CodeNoSignatures error code.
* [\#3319](https://github.com/cosmos/cosmos-sdk/issues/3319) [x/distribution] Queriers for all distribution state worth querying; distribution query commands
* [\#3356](https://github.com/cosmos/cosmos-sdk/issues/3356) [x/auth] bech32-ify accounts address in error message.
IMPROVEMENTS
* Gaia REST API
* [\#3176](https://github.com/cosmos/cosmos-sdk/issues/3176) Validate tx/sign endpoint POST body.
* [\#2948](https://github.com/cosmos/cosmos-sdk/issues/2948) Swagger UI now makes requests to light client node
* Gaia CLI (`gaiacli`)
* [\#3224](https://github.com/cosmos/cosmos-sdk/pull/3224) Support adding offline public keys to the keystore
* Gaia
* [\#2186](https://github.com/cosmos/cosmos-sdk/issues/2186) Add Address Interface
* [\#3158](https://github.com/cosmos/cosmos-sdk/pull/3158) Validate slashing genesis
* [\#3172](https://github.com/cosmos/cosmos-sdk/pull/3172) Support minimum fees in a local testnet.
* [\#3250](https://github.com/cosmos/cosmos-sdk/pull/3250) Refactor integration tests and increase coverage
* [\#3248](https://github.com/cosmos/cosmos-sdk/issues/3248) Refactor tx fee
model:
* Validators specify minimum gas prices instead of minimum fees
* Clients may provide either fees or gas prices directly
* The gas prices of a tx must meet a validator's minimum
* `gaiad start` and `gaia.toml` take --minimum-gas-prices flag and minimum-gas-price config key respectively.
* [\#2859](https://github.com/cosmos/cosmos-sdk/issues/2859) Rename `TallyResult` in gov proposals to `FinalTallyResult`
* [\#3286](https://github.com/cosmos/cosmos-sdk/pull/3286) Fix `gaiad gentx` printout of account's addresses, i.e. user bech32 instead of hex.
* [\#3249\(https://github.com/cosmos/cosmos-sdk/issues/3249) `--json` flag removed, users should use `--output=json` instead.
* SDK
* [\#3137](https://github.com/cosmos/cosmos-sdk/pull/3137) Add tag documentation
for each module along with cleaning up a few existing tags in the governance,
slashing, and staking modules.
* [\#3093](https://github.com/cosmos/cosmos-sdk/issues/3093) Ante handler does no longer read all accounts in one go when processing signatures as signature
verification may fail before last signature is checked.
* [staking] [\#1402](https://github.com/cosmos/cosmos-sdk/issues/1402) Add for multiple simultaneous redelegations or unbonding-delegations within an unbonding period
* [staking] [\#1268](https://github.com/cosmos/cosmos-sdk/issues/1268) staking spec rewrite
* CI
* [\#2498](https://github.com/cosmos/cosmos-sdk/issues/2498) Added macos CI job to CircleCI
* [#142](https://github.com/tendermint/devops/issues/142) Increased the number of blocks to be tested during multi-sim
* [#147](https://github.com/tendermint/devops/issues/142) Added docker image build to CI
BUG FIXES
* Gaia CLI (`gaiacli`)
* [\#3141](https://github.com/cosmos/cosmos-sdk/issues/3141) Fix the bug in GetAccount when `len(res) == 0` and `err == nil`
* [\#810](https://github.com/cosmos/cosmos-sdk/pull/3316) Fix regression in gaiacli config file handling
* Gaia
* [\#3148](https://github.com/cosmos/cosmos-sdk/issues/3148) Fix `gaiad export` by adding a boolean to `NewGaiaApp` determining whether or not to load the latest version
* [\#3181](https://github.com/cosmos/cosmos-sdk/issues/3181) Correctly reset total accum update height and jailed-validator bond height / unbonding height on export-for-zero-height
* [\#3172](https://github.com/cosmos/cosmos-sdk/pull/3172) Fix parsing `gaiad.toml`
when it already exists.
* [\#3223](https://github.com/cosmos/cosmos-sdk/issues/3223) Fix unset governance proposal queues when importing state from old chain
* [#3187](https://github.com/cosmos/cosmos-sdk/issues/3187) Fix `gaiad export`
by resetting each validator's slashing period.
## 0.29.1
BUG FIXES
@ -134,7 +282,7 @@ BREAKING CHANGES
* [\#2019](https://github.com/cosmos/cosmos-sdk/issues/2019) Cap total number of signatures. Current per-transaction limit is 7, and if that is exceeded transaction is rejected.
* [\#2801](https://github.com/cosmos/cosmos-sdk/pull/2801) Remove AppInit structure.
* [\#2798](https://github.com/cosmos/cosmos-sdk/issues/2798) Governance API has miss-spelled English word in JSON response ('depositer' -> 'depositor')
* [\#2943](https://github.com/cosmos/cosmos-sdk/pull/2943) Transaction action tags equal the message type. Stake EndBlocker tags are included.
* [\#2943](https://github.com/cosmos/cosmos-sdk/pull/2943) Transaction action tags equal the message type. Staking EndBlocker tags are included.
* Tendermint
* Update to Tendermint 0.27.0
@ -1062,7 +1210,7 @@ BREAKING CHANGES
* All module keepers now require a codespace, see basecoin or democoin for usage
* Many changes to names throughout
* Type as a prefix naming convention applied (ex. BondMsg -> MsgBond)
* Removed redundancy in names (ex. stake.StakeKeeper -> stake.Keeper)
* Removed redundancy in names (ex. stake.StakingKeeper -> stake.Keeper)
* Removed SealedAccountMapper
* gaiad init now requires use of `--name` flag
* Removed Get from Msg interface

View File

@ -69,7 +69,7 @@ If you open a PR on the Cosmos SDK, it is mandatory to update the relevant docum
* If your change relates to the core SDK (baseapp, store, ...), please update the docs/gaia folder, the docs/examples folder and possibly the docs/spec folder.
* If your changes relate specifically to the gaia application (not including modules), please modify the docs/gaia folder.
* If your changes relate to a module, please update the module's spec in docs/spec. If the module is used by gaia and/or basecoin, you might also need to modify docs/gaia and/or docs/examples.
* If your changes relate to a module, please update the module's spec in docs/spec. If the module is used by gaia, you might also need to modify docs/gaia and/or docs/examples.
* If your changes relate to the core of the CLI or Light-client (not specifically to module's CLI/Rest), please modify the docs/clients folder.
## Forking
@ -85,7 +85,7 @@ 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/cosmos/cosmos-sdk`)
- `git remote rename origin upstream`
- `git remote add origin git@github.com:ebuchman/basecoin.git`
- `git remote add origin git@github.com:ebuchman/cosmos-sdk.git`
Now `origin` refers to my fork and `upstream` refers to the Cosmos-SDK version.
So I can `git push -u origin master` to update my fork, and make pull requests to Cosmos-SDK from there.

View File

@ -15,8 +15,8 @@ COPY . .
# Install minimum necessary dependencies, build Cosmos SDK, remove packages
RUN apk add --no-cache $PACKAGES && \
make get_tools && \
make get_vendor_deps && \
make tools && \
make vendor-deps && \
make build && \
make install

11
Gopkg.lock generated
View File

@ -429,11 +429,12 @@
revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445"
[[projects]]
digest = "1:605b6546f3f43745695298ec2d342d3e952b6d91cdf9f349bea9315f677d759f"
digest = "1:83f5e189eea2baad419a6a410984514266ff690075759c87e9ede596809bd0b8"
name = "github.com/tendermint/btcd"
packages = ["btcec"]
pruneopts = "UT"
revision = "e5840949ff4fff0c56f9b6a541e22b63581ea9df"
revision = "80daadac05d1cd29571fccf27002d79667a88b58"
version = "v0.1.1"
[[projects]]
digest = "1:ad9c4c1a4e7875330b1f62906f2830f043a23edb5db997e3a5ac5d3e6eadf80a"
@ -452,11 +453,12 @@
version = "v0.12.0"
[[projects]]
digest = "1:f94f468c7cd1fc3693ebc16011f26ec26538761cdcd182b3a28faa649a7d55e2"
digest = "1:22a0fe58c626dd09549eb9451688fab5a2c8bef04d478c907f747d6151d431fd"
name = "github.com/tendermint/tendermint"
packages = [
"abci/client",
"abci/example/code",
"abci/example/counter",
"abci/example/kvstore",
"abci/server",
"abci/types",
@ -517,7 +519,7 @@
"version",
]
pruneopts = "UT"
revision = "v0.27.3"
revision = "v0.29.0"
[[projects]]
digest = "1:a7485b2a69f996923f9d3406a9a853fd8eb31818515e985a830d71f88f6a925b"
@ -695,7 +697,6 @@
"github.com/tendermint/tendermint/crypto/secp256k1",
"github.com/tendermint/tendermint/crypto/tmhash",
"github.com/tendermint/tendermint/crypto/xsalsa20symmetric",
"github.com/tendermint/tendermint/libs/autofile",
"github.com/tendermint/tendermint/libs/bech32",
"github.com/tendermint/tendermint/libs/cli",
"github.com/tendermint/tendermint/libs/cli/flags",

View File

@ -40,7 +40,7 @@
[[override]]
name = "github.com/tendermint/tendermint"
revision = "v0.27.3"
revision = "v0.29.0"
[[constraint]]
name = "github.com/zondax/ledger-cosmos-go"

View File

@ -1,23 +1,29 @@
PACKAGES_NOSIMULATION=$(shell go list ./... | grep -v '/simulation')
PACKAGES_SIMTEST=$(shell go list ./... | grep '/simulation')
VERSION := $(subst v,,$(shell git describe --tags --long))
COMMIT := $(shell git log -1 --format='%H')
BUILD_TAGS = netgo
BUILD_FLAGS = -tags "${BUILD_TAGS}" -ldflags "-X github.com/cosmos/cosmos-sdk/version.Version=${VERSION}"
CAT := $(if $(filter $(OS),Windows_NT),type,cat)
BUILD_FLAGS = -tags "${BUILD_TAGS}" -ldflags \
"-X github.com/cosmos/cosmos-sdk/version.Version=${VERSION} \
-X github.com/cosmos/cosmos-sdk/version.Commit=${COMMIT} \
-X github.com/cosmos/cosmos-sdk/version.VendorDirHash=$(shell $(CAT) vendor-deps)"
LEDGER_ENABLED ?= true
GOTOOLS = \
github.com/golang/dep/cmd/dep \
github.com/alecthomas/gometalinter \
github.com/rakyll/statik
GOBIN ?= $(GOPATH)/bin
all: get_tools get_vendor_deps install install_examples install_cosmos-sdk-cli test_lint test
# The below include contains the get_tools target.
all: devtools get_vendor_deps install test_lint test
# The below include contains the tools target.
include scripts/Makefile
########################################
### CI
ci: get_tools get_vendor_deps install test_cover test_lint test
ci: devtools vendor-deps install test_cover test_lint test
########################################
### Build/Install
@ -49,56 +55,24 @@ build:
ifeq ($(OS),Windows_NT)
go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaia/cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaia/cmd/gaiacli
go build $(BUILD_FLAGS) -o build/logjack ./cmd/logjack
else
go build $(BUILD_FLAGS) -o build/gaiad ./cmd/gaia/cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli
go build $(BUILD_FLAGS) -o build/gaiareplay ./cmd/gaia/cmd/gaiareplay
go build $(BUILD_FLAGS) -o build/gaiakeyutil ./cmd/gaia/cmd/gaiakeyutil
go build $(BUILD_FLAGS) -o build/logjack ./cmd/logjack
endif
build-linux:
build-linux: vendor-deps
LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build
update_gaia_lite_docs:
@statik -src=client/lcd/swagger-ui -dest=client/lcd -f
build_cosmos-sdk-cli:
ifeq ($(OS),Windows_NT)
go build $(BUILD_FLAGS) -o build/cosmos-sdk-cli.exe ./cmd/cosmos-sdk-cli
else
go build $(BUILD_FLAGS) -o build/cosmos-sdk-cli ./cmd/cosmos-sdk-cli
endif
build_examples:
ifeq ($(OS),Windows_NT)
go build $(BUILD_FLAGS) -o build/basecoind.exe ./docs/examples/basecoin/cmd/basecoind
go build $(BUILD_FLAGS) -o build/basecli.exe ./docs/examples/basecoin/cmd/basecli
go build $(BUILD_FLAGS) -o build/democoind.exe ./docs/examples/democoin/cmd/democoind
go build $(BUILD_FLAGS) -o build/democli.exe ./docs/examples/democoin/cmd/democli
else
go build $(BUILD_FLAGS) -o build/basecoind ./docs/examples/basecoin/cmd/basecoind
go build $(BUILD_FLAGS) -o build/basecli ./docs/examples/basecoin/cmd/basecli
go build $(BUILD_FLAGS) -o build/democoind ./docs/examples/democoin/cmd/democoind
go build $(BUILD_FLAGS) -o build/democli ./docs/examples/democoin/cmd/democli
endif
install: check-ledger update_gaia_lite_docs
install: vendor-deps check-ledger update_gaia_lite_docs
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiareplay
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiakeyutil
go install $(BUILD_FLAGS) ./cmd/logjack
install_examples:
go install $(BUILD_FLAGS) ./docs/examples/basecoin/cmd/basecoind
go install $(BUILD_FLAGS) ./docs/examples/basecoin/cmd/basecli
go install $(BUILD_FLAGS) ./docs/examples/democoin/cmd/democoind
go install $(BUILD_FLAGS) ./docs/examples/democoin/cmd/democli
install_cosmos-sdk-cli:
go install $(BUILD_FLAGS) ./cmd/cosmos-sdk-cli
install_debug:
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiadebug
@ -117,33 +91,38 @@ check_tools:
update_tools:
@echo "--> Updating tools to correct version"
$(MAKE) --always-make get_tools
$(MAKE) --always-make tools
update_dev_tools:
@echo "--> Downloading linters (this may take awhile)"
$(GOPATH)/src/github.com/alecthomas/gometalinter/scripts/install.sh -b $(GOBIN)
go get -u github.com/tendermint/lint/golint
get_dev_tools: get_tools
devtools: devtools-stamp
devtools-stamp: tools
@echo "--> Downloading linters (this may take awhile)"
$(GOPATH)/src/github.com/alecthomas/gometalinter/scripts/install.sh -b $(GOBIN)
go get github.com/tendermint/lint/golint
touch $@
get_vendor_deps: get_tools
vendor-deps: tools
@echo "--> Generating vendor directory via dep ensure"
@rm -rf .vendor-new
@dep ensure -v -vendor-only
tar -c vendor/ | sha1sum | cut -d' ' -f1 > $@
update_vendor_deps: get_tools
update_vendor_deps: tools
@echo "--> Running dep ensure"
@rm -rf .vendor-new
@dep ensure -v
draw_deps: get_tools
draw_deps: tools
@# requires brew install graphviz or apt-get install graphviz
go get github.com/RobotsAndPencils/goviz
@goviz -i github.com/cosmos/cosmos-sdk/cmd/gaia/cmd/gaiad -d 2 | dot -Tpng -o dependency-graph.png
clean:
rm -f devtools-stamp vendor-deps
########################################
### Documentation
@ -161,10 +140,6 @@ test: test_unit
test_cli:
@go test -p 4 `go list github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test` -tags=cli_test
test_examples:
@go test -count 1 -p 1 `go list github.com/cosmos/cosmos-sdk/docs/examples/basecoin/cli_test` -tags=cli_test
@go test -count 1 -p 1 `go list github.com/cosmos/cosmos-sdk/docs/examples/democoin/cli_test` -tags=cli_test
test_unit:
@VERSION=$(VERSION) go test $(PACKAGES_NOSIMULATION)
@ -181,15 +156,15 @@ test_sim_gaia_fast:
test_sim_gaia_import_export:
@echo "Running Gaia import/export simulation. This may take several minutes..."
@bash scripts/multisim.sh 50 TestGaiaImportExport
@bash scripts/multisim.sh 50 5 TestGaiaImportExport
test_sim_gaia_simulation_after_import:
@echo "Running Gaia simulation-after-import. This may take several minutes..."
@bash scripts/multisim.sh 50 TestGaiaSimulationAfterImport
@bash scripts/multisim.sh 50 5 TestGaiaSimulationAfterImport
test_sim_gaia_multi_seed:
@echo "Running multi-seed Gaia simulation. This may take awhile!"
@bash scripts/multisim.sh 400 TestFullGaiaSimulation
@bash scripts/multisim.sh 400 5 TestFullGaiaSimulation
SIM_NUM_BLOCKS ?= 500
SIM_BLOCK_SIZE ?= 200
@ -263,8 +238,8 @@ localnet-stop:
# To avoid unintended conflicts with file names, always add to .PHONY
# unless there is a reason not to.
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: build build_cosmos-sdk-cli build_examples install install_examples install_cosmos-sdk-cli install_debug dist \
check_tools check_dev_tools get_dev_tools get_vendor_deps draw_deps test test_cli test_unit \
.PHONY: build install install_debug dist \
check_tools check_dev_tools get_vendor_deps draw_deps test test_cli test_unit \
test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
build-linux build-docker-gaiadnode localnet-start localnet-stop \
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast \

View File

@ -17,7 +17,7 @@ It is being used to build `Gaia`, the first implementation of the Cosmos Hub.
**WARNING**: The SDK has mostly stabilized, but we are still making some
breaking changes.
**Note**: Requires [Go 1.11+](https://golang.org/dl/)
**Note**: Requires [Go 1.11.4+](https://golang.org/dl/)
## Cosmos Hub Public Testnet

2
Vagrantfile vendored
View File

@ -46,6 +46,6 @@ Vagrant.configure("2") do |config|
chown vagrant:vagrant /home/vagrant/.bash_profile
su - vagrant -c 'source /home/vagrant/.bash_profile'
su - vagrant -c 'cd /home/vagrant/go/src/github.com/cosmos/cosmos-sdk && make get_tools'
su - vagrant -c 'cd /home/vagrant/go/src/github.com/cosmos/cosmos-sdk && make tools'
SHELL
end

View File

@ -33,6 +33,9 @@ const (
runTxModeSimulate runTxMode = iota
// Deliver a transaction
runTxModeDeliver runTxMode = iota
// MainStoreKey is the string representation of the main store
MainStoreKey = "main"
)
// BaseApp reflects the ABCI application implementation.
@ -71,8 +74,9 @@ type BaseApp struct {
// TODO move this in the future to baseapp param store on main store.
consensusParams *abci.ConsensusParams
// spam prevention
minimumFees sdk.Coins
// The minimum gas prices a validator is willing to accept for processing a
// transaction. This is mainly used for DoS and spam prevention.
minGasPrices sdk.DecCoins
// flag for sealing
sealed bool
@ -210,14 +214,17 @@ func (app *BaseApp) initFromMainStore(mainKey *sdk.KVStoreKey) error {
return nil
}
// SetMinimumFees sets the minimum fees.
func (app *BaseApp) SetMinimumFees(fees sdk.Coins) { app.minimumFees = fees }
func (app *BaseApp) setMinGasPrices(gasPrices sdk.DecCoins) {
app.minGasPrices = gasPrices
}
// NewContext returns a new Context with the correct store, the given header, and nil txBytes.
func (app *BaseApp) NewContext(isCheckTx bool, header abci.Header) sdk.Context {
if isCheckTx {
return sdk.NewContext(app.checkState.ms, header, true, app.Logger).WithMinimumFees(app.minimumFees)
return sdk.NewContext(app.checkState.ms, header, true, app.Logger).
WithMinGasPrices(app.minGasPrices)
}
return sdk.NewContext(app.deliverState.ms, header, false, app.Logger)
}
@ -238,7 +245,7 @@ func (app *BaseApp) setCheckState(header abci.Header) {
ms := app.cms.CacheMultiStore()
app.checkState = &state{
ms: ms,
ctx: sdk.NewContext(ms, header, true, app.Logger).WithMinimumFees(app.minimumFees),
ctx: sdk.NewContext(ms, header, true, app.Logger).WithMinGasPrices(app.minGasPrices),
}
}
@ -453,8 +460,9 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
}
// Cache wrap the commit-multistore for safety.
ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger).
WithMinimumFees(app.minimumFees)
ctx := sdk.NewContext(
app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger,
).WithMinGasPrices(app.minGasPrices)
// Passes the rest of the path as an argument to the querier.
// For example, in the path "custom/gov/proposal/test", the gov querier gets []string{"proposal", "test"} as the path
@ -501,6 +509,7 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
} else {
gasMeter = sdk.NewInfiniteGasMeter()
}
app.deliverState.ctx = app.deliverState.ctx.WithBlockGasMeter(gasMeter)
if app.beginBlocker != nil {
@ -730,7 +739,10 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
defer func() {
if mode == runTxModeDeliver {
ctx.BlockGasMeter().ConsumeGas(
ctx.GasMeter().GasConsumedToLimit(), "block gas meter")
ctx.GasMeter().GasConsumedToLimit(),
"block gas meter",
)
if ctx.BlockGasMeter().GasConsumed() < startingGas {
panic(sdk.ErrorGasOverflow{"tx gas summation"})
}
@ -749,23 +761,29 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
// Cache wrap context before anteHandler call in case it aborts.
// This is required for both CheckTx and DeliverTx.
// https://github.com/cosmos/cosmos-sdk/issues/2772
// Ref: https://github.com/cosmos/cosmos-sdk/issues/2772
//
// NOTE: Alternatively, we could require that anteHandler ensures that
// writes do not happen if aborted/failed. This may have some
// performance benefits, but it'll be more difficult to get right.
anteCtx, msCache = app.cacheTxContext(ctx, txBytes)
newCtx, result, abort := app.anteHandler(anteCtx, tx, (mode == runTxModeSimulate))
if !newCtx.IsZero() {
// At this point, newCtx.MultiStore() is cache-wrapped, or something else
// replaced by the ante handler. We want the original multistore, not one
// which was cache-wrapped for the ante handler.
//
// Also, in the case of the tx aborting, we need to track gas consumed via
// the instantiated gas meter in the ante handler, so we update the context
// prior to returning.
ctx = newCtx.WithMultiStore(ms)
}
if abort {
return result
}
if !newCtx.IsZero() {
// At this point, newCtx.MultiStore() is cache wrapped,
// or something else replaced by anteHandler.
// We want the original ms, not one which was cache-wrapped
// for the ante handler.
ctx = newCtx.WithMultiStore(ms)
}
msCache.Write()
gasWanted = result.GasWanted
}

View File

@ -7,6 +7,8 @@ import (
"os"
"testing"
"github.com/cosmos/cosmos-sdk/store"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -85,12 +87,13 @@ func TestMountStores(t *testing.T) {
// Test that LoadLatestVersion actually does.
func TestLoadVersion(t *testing.T) {
logger := defaultLogger()
pruningOpt := SetPruning(store.PruneSyncable)
db := dbm.NewMemDB()
name := t.Name()
app := NewBaseApp(name, logger, db, nil)
app := NewBaseApp(name, logger, db, nil, pruningOpt)
// make a cap key and mount the store
capKey := sdk.NewKVStoreKey("main")
capKey := sdk.NewKVStoreKey(MainStoreKey)
app.MountStores(capKey)
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
require.Nil(t, err)
@ -116,7 +119,7 @@ func TestLoadVersion(t *testing.T) {
commitID2 := sdk.CommitID{2, res.Data}
// reload with LoadLatestVersion
app = NewBaseApp(name, logger, db, nil)
app = NewBaseApp(name, logger, db, nil, pruningOpt)
app.MountStores(capKey)
err = app.LoadLatestVersion(capKey)
require.Nil(t, err)
@ -124,7 +127,7 @@ func TestLoadVersion(t *testing.T) {
// reload with LoadVersion, see if you can commit the same block and get
// the same result
app = NewBaseApp(name, logger, db, nil)
app = NewBaseApp(name, logger, db, nil, pruningOpt)
app.MountStores(capKey)
err = app.LoadVersion(1, capKey)
require.Nil(t, err)
@ -160,7 +163,7 @@ func testChangeNameHelper(name string) func(*BaseApp) {
app := newBaseApp(t.Name())
// make a cap key and mount the store
capKey := sdk.NewKVStoreKey("main")
capKey := sdk.NewKVStoreKey(MainStoreKey)
app.MountStores(capKey)
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
require.Nil(t, err)
@ -217,7 +220,7 @@ func TestInitChainer(t *testing.T) {
db := dbm.NewMemDB()
logger := defaultLogger()
app := NewBaseApp(name, logger, db, nil)
capKey := sdk.NewKVStoreKey("main")
capKey := sdk.NewKVStoreKey(MainStoreKey)
capKey2 := sdk.NewKVStoreKey("key2")
app.MountStores(capKey, capKey2)

View File

@ -4,7 +4,5 @@ functionality and act as a bridge between the ABCI interface and the SDK
abstractions.
BaseApp has no state except the CommitMultiStore you provide upon init.
See examples/basecoin/app/* for usage.
*/
package baseapp

View File

@ -23,7 +23,7 @@ func (app *BaseApp) Deliver(tx sdk.Tx) (result sdk.Result) {
return app.runTx(runTxModeDeliver, nil, tx)
}
// RunForever - BasecoinApp execution and cleanup
// RunForever BasecoinApp execution and cleanup
func RunForever(app abci.Application) {
// Start the ABCI server

View File

@ -14,30 +14,18 @@ import (
// for options that need access to non-exported fields of the BaseApp
// SetPruning sets a pruning option on the multistore associated with the app
func SetPruning(pruning string) func(*BaseApp) {
var pruningEnum sdk.PruningStrategy
switch pruning {
case "nothing":
pruningEnum = sdk.PruneNothing
case "everything":
pruningEnum = sdk.PruneEverything
case "syncable":
pruningEnum = sdk.PruneSyncable
default:
panic(fmt.Sprintf("invalid pruning strategy: %s", pruning))
}
return func(bap *BaseApp) {
bap.cms.SetPruning(pruningEnum)
}
func SetPruning(opts sdk.PruningOptions) func(*BaseApp) {
return func(bap *BaseApp) { bap.cms.SetPruning(opts) }
}
// SetMinimumFees returns an option that sets the minimum fees on the app.
func SetMinimumFees(minFees string) func(*BaseApp) {
fees, err := sdk.ParseCoins(minFees)
// SetMinimumGasPrices returns an option that sets the minimum gas prices on the app.
func SetMinGasPrices(gasPricesStr string) func(*BaseApp) {
gasPrices, err := sdk.ParseDecCoins(gasPricesStr)
if err != nil {
panic(fmt.Sprintf("invalid minimum fees: %v", err))
panic(fmt.Sprintf("invalid minimum gas prices: %v", err))
}
return func(bap *BaseApp) { bap.SetMinimumFees(fees) }
return func(bap *BaseApp) { bap.setMinGasPrices(gasPrices) }
}
func (app *BaseApp) SetName(name string) {

View File

@ -24,7 +24,7 @@ var configDefaults map[string]string
func init() {
configDefaults = map[string]string{
"chain_id": "",
"chain-id": "",
"output": "text",
"node": "tcp://localhost:26657",
}
@ -78,7 +78,7 @@ func runConfigCmd(cmd *cobra.Command, args []string) error {
// Get value action
if getAction {
switch key {
case "trace", "trust_node":
case "trace", "trust-node", "indent":
fmt.Println(tree.GetDefault(key, false).(bool))
default:
if defaultValue, ok := configDefaults[key]; ok {
@ -91,11 +91,14 @@ func runConfigCmd(cmd *cobra.Command, args []string) error {
}
// Set value action
if len(args) != 2 {
return fmt.Errorf("wrong number of arguments")
}
value := args[1]
switch key {
case "chain_id", "output", "node":
case "chain-id", "output", "node":
tree.Set(key, value)
case "trace", "trust_node":
case "trace", "trust-node", "indent":
boolVal, err := strconv.ParseBool(value)
if err != nil {
return err

View File

@ -104,7 +104,7 @@ func (ctx CLIContext) broadcastTxAsync(txBytes []byte) (*ctypes.ResultBroadcastT
}
if ctx.Output != nil {
if ctx.JSON {
if ctx.OutputFormat == "json" {
type toJSON struct {
TxHash string
}
@ -131,7 +131,7 @@ func (ctx CLIContext) broadcastTxCommit(txBytes []byte) (*ctypes.ResultBroadcast
return res, err
}
if ctx.JSON {
if ctx.OutputFormat == "json" {
// Since JSON is intended for automated scripts, always include response in
// JSON mode.
type toJSON struct {

View File

@ -24,8 +24,6 @@ import (
"github.com/cosmos/cosmos-sdk/types"
)
const ctxAccStoreName = "acc"
var (
verifier tmlite.Verifier
)
@ -37,6 +35,7 @@ type CLIContext struct {
AccDecoder auth.AccountDecoder
Client rpcclient.Client
Output io.Writer
OutputFormat string
Height int64
NodeURI string
From string
@ -44,7 +43,6 @@ type CLIContext struct {
TrustNode bool
UseLedger bool
Async bool
JSON bool
PrintResponse bool
Verifier tmlite.Verifier
Simulate bool
@ -76,13 +74,13 @@ func NewCLIContext() CLIContext {
Client: rpc,
Output: os.Stdout,
NodeURI: nodeURI,
AccountStore: ctxAccStoreName,
AccountStore: auth.StoreKey,
From: viper.GetString(client.FlagFrom),
OutputFormat: viper.GetString(cli.OutputFlag),
Height: viper.GetInt64(client.FlagHeight),
TrustNode: viper.GetBool(client.FlagTrustNode),
UseLedger: viper.GetBool(client.FlagUseLedger),
Async: viper.GetBool(client.FlagAsync),
JSON: viper.GetBool(client.FlagJson),
PrintResponse: viper.GetBool(client.FlagPrintResponse),
Verifier: verifier,
Simulate: viper.GetBool(client.FlagDryRun),
@ -256,3 +254,28 @@ func (ctx CLIContext) WithSimulation(simulate bool) CLIContext {
ctx.Simulate = simulate
return ctx
}
// PrintOutput prints output while respecting output and indent flags
// NOTE: pass in marshalled structs that have been unmarshaled
// because this function will panic on marshaling errors
func (ctx CLIContext) PrintOutput(toPrint fmt.Stringer) (err error) {
var out []byte
switch ctx.OutputFormat {
case "text":
out = []byte(toPrint.String())
case "json":
if ctx.Indent {
out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ")
} else {
out, err = ctx.Codec.MarshalJSON(toPrint)
}
}
if err != nil {
return
}
fmt.Println(string(out))
return
}

View File

@ -70,7 +70,7 @@ func (ctx CLIContext) GetAccount(address []byte) (auth.Account, error) {
if err != nil {
return nil, err
} else if len(res) == 0 {
return nil, err
return nil, ErrInvalidAccount(address)
}
account, err := ctx.AccDecoder(res)

View File

@ -2,6 +2,7 @@ package client
import (
"fmt"
"os"
"strconv"
"github.com/spf13/cobra"
@ -15,7 +16,7 @@ const (
// occur between the tx simulation and the actual run.
DefaultGasAdjustment = 1.0
DefaultGasLimit = 200000
GasFlagSimulate = "simulate"
GasFlagAuto = "auto"
FlagUseLedger = "ledger"
FlagChainID = "chain-id"
@ -29,9 +30,9 @@ const (
FlagAccountNumber = "account-number"
FlagSequence = "sequence"
FlagMemo = "memo"
FlagFee = "fee"
FlagFees = "fees"
FlagGasPrices = "gas-prices"
FlagAsync = "async"
FlagJson = "json"
FlagPrintResponse = "print-response"
FlagDryRun = "dry-run"
FlagGenerateOnly = "generate-only"
@ -59,13 +60,13 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
c.Flags().Bool(FlagIndentResponse, false, "Add indent to JSON response")
c.Flags().Bool(FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device")
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().Int64(FlagHeight, 0, "block height to query, omit to get most recent provable block")
viper.BindPFlag(FlagTrustNode, c.Flags().Lookup(FlagTrustNode))
viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger))
viper.BindPFlag(FlagChainID, c.Flags().Lookup(FlagChainID))
viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode))
c.MarkFlagRequired(FlagChainID)
}
return cmds
}
@ -78,24 +79,24 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
c.Flags().Uint64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
c.Flags().Uint64(FlagSequence, 0, "Sequence number to sign the tx")
c.Flags().String(FlagMemo, "", "Memo to send along with transaction")
c.Flags().String(FlagFee, "", "Fee to pay along with transaction")
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
c.Flags().String(FlagFees, "", "Fees to pay along with transaction; eg: 10stake,1atom")
c.Flags().String(FlagGasPrices, "", "Gas prices to determine the transaction fee (e.g. 0.00001stake)")
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device")
c.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ")
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
c.Flags().Bool(FlagJson, false, "return output in json format")
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
c.Flags().Bool(FlagTrustNode, true, "Trust connected full node (don't verify proofs for responses)")
c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
c.Flags().Bool(FlagGenerateOnly, false, "build an unsigned transaction and write it to STDOUT")
// --gas can accept integers and "simulate"
c.Flags().Var(&GasFlagVar, "gas", fmt.Sprintf(
"gas limit to set per-transaction; set to %q to calculate required gas automatically (default %d)", GasFlagSimulate, DefaultGasLimit))
"gas limit to set per-transaction; set to %q to calculate required gas automatically (default %d)", GasFlagAuto, DefaultGasLimit))
viper.BindPFlag(FlagTrustNode, c.Flags().Lookup(FlagTrustNode))
viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger))
viper.BindPFlag(FlagChainID, c.Flags().Lookup(FlagChainID))
viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode))
c.MarkFlagRequired(FlagChainID)
}
return cmds
}
@ -133,30 +134,62 @@ func (v *GasSetting) Type() string { return "string" }
// Set parses and sets the value of the --gas flag.
func (v *GasSetting) Set(s string) (err error) {
v.Simulate, v.Gas, err = ReadGasFlag(s)
v.Simulate, v.Gas, err = ParseGas(s)
return
}
func (v *GasSetting) String() string {
if v.Simulate {
return GasFlagSimulate
return GasFlagAuto
}
return strconv.FormatUint(v.Gas, 10)
}
// ParseGasFlag parses the value of the --gas flag.
func ReadGasFlag(s string) (simulate bool, gas uint64, err error) {
switch s {
// ParseGas parses the value of the gas option.
func ParseGas(gasStr string) (simulateAndExecute bool, gas uint64, err error) {
switch gasStr {
case "":
gas = DefaultGasLimit
case GasFlagSimulate:
simulate = true
case GasFlagAuto:
simulateAndExecute = true
default:
gas, err = strconv.ParseUint(s, 10, 64)
gas, err = strconv.ParseUint(gasStr, 10, 64)
if err != nil {
err = fmt.Errorf("gas must be either integer or %q", GasFlagSimulate)
err = fmt.Errorf("gas must be either integer or %q", GasFlagAuto)
return
}
}
return
}
// NewCompletionCmd builds a cobra.Command that generate bash completion
// scripts for the given root command. If hidden is true, the command
// will not show up in the root command's list of available commands.
func NewCompletionCmd(rootCmd *cobra.Command, hidden bool) *cobra.Command {
flagZsh := "zsh"
cmd := &cobra.Command{
Use: "completion",
Short: "Generate Bash/Zsh completion script to STDOUT",
Long: `To load completion script run
. <(completion_script)
To configure your bash shell to load completions for each session add to your bashrc
# ~/.bashrc or ~/.profile
. <(completion_script)
`,
RunE: func(_ *cobra.Command, _ []string) error {
if viper.GetBool(flagZsh) {
return rootCmd.GenZshCompletion(os.Stdout)
}
return rootCmd.GenBashCompletion(os.Stdout)
},
Hidden: hidden,
Args: cobra.NoArgs,
}
cmd.Flags().Bool(flagZsh, false, "Generate Zsh completion script")
return cmd
}

View File

@ -1,23 +1,29 @@
package keys
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"sort"
"github.com/tendermint/tendermint/crypto/multisig"
"github.com/cosmos/go-bip39"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/client"
ccrypto "github.com/cosmos/cosmos-sdk/crypto"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
sdk "github.com/cosmos/cosmos-sdk/types"
)
const (
@ -28,6 +34,8 @@ const (
flagDryRun = "dry-run"
flagAccount = "account"
flagIndex = "index"
flagMultisig = "multisig"
flagNoSort = "nosort"
)
func addKeyCommand() *cobra.Command {
@ -36,16 +44,28 @@ func addKeyCommand() *cobra.Command {
Short: "Add an encrypted private key (either newly generated or recovered), encrypt it, and save to disk",
Long: `Derive a new private key and encrypt to disk.
Optionally specify a BIP39 mnemonic, a BIP39 passphrase to further secure the mnemonic,
and a bip32 HD path to derive a specific account. The key will be stored under the given name
and a bip32 HD path to derive a specific account. The key will be stored under the given name
and encrypted with the given password. The only input that is required is the encryption password.
If run with -i, it will prompt the user for BIP44 path, BIP39 mnemonic, and passphrase.
The flag --recover allows one to recover a key from a seed passphrase.
If run with --dry-run, a key would be generated (or recovered) but not stored to the local keystore.
If run with --dry-run, a key would be generated (or recovered) but not stored to the
local keystore.
Use the --pubkey flag to add arbitrary public keys to the keystore for constructing
multisig transactions.
You can add a multisig key by passing the list of key names you want the public
key to be composed of to the --multisig flag and the minimum number of signatures
required through --multisig-threshold. The keys are sorted by address, unless
the flag --nosort is set.
`,
Args: cobra.ExactArgs(1),
RunE: runAddCmd,
}
cmd.Flags().StringSlice(flagMultisig, nil, "Construct and store a multisig public key (implies --pubkey)")
cmd.Flags().Uint(flagMultiSigThreshold, 1, "K out of N required signatures. For use in conjunction with --multisig")
cmd.Flags().Bool(flagNoSort, false, "Keys passed to --multisig are taken in the order they're supplied")
cmd.Flags().String(FlagPublicKey, "", "Parse a public key in bech32 format and save it to disk")
cmd.Flags().BoolP(flagInteractive, "i", false, "Interactively prompt user for BIP39 passphrase and mnemonic")
cmd.Flags().Bool(client.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device")
cmd.Flags().String(flagBIP44Path, "44'/118'/0'/0/0", "BIP44 path from which to derive a private key")
@ -73,6 +93,9 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
buf := client.BufferStdin()
name := args[0]
interactive := viper.GetBool(flagInteractive)
if viper.GetBool(flagDryRun) {
// we throw this away, so don't enforce args,
// we want to get a new random seed phrase quickly
@ -93,8 +116,40 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
}
}
multisigKeys := viper.GetStringSlice(flagMultisig)
if len(multisigKeys) != 0 {
var pks []crypto.PubKey
multisigThreshold := viper.GetInt(flagMultiSigThreshold)
if err := validateMultisigThreshold(multisigThreshold, len(multisigKeys)); err != nil {
return err
}
for _, keyname := range multisigKeys {
k, err := kb.Get(keyname)
if err != nil {
return err
}
pks = append(pks, k.GetPubKey())
}
// Handle --nosort
if !viper.GetBool(flagNoSort) {
sort.Slice(pks, func(i, j int) bool {
return bytes.Compare(pks[i].Address(), pks[j].Address()) < 0
})
}
pk := multisig.NewPubKeyMultisigThreshold(multisigThreshold, pks)
if _, err := kb.CreateOffline(name, pk); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "Key %q saved to disk.", name)
return nil
}
// ask for a password when generating a local key
if !viper.GetBool(client.FlagUseLedger) {
if viper.GetString(FlagPublicKey) == "" && !viper.GetBool(client.FlagUseLedger) {
encryptPassword, err = client.GetCheckPassword(
"Enter a passphrase to encrypt your key to disk:",
"Repeat the passphrase:", buf)
@ -104,10 +159,16 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
}
}
interactive := viper.GetBool(flagInteractive)
flags := cmd.Flags()
bipFlag := flags.Lookup(flagBIP44Path)
if viper.GetString(FlagPublicKey) != "" {
pk, err := sdk.GetAccPubKeyBech32(viper.GetString(FlagPublicKey))
if err != nil {
return err
}
kb.CreateOffline(name, pk)
return nil
}
bipFlag := cmd.Flags().Lookup(flagBIP44Path)
bip44Params, err := getBIP44ParamsAndPath(bipFlag.Value.String(), bipFlag.Changed || !interactive)
if err != nil {
return err

View File

@ -17,6 +17,7 @@ import (
client "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
@ -27,18 +28,21 @@ import (
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
const (
name1 = "test1"
name2 = "test2"
name3 = "test3"
memo = "LCD test tx"
pw = app.DefaultKeyPass
altPw = "12345678901"
)
var fees = sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 5)}
func init() {
mintkey.BcryptSecurityParameter = 1
version.Version = os.Getenv("VERSION")
@ -160,7 +164,7 @@ func TestCoinSend(t *testing.T) {
initialBalance := acc.GetCoins()
// create TX
receiveAddr, resultTx := doTransfer(t, port, seed, name1, pw, addr)
receiveAddr, resultTx := doTransfer(t, port, seed, name1, memo, pw, addr, fees)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was committed
@ -170,44 +174,65 @@ func TestCoinSend(t *testing.T) {
// query sender
acc = getAccount(t, port, addr)
coins := acc.GetCoins()
mycoins := coins[0]
expectedBalance := initialBalance[0].Minus(fees[0])
require.Equal(t, stakeTypes.DefaultBondDenom, mycoins.Denom)
require.Equal(t, initialBalance[0].Amount.SubRaw(1), mycoins.Amount)
require.Equal(t, stakingTypes.DefaultBondDenom, coins[0].Denom)
require.Equal(t, expectedBalance.Amount.SubRaw(1), coins[0].Amount)
expectedBalance = coins[0]
// query receiver
acc = getAccount(t, port, receiveAddr)
coins = acc.GetCoins()
mycoins = coins[0]
require.Equal(t, stakeTypes.DefaultBondDenom, mycoins.Denom)
require.Equal(t, int64(1), mycoins.Amount.Int64())
acc2 := getAccount(t, port, receiveAddr)
coins2 := acc2.GetCoins()
require.Equal(t, stakingTypes.DefaultBondDenom, coins2[0].Denom)
require.Equal(t, int64(1), coins2[0].Amount.Int64())
// test failure with too little gas
res, body, _ = doTransferWithGas(t, port, seed, name1, pw, addr, "100", 0, false, false)
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "100", 0, false, false, fees)
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
require.Nil(t, err)
// test failure with negative gas
res, body, _ = doTransferWithGas(t, port, seed, name1, pw, addr, "-200", 0, false, false)
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "-200", 0, false, false, fees)
require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
// test failure with negative adjustment
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "10000", -0.1, true, false, fees)
require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
// test failure with 0 gas
res, body, _ = doTransferWithGas(t, port, seed, name1, pw, addr, "0", 0, false, false)
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "0", 0, false, false, fees)
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
// test failure with wrong adjustment
res, body, _ = doTransferWithGas(t, port, seed, name1, pw, addr, "simulate", 0.1, false, false)
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, client.GasFlagAuto, 0.1, false, false, fees)
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
// run simulation and test success with estimated gas
res, body, _ = doTransferWithGas(t, port, seed, name1, pw, addr, "", 0, true, false)
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "10000", 1.0, true, false, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var responseBody struct {
GasEstimate int64 `json:"gas_estimate"`
}
require.Nil(t, json.Unmarshal([]byte(body), &responseBody))
res, body, _ = doTransferWithGas(t, port, seed, name1, pw, addr, fmt.Sprintf("%v", responseBody.GasEstimate), 0, false, false)
acc = getAccount(t, port, addr)
require.Equal(t, expectedBalance.Amount, acc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom))
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr,
fmt.Sprintf("%d", responseBody.GasEstimate), 1.0, false, false, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
require.Nil(t, err)
tests.WaitForHeight(resultTx.Height+1, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
acc = getAccount(t, port, addr)
expectedBalance = expectedBalance.Minus(fees[0])
require.Equal(t, expectedBalance.Amount.SubRaw(1), acc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom))
}
func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
@ -217,7 +242,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
acc := getAccount(t, port, addr)
// generate TX
res, body, _ := doTransferWithGas(t, port, seed, name1, pw, addr, "simulate", 0, false, true)
res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, client.GasFlagAuto, 1, false, true, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var msg auth.StdTx
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &msg))
@ -225,7 +250,9 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
require.Equal(t, msg.Msgs[0].Route(), "bank")
require.Equal(t, msg.Msgs[0].GetSigners(), []sdk.AccAddress{addr})
require.Equal(t, 0, len(msg.Signatures))
gasEstimate := msg.Fee.Gas
require.Equal(t, memo, msg.Memo)
gasEstimate := int64(msg.Fee.Gas)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
@ -233,12 +260,11 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
var signedMsg auth.StdTx
payload := authrest.SignBody{
Tx: msg,
LocalAccountName: name1,
Password: pw,
ChainID: viper.GetString(client.FlagChainID),
AccountNumber: accnum,
Sequence: sequence,
Tx: msg,
BaseReq: utils.NewBaseReq(
name1, pw, "", viper.GetString(client.FlagChainID), "", "",
accnum, sequence, nil, nil, false, false,
),
}
json, err := cdc.MarshalJSON(payload)
require.Nil(t, err)
@ -265,8 +291,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &resultTx))
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
require.Equal(t, gasEstimate, uint64(resultTx.DeliverTx.GasWanted))
require.Equal(t, gasEstimate, uint64(resultTx.DeliverTx.GasUsed))
require.Equal(t, gasEstimate, resultTx.DeliverTx.GasWanted)
}
func TestTxs(t *testing.T) {
@ -290,7 +315,7 @@ func TestTxs(t *testing.T) {
require.Equal(t, emptyTxs, txs)
// create tx
receiveAddr, resultTx := doTransfer(t, port, seed, name1, pw, addr)
receiveAddr, resultTx := doTransfer(t, port, seed, name1, memo, pw, addr, fees)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx is queryable
@ -301,6 +326,7 @@ func TestTxs(t *testing.T) {
txs = getTransactions(t, port, fmt.Sprintf("sender=%s", addr.String()))
require.Len(t, txs, 1)
require.Equal(t, resultTx.Height, txs[0].Height)
fmt.Println(txs[0])
// query recipient
txs = getTransactions(t, port, fmt.Sprintf("recipient=%s", receiveAddr.String()))
@ -313,20 +339,20 @@ func TestPoolParamsQuery(t *testing.T) {
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()
defaultParams := stake.DefaultParams()
defaultParams := staking.DefaultParams()
params := getStakeParams(t, port)
params := getStakingParams(t, port)
require.True(t, defaultParams.Equal(params))
pool := getStakePool(t, port)
pool := getStakingPool(t, port)
initialPool := stake.InitialPool()
initialPool.LooseTokens = initialPool.LooseTokens.Add(sdk.NewDec(100))
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(100)) // Delegate tx on GaiaAppGenState
initialPool.LooseTokens = initialPool.LooseTokens.Add(sdk.NewDec(int64(50))) // freeFermionsAcc = 50 on GaiaAppGenState
initialPool := staking.InitialPool()
initialPool.NotBondedTokens = initialPool.NotBondedTokens.Add(sdk.NewInt(100))
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewInt(100)) // Delegate tx on GaiaAppGenState
initialPool.NotBondedTokens = initialPool.NotBondedTokens.Add(sdk.NewInt(50)) // freeFermionsAcc = 50 on GaiaAppGenState
require.Equal(t, initialPool.BondedTokens, pool.BondedTokens)
require.Equal(t, initialPool.LooseTokens, pool.LooseTokens)
require.Equal(t, initialPool.NotBondedTokens, pool.NotBondedTokens)
}
func TestValidatorsQuery(t *testing.T) {
@ -371,8 +397,11 @@ func TestBonding(t *testing.T) {
amt := sdk.NewDec(60)
validator := getValidator(t, port, operAddrs[0])
acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()
// create bond TX
resultTx := doDelegate(t, port, name1, pw, addr, operAddrs[0], 60)
resultTx := doDelegate(t, port, name1, pw, addr, operAddrs[0], 60, fees)
tests.WaitForHeight(resultTx.Height+1, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
@ -386,10 +415,12 @@ func TestBonding(t *testing.T) {
require.Len(t, txs, 1)
require.Equal(t, resultTx.Height, txs[0].Height)
acc := getAccount(t, port, addr)
// verify balance
acc = getAccount(t, port, addr)
coins := acc.GetCoins()
require.Equal(t, int64(40), coins.AmountOf(stakeTypes.DefaultBondDenom).Int64())
expectedBalance := initialBalance[0].Minus(fees[0])
require.Equal(t, expectedBalance.Amount.SubRaw(60), coins.AmountOf(stakingTypes.DefaultBondDenom))
expectedBalance = coins[0]
// query delegation
bond := getDelegation(t, port, addr, operAddrs[0])
@ -412,7 +443,7 @@ func TestBonding(t *testing.T) {
require.Equal(t, operAddrs[0], bondedValidator.OperatorAddr)
// testing unbonding
resultTx = doBeginUnbonding(t, port, name1, pw, addr, operAddrs[0], 30)
resultTx = doUndelegate(t, port, name1, pw, addr, operAddrs[0], 30, fees)
tests.WaitForHeight(resultTx.Height+1, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
@ -421,7 +452,13 @@ func TestBonding(t *testing.T) {
// sender should have not received any coins as the unbonding has only just begun
acc = getAccount(t, port, addr)
coins = acc.GetCoins()
require.Equal(t, int64(40), coins.AmountOf(stakeTypes.DefaultBondDenom).Int64())
expectedBalance = expectedBalance.Minus(fees[0])
require.True(t,
expectedBalance.Amount.LT(coins.AmountOf(stakingTypes.DefaultBondDenom)) ||
expectedBalance.Amount.Equal(coins.AmountOf(stakingTypes.DefaultBondDenom)),
"should get tokens back from automatic withdrawal after an unbonding delegation",
)
expectedBalance = coins[0]
// query tx
txs = getTransactions(t, port,
@ -431,16 +468,26 @@ func TestBonding(t *testing.T) {
require.Len(t, txs, 1)
require.Equal(t, resultTx.Height, txs[0].Height)
unbonding := getUndelegation(t, port, addr, operAddrs[0])
require.Equal(t, "30", unbonding.Balance.Amount.String())
ubd := getUnbondingDelegation(t, port, addr, operAddrs[0])
require.Len(t, ubd.Entries, 1)
require.Equal(t, int64(30), ubd.Entries[0].Balance.Amount.Int64())
// test redelegation
resultTx = doBeginRedelegation(t, port, name1, pw, addr, operAddrs[0], operAddrs[1], 30)
resultTx = doBeginRedelegation(t, port, name1, pw, addr, operAddrs[0], operAddrs[1], 30, fees)
tests.WaitForHeight(resultTx.Height+1, port)
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
// verify balance after paying fees
acc = getAccount(t, port, addr)
expectedBalance = expectedBalance.Minus(fees[0])
require.True(t,
expectedBalance.Amount.LT(coins.AmountOf(stakingTypes.DefaultBondDenom)) ||
expectedBalance.Amount.Equal(coins.AmountOf(stakingTypes.DefaultBondDenom)),
"should get tokens back from automatic withdrawal after an unbonding delegation",
)
// query tx
txs = getTransactions(t, port,
fmt.Sprintf("action=begin_redelegate&delegator=%s", addr),
@ -453,23 +500,32 @@ func TestBonding(t *testing.T) {
// query delegations, unbondings and redelegations from validator and delegator
delegatorDels = getDelegatorDelegations(t, port, addr)
require.Len(t, delegatorDels, 1)
require.Equal(t, "30.0000000000", delegatorDels[0].GetShares().String())
require.Equal(t, "30.000000000000000000", delegatorDels[0].GetShares().String())
redelegation := getRedelegations(t, port, addr, operAddrs[0], operAddrs[1])
require.Len(t, redelegation, 1)
require.Len(t, redelegation[0].Entries, 1)
require.Equal(t, "30", redelegation[0].Entries[0].Balance.Amount.String())
delegatorUbds := getDelegatorUnbondingDelegations(t, port, addr)
require.Len(t, delegatorUbds, 1)
require.Equal(t, "30", delegatorUbds[0].Balance.Amount.String())
require.Len(t, delegatorUbds[0].Entries, 1)
require.Equal(t, "30", delegatorUbds[0].Entries[0].Balance.Amount.String())
delegatorReds := getDelegatorRedelegations(t, port, addr)
delegatorReds := getRedelegations(t, port, addr, nil, nil)
require.Len(t, delegatorReds, 1)
require.Equal(t, "30", delegatorReds[0].Balance.Amount.String())
require.Len(t, delegatorReds[0].Entries, 1)
require.Equal(t, "30", delegatorReds[0].Entries[0].Balance.Amount.String())
validatorUbds := getValidatorUnbondingDelegations(t, port, operAddrs[0])
require.Len(t, validatorUbds, 1)
require.Equal(t, "30", validatorUbds[0].Balance.Amount.String())
require.Len(t, validatorUbds[0].Entries, 1)
require.Equal(t, "30", validatorUbds[0].Entries[0].Balance.Amount.String())
validatorReds := getValidatorRedelegations(t, port, operAddrs[0])
validatorReds := getRedelegations(t, port, nil, operAddrs[0], nil)
require.Len(t, validatorReds, 1)
require.Equal(t, "30", validatorReds[0].Balance.Amount.String())
require.Len(t, validatorReds[0].Entries, 1)
require.Equal(t, "30", validatorReds[0].Entries[0].Balance.Amount.String())
// TODO Undonding status not currently implemented
// require.Equal(t, sdk.Unbonding, bondedValidators[0].Status)
@ -493,8 +549,11 @@ func TestSubmitProposal(t *testing.T) {
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()
acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()
// create SubmitProposal TX
resultTx := doSubmitProposal(t, port, seed, name1, pw, addr, 5)
resultTx := doSubmitProposal(t, port, seed, name1, pw, addr, 5, fees)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was committed
@ -504,14 +563,18 @@ func TestSubmitProposal(t *testing.T) {
var proposalID uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
// verify balance
acc = getAccount(t, port, addr)
expectedBalance := initialBalance[0].Minus(fees[0])
require.Equal(t, expectedBalance.Amount.SubRaw(5), acc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom))
// query proposal
proposal := getProposal(t, port, proposalID)
require.Equal(t, "Test", proposal.GetTitle())
// query tx
txs := getTransactions(t, port, fmt.Sprintf("action=submit_proposal&proposer=%s", addr))
require.Len(t, txs, 1)
require.Equal(t, resultTx.Height, txs[0].Height)
proposer := getProposer(t, port, proposalID)
require.Equal(t, addr.String(), proposer.Proposer)
require.Equal(t, proposalID, proposer.ProposalID)
}
func TestDeposit(t *testing.T) {
@ -519,8 +582,11 @@ func TestDeposit(t *testing.T) {
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()
acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()
// create SubmitProposal TX
resultTx := doSubmitProposal(t, port, seed, name1, pw, addr, 5)
resultTx := doSubmitProposal(t, port, seed, name1, pw, addr, 5, fees)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was committed
@ -530,14 +596,26 @@ func TestDeposit(t *testing.T) {
var proposalID uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
// verify balance
acc = getAccount(t, port, addr)
coins := acc.GetCoins()
expectedBalance := initialBalance[0].Minus(fees[0])
require.Equal(t, expectedBalance.Amount.SubRaw(5), coins.AmountOf(stakingTypes.DefaultBondDenom))
expectedBalance = coins[0]
// query proposal
proposal := getProposal(t, port, proposalID)
require.Equal(t, "Test", proposal.GetTitle())
// create SubmitProposal TX
resultTx = doDeposit(t, port, seed, name1, pw, addr, proposalID, 5)
resultTx = doDeposit(t, port, seed, name1, pw, addr, proposalID, 5, fees)
tests.WaitForHeight(resultTx.Height+1, port)
// verify balance after deposit and fee
acc = getAccount(t, port, addr)
expectedBalance = expectedBalance.Minus(fees[0])
require.Equal(t, expectedBalance.Amount.SubRaw(5), acc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom))
// query tx
txs := getTransactions(t, port, fmt.Sprintf("action=deposit&depositor=%s", addr))
require.Len(t, txs, 1)
@ -545,11 +623,11 @@ func TestDeposit(t *testing.T) {
// query proposal
proposal = getProposal(t, port, proposalID)
require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)}))
require.True(t, proposal.GetTotalDeposit().IsEqual(sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 10)}))
// query deposit
deposit := getDeposit(t, port, proposalID, addr)
require.True(t, deposit.Amount.IsEqual(sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 10)}))
require.True(t, deposit.Amount.IsEqual(sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 10)}))
}
func TestVote(t *testing.T) {
@ -557,8 +635,11 @@ func TestVote(t *testing.T) {
cleanup, _, operAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()
acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()
// create SubmitProposal TX
resultTx := doSubmitProposal(t, port, seed, name1, pw, addr, 5)
resultTx := doSubmitProposal(t, port, seed, name1, pw, addr, 10, fees)
tests.WaitForHeight(resultTx.Height+1, port)
// check if tx was committed
@ -568,22 +649,29 @@ func TestVote(t *testing.T) {
var proposalID uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
// verify balance
acc = getAccount(t, port, addr)
coins := acc.GetCoins()
expectedBalance := initialBalance[0].Minus(fees[0])
require.Equal(t, expectedBalance.Amount.SubRaw(10), coins.AmountOf(stakingTypes.DefaultBondDenom))
expectedBalance = coins[0]
// query proposal
proposal := getProposal(t, port, proposalID)
require.Equal(t, "Test", proposal.GetTitle())
// deposit
resultTx = doDeposit(t, port, seed, name1, pw, addr, proposalID, 5)
tests.WaitForHeight(resultTx.Height+1, port)
// query proposal
proposal = getProposal(t, port, proposalID)
require.Equal(t, gov.StatusVotingPeriod, proposal.GetStatus())
// vote
resultTx = doVote(t, port, seed, name1, pw, addr, proposalID)
resultTx = doVote(t, port, seed, name1, pw, addr, proposalID, "Yes", fees)
tests.WaitForHeight(resultTx.Height+1, port)
// verify balance after vote and fee
acc = getAccount(t, port, addr)
coins = acc.GetCoins()
expectedBalance = expectedBalance.Minus(fees[0])
require.Equal(t, expectedBalance.Amount, coins.AmountOf(stakingTypes.DefaultBondDenom))
expectedBalance = coins[0]
// query tx
txs := getTransactions(t, port, fmt.Sprintf("action=vote&voter=%s", addr))
require.Len(t, txs, 1)
@ -597,15 +685,31 @@ func TestVote(t *testing.T) {
require.Equal(t, sdk.ZeroDec(), tally.Yes, "tally should be 0 as the address is not bonded")
// create bond TX
resultTx = doDelegate(t, port, name1, pw, addr, operAddrs[0], 60)
resultTx = doDelegate(t, port, name1, pw, addr, operAddrs[0], 60, fees)
tests.WaitForHeight(resultTx.Height+1, port)
// vote
resultTx = doVote(t, port, seed, name1, pw, addr, proposalID)
tests.WaitForHeight(resultTx.Height+1, port)
// verify balance
acc = getAccount(t, port, addr)
coins = acc.GetCoins()
expectedBalance = expectedBalance.Minus(fees[0])
require.Equal(t, expectedBalance.Amount.SubRaw(60), coins.AmountOf(stakingTypes.DefaultBondDenom))
expectedBalance = coins[0]
tally = getTally(t, port, proposalID)
require.Equal(t, sdk.NewDec(60), tally.Yes, "tally should be equal to the amount delegated")
// change vote option
resultTx = doVote(t, port, seed, name1, pw, addr, proposalID, "No", fees)
tests.WaitForHeight(resultTx.Height+1, port)
// verify balance
acc = getAccount(t, port, addr)
expectedBalance = expectedBalance.Minus(fees[0])
require.Equal(t, expectedBalance.Amount, acc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom))
tally = getTally(t, port, proposalID)
require.Equal(t, sdk.ZeroDec(), tally.Yes, "tally should be 0 the user changed the option")
require.Equal(t, sdk.NewDec(60), tally.No, "tally should be equal to the amount delegated")
}
func TestUnjail(t *testing.T) {
@ -630,32 +734,32 @@ func TestProposalsQuery(t *testing.T) {
defer cleanup()
depositParam := getDepositParam(t, port)
halfMinDeposit := depositParam.MinDeposit.AmountOf(stakeTypes.DefaultBondDenom).Int64() / 2
halfMinDeposit := depositParam.MinDeposit.AmountOf(stakingTypes.DefaultBondDenom).Int64() / 2
getVotingParam(t, port)
getTallyingParam(t, port)
// Addr1 proposes (and deposits) proposals #1 and #2
resultTx := doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit)
resultTx := doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit, fees)
var proposalID1 uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID1)
tests.WaitForHeight(resultTx.Height+1, port)
resultTx = doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit)
resultTx = doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit, fees)
var proposalID2 uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID2)
tests.WaitForHeight(resultTx.Height+1, port)
// Addr2 proposes (and deposits) proposals #3
resultTx = doSubmitProposal(t, port, seeds[1], names[1], passwords[1], addrs[1], halfMinDeposit)
resultTx = doSubmitProposal(t, port, seeds[1], names[1], passwords[1], addrs[1], halfMinDeposit, fees)
var proposalID3 uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID3)
tests.WaitForHeight(resultTx.Height+1, port)
// Addr2 deposits on proposals #2 & #3
resultTx = doDeposit(t, port, seeds[1], names[1], passwords[1], addrs[1], proposalID2, halfMinDeposit)
resultTx = doDeposit(t, port, seeds[1], names[1], passwords[1], addrs[1], proposalID2, halfMinDeposit, fees)
tests.WaitForHeight(resultTx.Height+1, port)
resultTx = doDeposit(t, port, seeds[1], names[1], passwords[1], addrs[1], proposalID3, halfMinDeposit)
resultTx = doDeposit(t, port, seeds[1], names[1], passwords[1], addrs[1], proposalID3, halfMinDeposit, fees)
tests.WaitForHeight(resultTx.Height+1, port)
// check deposits match proposal and individual deposits
@ -677,7 +781,7 @@ func TestProposalsQuery(t *testing.T) {
require.Equal(t, deposit, deposits[0])
// increasing the amount of the deposit should update the existing one
resultTx = doDeposit(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID1, 1)
resultTx = doDeposit(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID1, 1, fees)
tests.WaitForHeight(resultTx.Height+1, port)
deposits = getDeposits(t, port, proposalID1)
@ -695,13 +799,13 @@ func TestProposalsQuery(t *testing.T) {
require.Equal(t, proposalID3, proposals[1].GetProposalID())
// Addr1 votes on proposals #2 & #3
resultTx = doVote(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID2)
resultTx = doVote(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID2, "Yes", fees)
tests.WaitForHeight(resultTx.Height+1, port)
resultTx = doVote(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID3)
resultTx = doVote(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID3, "Yes", fees)
tests.WaitForHeight(resultTx.Height+1, port)
// Addr2 votes on proposal #3
resultTx = doVote(t, port, seeds[1], names[1], passwords[1], addrs[1], proposalID3)
resultTx = doVote(t, port, seeds[1], names[1], passwords[1], addrs[1], proposalID3, "Yes", fees)
tests.WaitForHeight(resultTx.Height+1, port)
// Test query all proposals

View File

@ -41,11 +41,6 @@ type RestServer struct {
func NewRestServer(cdc *codec.Codec) *RestServer {
r := mux.NewRouter()
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(cdc)
// Register version methods on the router
r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET")
r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET")
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server")
return &RestServer{
@ -82,68 +77,52 @@ func (rs *RestServer) Start(listenAddr string, sslHosts string,
rs.log.Error("error closing listener", "err", err)
})
// TODO: re-enable insecure mode once #2715 has been addressed
rs.listener, err = rpcserver.Listen(
listenAddr,
rpcserver.Config{MaxOpenConnections: maxOpen},
)
if err != nil {
return
}
rs.log.Info("Starting Gaia Lite REST service...")
// launch rest-server in insecure mode
if insecure {
fmt.Println(
"Insecure mode is temporarily disabled, please locally generate an " +
"SSL certificate to test. Support will be re-enabled soon!",
)
// listener, err = rpcserver.StartHTTPServer(
// listenAddr, handler, logger,
// rpcserver.Config{MaxOpenConnections: maxOpen},
// )
// if err != nil {
// return
// }
} else {
if certFile != "" {
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
err = validateCertKeyFiles(certFile, keyFile)
if err != nil {
return err
}
return rpcserver.StartHTTPServer(rs.listener, rs.Mux, rs.log)
}
// cert/key pair is provided, read the fingerprint
rs.fingerprint, err = fingerprintFromFile(certFile)
if err != nil {
return err
}
} else {
// if certificate is not supplied, generate a self-signed one
certFile, keyFile, rs.fingerprint, err = genCertKeyFilesAndReturnFingerprint(sslHosts)
if err != nil {
return err
}
defer func() {
os.Remove(certFile)
os.Remove(keyFile)
}()
// handle certificates
if certFile != "" {
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
if err := validateCertKeyFiles(certFile, keyFile); err != nil {
return err
}
rs.listener, err = rpcserver.Listen(
listenAddr,
rpcserver.Config{MaxOpenConnections: maxOpen},
)
if err != nil {
return
}
rs.log.Info("Starting Gaia Lite REST service...")
rs.log.Info(rs.fingerprint)
err := rpcserver.StartHTTPAndTLSServer(
rs.listener,
rs.Mux,
certFile, keyFile,
rs.log,
)
// cert/key pair is provided, read the fingerprint
rs.fingerprint, err = fingerprintFromFile(certFile)
if err != nil {
return err
}
} else {
// if certificate is not supplied, generate a self-signed one
certFile, keyFile, rs.fingerprint, err = genCertKeyFilesAndReturnFingerprint(sslHosts)
if err != nil {
return err
}
defer func() {
os.Remove(certFile)
os.Remove(keyFile)
}()
}
return nil
rs.log.Info(rs.fingerprint)
return rpcserver.StartHTTPAndTLSServer(
rs.listener,
rs.Mux,
certFile, keyFile,
rs.log,
)
}
// ServeCommand will start a Gaia Lite REST service as a blocking process. It

View File

@ -18,11 +18,12 @@ tags:
- name: ICS23
description: Slashing module APIs
- name: ICS24
description: Fee distribution module APIs
description: WIP - Fee distribution module APIs
- name: version
description: Query app version
schemes:
- https
host: fabo.interblock.io:1317
securityDefinitions:
kms:
type: basic
@ -286,20 +287,10 @@ paths:
schema:
type: object
properties:
base_req:
$ref: "#/definitions/BaseReq"
tx:
$ref: "#/definitions/StdTx"
name:
type: string
password:
type: string
chain_id:
type: string
account_number:
type: string
example: "0"
sequence:
type: string
example: "0"
append_sig:
type: boolean
example: true
@ -620,7 +611,7 @@ paths:
description: No content about this account address
500:
description: Server internel error
/stake/delegators/{delegatorAddr}/delegations:
/staking/delegators/{delegatorAddr}/delegations:
parameters:
- in: path
name: delegatorAddr
@ -678,7 +669,7 @@ paths:
description: Key password is wrong
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/delegations/{validatorAddr}:
/staking/delegators/{delegatorAddr}/delegations/{validatorAddr}:
parameters:
- in: path
name: delegatorAddr
@ -705,7 +696,7 @@ paths:
description: Invalid delegator address or validator address
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/unbonding_delegations:
/staking/delegators/{delegatorAddr}/unbonding_delegations:
parameters:
- in: path
name: delegatorAddr
@ -774,7 +765,7 @@ paths:
description: Key password is wrong
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}:
/staking/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}:
parameters:
- in: path
name: delegatorAddr
@ -803,15 +794,25 @@ paths:
description: Invalid delegator address or validator address
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/redelegations:
/staking/redelegations:
parameters:
- in: path
name: delegatorAddr
- in: query
name: delegator
description: Bech32 AccAddress of Delegator
required: true
required: false
type: string
- in: query
name: validator_from
description: Bech32 ValAddress of SrcValidator
required: false
type: string
- in: query
name: validator_to
description: Bech32 ValAddress of DstValidator
required: false
type: string
get:
summary: Get all redelegations from a delegator
summary: Get all redelegations (filter by query params)
tags:
- ICS21
produces:
@ -823,10 +824,15 @@ paths:
type: array
items:
$ref: "#/definitions/Redelegation"
400:
description: Invalid delegator address
500:
description: Internal Server Error
/staking/delegators/{delegatorAddr}/redelegations:
parameters:
- in: path
name: delegatorAddr
description: Bech32 AccAddress of Delegator
required: true
type: string
post:
summary: Submit a redelegation
parameters:
@ -874,7 +880,7 @@ paths:
description: Key password is wrong
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/validators:
/staking/delegators/{delegatorAddr}/validators:
parameters:
- in: path
name: delegatorAddr
@ -898,7 +904,7 @@ paths:
description: Invalid delegator address
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/validators/{validatorAddr}:
/staking/delegators/{delegatorAddr}/validators/{validatorAddr}:
parameters:
- in: path
name: delegatorAddr
@ -925,7 +931,7 @@ paths:
description: Invalid delegator address or validator address
500:
description: Internal Server Error
/stake/delegators/{delegatorAddr}/txs:
/staking/delegators/{delegatorAddr}/txs:
parameters:
- in: path
name: delegatorAddr
@ -951,7 +957,7 @@ paths:
description: Invalid delegator address
500:
description: Internal Server Error
/stake/validators:
/staking/validators:
get:
summary: Get all validator candidates
tags:
@ -967,7 +973,7 @@ paths:
$ref: "#/definitions/Validator"
500:
description: Internal Server Error
/stake/validators/{validatorAddr}:
/staking/validators/{validatorAddr}:
parameters:
- in: path
name: validatorAddr
@ -989,7 +995,7 @@ paths:
description: Invalid validator address
500:
description: Internal Server Error
/stake/validators/{validatorAddr}/delegations:
/staking/validators/{validatorAddr}/delegations:
parameters:
- in: path
name: validatorAddr
@ -1013,7 +1019,7 @@ paths:
description: Invalid validator address
500:
description: Internal Server Error
/stake/validators/{validatorAddr}/unbonding_delegations:
/staking/validators/{validatorAddr}/unbonding_delegations:
parameters:
- in: path
name: validatorAddr
@ -1037,31 +1043,7 @@ paths:
description: Invalid validator address
500:
description: Internal Server Error
/stake/validators/{validatorAddr}/redelegations:
parameters:
- in: path
name: validatorAddr
description: Bech32 OperatorAddress of validator
required: true
type: string
get:
summary: Get all outgoing redelegations from a validator
tags:
- ICS21
produces:
- application/json
responses:
200:
description: OK
schema:
type: array
items:
$ref: "#/definitions/Redelegation"
400:
description: Invalid validator address
500:
description: Internal Server Error
/stake/pool:
/staking/pool:
get:
summary: Get the current state of the staking pool
tags:
@ -1088,7 +1070,7 @@ paths:
type: string
500:
description: Internal Server Error
/stake/parameters:
/staking/parameters:
get:
summary: Get the current staking parameter values
tags:
@ -1316,6 +1298,28 @@ paths:
description: Invalid proposal id
500:
description: Internal Server Error
/gov/proposals/{proposalId}/proposer:
get:
summary: Query proposer
description: Query for the proposer for a proposal
produces:
- application/json
tags:
- ICS22
parameters:
- type: string
name: proposalId
required: true
in: path
responses:
200:
description: OK
schema:
$ref: "#/definitions/Proposer"
400:
description: Invalid proposal ID
500:
description: Internal Server Error
/gov/proposals/{proposalId}/deposits:
get:
summary: Query deposits
@ -2208,23 +2212,36 @@ definitions:
properties:
name:
type: string
example: "my_name"
password:
type: string
example: "12345678"
memo:
type: string
example: "Sent via Cosmos Voyager 🚀"
chain_id:
type: string
example: "Cosmos-Hub"
account_number:
type: string
example: "0"
sequence:
type: string
example: "0"
example: "1"
gas:
type: string
example: "200000"
gas_adjustment:
type: string
example: "1.2"
fees:
type: array
items:
$ref: "#/definitions/Coin"
gas_prices:
type: array
items:
$ref: "#/definitions/DecCoin"
generate_only:
type: boolean
example: false
@ -2258,7 +2275,7 @@ definitions:
type: string
proposal_status:
type: string
tally_result:
final_tally_result:
$ref: "#/definitions/TallyResult"
submit_time:
type: string
@ -2268,6 +2285,13 @@ definitions:
$ref: "#/definitions/Coin"
voting_start_time:
type: string
Proposer:
type: object
properties:
proposal_id:
type: integer
proposer:
type: string
Deposit:
type: object
properties:

View File

@ -15,13 +15,14 @@ import (
"strings"
"testing"
"github.com/tendermint/tendermint/crypto/secp256k1"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/tendermint/tendermint/crypto/secp256k1"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
@ -35,7 +36,8 @@ import (
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/stake"
gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
@ -60,7 +62,7 @@ import (
bankRest "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
govRest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
slashingRest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
stakeRest "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
stakingRest "github.com/cosmos/cosmos-sdk/x/staking/client/rest"
)
// makePathname creates a unique pathname for each test. It will panic if it
@ -225,8 +227,8 @@ func InitializeTestLCD(
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError())
privValidatorFile := config.PrivValidatorFile()
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
privVal := pvm.LoadOrGenFilePV(config.PrivValidatorKeyFile(),
config.PrivValidatorStateFile())
privVal.Reset()
db := dbm.NewMemDB()
@ -245,18 +247,18 @@ func InitializeTestLCD(
for i := 0; i < nValidators; i++ {
operPrivKey := secp256k1.GenPrivKey()
operAddr := operPrivKey.PubKey().Address()
pubKey := privVal.PubKey
pubKey := privVal.GetPubKey()
delegation := 100
if i > 0 {
pubKey = ed25519.GenPrivKey().PubKey()
delegation = 1
}
msg := stake.NewMsgCreateValidator(
msg := staking.NewMsgCreateValidator(
sdk.ValAddress(operAddr),
pubKey,
sdk.NewCoin(stakeTypes.DefaultBondDenom, sdk.NewInt(int64(delegation))),
stake.Description{Moniker: fmt.Sprintf("validator-%d", i+1)},
stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
sdk.NewCoin(stakingTypes.DefaultBondDenom, sdk.NewInt(int64(delegation))),
staking.Description{Moniker: fmt.Sprintf("validator-%d", i+1)},
staking.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
)
stdSignMsg := txbuilder.StdSignMsg{
ChainID: genDoc.ChainID,
@ -272,7 +274,7 @@ func InitializeTestLCD(
valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr))
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(operAddr))
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 150)}
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 150)}
accs = append(accs, gapp.NewGenesisAccount(&accAuth))
}
@ -286,10 +288,10 @@ func InitializeTestLCD(
// add some tokens to init accounts
for _, addr := range initAddrs {
accAuth := auth.NewBaseAccountWithAddress(addr)
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 100)}
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 100)}
acc := gapp.NewGenesisAccount(&accAuth)
genesisState.Accounts = append(genesisState.Accounts, acc)
genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100))
genesisState.StakingData.Pool.NotBondedTokens = genesisState.StakingData.Pool.NotBondedTokens.Add(sdk.NewInt(100))
}
appState, err := codec.MarshalJSONIndent(cdc, genesisState)
@ -386,9 +388,9 @@ func registerRoutes(rs *RestServer) {
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
authRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, "acc")
authRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, auth.StoreKey)
bankRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
stakeRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
stakingRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashingRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
govRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
}
@ -643,12 +645,10 @@ func getAccount(t *testing.T, port string, addr sdk.AccAddress) auth.Account {
func doSign(t *testing.T, port, name, password, chainID string, accnum, sequence uint64, msg auth.StdTx) auth.StdTx {
var signedMsg auth.StdTx
payload := authrest.SignBody{
Tx: msg,
LocalAccountName: name,
Password: password,
ChainID: chainID,
AccountNumber: accnum,
Sequence: sequence,
Tx: msg,
BaseReq: utils.NewBaseReq(
name, password, "", chainID, "", "", accnum, sequence, nil, nil, false, false,
),
}
json, err := cdc.MarshalJSON(payload)
require.Nil(t, err)
@ -678,8 +678,8 @@ type broadcastReq struct {
// GET /bank/balances/{address} Get the account balances
// POST /bank/accounts/{address}/transfers Send coins (build -> sign -> send)
func doTransfer(t *testing.T, port, seed, name, password string, addr sdk.AccAddress) (receiveAddr sdk.AccAddress, resultTx ctypes.ResultBroadcastTxCommit) {
res, body, receiveAddr := doTransferWithGas(t, port, seed, name, password, addr, "", 0, false, false)
func doTransfer(t *testing.T, port, seed, name, memo, password string, addr sdk.AccAddress, fees sdk.Coins) (receiveAddr sdk.AccAddress, resultTx ctypes.ResultBroadcastTxCommit) {
res, body, receiveAddr := doTransferWithGas(t, port, seed, name, memo, password, addr, "", 1.0, false, false, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)
err := cdc.UnmarshalJSON([]byte(body), &resultTx)
@ -688,8 +688,8 @@ func doTransfer(t *testing.T, port, seed, name, password string, addr sdk.AccAdd
return receiveAddr, resultTx
}
func doTransferWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas string,
gasAdjustment float64, simulate, generateOnly bool) (
func doTransferWithGas(t *testing.T, port, seed, name, memo, password string, addr sdk.AccAddress, gas string,
gasAdjustment float64, simulate, generateOnly bool, fees sdk.Coins) (
res *http.Response, body string, receiveAddr sdk.AccAddress) {
// create receive address
@ -703,25 +703,15 @@ func doTransferWithGas(t *testing.T, port, seed, name, password string, addr sdk
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
baseReq := utils.NewBaseReq(
name, password, memo, chainID, gas,
fmt.Sprintf("%f", gasAdjustment), accnum, sequence, fees, nil,
generateOnly, simulate,
)
sr := sendReq{
Amount: sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 1)},
BaseReq: utils.BaseReq{
Name: name,
Password: password,
ChainID: chainID,
AccountNumber: accnum,
Sequence: sequence,
Simulate: simulate,
GenerateOnly: generateOnly,
},
}
if len(gas) != 0 {
sr.BaseReq.Gas = gas
}
if gasAdjustment > 0 {
sr.BaseReq.GasAdjustment = fmt.Sprintf("%f", gasAdjustment)
Amount: sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 1)},
BaseReq: baseReq,
}
req, err := cdc.MarshalJSON(sr)
@ -740,34 +730,30 @@ type sendReq struct {
// ICS 21 - Stake
// ----------------------------------------------------------------------
// POST /stake/delegators/{delegatorAddr}/delegations Submit delegation
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
func doDelegate(t *testing.T, port, name, password string,
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
ed := msgDelegationsInput{
BaseReq: utils.BaseReq{
Name: name,
Password: password,
ChainID: chainID,
AccountNumber: accnum,
Sequence: sequence,
},
baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
msg := msgDelegationsInput{
BaseReq: baseReq,
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
Delegation: sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, amount),
Delegation: sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, amount),
}
req, err := cdc.MarshalJSON(ed)
req, err := cdc.MarshalJSON(msg)
require.NoError(t, err)
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr.String()), req)
res, body := Request(t, port, "POST", fmt.Sprintf("/staking/delegators/%s/delegations", delAddr.String()), req)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results ctypes.ResultBroadcastTxCommit
err = cdc.UnmarshalJSON([]byte(body), &results)
var result ctypes.ResultBroadcastTxCommit
err = cdc.UnmarshalJSON([]byte(body), &result)
require.Nil(t, err)
return results
return result
}
type msgDelegationsInput struct {
@ -777,79 +763,70 @@ type msgDelegationsInput struct {
Delegation sdk.Coin `json:"delegation"`
}
// POST /stake/delegators/{delegatorAddr}/delegations Submit delegation
func doBeginUnbonding(t *testing.T, port, name, password string,
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
func doUndelegate(t *testing.T, port, name, password string,
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
ed := msgBeginUnbondingInput{
BaseReq: utils.BaseReq{
Name: name,
Password: password,
ChainID: chainID,
AccountNumber: accnum,
Sequence: sequence,
},
baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
msg := msgUndelegateInput{
BaseReq: baseReq,
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
SharesAmount: sdk.NewDec(amount),
}
req, err := cdc.MarshalJSON(ed)
req, err := cdc.MarshalJSON(msg)
require.NoError(t, err)
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations", delAddr), req)
res, body := Request(t, port, "POST", fmt.Sprintf("/staking/delegators/%s/unbonding_delegations", delAddr), req)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results ctypes.ResultBroadcastTxCommit
err = cdc.UnmarshalJSON([]byte(body), &results)
var result ctypes.ResultBroadcastTxCommit
err = cdc.UnmarshalJSON([]byte(body), &result)
require.Nil(t, err)
return results
return result
}
type msgBeginUnbondingInput struct {
type msgUndelegateInput struct {
BaseReq utils.BaseReq `json:"base_req"`
DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // in bech32
ValidatorAddr sdk.ValAddress `json:"validator_addr"` // in bech32
SharesAmount sdk.Dec `json:"shares"`
}
// POST /stake/delegators/{delegatorAddr}/delegations Submit delegation
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
func doBeginRedelegation(t *testing.T, port, name, password string,
delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, amount int64, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
ed := msgBeginRedelegateInput{
BaseReq: utils.BaseReq{
Name: name,
Password: password,
ChainID: chainID,
AccountNumber: accnum,
Sequence: sequence,
},
baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
msg := msgBeginRedelegateInput{
BaseReq: baseReq,
DelegatorAddr: delAddr,
ValidatorSrcAddr: valSrcAddr,
ValidatorDstAddr: valDstAddr,
SharesAmount: sdk.NewDec(amount),
}
req, err := cdc.MarshalJSON(ed)
req, err := cdc.MarshalJSON(msg)
require.NoError(t, err)
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/redelegations", delAddr), req)
res, body := Request(t, port, "POST", fmt.Sprintf("/staking/delegators/%s/redelegations", delAddr), req)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results ctypes.ResultBroadcastTxCommit
err = cdc.UnmarshalJSON([]byte(body), &results)
var result ctypes.ResultBroadcastTxCommit
err = cdc.UnmarshalJSON([]byte(body), &result)
require.Nil(t, err)
return results
return result
}
type msgBeginRedelegateInput struct {
@ -860,12 +837,12 @@ type msgBeginRedelegateInput struct {
SharesAmount sdk.Dec `json:"shares"`
}
// GET /stake/delegators/{delegatorAddr}/delegations Get all delegations from a delegator
func getDelegatorDelegations(t *testing.T, port string, delegatorAddr sdk.AccAddress) []stake.Delegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), nil)
// GET /staking/delegators/{delegatorAddr}/delegations Get all delegations from a delegator
func getDelegatorDelegations(t *testing.T, port string, delegatorAddr sdk.AccAddress) []staking.Delegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/delegations", delegatorAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var dels []stake.Delegation
var dels []staking.Delegation
err := cdc.UnmarshalJSON([]byte(body), &dels)
require.Nil(t, err)
@ -873,12 +850,12 @@ func getDelegatorDelegations(t *testing.T, port string, delegatorAddr sdk.AccAdd
return dels
}
// GET /stake/delegators/{delegatorAddr}/unbonding_delegations Get all unbonding delegations from a delegator
func getDelegatorUnbondingDelegations(t *testing.T, port string, delegatorAddr sdk.AccAddress) []stake.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations", delegatorAddr), nil)
// GET /staking/delegators/{delegatorAddr}/unbonding_delegations Get all unbonding delegations from a delegator
func getDelegatorUnbondingDelegations(t *testing.T, port string, delegatorAddr sdk.AccAddress) []staking.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/unbonding_delegations", delegatorAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var ubds []stake.UnbondingDelegation
var ubds []staking.UnbondingDelegation
err := cdc.UnmarshalJSON([]byte(body), &ubds)
require.Nil(t, err)
@ -886,25 +863,34 @@ func getDelegatorUnbondingDelegations(t *testing.T, port string, delegatorAddr s
return ubds
}
// GET /stake/delegators/{delegatorAddr}/redelegations Get all redelegations from a delegator
func getDelegatorRedelegations(t *testing.T, port string, delegatorAddr sdk.AccAddress) []stake.Redelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/redelegations", delegatorAddr), nil)
// GET /staking/redelegations?delegator=0xdeadbeef&validator_from=0xdeadbeef&validator_to=0xdeadbeef& Get redelegations filters by params passed in
func getRedelegations(t *testing.T, port string, delegatorAddr sdk.AccAddress, srcValidatorAddr sdk.ValAddress, dstValidatorAddr sdk.ValAddress) []staking.Redelegation {
var res *http.Response
var body string
endpoint := "/staking/redelegations?"
if !delegatorAddr.Empty() {
endpoint += fmt.Sprintf("delegator=%s&", delegatorAddr)
}
if !srcValidatorAddr.Empty() {
endpoint += fmt.Sprintf("validator_from=%s&", srcValidatorAddr)
}
if !dstValidatorAddr.Empty() {
endpoint += fmt.Sprintf("validator_to=%s&", dstValidatorAddr)
}
res, body = Request(t, port, "GET", endpoint, nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var reds []stake.Redelegation
err := cdc.UnmarshalJSON([]byte(body), &reds)
var redels []staking.Redelegation
err := cdc.UnmarshalJSON([]byte(body), &redels)
require.Nil(t, err)
return reds
return redels
}
// GET /stake/delegators/{delegatorAddr}/validators Query all validators that a delegator is bonded to
func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddress) []stake.Validator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators", delegatorAddr), nil)
// GET /staking/delegators/{delegatorAddr}/validators Query all validators that a delegator is bonded to
func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddress) []staking.Validator {
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/validators", delegatorAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bondedValidators []stake.Validator
var bondedValidators []staking.Validator
err := cdc.UnmarshalJSON([]byte(body), &bondedValidators)
require.Nil(t, err)
@ -912,27 +898,27 @@ func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddr
return bondedValidators
}
// GET /stake/delegators/{delegatorAddr}/validators/{validatorAddr} Query a validator that a delegator is bonded to
func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.Validator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delegatorAddr, validatorAddr), nil)
// GET /staking/delegators/{delegatorAddr}/validators/{validatorAddr} Query a validator that a delegator is bonded to
func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) staking.Validator {
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/validators/%s", delegatorAddr, validatorAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bondedValidator stake.Validator
var bondedValidator staking.Validator
err := cdc.UnmarshalJSON([]byte(body), &bondedValidator)
require.Nil(t, err)
return bondedValidator
}
// GET /stake/delegators/{delegatorAddr}/txs Get all staking txs (i.e msgs) from a delegator
// GET /staking/delegators/{delegatorAddr}/txs Get all staking txs (i.e msgs) from a delegator
func getBondingTxs(t *testing.T, port string, delegatorAddr sdk.AccAddress, query string) []tx.Info {
var res *http.Response
var body string
if len(query) > 0 {
res, body = Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/txs?type=%s", delegatorAddr, query), nil)
res, body = Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/txs?type=%s", delegatorAddr, query), nil)
} else {
res, body = Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/txs", delegatorAddr), nil)
res, body = Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/txs", delegatorAddr), nil)
}
require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -944,107 +930,100 @@ func getBondingTxs(t *testing.T, port string, delegatorAddr sdk.AccAddress, quer
return txs
}
// GET /stake/delegators/{delegatorAddr}/delegations/{validatorAddr} Query the current delegation between a delegator and a validator
func getDelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.Delegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delegatorAddr, validatorAddr), nil)
// GET /staking/delegators/{delegatorAddr}/delegations/{validatorAddr} Query the current delegation between a delegator and a validator
func getDelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) staking.Delegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/delegations/%s", delegatorAddr, validatorAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bond stake.Delegation
var bond staking.Delegation
err := cdc.UnmarshalJSON([]byte(body), &bond)
require.Nil(t, err)
return bond
}
// GET /stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr} Query all unbonding delegations between a delegator and a validator
func getUndelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil)
// GET /staking/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr} Query all unbonding delegations between a delegator and a validator
func getUnbondingDelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress,
validatorAddr sdk.ValAddress) staking.UnbondingDelegation {
res, body := Request(t, port, "GET",
fmt.Sprintf("/staking/delegators/%s/unbonding_delegations/%s",
delegatorAddr, validatorAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var unbond stake.UnbondingDelegation
var unbond staking.UnbondingDelegation
err := cdc.UnmarshalJSON([]byte(body), &unbond)
require.Nil(t, err)
return unbond
}
// GET /stake/validators Get all validator candidates
func getValidators(t *testing.T, port string) []stake.Validator {
res, body := Request(t, port, "GET", "/stake/validators", nil)
// GET /staking/validators Get all validator candidates
func getValidators(t *testing.T, port string) []staking.Validator {
res, body := Request(t, port, "GET", "/staking/validators", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var validators []stake.Validator
var validators []staking.Validator
err := cdc.UnmarshalJSON([]byte(body), &validators)
require.Nil(t, err)
return validators
}
// GET /stake/validators/{validatorAddr} Query the information from a single validator
func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) stake.Validator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", validatorAddr.String()), nil)
// GET /staking/validators/{validatorAddr} Query the information from a single validator
func getValidator(t *testing.T, port string, validatorAddr sdk.ValAddress) staking.Validator {
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/validators/%s", validatorAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var validator stake.Validator
var validator staking.Validator
err := cdc.UnmarshalJSON([]byte(body), &validator)
require.Nil(t, err)
return validator
}
// GET /stake/validators/{validatorAddr}/delegations Get all delegations from a validator
func getValidatorDelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.Delegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/delegations", validatorAddr.String()), nil)
// GET /staking/validators/{validatorAddr}/delegations Get all delegations from a validator
func getValidatorDelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []staking.Delegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/validators/%s/delegations", validatorAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var delegations []stake.Delegation
var delegations []staking.Delegation
err := cdc.UnmarshalJSON([]byte(body), &delegations)
require.Nil(t, err)
return delegations
}
// GET /stake/validators/{validatorAddr}/unbonding_delegations Get all unbonding delegations from a validator
func getValidatorUnbondingDelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/unbonding_delegations", validatorAddr.String()), nil)
// GET /staking/validators/{validatorAddr}/unbonding_delegations Get all unbonding delegations from a validator
func getValidatorUnbondingDelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []staking.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/validators/%s/unbonding_delegations", validatorAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var ubds []stake.UnbondingDelegation
var ubds []staking.UnbondingDelegation
err := cdc.UnmarshalJSON([]byte(body), &ubds)
require.Nil(t, err)
return ubds
}
// GET /stake/validators/{validatorAddr}/redelegations Get all outgoing redelegations from a validator
func getValidatorRedelegations(t *testing.T, port string, validatorAddr sdk.ValAddress) []stake.Redelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s/redelegations", validatorAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var reds []stake.Redelegation
err := cdc.UnmarshalJSON([]byte(body), &reds)
require.Nil(t, err)
return reds
}
// GET /stake/pool Get the current state of the staking pool
func getStakePool(t *testing.T, port string) stake.Pool {
res, body := Request(t, port, "GET", "/stake/pool", nil)
// GET /staking/pool Get the current state of the staking pool
func getStakingPool(t *testing.T, port string) staking.Pool {
res, body := Request(t, port, "GET", "/staking/pool", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.NotNil(t, body)
var pool stake.Pool
var pool staking.Pool
err := cdc.UnmarshalJSON([]byte(body), &pool)
require.Nil(t, err)
return pool
}
// GET /stake/parameters Get the current staking parameter values
func getStakeParams(t *testing.T, port string) stake.Params {
res, body := Request(t, port, "GET", "/stake/parameters", nil)
// GET /staking/parameters Get the current staking parameter values
func getStakingParams(t *testing.T, port string) staking.Params {
res, body := Request(t, port, "GET", "/staking/parameters", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var params stake.Params
var params staking.Params
err := cdc.UnmarshalJSON([]byte(body), &params)
require.Nil(t, err)
return params
@ -1054,26 +1033,20 @@ func getStakeParams(t *testing.T, port string) stake.Params {
// ICS 22 - Gov
// ----------------------------------------------------------------------
// POST /gov/proposals Submit a proposal
func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, amount int64, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, proposerAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
pr := postProposalReq{
Title: "Test",
Description: "test",
ProposalType: "Text",
Proposer: proposerAddr,
InitialDeposit: sdk.Coins{sdk.NewCoin(stakeTypes.DefaultBondDenom, sdk.NewInt(amount))},
BaseReq: utils.BaseReq{
Name: name,
Password: password,
ChainID: chainID,
AccountNumber: accnum,
Sequence: sequence,
},
InitialDeposit: sdk.Coins{sdk.NewCoin(stakingTypes.DefaultBondDenom, sdk.NewInt(amount))},
BaseReq: baseReq,
}
req, err := cdc.MarshalJSON(pr)
@ -1155,23 +1128,18 @@ func getProposalsFilterStatus(t *testing.T, port string, status gov.ProposalStat
}
// POST /gov/proposals/{proposalId}/deposits Deposit tokens to a proposal
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64, amount int64, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, proposerAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
dr := depositReq{
Depositor: proposerAddr,
Amount: sdk.Coins{sdk.NewCoin(stakeTypes.DefaultBondDenom, sdk.NewInt(amount))},
BaseReq: utils.BaseReq{
Name: name,
Password: password,
ChainID: chainID,
AccountNumber: accnum,
Sequence: sequence,
},
Amount: sdk.Coins{sdk.NewCoin(stakingTypes.DefaultBondDenom, sdk.NewInt(amount))},
BaseReq: baseReq,
}
req, err := cdc.MarshalJSON(dr)
@ -1214,23 +1182,18 @@ func getTally(t *testing.T, port string, proposalID uint64) gov.TallyResult {
}
// POST /gov/proposals/{proposalId}/votes Vote a proposal
func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64) (resultTx ctypes.ResultBroadcastTxCommit) {
func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64, option string, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) {
// get the account to get the sequence
acc := getAccount(t, port, proposerAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", accnum, sequence, fees, nil, false, false)
vr := voteReq{
Voter: proposerAddr,
Option: "Yes",
BaseReq: utils.BaseReq{
Name: name,
Password: password,
ChainID: chainID,
AccountNumber: accnum,
Sequence: sequence,
},
Voter: proposerAddr,
Option: option,
BaseReq: baseReq,
}
req, err := cdc.MarshalJSON(vr)
@ -1292,6 +1255,18 @@ func getVote(t *testing.T, port string, proposalID uint64, voterAddr sdk.AccAddr
return vote
}
// GET /gov/proposals/{proposalId}/proposer
func getProposer(t *testing.T, port string, proposalID uint64) gcutils.Proposer {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/proposer", proposalID), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var proposer gcutils.Proposer
err := cdc.UnmarshalJSON([]byte(body), &proposer)
require.Nil(t, err)
return proposer
}
// GET /gov/parameters/deposit Query governance deposit parameters
func getDepositParam(t *testing.T, port string) gov.DepositParams {
res, body := Request(t, port, "GET", "/gov/parameters/deposit", nil)
@ -1343,16 +1318,13 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.
// TODO: Test this functionality, it is not currently in any of the tests
// POST /slashing/validators/{validatorAddr}/unjail Unjail a jailed validator
func doUnjail(t *testing.T, port, seed, name, password string,
valAddr sdk.ValAddress) (resultTx ctypes.ResultBroadcastTxCommit) {
valAddr sdk.ValAddress, fees sdk.Coins) (resultTx ctypes.ResultBroadcastTxCommit) {
chainID := viper.GetString(client.FlagChainID)
baseReq := utils.NewBaseReq(name, password, "", chainID, "", "", 1, 1, fees, nil, false, false)
ur := unjailReq{utils.BaseReq{
Name: name,
Password: password,
ChainID: chainID,
AccountNumber: 1,
Sequence: 1,
}}
ur := unjailReq{
BaseReq: baseReq,
}
req, err := cdc.MarshalJSON(ur)
require.NoError(t, err)
res, body := Request(t, port, "POST", fmt.Sprintf("/slashing/validators/%s/unjail", valAddr.String()), req)

View File

@ -1,29 +0,0 @@
package lcd
import (
"net/http"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/version"
)
// cli version REST handler endpoint
func CLIVersionRequestHandler(w http.ResponseWriter, r *http.Request) {
v := version.GetVersion()
w.Write([]byte(v))
}
// connected node version REST handler endpoint
func NodeVersionRequestHandler(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
version, err := cliCtx.Query("/app/version", nil)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(version)
}
}

View File

@ -28,7 +28,6 @@ func BlockCommand() *cobra.Command {
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
return cmd
}

View File

@ -1,48 +1,20 @@
package rpc
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/version"
)
const (
// one of the following should be provided to verify the connection
flagGenesis = "genesis"
flagCommit = "commit"
flagValHash = "validator-set"
)
// XXX: remove this when not needed
func todoNotImplemented(_ *cobra.Command, _ []string) error {
return errors.New("todo: Command not yet implemented")
}
// InitClientCommand initializes client commands
func InitClientCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Initialize light client",
RunE: todoNotImplemented,
}
cmd.Flags().StringP(client.FlagChainID, "c", "", "ID of chain we connect to")
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
cmd.Flags().String(flagGenesis, "", "Genesis file to verify header validity")
cmd.Flags().String(flagCommit, "", "File with trusted and signed header")
cmd.Flags().String(flagValHash, "", "Hash of trusted validator set (hex-encoded)")
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
return cmd
}
// Register REST endpoints
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET")
r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET")
r.HandleFunc("/node_info", NodeInfoRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/syncing", NodeSyncingRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/blocks/latest", LatestBlockRequestHandlerFn(cliCtx)).Methods("GET")
@ -50,3 +22,23 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/validatorsets/latest", LatestValidatorSetRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/validatorsets/{height}", ValidatorSetRequestHandlerFn(cliCtx)).Methods("GET")
}
// cli version REST handler endpoint
func CLIVersionRequestHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(fmt.Sprintf("{\"version\": \"%s\"}", version.GetVersion())))
}
// connected node version REST handler endpoint
func NodeVersionRequestHandler(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
version, err := cliCtx.Query("/app/version", nil)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(version)
}
}

View File

@ -32,8 +32,6 @@ func ValidatorCommand() *cobra.Command {
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
return cmd
}

View File

@ -46,8 +46,6 @@ func QueryTxCmd(cdc *codec.Codec) *cobra.Command {
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
return cmd

View File

@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"github.com/cosmos/cosmos-sdk/client"
@ -17,11 +18,16 @@ import (
"github.com/spf13/viper"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
)
const (
flagTags = "tags"
flagAny = "any"
flagTags = "tags"
flagAny = "any"
flagPage = "page"
flagLimit = "limit"
defaultPage = 1
defaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19
)
// default client command to search through tagged transactions
@ -32,7 +38,7 @@ func SearchTxCmd(cdc *codec.Codec) *cobra.Command {
Long: strings.TrimSpace(`
Search for transactions that match exactly the given tags. For example:
$ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>'
$ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>' --page 1 --limit 30
`),
RunE: func(cmd *cobra.Command, args []string) error {
tagsStr := viper.GetString(flagTags)
@ -53,12 +59,18 @@ $ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>'
}
keyValue := strings.Split(tag, ":")
tag = fmt.Sprintf("%s='%s'", keyValue[0], keyValue[1])
if keyValue[0] == types.TxHeightKey {
tag = fmt.Sprintf("%s=%s", keyValue[0], keyValue[1])
} else {
tag = fmt.Sprintf("%s='%s'", keyValue[0], keyValue[1])
}
tmTags = append(tmTags, tag)
}
page := viper.GetInt(flagPage)
limit := viper.GetInt(flagLimit)
cliCtx := context.NewCLIContext().WithCodec(cdc)
txs, err := SearchTxs(cliCtx, cdc, tmTags)
txs, err := SearchTxs(cliCtx, cdc, tmTags, page, limit)
if err != nil {
return err
}
@ -81,22 +93,31 @@ $ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>'
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
cmd.Flags().String(flagTags, "", "tag:value list of tags that must match")
cmd.Flags().Int32(flagPage, defaultPage, "Query a specific page of paginated results")
cmd.Flags().Int32(flagLimit, defaultLimit, "Query number of transactions results per page returned")
cmd.MarkFlagRequired(flagTags)
return cmd
}
// SearchTxs performs a search for transactions for a given set of tags via
// Tendermint RPC. It returns a slice of Info object containing txs and metadata.
// An error is returned if the query fails.
func SearchTxs(cliCtx context.CLIContext, cdc *codec.Codec, tags []string) ([]Info, error) {
func SearchTxs(cliCtx context.CLIContext, cdc *codec.Codec, tags []string, page, limit int) ([]Info, error) {
if len(tags) == 0 {
return nil, errors.New("must declare at least one tag to search")
}
if page <= 0 {
return nil, errors.New("page must greater than 0")
}
if limit <= 0 {
return nil, errors.New("limit must greater than 0")
}
// XXX: implement ANY
query := strings.Join(tags, " AND ")
@ -108,10 +129,7 @@ func SearchTxs(cliCtx context.CLIContext, cdc *codec.Codec, tags []string) ([]In
prove := !cliCtx.TrustNode
// TODO: take these as args
page := 0
perPage := 100
res, err := node.TxSearch(query, prove, page, perPage)
res, err := node.TxSearch(query, prove, page, limit)
if err != nil {
return nil, err
}
@ -153,6 +171,7 @@ func FormatTxResults(cdc *codec.Codec, res []*ctypes.ResultTx) ([]Info, error) {
func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var tags []string
var page, limit int
var txs []Info
err := r.ParseForm()
if err != nil {
@ -164,18 +183,14 @@ func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.
return
}
for key, values := range r.Form {
value, err := url.QueryUnescape(values[0])
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, sdk.AppendMsgToErr("could not decode query value", err.Error()))
return
}
tags, page, limit, err = parseHTTPArgs(r)
tag := fmt.Sprintf("%s='%s'", key, value)
tags = append(tags, tag)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
txs, err = SearchTxs(cliCtx, cdc, tags)
txs, err = SearchTxs(cliCtx, cdc, tags, page, limit)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
@ -184,3 +199,51 @@ func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.
utils.PostProcessResponse(w, cdc, txs, cliCtx.Indent)
}
}
func parseHTTPArgs(r *http.Request) (tags []string, page, limit int, err error) {
tags = make([]string, 0, len(r.Form))
for key, values := range r.Form {
if key == "page" || key == "limit" {
continue
}
var value string
value, err = url.QueryUnescape(values[0])
if err != nil {
return tags, page, limit, err
}
var tag string
if key == types.TxHeightKey {
tag = fmt.Sprintf("%s=%s", key, value)
} else {
tag = fmt.Sprintf("%s='%s'", key, value)
}
tags = append(tags, tag)
}
pageStr := r.FormValue("page")
if pageStr == "" {
page = defaultPage
} else {
page, err = strconv.Atoi(pageStr)
if err != nil {
return tags, page, limit, err
} else if page <= 0 {
return tags, page, limit, errors.New("page must greater than 0")
}
}
limitStr := r.FormValue("limit")
if limitStr == "" {
limit = defaultLimit
} else {
limit, err = strconv.Atoi(limitStr)
if err != nil {
return tags, page, limit, err
} else if limit <= 0 {
return tags, page, limit, errors.New("limit must greater than 0")
}
}
return tags, page, limit, nil
}

View File

@ -101,30 +101,82 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec, txBldr
// BaseReq defines a structure that can be embedded in other request structures
// that all share common "base" fields.
type BaseReq struct {
Name string `json:"name"`
Password string `json:"password"`
ChainID string `json:"chain_id"`
AccountNumber uint64 `json:"account_number"`
Sequence uint64 `json:"sequence"`
Gas string `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
GenerateOnly bool `json:"generate_only"`
Simulate bool `json:"simulate"`
Name string `json:"name"`
Password string `json:"password"`
Memo string `json:"memo"`
ChainID string `json:"chain_id"`
AccountNumber uint64 `json:"account_number"`
Sequence uint64 `json:"sequence"`
Fees sdk.Coins `json:"fees"`
GasPrices sdk.DecCoins `json:"gas_prices"`
Gas string `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
GenerateOnly bool `json:"generate_only"`
Simulate bool `json:"simulate"`
}
// NewBaseReq creates a new basic request instance and sanitizes its values
func NewBaseReq(
name, password, memo, chainID string, gas, gasAdjustment string,
accNumber, seq uint64, fees sdk.Coins, gasPrices sdk.DecCoins, genOnly, simulate bool,
) BaseReq {
return BaseReq{
Name: strings.TrimSpace(name),
Password: password,
Memo: strings.TrimSpace(memo),
ChainID: strings.TrimSpace(chainID),
Fees: fees,
GasPrices: gasPrices,
Gas: strings.TrimSpace(gas),
GasAdjustment: strings.TrimSpace(gasAdjustment),
AccountNumber: accNumber,
Sequence: seq,
GenerateOnly: genOnly,
Simulate: simulate,
}
}
// Sanitize performs basic sanitization on a BaseReq object.
func (br BaseReq) Sanitize() BaseReq {
return BaseReq{
Name: strings.TrimSpace(br.Name),
Password: strings.TrimSpace(br.Password),
ChainID: strings.TrimSpace(br.ChainID),
Gas: strings.TrimSpace(br.Gas),
GasAdjustment: strings.TrimSpace(br.GasAdjustment),
AccountNumber: br.AccountNumber,
Sequence: br.Sequence,
GenerateOnly: br.GenerateOnly,
Simulate: br.Simulate,
return NewBaseReq(
br.Name, br.Password, br.Memo, br.ChainID, br.Gas, br.GasAdjustment,
br.AccountNumber, br.Sequence, br.Fees, br.GasPrices, br.GenerateOnly, br.Simulate,
)
}
// ValidateBasic performs basic validation of a BaseReq. If custom validation
// logic is needed, the implementing request handler should perform those
// checks manually.
func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool {
if !br.GenerateOnly && !br.Simulate {
switch {
case len(br.Password) == 0:
WriteErrorResponse(w, http.StatusUnauthorized, "password required but not specified")
return false
case len(br.ChainID) == 0:
WriteErrorResponse(w, http.StatusUnauthorized, "chain-id required but not specified")
return false
case !br.Fees.IsZero() && !br.GasPrices.IsZero():
// both fees and gas prices were provided
WriteErrorResponse(w, http.StatusBadRequest, "cannot provide both fees and gas prices")
return false
case !br.Fees.IsValid() && !br.GasPrices.IsValid():
// neither fees or gas prices were provided
WriteErrorResponse(w, http.StatusPaymentRequired, "invalid fees or gas prices provided")
return false
}
}
if len(br.Name) == 0 {
WriteErrorResponse(w, http.StatusUnauthorized, "name required but not specified")
return false
}
return true
}
/*
@ -149,34 +201,13 @@ func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req i
err = cdc.UnmarshalJSON(body, req)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to decode JSON payload: %s", err))
return err
}
return nil
}
// ValidateBasic performs basic validation of a BaseReq. If custom validation
// logic is needed, the implementing request handler should perform those
// checks manually.
func (br BaseReq) ValidateBasic(w http.ResponseWriter, cliCtx context.CLIContext) bool {
if !cliCtx.GenerateOnly && !cliCtx.Simulate {
switch {
case len(br.Password) == 0:
WriteErrorResponse(w, http.StatusUnauthorized, "password required but not specified")
return false
case len(br.ChainID) == 0:
WriteErrorResponse(w, http.StatusUnauthorized, "chain-id required but not specified")
return false
}
}
if len(br.Name) == 0 {
WriteErrorResponse(w, http.StatusUnauthorized, "name required but not specified")
return false
}
return true
}
// CompleteAndBroadcastTxREST implements a utility function that facilitates
// sending a series of messages in a signed transaction given a TxBuilder and a
// QueryContext. It ensures that the account exists, has a proper number and
@ -185,41 +216,44 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter, cliCtx context.CLIContext
//
// NOTE: Also see CompleteAndBroadcastTxCli.
// NOTE: Also see x/stake/client/rest/tx.go delegationsRequestHandlerFn.
func CompleteAndBroadcastTxREST(w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext, baseReq BaseReq, msgs []sdk.Msg, cdc *codec.Codec) {
simulateGas, gas, err := client.ReadGasFlag(baseReq.Gas)
func CompleteAndBroadcastTxREST(
w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext,
baseReq BaseReq, msgs []sdk.Msg, cdc *codec.Codec,
) {
gasAdjustment, ok := ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
simulateAndExecute, gas, err := client.ParseGas(baseReq.Gas)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
adjustment, ok := ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
txBldr := authtxb.NewTxBuilder(
GetTxEncoder(cdc), baseReq.AccountNumber,
baseReq.Sequence, gas, gasAdjustment, baseReq.Simulate,
baseReq.ChainID, baseReq.Memo, baseReq.Fees, baseReq.GasPrices,
)
txBldr := authtxb.TxBuilder{
TxEncoder: GetTxEncoder(cdc),
Gas: gas,
GasAdjustment: adjustment,
SimulateGas: simulateGas,
ChainID: baseReq.ChainID,
AccountNumber: baseReq.AccountNumber,
Sequence: baseReq.Sequence,
}
if baseReq.Simulate || simulateAndExecute {
if gasAdjustment < 0 {
WriteErrorResponse(w, http.StatusBadRequest, "gas adjustment must be a positive float")
return
}
if baseReq.Simulate || txBldr.SimulateGas {
newBldr, err := EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, msgs)
txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, msgs)
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if baseReq.Simulate {
WriteSimulationResponse(w, newBldr.Gas)
WriteSimulationResponse(w, txBldr.GetGas())
return
}
txBldr = newBldr
}
if baseReq.GenerateOnly {

View File

@ -3,10 +3,11 @@ package utils
import (
"bytes"
"fmt"
"github.com/cosmos/cosmos-sdk/codec"
"io"
"os"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/libs/common"
@ -35,12 +36,12 @@ func CompleteAndBroadcastTxCli(txBldr authtxb.TxBuilder, cliCtx context.CLIConte
return err
}
if txBldr.SimulateGas || cliCtx.Simulate {
if txBldr.GetSimulateAndExecute() || cliCtx.Simulate {
txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs)
if err != nil {
return err
}
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.Gas)
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.GetGas())
}
if cliCtx.Simulate {
return nil
@ -56,6 +57,7 @@ func CompleteAndBroadcastTxCli(txBldr authtxb.TxBuilder, cliCtx context.CLIConte
if err != nil {
return err
}
// broadcast to a Tendermint node
_, err = cliCtx.BroadcastTx(txBytes)
return err
@ -131,20 +133,12 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
"The generated transaction's intended signer does not match the given signer: %q", name)
}
if !offline && txBldr.AccountNumber == 0 {
accNum, err := cliCtx.GetAccountNumber(addr)
if !offline {
txBldr, err = populateAccountFromState(
txBldr, cliCtx, sdk.AccAddress(addr))
if err != nil {
return signedStdTx, err
}
txBldr = txBldr.WithAccountNumber(accNum)
}
if !offline && txBldr.Sequence == 0 {
accSeq, err := cliCtx.GetAccountSequence(addr)
if err != nil {
return signedStdTx, err
}
txBldr = txBldr.WithSequence(accSeq)
}
passphrase, err := keys.GetPassphrase(name)
@ -155,6 +149,55 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
return txBldr.SignStdTx(name, passphrase, stdTx, appendSig)
}
// SignStdTxWithSignerAddress attaches a signature to a StdTx and returns a copy of a it.
// Don't perform online validation or lookups if offline is true, else
// populate account and sequence numbers from a foreign account.
func SignStdTxWithSignerAddress(txBldr authtxb.TxBuilder, cliCtx context.CLIContext,
addr sdk.AccAddress, name string, stdTx auth.StdTx,
offline bool) (signedStdTx auth.StdTx, err error) {
// check whether the address is a signer
if !isTxSigner(addr, stdTx.GetSigners()) {
return signedStdTx, fmt.Errorf(
"The generated transaction's intended signer does not match the given signer: %q", name)
}
if !offline {
txBldr, err = populateAccountFromState(txBldr, cliCtx, addr)
if err != nil {
return signedStdTx, err
}
}
passphrase, err := keys.GetPassphrase(name)
if err != nil {
return signedStdTx, err
}
return txBldr.SignStdTx(name, passphrase, stdTx, false)
}
func populateAccountFromState(txBldr authtxb.TxBuilder, cliCtx context.CLIContext,
addr sdk.AccAddress) (authtxb.TxBuilder, error) {
if txBldr.GetAccountNumber() == 0 {
accNum, err := cliCtx.GetAccountNumber(addr)
if err != nil {
return txBldr, err
}
txBldr = txBldr.WithAccountNumber(accNum)
}
if txBldr.GetSequence() == 0 {
accSeq, err := cliCtx.GetAccountSequence(addr)
if err != nil {
return txBldr, err
}
txBldr = txBldr.WithSequence(accSeq)
}
return txBldr, nil
}
// GetTxEncoder return tx encoder from global sdk configuration if ones is defined.
// Otherwise returns encoder with default logic.
func GetTxEncoder(cdc *codec.Codec) (encoder sdk.TxEncoder) {
@ -172,7 +215,7 @@ func simulateMsgs(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name stri
if err != nil {
return
}
estimated, adjusted, err = CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, txBldr.GasAdjustment)
estimated, adjusted, err = CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, txBldr.GetGasAdjustment())
return
}
@ -200,7 +243,7 @@ func prepareTxBuilder(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (auth
// TODO: (ref #1903) Allow for user supplied account number without
// automatically doing a manual lookup.
if txBldr.AccountNumber == 0 {
if txBldr.GetAccountNumber() == 0 {
accNum, err := cliCtx.GetAccountNumber(from)
if err != nil {
return txBldr, err
@ -210,7 +253,7 @@ func prepareTxBuilder(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (auth
// TODO: (ref #1903) Allow for user supplied account sequence without
// automatically doing a manual lookup.
if txBldr.Sequence == 0 {
if txBldr.GetSequence() == 0 {
accSeq, err := cliCtx.GetAccountSequence(from)
if err != nil {
return txBldr, err
@ -231,7 +274,7 @@ func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg
}
func buildUnsignedStdTxOffline(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) {
if txBldr.SimulateGas {
if txBldr.GetSimulateAndExecute() {
var name string
name, err = cliCtx.GetFromName()
if err != nil {
@ -242,7 +285,7 @@ func buildUnsignedStdTxOffline(txBldr authtxb.TxBuilder, cliCtx context.CLIConte
if err != nil {
return
}
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.Gas)
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.GetGas())
}
stdSignMsg, err := txBldr.Build(msgs)
if err != nil {

View File

@ -3,11 +3,13 @@ package utils
import (
"encoding/json"
"errors"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth"
"testing"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
"testing"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/stretchr/testify/assert"
"github.com/tendermint/tendermint/libs/common"

View File

@ -1,162 +0,0 @@
package cmd
import (
"fmt"
"go/build"
"io/ioutil"
"os"
"strings"
"path/filepath"
"github.com/spf13/cobra"
tmversion "github.com/tendermint/tendermint/version"
"github.com/cosmos/cosmos-sdk/version"
)
var remoteBasecoinPath = "github.com/cosmos/cosmos-sdk/docs/examples/basecoin"
// Replacer to replace all instances of basecoin/basecli/BasecoinApp to project specific names
// Gets initialized when initCmd is executing after getting the project name from user
var replacer *strings.Replacer
// Remote path for the project.
var remoteProjectPath string
func init() {
initCmd.Flags().StringVarP(&remoteProjectPath, "project-path", "p", "", "Remote project path. eg: github.com/your_user_name/project_name")
rootCmd.AddCommand(initCmd)
}
var initCmd = &cobra.Command{
Use: "init [ProjectName]",
Short: "Initialize your new cosmos zone",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Print("Thanks for choosing Cosmos-SDK to build your project.\n\n")
projectName := args[0]
capitalizedProjectName := strings.Title(projectName)
shortProjectName := strings.ToLower(projectName)
remoteProjectPath = strings.ToLower(strings.TrimSpace(remoteProjectPath))
if remoteProjectPath == "" {
remoteProjectPath = strings.ToLower(shortProjectName)
}
replacer = strings.NewReplacer("basecli", shortProjectName+"cli",
"basecoind", shortProjectName+"d",
"BasecoinApp", capitalizedProjectName+"App",
remoteBasecoinPath, remoteProjectPath,
"basecoin", shortProjectName,
"Basecoin", capitalizedProjectName)
return setupBasecoinWorkspace(shortProjectName, remoteProjectPath)
},
}
func resolveProjectPath(remoteProjectPath string) string {
gopath := os.Getenv("GOPATH")
if gopath == "" {
gopath = build.Default.GOPATH
// Use $HOME/go
}
return gopath + string(os.PathSeparator) + "src" + string(os.PathSeparator) + remoteProjectPath
}
// nolint: unparam, errcheck
func copyBasecoinTemplate(projectName string, projectPath string, remoteProjectPath string) {
basecoinProjectPath := resolveProjectPath(remoteBasecoinPath)
filepath.Walk(basecoinProjectPath, func(path string, f os.FileInfo, err error) error {
if !f.IsDir() {
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
contents := string(data)
// Extract relative file path eg: app/app.go instead of /Users/..../github.com/cosmos/...examples/basecoin/app/app.go
relativeFilePath := path[len(basecoinProjectPath)+1:]
// Evaluating the filepath in the new project folder
projectFilePath := projectPath + string(os.PathSeparator) + relativeFilePath
projectFilePath = replacer.Replace(projectFilePath)
lengthOfRootDir := strings.LastIndex(projectFilePath, string(os.PathSeparator))
// Extracting the path of root directory from the filepath
rootDir := projectFilePath[0:lengthOfRootDir]
// Creating the required directory first
os.MkdirAll(rootDir, os.ModePerm)
fmt.Println("Creating " + projectFilePath)
// Writing the contents to a file in the project folder
contents = replacer.Replace(contents)
ioutil.WriteFile(projectFilePath, []byte(contents), os.ModePerm)
}
return nil
})
}
// nolint: errcheck
func createGopkg(projectPath string) {
// Create gopkg.toml file
dependencies := map[string]string{
"github.com/cosmos/cosmos-sdk": "=" + version.Version,
"github.com/stretchr/testify": "=1.2.1",
"github.com/spf13/cobra": "=0.0.1",
"github.com/spf13/viper": "=1.0.0",
}
overrides := map[string]string{
"github.com/golang/protobuf": "1.1.0",
"github.com/tendermint/tendermint": tmversion.Version,
}
contents := ""
for dependency, version := range dependencies {
contents += "[[constraint]]\n\tname = \"" + dependency + "\"\n\tversion = \"" + version + "\"\n\n"
}
for dependency, version := range overrides {
contents += "[[override]]\n\tname = \"" + dependency + "\"\n\tversion = \"=" + version + "\"\n\n"
}
contents += "[prune]\n\tgo-tests = true\n\tunused-packages = true"
ioutil.WriteFile(projectPath+"/Gopkg.toml", []byte(contents), os.ModePerm)
}
// nolint: errcheck
func createMakefile(projectPath string) {
// Create makefile
// TODO: Should we use tools/ directory as in Cosmos-SDK to get tools for linting etc.
makefileContents := `PACKAGES=$(shell go list ./... | grep -v '/vendor/')
all: get_tools get_vendor_deps build test
get_tools:
go get github.com/golang/dep/cmd/dep
build:
go build -o bin/basecli cmd/basecli/main.go && go build -o bin/basecoind cmd/basecoind/main.go
get_vendor_deps:
@rm -rf vendor/
@dep ensure
test:
@go test $(PACKAGES)
benchmark:
@go test -bench=. $(PACKAGES)
.PHONY: all build test benchmark`
// Replacing instances of base* to project specific names
makefileContents = replacer.Replace(makefileContents)
ioutil.WriteFile(projectPath+"/Makefile", []byte(makefileContents), os.ModePerm)
}
func setupBasecoinWorkspace(projectName string, remoteProjectPath string) error {
projectPath := resolveProjectPath(remoteProjectPath)
fmt.Println("Configuring your project in " + projectPath)
// Check if the projectPath already exists or not
if _, err := os.Stat(projectPath); !os.IsNotExist(err) {
return fmt.Errorf("Unable to initialize the project. %s already exists", projectPath)
}
copyBasecoinTemplate(projectName, projectPath, remoteProjectPath)
createGopkg(projectPath)
createMakefile(projectPath)
fmt.Printf("Initialized a new project at %s.\nHappy hacking!\n", projectPath)
return nil
}

View File

@ -1,21 +0,0 @@
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "cosmos-sdk-cli",
Short: "Tools to develop on cosmos-sdk",
}
// Execute the command
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

View File

@ -1,9 +0,0 @@
package main
import (
"github.com/cosmos/cosmos-sdk/cmd/cosmos-sdk-cli/cmd"
)
func main() {
cmd.Execute()
}

View File

@ -21,7 +21,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/staking"
)
const (
@ -44,8 +44,8 @@ type GaiaApp struct {
// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
keyStake *sdk.KVStoreKey
tkeyStake *sdk.TransientStoreKey
keyStaking *sdk.KVStoreKey
tkeyStaking *sdk.TransientStoreKey
keySlashing *sdk.KVStoreKey
keyMint *sdk.KVStoreKey
keyDistr *sdk.KVStoreKey
@ -59,7 +59,7 @@ type GaiaApp struct {
accountKeeper auth.AccountKeeper
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
stakeKeeper stake.Keeper
stakingKeeper staking.Keeper
slashingKeeper slashing.Keeper
mintKeeper mint.Keeper
distrKeeper distr.Keeper
@ -77,25 +77,28 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
var app = &GaiaApp{
BaseApp: bApp,
cdc: cdc,
keyMain: sdk.NewKVStoreKey("main"),
keyAccount: sdk.NewKVStoreKey("acc"),
keyStake: sdk.NewKVStoreKey("stake"),
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
keyMint: sdk.NewKVStoreKey("mint"),
keyDistr: sdk.NewKVStoreKey("distr"),
tkeyDistr: sdk.NewTransientStoreKey("transient_distr"),
keySlashing: sdk.NewKVStoreKey("slashing"),
keyGov: sdk.NewKVStoreKey("gov"),
keyFeeCollection: sdk.NewKVStoreKey("fee"),
keyParams: sdk.NewKVStoreKey("params"),
tkeyParams: sdk.NewTransientStoreKey("transient_params"),
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
keyMint: sdk.NewKVStoreKey(mint.StoreKey),
keyDistr: sdk.NewKVStoreKey(distr.StoreKey),
tkeyDistr: sdk.NewTransientStoreKey(distr.TStoreKey),
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
keyGov: sdk.NewKVStoreKey(gov.StoreKey),
keyFeeCollection: sdk.NewKVStoreKey(auth.FeeStoreKey),
keyParams: sdk.NewKVStoreKey(params.StoreKey),
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
}
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams)
// define the accountKeeper
app.accountKeeper = auth.NewAccountKeeper(
app.cdc,
app.keyAccount, // target store
auth.ProtoBaseAccount, // prototype
app.keyAccount,
app.paramsKeeper.Subspace(auth.DefaultParamspace),
auth.ProtoBaseAccount,
)
// add handlers
@ -104,67 +107,64 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
app.cdc,
app.keyFeeCollection,
)
app.paramsKeeper = params.NewKeeper(
stakingKeeper := staking.NewKeeper(
app.cdc,
app.keyParams, app.tkeyParams,
)
stakeKeeper := stake.NewKeeper(
app.cdc,
app.keyStake, app.tkeyStake,
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
stake.DefaultCodespace,
app.keyStaking, app.tkeyStaking,
app.bankKeeper, app.paramsKeeper.Subspace(staking.DefaultParamspace),
staking.DefaultCodespace,
)
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint,
app.paramsKeeper.Subspace(mint.DefaultParamspace),
&stakeKeeper, app.feeCollectionKeeper,
&stakingKeeper, app.feeCollectionKeeper,
)
app.distrKeeper = distr.NewKeeper(
app.cdc,
app.keyDistr,
app.paramsKeeper.Subspace(distr.DefaultParamspace),
app.bankKeeper, &stakeKeeper, app.feeCollectionKeeper,
app.bankKeeper, &stakingKeeper, app.feeCollectionKeeper,
distr.DefaultCodespace,
)
app.slashingKeeper = slashing.NewKeeper(
app.cdc,
app.keySlashing,
&stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
&stakingKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
slashing.DefaultCodespace,
)
app.govKeeper = gov.NewKeeper(
app.cdc,
app.keyGov,
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakeKeeper,
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakingKeeper,
gov.DefaultCodespace,
)
// register the staking hooks
// NOTE: The stakeKeeper above is passed by reference, so that it can be
// NOTE: The stakingKeeper above is passed by reference, so that it can be
// modified like below:
app.stakeKeeper = *stakeKeeper.SetHooks(
app.stakingKeeper = *stakingKeeper.SetHooks(
NewStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()),
)
// register message routes
app.Router().
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("stake", stake.NewHandler(app.stakeKeeper)).
AddRoute("distr", distr.NewHandler(app.distrKeeper)).
AddRoute("slashing", slashing.NewHandler(app.slashingKeeper)).
AddRoute("gov", gov.NewHandler(app.govKeeper))
AddRoute(bank.RouterKey, bank.NewHandler(app.bankKeeper)).
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)).
AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)).
AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)).
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper))
app.QueryRouter().
AddRoute("gov", gov.NewQuerier(app.govKeeper)).
AddRoute(distr.QuerierRoute, distr.NewQuerier(app.distrKeeper)).
AddRoute(gov.QuerierRoute, gov.NewQuerier(app.govKeeper)).
AddRoute(slashing.QuerierRoute, slashing.NewQuerier(app.slashingKeeper, app.cdc)).
AddRoute("stake", stake.NewQuerier(app.stakeKeeper, app.cdc))
AddRoute(staking.QuerierRoute, staking.NewQuerier(app.stakingKeeper, app.cdc))
// initialize BaseApp
app.MountStores(app.keyMain, app.keyAccount, app.keyStake, app.keyMint, app.keyDistr,
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint, app.keyDistr,
app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams)
app.SetInitChainer(app.initChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper))
app.MountStoresTransient(app.tkeyParams, app.tkeyStake, app.tkeyDistr)
app.MountStoresTransient(app.tkeyParams, app.tkeyStaking, app.tkeyDistr)
app.SetEndBlocker(app.EndBlocker)
if loadLatest {
@ -181,7 +181,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
func MakeCodec() *codec.Codec {
var cdc = codec.New()
bank.RegisterCodec(cdc)
stake.RegisterCodec(cdc)
staking.RegisterCodec(cdc)
distr.RegisterCodec(cdc)
slashing.RegisterCodec(cdc)
gov.RegisterCodec(cdc)
@ -193,7 +193,6 @@ func MakeCodec() *codec.Codec {
// application updates every end block
func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
// mint new tokens for the previous block
mint.BeginBlocker(ctx, app.mintKeeper)
@ -215,9 +214,8 @@ func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) ab
// application updates every end block
// nolint: unparam
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
tags := gov.EndBlocker(ctx, app.govKeeper)
validatorUpdates, endBlockerTags := stake.EndBlocker(ctx, app.stakeKeeper)
validatorUpdates, endBlockerTags := staking.EndBlocker(ctx, app.stakingKeeper)
tags = append(tags, endBlockerTags...)
app.assertRuntimeInvariants()
@ -234,25 +232,28 @@ func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisSt
sort.Slice(genesisState.Accounts, func(i, j int) bool {
return genesisState.Accounts[i].AccountNumber < genesisState.Accounts[j].AccountNumber
})
// load the accounts
for _, gacc := range genesisState.Accounts {
acc := gacc.ToAccount()
acc.AccountNumber = app.accountKeeper.GetNextAccountNumber(ctx)
acc = app.accountKeeper.NewAccount(ctx, acc) // set account number
app.accountKeeper.SetAccount(ctx, acc)
}
// load the initial stake information
validators, err := stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
// initialize distribution (must happen before staking)
distr.InitGenesis(ctx, app.distrKeeper, genesisState.DistrData)
// load the initial staking information
validators, err := staking.InitGenesis(ctx, app.stakingKeeper, genesisState.StakingData)
if err != nil {
panic(err) // TODO find a way to do this w/o panics
}
// initialize module-specific stores
auth.InitGenesis(ctx, app.feeCollectionKeeper, genesisState.AuthData)
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
auth.InitGenesis(ctx, app.accountKeeper, app.feeCollectionKeeper, genesisState.AuthData)
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakingData)
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
distr.InitGenesis(ctx, app.distrKeeper, genesisState.DistrData)
// validate genesis state
err = GaiaValidateGenesisState(genesisState)
@ -274,7 +275,7 @@ func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisSt
}
}
validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
validators = app.stakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
}
return validators
}
@ -337,39 +338,47 @@ func NewStakingHooks(dh distr.Hooks, sh slashing.Hooks) StakingHooks {
}
// nolint
func (h StakingHooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
h.dh.OnValidatorCreated(ctx, valAddr)
h.sh.OnValidatorCreated(ctx, valAddr)
func (h StakingHooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
h.dh.AfterValidatorCreated(ctx, valAddr)
h.sh.AfterValidatorCreated(ctx, valAddr)
}
func (h StakingHooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
h.dh.OnValidatorModified(ctx, valAddr)
h.sh.OnValidatorModified(ctx, valAddr)
func (h StakingHooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
h.dh.BeforeValidatorModified(ctx, valAddr)
h.sh.BeforeValidatorModified(ctx, valAddr)
}
func (h StakingHooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.OnValidatorRemoved(ctx, consAddr, valAddr)
h.sh.OnValidatorRemoved(ctx, consAddr, valAddr)
func (h StakingHooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.AfterValidatorRemoved(ctx, consAddr, valAddr)
h.sh.AfterValidatorRemoved(ctx, consAddr, valAddr)
}
func (h StakingHooks) OnValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.OnValidatorBonded(ctx, consAddr, valAddr)
h.sh.OnValidatorBonded(ctx, consAddr, valAddr)
func (h StakingHooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.AfterValidatorBonded(ctx, consAddr, valAddr)
h.sh.AfterValidatorBonded(ctx, consAddr, valAddr)
}
func (h StakingHooks) OnValidatorPowerDidChange(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.OnValidatorPowerDidChange(ctx, consAddr, valAddr)
h.sh.OnValidatorPowerDidChange(ctx, consAddr, valAddr)
func (h StakingHooks) AfterValidatorPowerDidChange(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.AfterValidatorPowerDidChange(ctx, consAddr, valAddr)
h.sh.AfterValidatorPowerDidChange(ctx, consAddr, valAddr)
}
func (h StakingHooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.OnValidatorBeginUnbonding(ctx, consAddr, valAddr)
h.sh.OnValidatorBeginUnbonding(ctx, consAddr, valAddr)
func (h StakingHooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.AfterValidatorBeginUnbonding(ctx, consAddr, valAddr)
h.sh.AfterValidatorBeginUnbonding(ctx, consAddr, valAddr)
}
func (h StakingHooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.OnDelegationCreated(ctx, delAddr, valAddr)
h.sh.OnDelegationCreated(ctx, delAddr, valAddr)
func (h StakingHooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.BeforeDelegationCreated(ctx, delAddr, valAddr)
h.sh.BeforeDelegationCreated(ctx, delAddr, valAddr)
}
func (h StakingHooks) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.OnDelegationSharesModified(ctx, delAddr, valAddr)
h.sh.OnDelegationSharesModified(ctx, delAddr, valAddr)
func (h StakingHooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.BeforeDelegationSharesModified(ctx, delAddr, valAddr)
h.sh.BeforeDelegationSharesModified(ctx, delAddr, valAddr)
}
func (h StakingHooks) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.OnDelegationRemoved(ctx, delAddr, valAddr)
h.sh.OnDelegationRemoved(ctx, delAddr, valAddr)
func (h StakingHooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.BeforeDelegationRemoved(ctx, delAddr, valAddr)
h.sh.BeforeDelegationRemoved(ctx, delAddr, valAddr)
}
func (h StakingHooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.AfterDelegationModified(ctx, delAddr, valAddr)
h.sh.AfterDelegationModified(ctx, delAddr, valAddr)
}
func (h StakingHooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) {
h.dh.BeforeValidatorSlashed(ctx, valAddr, fraction)
h.sh.BeforeValidatorSlashed(ctx, valAddr, fraction)
}

View File

@ -14,7 +14,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/staking"
abci "github.com/tendermint/tendermint/abci/types"
)
@ -28,7 +28,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
genesisState := NewGenesisState(
genaccs,
auth.DefaultGenesisState(),
stake.DefaultGenesisState(),
staking.DefaultGenesisState(),
mint.DefaultGenesisState(),
distr.DefaultGenesisState(),
gov.DefaultGenesisState(),

View File

@ -22,12 +22,12 @@ func ExampleTxSendSize() {
addr1 := sdk.AccAddress(priv1.PubKey().Address())
priv2 := secp256k1.GenPrivKeySecp256k1([]byte{1})
addr2 := sdk.AccAddress(priv2.PubKey().Address())
coins := []sdk.Coin{sdk.NewCoin("denom", sdk.NewInt(10))}
coins := sdk.Coins{sdk.NewCoin("denom", sdk.NewInt(10))}
msg1 := bank.MsgSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
fee := auth.NewStdFee(gas, coins...)
fee := auth.NewStdFee(gas, coins)
signBytes := auth.StdSignBytes("example-chain-ID",
1, 1, fee, []sdk.Msg{msg1}, "")
sig, _ := priv1.Sign(signBytes)

View File

@ -2,7 +2,6 @@ package app
import (
"encoding/json"
"fmt"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
@ -14,7 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/slashing"
stake "github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/staking"
)
// export the state of gaia for a genesis file
@ -39,8 +38,8 @@ func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool) (
genState := NewGenesisState(
accounts,
auth.ExportGenesis(ctx, app.feeCollectionKeeper),
stake.ExportGenesis(ctx, app.stakeKeeper),
auth.ExportGenesis(ctx, app.accountKeeper, app.feeCollectionKeeper),
staking.ExportGenesis(ctx, app.stakingKeeper),
mint.ExportGenesis(ctx, app.mintKeeper),
distr.ExportGenesis(ctx, app.distrKeeper),
gov.ExportGenesis(ctx, app.govKeeper),
@ -50,7 +49,7 @@ func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool) (
if err != nil {
return nil, nil, err
}
validators = stake.WriteValidators(ctx, app.stakeKeeper)
validators = staking.WriteValidators(ctx, app.stakingKeeper)
return appState, validators, nil
}
@ -62,83 +61,95 @@ func (app *GaiaApp) prepForZeroHeightGenesis(ctx sdk.Context) {
/* Handle fee distribution state. */
// withdraw all delegator & validator rewards
vdiIter := func(_ int64, valInfo distr.ValidatorDistInfo) (stop bool) {
err := app.distrKeeper.WithdrawValidatorRewardsAll(ctx, valInfo.OperatorAddr)
if err != nil {
panic(err)
}
return false
}
app.distrKeeper.IterateValidatorDistInfos(ctx, vdiIter)
ddiIter := func(_ int64, distInfo distr.DelegationDistInfo) (stop bool) {
err := app.distrKeeper.WithdrawDelegationReward(
ctx, distInfo.DelegatorAddr, distInfo.ValOperatorAddr)
if err != nil {
panic(err)
}
return false
}
app.distrKeeper.IterateDelegationDistInfos(ctx, ddiIter)
app.assertRuntimeInvariantsOnContext(ctx)
// set distribution info withdrawal heights to 0
app.distrKeeper.IterateDelegationDistInfos(ctx, func(_ int64, delInfo distr.DelegationDistInfo) (stop bool) {
delInfo.DelPoolWithdrawalHeight = 0
app.distrKeeper.SetDelegationDistInfo(ctx, delInfo)
return false
})
app.distrKeeper.IterateValidatorDistInfos(ctx, func(_ int64, valInfo distr.ValidatorDistInfo) (stop bool) {
valInfo.FeePoolWithdrawalHeight = 0
app.distrKeeper.SetValidatorDistInfo(ctx, valInfo)
// withdraw all validator commission
app.stakingKeeper.IterateValidators(ctx, func(_ int64, val sdk.Validator) (stop bool) {
_ = app.distrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator())
return false
})
// assert that the fee pool is empty
feePool := app.distrKeeper.GetFeePool(ctx)
if !feePool.TotalValAccum.Accum.IsZero() {
panic("unexpected leftover validator accum")
}
bondDenom := app.stakeKeeper.GetParams(ctx).BondDenom
if !feePool.ValPool.AmountOf(bondDenom).IsZero() {
panic(fmt.Sprintf("unexpected leftover validator pool coins: %v",
feePool.ValPool.AmountOf(bondDenom).String()))
// withdraw all delegator rewards
dels := app.stakingKeeper.GetAllDelegations(ctx)
for _, delegation := range dels {
_ = app.distrKeeper.WithdrawDelegationRewards(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
}
// reset fee pool height, save fee pool
feePool.TotalValAccum = distr.NewTotalAccum(0)
app.distrKeeper.SetFeePool(ctx, feePool)
// clear validator slash events
app.distrKeeper.DeleteAllValidatorSlashEvents(ctx)
/* Handle stake state. */
// clear validator historical rewards
app.distrKeeper.DeleteAllValidatorHistoricalRewards(ctx)
// iterate through validators by power descending, reset bond height, update bond intra-tx counter
store := ctx.KVStore(app.keyStake)
iter := sdk.KVStoreReversePrefixIterator(store, stake.ValidatorsByPowerIndexKey)
// set context height to zero
height := ctx.BlockHeight()
ctx = ctx.WithBlockHeight(0)
// reinitialize all validators
app.stakingKeeper.IterateValidators(ctx, func(_ int64, val sdk.Validator) (stop bool) {
app.distrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator())
return false
})
// reinitialize all delegations
for _, del := range dels {
app.distrKeeper.Hooks().BeforeDelegationCreated(ctx, del.DelegatorAddr, del.ValidatorAddr)
}
// reset context height
ctx = ctx.WithBlockHeight(height)
/* Handle staking state. */
// iterate through redelegations, reset creation height
app.stakingKeeper.IterateRedelegations(ctx, func(_ int64, red staking.Redelegation) (stop bool) {
for i := range red.Entries {
red.Entries[i].CreationHeight = 0
}
app.stakingKeeper.SetRedelegation(ctx, red)
return false
})
// iterate through unbonding delegations, reset creation height
app.stakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd staking.UnbondingDelegation) (stop bool) {
for i := range ubd.Entries {
ubd.Entries[i].CreationHeight = 0
}
app.stakingKeeper.SetUnbondingDelegation(ctx, ubd)
return false
})
// Iterate through validators by power descending, reset bond heights, and
// update bond intra-tx counters.
store := ctx.KVStore(app.keyStaking)
iter := sdk.KVStoreReversePrefixIterator(store, staking.ValidatorsKey)
counter := int16(0)
var valConsAddrs []sdk.ConsAddress
for ; iter.Valid(); iter.Next() {
addr := sdk.ValAddress(iter.Value())
validator, found := app.stakeKeeper.GetValidator(ctx, addr)
addr := sdk.ValAddress(iter.Key()[1:])
validator, found := app.stakingKeeper.GetValidator(ctx, addr)
if !found {
panic("expected validator, not found")
}
validator.BondHeight = 0
validator.UnbondingHeight = 0
app.stakeKeeper.SetValidator(ctx, validator)
valConsAddrs = append(valConsAddrs, validator.ConsAddress())
app.stakingKeeper.SetValidator(ctx, validator)
counter++
}
iter.Close()
/* Handle slashing state. */
// we have to clear the slashing periods, since they reference heights
app.slashingKeeper.DeleteValidatorSlashingPeriods(ctx)
// reset start height on signing infos
app.slashingKeeper.IterateValidatorSigningInfos(ctx, func(addr sdk.ConsAddress, info slashing.ValidatorSigningInfo) (stop bool) {
info.StartHeight = 0
app.slashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
return false
})
app.slashingKeeper.IterateValidatorSigningInfos(
ctx,
func(addr sdk.ConsAddress, info slashing.ValidatorSigningInfo) (stop bool) {
info.StartHeight = 0
app.slashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
return false
},
)
}

View File

@ -19,22 +19,22 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
var (
// bonded tokens given to genesis validators/accounts
freeFermionVal = int64(100)
freeFermionsAcc = sdk.NewInt(150)
bondDenom = stakeTypes.DefaultBondDenom
bondDenom = stakingTypes.DefaultBondDenom
)
// State to Unmarshal
type GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
AuthData auth.GenesisState `json:"auth"`
StakeData stake.GenesisState `json:"stake"`
StakingData staking.GenesisState `json:"staking"`
MintData mint.GenesisState `json:"mint"`
DistrData distr.GenesisState `json:"distr"`
GovData gov.GenesisState `json:"gov"`
@ -43,14 +43,14 @@ type GenesisState struct {
}
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
stakeData stake.GenesisState, mintData mint.GenesisState,
stakingData staking.GenesisState, mintData mint.GenesisState,
distrData distr.GenesisState, govData gov.GenesisState,
slashingData slashing.GenesisState) GenesisState {
return GenesisState{
Accounts: accounts,
AuthData: authData,
StakeData: stakeData,
StakingData: stakingData,
MintData: mintData,
DistrData: distrData,
GovData: govData,
@ -58,12 +58,19 @@ func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
}
}
// nolint
// GenesisAccount defines an account initialized at genesis.
type GenesisAccount struct {
Address sdk.AccAddress `json:"address"`
Coins sdk.Coins `json:"coins"`
Sequence uint64 `json:"sequence_number"`
AccountNumber uint64 `json:"account_number"`
// vesting account fields
OriginalVesting sdk.Coins `json:"original_vesting"` // total vesting coins upon initialization
DelegatedFree sdk.Coins `json:"delegated_free"` // delegated vested coins at time of delegation
DelegatedVesting sdk.Coins `json:"delegated_vesting"` // delegated vesting coins at time of delegation
StartTime int64 `json:"start_time"` // vesting start time
EndTime int64 `json:"end_time"` // vesting end time
}
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
@ -76,22 +83,58 @@ func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
}
func NewGenesisAccountI(acc auth.Account) GenesisAccount {
return GenesisAccount{
gacc := GenesisAccount{
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
AccountNumber: acc.GetAccountNumber(),
Sequence: acc.GetSequence(),
}
vacc, ok := acc.(auth.VestingAccount)
if ok {
gacc.OriginalVesting = vacc.GetOriginalVesting()
gacc.DelegatedFree = vacc.GetDelegatedFree()
gacc.DelegatedVesting = vacc.GetDelegatedVesting()
gacc.StartTime = vacc.GetStartTime()
gacc.EndTime = vacc.GetEndTime()
}
return gacc
}
// convert GenesisAccount to auth.BaseAccount
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
return &auth.BaseAccount{
func (ga *GenesisAccount) ToAccount() auth.Account {
bacc := &auth.BaseAccount{
Address: ga.Address,
Coins: ga.Coins.Sort(),
AccountNumber: ga.AccountNumber,
Sequence: ga.Sequence,
}
if !ga.OriginalVesting.IsZero() {
baseVestingAcc := &auth.BaseVestingAccount{
BaseAccount: bacc,
OriginalVesting: ga.OriginalVesting,
DelegatedFree: ga.DelegatedFree,
DelegatedVesting: ga.DelegatedVesting,
EndTime: ga.EndTime,
}
if ga.StartTime != 0 && ga.EndTime != 0 {
return &auth.ContinuousVestingAccount{
BaseVestingAccount: baseVestingAcc,
StartTime: ga.StartTime,
}
} else if ga.EndTime != 0 {
return &auth.DelayedVestingAccount{
BaseVestingAccount: baseVestingAcc,
}
} else {
panic(fmt.Sprintf("invalid genesis vesting account: %+v", ga))
}
}
return bacc
}
// Create the core parameters for genesis initialization for gaia
@ -108,34 +151,37 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js
return genesisState, errors.New("there must be at least one genesis tx")
}
stakeData := genesisState.StakeData
stakingData := genesisState.StakingData
for i, genTx := range appGenTxs {
var tx auth.StdTx
if err := cdc.UnmarshalJSON(genTx, &tx); err != nil {
return genesisState, err
}
msgs := tx.GetMsgs()
if len(msgs) != 1 {
return genesisState, errors.New(
"must provide genesis StdTx with exactly 1 CreateValidator message")
}
if _, ok := msgs[0].(stake.MsgCreateValidator); !ok {
if _, ok := msgs[0].(staking.MsgCreateValidator); !ok {
return genesisState, fmt.Errorf(
"Genesis transaction %v does not contain a MsgCreateValidator", i)
}
}
for _, acc := range genesisState.Accounts {
// create the genesis account, give'm few steaks and a buncha token with there name
for _, coin := range acc.Coins {
if coin.Denom == bondDenom {
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.
Add(sdk.NewDecFromInt(coin.Amount)) // increase the supply
stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.
Add(coin.Amount) // increase the supply
}
}
}
genesisState.StakeData = stakeData
genesisState.StakingData = stakingData
genesisState.GenTxs = appGenTxs
return genesisState, nil
}
@ -143,7 +189,8 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js
func NewDefaultGenesisState() GenesisState {
return GenesisState{
Accounts: nil,
StakeData: stake.DefaultGenesisState(),
AuthData: auth.DefaultGenesisState(),
StakingData: staking.DefaultGenesisState(),
MintData: mint.DefaultGenesisState(),
DistrData: distr.DefaultGenesisState(),
GovData: gov.DefaultGenesisState(),
@ -157,37 +204,32 @@ func NewDefaultGenesisState() GenesisState {
// TODO: Error if there is a duplicate validator (#1708)
// TODO: Ensure all state machine parameters are in genesis (#1704)
func GaiaValidateGenesisState(genesisState GenesisState) error {
err := validateGenesisStateAccounts(genesisState.Accounts)
if err != nil {
if err := validateGenesisStateAccounts(genesisState.Accounts); err != nil {
return err
}
// skip stakeData validation as genesis is created from txs
// skip stakingData validation as genesis is created from txs
if len(genesisState.GenTxs) > 0 {
return nil
}
err = stake.ValidateGenesis(genesisState.StakeData)
if err != nil {
if err := auth.ValidateGenesis(genesisState.AuthData); err != nil {
return err
}
err = mint.ValidateGenesis(genesisState.MintData)
if err != nil {
if err := staking.ValidateGenesis(genesisState.StakingData); err != nil {
return err
}
err = distr.ValidateGenesis(genesisState.DistrData)
if err != nil {
if err := mint.ValidateGenesis(genesisState.MintData); err != nil {
return err
}
err = gov.ValidateGenesis(genesisState.GovData)
if err != nil {
if err := distr.ValidateGenesis(genesisState.DistrData); err != nil {
return err
}
err = slashing.ValidateGenesis(genesisState.SlashingData)
if err != nil {
if err := gov.ValidateGenesis(genesisState.GovData); err != nil {
return err
}
return nil
return slashing.ValidateGenesis(genesisState.SlashingData)
}
// Ensures that there are no duplicate accounts in the genesis state,
@ -276,7 +318,7 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm
"each genesis transaction must provide a single genesis message")
}
msg := msgs[0].(stake.MsgCreateValidator)
msg := msgs[0].(staking.MsgCreateValidator)
// validate delegator and validator addresses and funds against the accounts in the state
delAddr := msg.DelegatorAddr.String()
valAddr := sdk.AccAddress(msg.ValidatorAddr).String()
@ -296,10 +338,10 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm
"account(s) %v not in genesis.json: %+v", strings.Join(accsNotInGenesis, " "), addrMap)
}
if delAcc.Coins.AmountOf(msg.Delegation.Denom).LT(msg.Delegation.Amount) {
if delAcc.Coins.AmountOf(msg.Value.Denom).LT(msg.Value.Amount) {
return appGenTxs, persistentPeers, fmt.Errorf(
"insufficient fund for delegation %v: %v < %v",
delAcc.Address, delAcc.Coins.AmountOf(msg.Delegation.Denom), msg.Delegation.Amount,
delAcc.Address, delAcc.Coins.AmountOf(msg.Value.Denom), msg.Value.Amount,
)
}
@ -318,7 +360,7 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
accAuth := auth.NewBaseAccountWithAddress(addr)
coins := sdk.Coins{
sdk.NewCoin("fooToken", sdk.NewInt(1000)),
sdk.NewCoin("footoken", sdk.NewInt(1000)),
sdk.NewCoin(bondDenom, freeFermionsAcc),
}

View File

@ -3,6 +3,7 @@ package app
import (
"encoding/json"
"testing"
"time"
"github.com/tendermint/tendermint/crypto/secp256k1"
tmtypes "github.com/tendermint/tendermint/types"
@ -13,8 +14,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/stake"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
var (
@ -32,18 +33,18 @@ var (
func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
// start with the default staking genesis state
appState := NewDefaultGenesisState()
stakeData := appState.StakeData
stakingData := appState.StakingData
genAccs := make([]GenesisAccount, len(genTxs))
for i, genTx := range genTxs {
msgs := genTx.GetMsgs()
require.Equal(t, 1, len(msgs))
msg := msgs[0].(stake.MsgCreateValidator)
msg := msgs[0].(staking.MsgCreateValidator)
acc := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddr))
acc.Coins = sdk.Coins{sdk.NewInt64Coin(bondDenom, 150)}
genAccs[i] = NewGenesisAccount(&acc)
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(150)) // increase the supply
stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.Add(sdk.NewInt(150)) // increase the supply
}
// create the final app state
@ -55,8 +56,19 @@ func TestToAccount(t *testing.T) {
priv := ed25519.GenPrivKey()
addr := sdk.AccAddress(priv.PubKey().Address())
authAcc := auth.NewBaseAccountWithAddress(addr)
authAcc.SetCoins(sdk.Coins{sdk.NewInt64Coin(bondDenom, 150)})
genAcc := NewGenesisAccount(&authAcc)
require.Equal(t, authAcc, *genAcc.ToAccount())
acc := genAcc.ToAccount()
require.IsType(t, &auth.BaseAccount{}, acc)
require.Equal(t, &authAcc, acc.(*auth.BaseAccount))
vacc := auth.NewContinuousVestingAccount(
&authAcc, time.Now().Unix(), time.Now().Add(24*time.Hour).Unix(),
)
genAcc = NewGenesisAccountI(vacc)
acc = genAcc.ToAccount()
require.IsType(t, &auth.ContinuousVestingAccount{}, acc)
require.Equal(t, vacc, acc.(*auth.ContinuousVestingAccount))
}
func TestGaiaAppGenTx(t *testing.T) {
@ -91,9 +103,9 @@ func TestGaiaAppGenState(t *testing.T) {
}
func makeMsg(name string, pk crypto.PubKey) auth.StdTx {
desc := stake.NewDescription(name, "", "", "")
comm := stakeTypes.CommissionMsg{}
msg := stake.NewMsgCreateValidator(sdk.ValAddress(pk.Address()), pk, sdk.NewInt64Coin(bondDenom,
desc := staking.NewDescription(name, "", "", "")
comm := stakingTypes.CommissionMsg{}
msg := staking.NewMsgCreateValidator(sdk.ValAddress(pk.Address()), pk, sdk.NewInt64Coin(bondDenom,
50), desc, comm)
return auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, nil, "")
}
@ -108,18 +120,18 @@ func TestGaiaGenesisValidation(t *testing.T) {
require.NotNil(t, err)
// Test bonded + jailed validator fails
genesisState = makeGenesisState(t, genTxs)
val1 := stakeTypes.NewValidator(addr1, pk1, stakeTypes.Description{Moniker: "test #2"})
val1 := stakingTypes.NewValidator(addr1, pk1, stakingTypes.Description{Moniker: "test #2"})
val1.Jailed = true
val1.Status = sdk.Bonded
genesisState.StakeData.Validators = append(genesisState.StakeData.Validators, val1)
genesisState.StakingData.Validators = append(genesisState.StakingData.Validators, val1)
err = GaiaValidateGenesisState(genesisState)
require.NotNil(t, err)
// Test duplicate validator fails
val1.Jailed = false
genesisState = makeGenesisState(t, genTxs)
val2 := stakeTypes.NewValidator(addr1, pk1, stakeTypes.Description{Moniker: "test #3"})
genesisState.StakeData.Validators = append(genesisState.StakeData.Validators, val1)
genesisState.StakeData.Validators = append(genesisState.StakeData.Validators, val2)
val2 := stakingTypes.NewValidator(addr1, pk1, stakingTypes.Description{Moniker: "test #3"})
genesisState.StakingData.Validators = append(genesisState.StakingData.Validators, val1)
genesisState.StakingData.Validators = append(genesisState.StakingData.Validators, val2)
err = GaiaValidateGenesisState(genesisState)
require.NotNil(t, err)
}
@ -127,6 +139,6 @@ func TestGaiaGenesisValidation(t *testing.T) {
func TestNewDefaultGenesisAccount(t *testing.T) {
addr := secp256k1.GenPrivKeySecp256k1([]byte("")).PubKey().Address()
acc := NewDefaultGenesisAccount(sdk.AccAddress(addr))
require.Equal(t, sdk.NewInt(1000), acc.Coins.AmountOf("fooToken"))
require.Equal(t, sdk.NewInt(1000), acc.Coins.AmountOf("footoken"))
require.Equal(t, sdk.NewInt(150), acc.Coins.AmountOf(bondDenom))
}

View File

@ -10,16 +10,16 @@ import (
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
distrsim "github.com/cosmos/cosmos-sdk/x/distribution/simulation"
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
stakesim "github.com/cosmos/cosmos-sdk/x/stake/simulation"
stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation"
)
func (app *GaiaApp) runtimeInvariants() []simulation.Invariant {
return []simulation.Invariant{
banksim.NonnegativeBalanceInvariant(app.accountKeeper),
distrsim.ValAccumInvariants(app.distrKeeper, app.stakeKeeper),
stakesim.SupplyInvariants(app.bankKeeper, app.stakeKeeper,
distrsim.NonNegativeOutstandingInvariant(app.distrKeeper),
stakingsim.SupplyInvariants(app.bankKeeper, app.stakingKeeper,
app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper),
stakesim.NonNegativePowerInvariant(app.stakeKeeper),
stakingsim.NonNegativePowerInvariant(app.stakingKeeper),
}
}

View File

@ -18,6 +18,7 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authsim "github.com/cosmos/cosmos-sdk/x/auth/simulation"
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
@ -28,9 +29,9 @@ import (
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
"github.com/cosmos/cosmos-sdk/x/slashing"
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
stake "github.com/cosmos/cosmos-sdk/x/stake"
stakesim "github.com/cosmos/cosmos-sdk/x/stake/simulation"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation"
stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
var (
@ -53,7 +54,7 @@ func init() {
flag.IntVar(&period, "SimulationPeriod", 1, "Run slow invariants only once every period assertions")
}
func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) json.RawMessage {
var genesisAccounts []GenesisAccount
amount := int64(r.Intn(1e6))
@ -66,21 +67,63 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
"\t{amount of steak per account: %v, initially bonded validators: %v}\n",
amount, numInitiallyBonded)
// Randomly generate some genesis accounts
for _, acc := range accs {
coins := sdk.Coins{sdk.NewCoin(stakeTypes.DefaultBondDenom, sdk.NewInt(amount))}
genesisAccounts = append(genesisAccounts, GenesisAccount{
Address: acc.Address,
Coins: coins,
})
// randomly generate some genesis accounts
for i, acc := range accs {
coins := sdk.Coins{sdk.NewCoin(stakingTypes.DefaultBondDenom, sdk.NewInt(amount))}
bacc := auth.NewBaseAccountWithAddress(acc.Address)
bacc.SetCoins(coins)
var gacc GenesisAccount
// Only consider making a vesting account once the initial bonded validator
// set is exhausted due to needing to track DelegatedVesting.
if int64(i) > numInitiallyBonded && r.Intn(100) < 50 {
var (
vacc auth.VestingAccount
endTime int
)
startTime := genesisTimestamp.Unix()
// Allow for some vesting accounts to vest very quickly while others very
// slowly.
if r.Intn(100) < 50 {
endTime = randIntBetween(r, int(startTime), int(startTime+(60*60*24*30)))
} else {
endTime = randIntBetween(r, int(startTime), int(startTime+(60*60*12)))
}
if r.Intn(100) < 50 {
vacc = auth.NewContinuousVestingAccount(&bacc, startTime, int64(endTime))
} else {
vacc = auth.NewDelayedVestingAccount(&bacc, int64(endTime))
}
gacc = NewGenesisAccountI(vacc)
} else {
gacc = NewGenesisAccount(&bacc)
}
genesisAccounts = append(genesisAccounts, gacc)
}
authGenesis := auth.GenesisState{
Params: auth.Params{
MemoCostPerByte: uint64(r.Intn(10) + 1),
MaxMemoCharacters: uint64(r.Intn(200-100) + 100),
TxSigLimit: uint64(r.Intn(7) + 1),
SigVerifyCostED25519: uint64(r.Intn(1000-500) + 500),
SigVerifyCostSecp256k1: uint64(r.Intn(1000-500) + 500),
},
}
fmt.Printf("Selected randomly generated auth parameters:\n\t%+v\n", authGenesis)
// Random genesis states
vp := time.Duration(r.Intn(2*172800)) * time.Second
govGenesis := gov.GenesisState{
StartingProposalID: uint64(r.Intn(100)),
DepositParams: gov.DepositParams{
MinDeposit: sdk.Coins{sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, int64(r.Intn(1e3)))},
MinDeposit: sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, int64(r.Intn(1e3)))},
MaxDepositPeriod: vp,
},
VotingParams: gov.VotingParams{
@ -94,25 +137,24 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
}
fmt.Printf("Selected randomly generated governance parameters:\n\t%+v\n", govGenesis)
stakeGenesis := stake.GenesisState{
Pool: stake.InitialPool(),
Params: stake.Params{
UnbondingTime: time.Duration(r.Intn(60*60*24*3*2)) * time.Second,
stakingGenesis := staking.GenesisState{
Pool: staking.InitialPool(),
Params: staking.Params{
UnbondingTime: time.Duration(randIntBetween(r, 60, 60*60*24*3*2)) * time.Second,
MaxValidators: uint16(r.Intn(250)),
BondDenom: stakeTypes.DefaultBondDenom,
BondDenom: stakingTypes.DefaultBondDenom,
},
}
fmt.Printf("Selected randomly generated staking parameters:\n\t%+v\n", stakeGenesis)
fmt.Printf("Selected randomly generated staking parameters:\n\t%+v\n", stakingGenesis)
slashingGenesis := slashing.GenesisState{
Params: slashing.Params{
MaxEvidenceAge: stakeGenesis.Params.UnbondingTime,
DoubleSignUnbondDuration: time.Duration(r.Intn(60*60*24)) * time.Second,
SignedBlocksWindow: int64(r.Intn(1000)),
DowntimeUnbondDuration: time.Duration(r.Intn(86400)) * time.Second,
MinSignedPerWindow: sdk.NewDecWithPrec(int64(r.Intn(10)), 1),
SlashFractionDoubleSign: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(50) + 1))),
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(200) + 1))),
MaxEvidenceAge: stakingGenesis.Params.UnbondingTime,
SignedBlocksWindow: int64(randIntBetween(r, 10, 1000)),
MinSignedPerWindow: sdk.NewDecWithPrec(int64(r.Intn(10)), 1),
DowntimeJailDuration: time.Duration(randIntBetween(r, 60, 60*60*24)) * time.Second,
SlashFractionDoubleSign: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(50) + 1))),
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(200) + 1))),
},
}
fmt.Printf("Selected randomly generated slashing parameters:\n\t%+v\n", slashingGenesis)
@ -121,7 +163,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
Minter: mint.InitialMinter(
sdk.NewDecWithPrec(int64(r.Intn(99)), 2)),
Params: mint.NewParams(
stakeTypes.DefaultBondDenom,
stakingTypes.DefaultBondDenom,
sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
sdk.NewDecWithPrec(20, 2),
sdk.NewDecWithPrec(7, 2),
@ -130,30 +172,40 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
}
fmt.Printf("Selected randomly generated minting parameters:\n\t%+v\n", mintGenesis)
var validators []stake.Validator
var delegations []stake.Delegation
var validators []staking.Validator
var delegations []staking.Delegation
valAddrs := make([]sdk.ValAddress, numInitiallyBonded)
for i := 0; i < int(numInitiallyBonded); i++ {
valAddr := sdk.ValAddress(accs[i].Address)
valAddrs[i] = valAddr
validator := stake.NewValidator(valAddr, accs[i].PubKey, stake.Description{})
validator.Tokens = sdk.NewDec(amount)
validator := staking.NewValidator(valAddr, accs[i].PubKey, staking.Description{})
validator.Tokens = sdk.NewInt(amount)
validator.DelegatorShares = sdk.NewDec(amount)
delegation := stake.Delegation{accs[i].Address, valAddr, sdk.NewDec(amount)}
delegation := staking.Delegation{accs[i].Address, valAddr, sdk.NewDec(amount)}
validators = append(validators, validator)
delegations = append(delegations, delegation)
}
stakeGenesis.Pool.LooseTokens = sdk.NewDec((amount * numAccs) + (numInitiallyBonded * amount))
stakeGenesis.Validators = validators
stakeGenesis.Bonds = delegations
stakingGenesis.Pool.NotBondedTokens = sdk.NewInt((amount * numAccs) + (numInitiallyBonded * amount))
stakingGenesis.Validators = validators
stakingGenesis.Bonds = delegations
distrGenesis := distr.GenesisState{
FeePool: distr.InitialFeePool(),
CommunityTax: sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(int64(r.Intn(30)), 2)),
BaseProposerReward: sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(int64(r.Intn(30)), 2)),
BonusProposerReward: sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(int64(r.Intn(30)), 2)),
}
fmt.Printf("Selected randomly generated distribution parameters:\n\t%+v\n", distrGenesis)
genesis := GenesisState{
Accounts: genesisAccounts,
StakeData: stakeGenesis,
AuthData: authGenesis,
StakingData: stakingGenesis,
MintData: mintGenesis,
DistrData: distr.DefaultGenesisWithValidators(valAddrs),
DistrData: distrGenesis,
SlashingData: slashingGenesis,
GovData: govGenesis,
}
@ -167,21 +219,24 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
return appState
}
func randIntBetween(r *rand.Rand, min, max int) int {
return r.Intn(max-min) + min
}
func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
return []simulation.WeightedOperation{
{5, authsim.SimulateDeductFee(app.accountKeeper, app.feeCollectionKeeper)},
{100, banksim.SingleInputSendMsg(app.accountKeeper, app.bankKeeper)},
{50, distrsim.SimulateMsgSetWithdrawAddress(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawDelegatorRewardsAll(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawValidatorRewardsAll(app.accountKeeper, app.distrKeeper)},
{5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakeKeeper)},
{50, distrsim.SimulateMsgWithdrawValidatorCommission(app.accountKeeper, app.distrKeeper)},
{5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakingKeeper)},
{100, govsim.SimulateMsgDeposit(app.govKeeper)},
{100, stakesim.SimulateMsgCreateValidator(app.accountKeeper, app.stakeKeeper)},
{5, stakesim.SimulateMsgEditValidator(app.stakeKeeper)},
{100, stakesim.SimulateMsgDelegate(app.accountKeeper, app.stakeKeeper)},
{100, stakesim.SimulateMsgBeginUnbonding(app.accountKeeper, app.stakeKeeper)},
{100, stakesim.SimulateMsgBeginRedelegate(app.accountKeeper, app.stakeKeeper)},
{100, stakingsim.SimulateMsgCreateValidator(app.accountKeeper, app.stakingKeeper)},
{5, stakingsim.SimulateMsgEditValidator(app.stakingKeeper)},
{100, stakingsim.SimulateMsgDelegate(app.accountKeeper, app.stakingKeeper)},
{100, stakingsim.SimulateMsgUndelegate(app.accountKeeper, app.stakingKeeper)},
{100, stakingsim.SimulateMsgBeginRedelegate(app.accountKeeper, app.stakingKeeper)},
{100, slashingsim.SimulateMsgUnjail(app.slashingKeeper)},
}
}
@ -190,8 +245,8 @@ func invariants(app *GaiaApp) []simulation.Invariant {
return []simulation.Invariant{
simulation.PeriodicInvariant(banksim.NonnegativeBalanceInvariant(app.accountKeeper), period, 0),
simulation.PeriodicInvariant(govsim.AllInvariants(), period, 0),
simulation.PeriodicInvariant(distrsim.AllInvariants(app.distrKeeper, app.stakeKeeper), period, 0),
simulation.PeriodicInvariant(stakesim.AllInvariants(app.bankKeeper, app.stakeKeeper,
simulation.PeriodicInvariant(distrsim.AllInvariants(app.distrKeeper, app.stakingKeeper), period, 0),
simulation.PeriodicInvariant(stakingsim.AllInvariants(app.bankKeeper, app.stakingKeeper,
app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper), period, 0),
simulation.PeriodicInvariant(slashingsim.AllInvariants(), period, 0),
}
@ -354,7 +409,7 @@ func TestGaiaImportExport(t *testing.T) {
storeKeysPrefixes := []StoreKeysPrefixes{
{app.keyMain, newApp.keyMain, [][]byte{}},
{app.keyAccount, newApp.keyAccount, [][]byte{}},
{app.keyStake, newApp.keyStake, [][]byte{stake.UnbondingQueueKey, stake.RedelegationQueueKey, stake.ValidatorQueueKey}}, // ordering may change but it doesn't matter
{app.keyStaking, newApp.keyStaking, [][]byte{staking.UnbondingQueueKey, staking.RedelegationQueueKey, staking.ValidatorQueueKey}}, // ordering may change but it doesn't matter
{app.keySlashing, newApp.keySlashing, [][]byte{}},
{app.keyMint, newApp.keyMint, [][]byte{}},
{app.keyDistr, newApp.keyDistr, [][]byte{}},
@ -370,8 +425,10 @@ func TestGaiaImportExport(t *testing.T) {
storeB := ctxB.KVStore(storeKeyB)
kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB, prefixes)
fmt.Printf("Compared %d key/value pairs between %s and %s\n", count, storeKeyA, storeKeyB)
require.True(t, equal, "unequal stores: %s / %s:\nstore A %s (%X) => %s (%X)\nstore B %s (%X) => %s (%X)",
storeKeyA, storeKeyB, kvA.Key, kvA.Key, kvA.Value, kvA.Value, kvB.Key, kvB.Key, kvB.Value, kvB.Value)
require.True(t, equal,
"unequal stores: %s / %s:\nstore A %X => %X\nstore B %X => %X",
storeKeyA, storeKeyB, kvA.Key, kvA.Value, kvB.Key, kvB.Value,
)
}
}

View File

@ -0,0 +1,51 @@
# Gaia CLI Integration tests
The gaia cli integration tests live in this folder. You can run the full suite by running:
```bash
$ go test -v -p 4 ./cmd/gaia/cli_test/...
# OR!
$ make test_cli
```
> NOTE: While the full suite runs in parallel, some of the tests can take up to a minute to complete
### Test Structure
This integration suite [uses a thin wrapper](https://godoc.org/github.com/cosmos/cosmos-sdk/tests) over the [`os/exec`](https://golang.org/pkg/os/exec/) package. This allows the integration test to run against built binaries (both `gaiad` and `gaiacli` are used) while being written in golang. This allows tests to take advantage of the various golang code we have for operations like marshal/unmarshal, crypto, etc...
> NOTE: The tests will use whatever `gaiad` or `gaiacli` binaries are available in your `$PATH`. You can check which binary will be run by the suite by running `which gaiad` or `which gaiacli`. If you have your `$GOPATH` properly setup they should be in `$GOPATH/bin/gaia*`. This will ensure that your test uses the latest binary you have built
Tests generally follow this structure:
```go
func TestMyNewCommand(t *testing.T) {
t.Parallel()
f := InitFixtures(t)
// start gaiad server
proc := f.GDStart()
defer proc.Stop(false)
// Your test code goes here...
f.Cleanup()
}
```
This boilerplate above:
- Ensures the tests run in parallel. Because the tests are calling out to `os/exec` for many operations these tests can take a long time to run.
- Creates `.gaiad` and `.gaiacli` folders in a new temp folder.
- Uses `gaiacli` to create 2 accounts for use in testing: `foo` and `bar`
- Creates a genesis file with coins (`1000footoken,1000feetoken,150stake`) controlled by the `foo` key
- Generates an initial bonding transaction (`gentx`) to make the `foo` key a validator at genesis
- Starts `gaiad` and stops it once the test exits
- Cleans up test state on a successful run
### Notes when adding/running tests
- Because the tests run against a built binary, you should make sure you build every time the code changes and you want to test again, otherwise you will be testing against an older version. If you are adding new tests this can easily lead to confusing test results.
- The [`test_helpers.go`](./test_helpers.go) file is organized according to the format of `gaiacli` and `gaiad` commands. There are comments with section headers describing the different areas. Helper functions to call CLI functionality are generally named after the command (e.g. `gaiacli query staking validator` would be `QueryStakingValidator`). Try to keep functions grouped by their position in the command tree.
- Test state that is needed by `tx` and `query` commands (`home`, `chain_id`, etc...) is stored on the `Fixtures` object. This makes constructing your new tests almost trivial.
- Sometimes if you exit a test early there can be still running `gaiad` and `gaiacli` processes that will interrupt subsequent runs. Still running `gaiacli` processes will block access to the keybase while still running `gaiad` processes will block ports and prevent new tests from spinning up. You can ensure new tests spin up clean by running `pkill -9 gaiad && pkill -9 gaiacli` before each test run.
- Most `query` and `tx` commands take a variadic `flags` argument. This pattern allows for the creation of a general function which is easily modified by adding flags. See the `TxSend` function and its use for a good example.
- `Tx*` functions follow a general pattern and return `(success bool, stdout string, stderr string)`. This allows for easy testing of multiple different flag configurations. See `TestGaiaCLICreateValidator` or `TestGaiaCLISubmitProposal` for a good example of the pattern.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,591 @@
package clitest
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/require"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
)
const (
denom = "stake"
keyFoo = "foo"
keyBar = "bar"
fooDenom = "footoken"
feeDenom = "feetoken"
fee2Denom = "fee2token"
keyBaz = "baz"
keyFooBarBaz = "foobarbaz"
)
var startCoins = sdk.Coins{
sdk.NewInt64Coin(feeDenom, 1000000),
sdk.NewInt64Coin(fee2Denom, 1000000),
sdk.NewInt64Coin(fooDenom, 1000),
sdk.NewInt64Coin(denom, 150),
}
//___________________________________________________________________________________
// Fixtures
// Fixtures is used to setup the testing environment
type Fixtures struct {
ChainID string
RPCAddr string
Port string
GDHome string
GCLIHome string
P2PAddr string
T *testing.T
}
// NewFixtures creates a new instance of Fixtures with many vars set
func NewFixtures(t *testing.T) *Fixtures {
tmpDir, err := ioutil.TempDir("", "gaia_integration_"+t.Name()+"_")
require.NoError(t, err)
servAddr, port, err := server.FreeTCPAddr()
require.NoError(t, err)
p2pAddr, _, err := server.FreeTCPAddr()
require.NoError(t, err)
return &Fixtures{
T: t,
GDHome: filepath.Join(tmpDir, ".gaiad"),
GCLIHome: filepath.Join(tmpDir, ".gaiacli"),
RPCAddr: servAddr,
P2PAddr: p2pAddr,
Port: port,
}
}
// InitFixtures is called at the beginning of a test
// and initializes a chain with 1 validator
func InitFixtures(t *testing.T) (f *Fixtures) {
f = NewFixtures(t)
// Reset test state
f.UnsafeResetAll()
// Ensure keystore has foo and bar keys
f.KeysDelete(keyFoo)
f.KeysDelete(keyBar)
f.KeysDelete(keyBar)
f.KeysDelete(keyFooBarBaz)
f.KeysAdd(keyFoo)
f.KeysAdd(keyBar)
f.KeysAdd(keyBaz)
f.KeysAdd(keyFooBarBaz, "--multisig-threshold=2", fmt.Sprintf(
"--multisig=%s,%s,%s", keyFoo, keyBar, keyBaz))
// Ensure that CLI output is in JSON format
f.CLIConfig("output", "json")
// NOTE: GDInit sets the ChainID
f.GDInit(keyFoo)
f.CLIConfig("chain-id", f.ChainID)
// Start an account with tokens
f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins)
f.GenTx(keyFoo)
f.CollectGenTxs()
return
}
// Cleanup is meant to be run at the end of a test to clean up an remaining test state
func (f *Fixtures) Cleanup(dirs ...string) {
clean := append(dirs, f.GDHome, f.GCLIHome)
for _, d := range clean {
err := os.RemoveAll(d)
require.NoError(f.T, err)
}
}
// Flags returns the flags necessary for making most CLI calls
func (f *Fixtures) Flags() string {
return fmt.Sprintf("--home=%s --node=%s", f.GCLIHome, f.RPCAddr)
}
//___________________________________________________________________________________
// gaiad
// UnsafeResetAll is gaiad unsafe-reset-all
func (f *Fixtures) UnsafeResetAll(flags ...string) {
cmd := fmt.Sprintf("gaiad --home=%s unsafe-reset-all", f.GDHome)
executeWrite(f.T, addFlags(cmd, flags))
err := os.RemoveAll(filepath.Join(f.GDHome, "config", "gentx"))
require.NoError(f.T, err)
}
// GDInit is gaiad init
// NOTE: GDInit sets the ChainID for the Fixtures instance
func (f *Fixtures) GDInit(moniker string, flags ...string) {
cmd := fmt.Sprintf("gaiad init -o --moniker=%s --home=%s", moniker, f.GDHome)
_, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
var chainID string
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(stderr), &initRes)
require.NoError(f.T, err)
err = json.Unmarshal(initRes["chain_id"], &chainID)
require.NoError(f.T, err)
f.ChainID = chainID
}
// AddGenesisAccount is gaiad add-genesis-account
func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, flags ...string) {
cmd := fmt.Sprintf("gaiad add-genesis-account %s %s --home=%s", address, coins, f.GDHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags))
}
// GenTx is gaiad gentx
func (f *Fixtures) GenTx(name string, flags ...string) {
cmd := fmt.Sprintf("gaiad gentx --name=%s --home=%s --home-client=%s", name, f.GDHome, f.GCLIHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// CollectGenTxs is gaiad collect-gentxs
func (f *Fixtures) CollectGenTxs(flags ...string) {
cmd := fmt.Sprintf("gaiad collect-gentxs --home=%s", f.GDHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// GDStart runs gaiad start with the appropriate flags and returns a process
func (f *Fixtures) GDStart(flags ...string) *tests.Process {
cmd := fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", f.GDHome, f.RPCAddr, f.P2PAddr)
proc := tests.GoExecuteTWithStdout(f.T, addFlags(cmd, flags))
tests.WaitForTMStart(f.Port)
tests.WaitForNextNBlocksTM(1, f.Port)
return proc
}
//___________________________________________________________________________________
// gaiacli keys
// KeysDelete is gaiacli keys delete
func (f *Fixtures) KeysDelete(name string, flags ...string) {
cmd := fmt.Sprintf("gaiacli keys delete --home=%s %s", f.GCLIHome, name)
executeWrite(f.T, addFlags(cmd, append(append(flags, "-y"), "-f")))
}
// KeysAdd is gaiacli keys add
func (f *Fixtures) KeysAdd(name string, flags ...string) {
cmd := fmt.Sprintf("gaiacli keys add --home=%s %s", f.GCLIHome, name)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// KeysShow is gaiacli keys show
func (f *Fixtures) KeysShow(name string, flags ...string) keys.KeyOutput {
cmd := fmt.Sprintf("gaiacli keys show --home=%s %s", f.GCLIHome, name)
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var ko keys.KeyOutput
err := keys.UnmarshalJSON([]byte(out), &ko)
require.NoError(f.T, err)
return ko
}
// KeyAddress returns the SDK account address from the key
func (f *Fixtures) KeyAddress(name string) sdk.AccAddress {
ko := f.KeysShow(name)
accAddr, err := sdk.AccAddressFromBech32(ko.Address)
require.NoError(f.T, err)
return accAddr
}
//___________________________________________________________________________________
// gaiacli config
// CLIConfig is gaiacli config
func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
cmd := fmt.Sprintf("gaiacli config --home=%s %s %s", f.GCLIHome, key, value)
executeWriteCheckErr(f.T, addFlags(cmd, flags))
}
//___________________________________________________________________________________
// gaiacli tx send/sign/broadcast
// TxSend is gaiacli tx send
func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx send %v --amount=%s --to=%s --from=%s", f.Flags(), amount, to, from)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxSign is gaiacli tx sign
func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx sign %v --name=%s %v", f.Flags(), signer, fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxBroadcast is gaiacli tx sign
func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx broadcast %v %v", f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxMultisign is gaiacli tx multisign
func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string,
flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx multisign %v %s %s %s", f.Flags(),
fileName, name, strings.Join(signaturesFiles, " "),
)
return executeWriteRetStdStreams(f.T, cmd)
}
//___________________________________________________________________________________
// gaiacli tx staking
// TxStakingCreateValidator is gaiacli tx staking create-validator
func (f *Fixtures) TxStakingCreateValidator(from, consPubKey string, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx staking create-validator %v --from=%s --pubkey=%s", 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")
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxStakingUnbond is gaiacli tx staking unbond
func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress, flags ...string) bool {
cmd := fmt.Sprintf("gaiacli tx staking unbond %v --from=%s --validator=%s --shares-amount=%v", f.Flags(), from, validator, shares)
return executeWrite(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
//___________________________________________________________________________________
// gaiacli tx gov
// TxGovSubmitProposal is gaiacli tx gov submit-proposal
func (f *Fixtures) TxGovSubmitProposal(from, typ, title, description string, deposit sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx gov submit-proposal %v --from=%s --type=%s", f.Flags(), from, typ)
cmd += fmt.Sprintf(" --title=%s --description=%s --deposit=%s", title, description, deposit)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxGovDeposit is gaiacli tx gov deposit
func (f *Fixtures) TxGovDeposit(proposalID int, from string, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx gov deposit %d %s --from=%s %v", proposalID, amount, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxGovVote is gaiacli tx gov vote
func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx gov vote %d %s --from=%s %v", proposalID, option, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
//___________________________________________________________________________________
// gaiacli query account
// QueryAccount is gaiacli query account
func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.BaseAccount {
cmd := fmt.Sprintf("gaiacli query account %s %v", address, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(out), &initRes)
require.NoError(f.T, err, "out %v, err %v", out, err)
value := initRes["value"]
var acc auth.BaseAccount
cdc := codec.New()
codec.RegisterCrypto(cdc)
err = cdc.UnmarshalJSON(value, &acc)
require.NoError(f.T, err, "value %v, err %v", string(value), err)
return acc
}
//___________________________________________________________________________________
// gaiacli query txs
// QueryTxs is gaiacli query txs
func (f *Fixtures) QueryTxs(page, limit int, tags ...string) []tx.Info {
cmd := fmt.Sprintf("gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var txs []tx.Info
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &txs)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return txs
}
// QueryTxsInvalid query txs with wrong parameters and compare expected error
func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, tags ...string) {
cmd := fmt.Sprintf("gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
_, err := tests.ExecuteT(f.T, cmd, "")
require.EqualError(f.T, expectedErr, err)
}
//___________________________________________________________________________________
// gaiacli query staking
// QueryStakingValidator is gaiacli query staking validator
func (f *Fixtures) QueryStakingValidator(valAddr sdk.ValAddress, flags ...string) staking.Validator {
cmd := fmt.Sprintf("gaiacli query staking validator %s %v", valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var validator staking.Validator
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &validator)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return validator
}
// QueryStakingUnbondingDelegationsFrom is gaiacli query staking unbonding-delegations-from
func (f *Fixtures) QueryStakingUnbondingDelegationsFrom(valAddr sdk.ValAddress, flags ...string) []staking.UnbondingDelegation {
cmd := fmt.Sprintf("gaiacli query staking unbonding-delegations-from %s %v", valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var ubds []staking.UnbondingDelegation
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &ubds)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return ubds
}
// QueryStakingDelegationsTo is gaiacli query staking delegations-to
func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...string) []staking.Delegation {
cmd := fmt.Sprintf("gaiacli query staking delegations-to %s %v", valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var delegations []staking.Delegation
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &delegations)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return delegations
}
// QueryStakingPool is gaiacli query staking pool
func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool {
cmd := fmt.Sprintf("gaiacli query staking pool %v", f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var pool staking.Pool
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &pool)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return pool
}
// QueryStakingParameters is gaiacli query staking parameters
func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params {
cmd := fmt.Sprintf("gaiacli query staking params %v", f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var params staking.Params
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &params)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return params
}
//___________________________________________________________________________________
// gaiacli query gov
// QueryGovParamDeposit is gaiacli query gov param deposit
func (f *Fixtures) QueryGovParamDeposit() gov.DepositParams {
cmd := fmt.Sprintf("gaiacli query gov param deposit %s", f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var depositParam gov.DepositParams
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &depositParam)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return depositParam
}
// QueryGovParamVoting is gaiacli query gov param voting
func (f *Fixtures) QueryGovParamVoting() gov.VotingParams {
cmd := fmt.Sprintf("gaiacli query gov param voting %s", f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var votingParam gov.VotingParams
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &votingParam)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return votingParam
}
// QueryGovParamTallying is gaiacli query gov param tallying
func (f *Fixtures) QueryGovParamTallying() gov.TallyParams {
cmd := fmt.Sprintf("gaiacli query gov param tallying %s", f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var tallyingParam gov.TallyParams
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &tallyingParam)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return tallyingParam
}
// QueryGovProposals is gaiacli query gov proposals
func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals {
cmd := fmt.Sprintf("gaiacli query gov proposals %v", f.Flags())
stdout, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
if strings.Contains(stderr, "No matching proposals found") {
return gov.Proposals{}
}
require.Empty(f.T, stderr)
var out gov.Proposals
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(stdout), &out)
require.NoError(f.T, err)
return out
}
// QueryGovProposal is gaiacli query gov proposal
func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposal {
cmd := fmt.Sprintf("gaiacli query gov proposal %d %v", proposalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var proposal gov.Proposal
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &proposal)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return proposal
}
// QueryGovVote is gaiacli query gov vote
func (f *Fixtures) QueryGovVote(proposalID int, voter sdk.AccAddress, flags ...string) gov.Vote {
cmd := fmt.Sprintf("gaiacli query gov vote %d %s %v", proposalID, voter, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var vote gov.Vote
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &vote)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return vote
}
// QueryGovVotes is gaiacli query gov votes
func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote {
cmd := fmt.Sprintf("gaiacli query gov votes %d %v", proposalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var votes []gov.Vote
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &votes)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return votes
}
// QueryGovDeposit is gaiacli query gov deposit
func (f *Fixtures) QueryGovDeposit(proposalID int, depositor sdk.AccAddress, flags ...string) gov.Deposit {
cmd := fmt.Sprintf("gaiacli query gov deposit %d %s %v", proposalID, depositor, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var deposit gov.Deposit
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &deposit)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return deposit
}
// QueryGovDeposits is gaiacli query gov deposits
func (f *Fixtures) QueryGovDeposits(propsalID int, flags ...string) []gov.Deposit {
cmd := fmt.Sprintf("gaiacli query gov deposits %d %v", propsalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var deposits []gov.Deposit
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &deposits)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return deposits
}
//___________________________________________________________________________________
// query slashing
// QuerySlashingParams is gaiacli query slashing params
func (f *Fixtures) QuerySlashingParams() slashing.Params {
cmd := fmt.Sprintf("gaiacli query slashing params %s", f.Flags())
res, errStr := tests.ExecuteT(f.T, cmd, "")
require.Empty(f.T, errStr)
cdc := app.MakeCodec()
var params slashing.Params
err := cdc.UnmarshalJSON([]byte(res), &params)
require.NoError(f.T, err)
return params
}
//___________________________________________________________________________________
// executors
func executeWriteCheckErr(t *testing.T, cmdStr string, writes ...string) {
require.True(t, executeWrite(t, cmdStr, writes...))
}
func executeWrite(t *testing.T, cmdStr string, writes ...string) (exitSuccess bool) {
exitSuccess, _, _ = executeWriteRetStdStreams(t, cmdStr, writes...)
return
}
func executeWriteRetStdStreams(t *testing.T, cmdStr string, writes ...string) (bool, string, string) {
proc := tests.GoExecuteT(t, cmdStr)
// Enables use of interactive commands
for _, write := range writes {
_, err := proc.StdinPipe.Write([]byte(write + "\n"))
require.NoError(t, err)
}
// Read both stdout and stderr from the process
stdout, stderr, err := proc.ReadAll()
if err != nil {
fmt.Println("Err on proc.ReadAll()", err, cmdStr)
}
// Log output.
if len(stdout) > 0 {
t.Log("Stdout:", cmn.Green(string(stdout)))
}
if len(stderr) > 0 {
t.Log("Stderr:", cmn.Red(string(stderr)))
}
// Wait for process to exit
proc.Wait()
// Return succes, stdout, stderr
return proc.ExitState.Success(), string(stdout), string(stderr)
}
//___________________________________________________________________________________
// utils
func addFlags(cmd string, flags []string) string {
for _, f := range flags {
cmd += " " + f
}
return strings.TrimSpace(cmd)
}
func queryTags(tags []string) (out string) {
for _, tag := range tags {
out += tag + "&"
}
return strings.TrimSuffix(out, "&")
}
func writeToNewTempFile(t *testing.T, s string) *os.File {
fp, err := ioutil.TempFile(os.TempDir(), "cosmos_cli_test_")
require.Nil(t, err)
_, err = fp.WriteString(s)
require.Nil(t, err)
return fp
}
func marshalStdTx(t *testing.T, stdTx auth.StdTx) []byte {
cdc := app.MakeCodec()
bz, err := cdc.MarshalBinaryBare(stdTx)
require.NoError(t, err)
return bz
}
func unmarshalStdTx(t *testing.T, s string) (stdTx auth.StdTx) {
cdc := app.MakeCodec()
require.Nil(t, cdc.UnmarshalJSON([]byte(s), &stdTx))
return
}

View File

@ -22,30 +22,27 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
at "github.com/cosmos/cosmos-sdk/x/auth"
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
dist "github.com/cosmos/cosmos-sdk/x/distribution"
gv "github.com/cosmos/cosmos-sdk/x/gov"
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
sl "github.com/cosmos/cosmos-sdk/x/slashing"
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
st "github.com/cosmos/cosmos-sdk/x/staking"
staking "github.com/cosmos/cosmos-sdk/x/staking/client/rest"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
distClient "github.com/cosmos/cosmos-sdk/x/distribution/client"
govClient "github.com/cosmos/cosmos-sdk/x/gov/client"
slashingClient "github.com/cosmos/cosmos-sdk/x/slashing/client"
stakeClient "github.com/cosmos/cosmos-sdk/x/stake/client"
stakingClient "github.com/cosmos/cosmos-sdk/x/staking/client"
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
)
const (
storeAcc = "acc"
storeGov = "gov"
storeSlashing = "slashing"
storeStake = "stake"
storeDist = "distr"
)
func main() {
// Configure cobra to sort commands
cobra.EnableCommandSorting = false
@ -67,10 +64,10 @@ func main() {
// Module clients hold cli commnads (tx,query) and lcd routes
// TODO: Make the lcd command take a list of ModuleClient
mc := []sdk.ModuleClients{
govClient.NewModuleClient(storeGov, cdc),
distClient.NewModuleClient(storeDist, cdc),
stakeClient.NewModuleClient(storeStake, cdc),
slashingClient.NewModuleClient(storeSlashing, cdc),
govClient.NewModuleClient(gv.StoreKey, cdc),
distClient.NewModuleClient(dist.StoreKey, cdc),
stakingClient.NewModuleClient(st.StoreKey, cdc),
slashingClient.NewModuleClient(sl.StoreKey, cdc),
}
rootCmd := &cobra.Command{
@ -78,9 +75,14 @@ func main() {
Short: "Command line interface for interacting with gaiad",
}
// Add --chain-id to persistent flags and mark it required
rootCmd.PersistentFlags().String(client.FlagChainID, "", "Chain ID of tendermint node")
rootCmd.PersistentPreRunE = func(_ *cobra.Command, _ []string) error {
return initConfig(rootCmd)
}
// Construct Root Command
rootCmd.AddCommand(
rpc.InitClientCommand(),
rpc.StatusCommand(),
client.ConfigCmd(),
queryCmd(cdc, mc),
@ -91,16 +93,13 @@ func main() {
keys.Commands(),
client.LineBreak,
version.VersionCmd,
client.NewCompletionCmd(rootCmd, true),
)
// Add flags and prefix all env exposed with GA
executor := cli.PrepareMainCmd(rootCmd, "GA", app.DefaultCLIHome)
err := initConfig(rootCmd)
if err != nil {
panic(err)
}
err = executor.Execute()
err := executor.Execute()
if err != nil {
fmt.Printf("Failed executing CLI command: %s, exiting...\n", err)
os.Exit(1)
@ -120,7 +119,7 @@ func queryCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
tx.SearchTxCmd(cdc),
tx.QueryTxCmd(cdc),
client.LineBreak,
authcmd.GetAccountCmd(storeAcc, cdc),
authcmd.GetAccountCmd(at.StoreKey, cdc),
)
for _, m := range mc {
@ -140,6 +139,7 @@ func txCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
bankcmd.SendTxCmd(cdc),
client.LineBreak,
authcmd.GetSignCommand(cdc),
authcmd.GetMultiSignCommand(cdc),
bankcmd.GetBroadcastCommand(cdc),
client.LineBreak,
)
@ -159,9 +159,9 @@ func registerRoutes(rs *lcd.RestServer) {
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, storeAcc)
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, at.StoreKey)
bank.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
stake.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
staking.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashing.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
gov.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
}
@ -189,7 +189,9 @@ func initConfig(cmd *cobra.Command) error {
return err
}
}
if err := viper.BindPFlag(client.FlagChainID, cmd.PersistentFlags().Lookup(client.FlagChainID)); err != nil {
return err
}
if err := viper.BindPFlag(cli.EncodingFlag, cmd.PersistentFlags().Lookup(cli.EncodingFlag)); err != nil {
return err
}

View File

@ -4,8 +4,6 @@ import (
"encoding/json"
"io"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -15,9 +13,12 @@ import (
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -42,6 +43,7 @@ func main() {
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc))
rootCmd.AddCommand(gaiaInit.GenTxCmd(ctx, cdc))
rootCmd.AddCommand(gaiaInit.AddGenesisAccountCmd(ctx, cdc))
rootCmd.AddCommand(client.NewCompletionCmd(rootCmd, true))
server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators)
@ -55,21 +57,24 @@ func main() {
}
func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application {
return app.NewGaiaApp(logger, db, traceStore, true,
baseapp.SetPruning(viper.GetString("pruning")),
baseapp.SetMinimumFees(viper.GetString("minimum_fees")),
return app.NewGaiaApp(
logger, db, traceStore, true,
baseapp.SetPruning(store.NewPruningOptions(viper.GetString("pruning"))),
baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)),
)
}
func exportAppStateAndTMValidators(
logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool,
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
gApp := app.NewGaiaApp(logger, db, traceStore, false)
if height != -1 {
gApp := app.NewGaiaApp(logger, db, traceStore, false)
err := gApp.LoadHeight(height)
if err != nil {
return nil, nil, err
}
return gApp.ExportAppStateAndValidators(forZeroHeight)
}
gApp := app.NewGaiaApp(logger, db, traceStore, true)
return gApp.ExportAppStateAndValidators(forZeroHeight)
}

View File

@ -7,6 +7,8 @@ import (
"os"
"path"
"github.com/cosmos/cosmos-sdk/store"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/spf13/cobra"
@ -26,7 +28,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/staking"
gaia "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
)
@ -48,7 +50,7 @@ func runHackCmd(cmd *cobra.Command, args []string) error {
fmt.Println(err)
os.Exit(1)
}
app := NewGaiaApp(logger, db, baseapp.SetPruning(viper.GetString("pruning")))
app := NewGaiaApp(logger, db, baseapp.SetPruning(store.NewPruningOptions(viper.GetString("pruning"))))
// print some info
id := app.LastCommitID()
@ -82,9 +84,9 @@ func runHackCmd(cmd *cobra.Command, args []string) error {
ctx := app.NewContext(true, abci.Header{})
// check for the powerkey and the validator from the store
store := ctx.KVStore(app.keyStake)
store := ctx.KVStore(app.keyStaking)
res := store.Get(powerKey)
val, _ := app.stakeKeeper.GetValidator(ctx, trouble)
val, _ := app.stakingKeeper.GetValidator(ctx, trouble)
fmt.Println("checking height", checkHeight, res, val)
if res == nil {
bottomHeight = checkHeight
@ -131,8 +133,8 @@ type GaiaApp struct {
// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
keyStake *sdk.KVStoreKey
tkeyStake *sdk.TransientStoreKey
keyStaking *sdk.KVStoreKey
tkeyStaking *sdk.TransientStoreKey
keySlashing *sdk.KVStoreKey
keyParams *sdk.KVStoreKey
tkeyParams *sdk.TransientStoreKey
@ -141,7 +143,7 @@ type GaiaApp struct {
accountKeeper auth.AccountKeeper
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
stakeKeeper stake.Keeper
stakingKeeper staking.Keeper
slashingKeeper slashing.Keeper
paramsKeeper params.Keeper
}
@ -156,39 +158,41 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
var app = &GaiaApp{
BaseApp: bApp,
cdc: cdc,
keyMain: sdk.NewKVStoreKey("main"),
keyAccount: sdk.NewKVStoreKey("acc"),
keyStake: sdk.NewKVStoreKey("stake"),
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
keySlashing: sdk.NewKVStoreKey("slashing"),
keyParams: sdk.NewKVStoreKey("params"),
tkeyParams: sdk.NewTransientStoreKey("transient_params"),
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
keyParams: sdk.NewKVStoreKey(params.StoreKey),
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
}
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams)
// define the accountKeeper
app.accountKeeper = auth.NewAccountKeeper(
app.cdc,
app.keyAccount, // target store
app.keyAccount, // target store
app.paramsKeeper.Subspace(auth.DefaultParamspace),
auth.ProtoBaseAccount, // prototype
)
// add handlers
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams)
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace), stake.DefaultCodespace)
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), slashing.DefaultCodespace)
app.stakingKeeper = staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking, app.bankKeeper, app.paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakingKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), slashing.DefaultCodespace)
// register message routes
app.Router().
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper))
// initialize BaseApp
app.SetInitChainer(app.initChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper))
app.MountStores(app.keyMain, app.keyAccount, app.keyStake, app.keySlashing, app.keyParams)
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keySlashing, app.keyParams)
app.MountStore(app.tkeyParams, sdk.StoreTypeTransient)
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
@ -204,7 +208,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
func MakeCodec() *codec.Codec {
var cdc = codec.New()
bank.RegisterCodec(cdc)
stake.RegisterCodec(cdc)
staking.RegisterCodec(cdc)
slashing.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
@ -225,7 +229,7 @@ func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) ab
// application updates every end block
// nolint: unparam
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
validatorUpdates, tags := stake.EndBlocker(ctx, app.stakeKeeper)
validatorUpdates, tags := staking.EndBlocker(ctx, app.stakingKeeper)
return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates,
@ -250,13 +254,13 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
app.accountKeeper.SetAccount(ctx, acc)
}
// load the initial stake information
validators, err := stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
// load the initial staking information
validators, err := staking.InitGenesis(ctx, app.stakingKeeper, genesisState.StakingData)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "")
}
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakingData)
return abci.ResponseInitChain{
Validators: validators,

View File

@ -7,6 +7,8 @@ import (
"path/filepath"
"time"
"github.com/cosmos/cosmos-sdk/store"
cpm "github.com/otiai10/copy"
"github.com/spf13/cobra"
@ -106,7 +108,7 @@ func run(rootDir string) {
fmt.Println("Creating application")
myapp := app.NewGaiaApp(
ctx.Logger, appDB, traceStoreWriter, true,
baseapp.SetPruning("everything"), // nothing
baseapp.SetPruning(store.PruneEverything), // nothing
)
// Genesis

View File

@ -9,6 +9,7 @@ import (
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
@ -19,7 +20,7 @@ import (
// AddGenesisAccountCmd returns add-genesis-account cobra Command
func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "add-genesis-account [address] [coin][,[coin]]",
Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]",
Short: "Add genesis account to genesis.json",
Args: cobra.ExactArgs(2),
RunE: func(_ *cobra.Command, args []string) error {
@ -28,7 +29,15 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
addr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
kb, err := keys.GetKeyBaseFromDir(viper.GetString(flagClientHome))
if err != nil {
return err
}
info, err := kb.Get(args[0])
if err != nil {
return err
}
addr = info.GetAddress()
}
coins, err := sdk.ParseCoins(args[1])
if err != nil {
@ -60,6 +69,7 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
}
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
return cmd
}

View File

@ -26,12 +26,12 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/stake/client/cli"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
stakingTypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
const (
defaultAmount = "100" + stakeTypes.DefaultBondDenom
defaultAmount = "100" + stakingTypes.DefaultBondDenom
defaultCommissionRate = "0.1"
defaultCommissionMaxRate = "0.2"
defaultCommissionMaxChangeRate = "0.01"
@ -113,7 +113,7 @@ following delegation and commission default parameters:
// Run gaiad tx create-validator
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContext().WithCodec(cdc)
cliCtx, txBldr, msg, err := cli.BuildCreateValidatorMsg(cliCtx, txBldr)
txBldr, msg, err := cli.BuildCreateValidatorMsg(cliCtx, txBldr)
if err != nil {
return err
}
@ -168,7 +168,7 @@ following delegation and commission default parameters:
func accountInGenesis(genesisState app.GenesisState, key sdk.AccAddress, coins sdk.Coins) error {
accountIsInGenesis := false
bondDenom := genesisState.StakeData.Params.BondDenom
bondDenom := genesisState.StakingData.Params.BondDenom
// Check if the account is in genesis
for _, acc := range genesisState.Accounts {
@ -178,8 +178,8 @@ func accountInGenesis(genesisState app.GenesisState, key sdk.AccAddress, coins s
// Ensure account contains enough funds of default bond denom
if coins.AmountOf(bondDenom).GT(acc.Coins.AmountOf(bondDenom)) {
return fmt.Errorf(
"Account %v is in genesis, but the only has %v%v available to stake, not %v%v",
key, acc.Coins.AmountOf(bondDenom), bondDenom, coins.AmountOf(bondDenom), bondDenom,
"account %v is in genesis, but it only has %v%v available to stake, not %v%v",
key.String(), acc.Coins.AmountOf(bondDenom), bondDenom, coins.AmountOf(bondDenom), bondDenom,
)
}
accountIsInGenesis = true
@ -191,7 +191,7 @@ func accountInGenesis(genesisState app.GenesisState, key sdk.AccAddress, coins s
return nil
}
return fmt.Errorf("Account %s in not in the app_state.accounts array of genesis.json", key)
return fmt.Errorf("account %s in not in the app_state.accounts array of genesis.json", key)
}
func prepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, ip, chainID string,

View File

@ -10,15 +10,16 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/stake"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cfg "github.com/tendermint/tendermint/config"
tmconfig "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/types"
@ -76,13 +77,20 @@ 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")
cmd.Flags().String(
client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created",
)
cmd.Flags().String(
server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", stakingtypes.DefaultBondDenom),
"Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)",
)
return cmd
}
func initTestnet(config *cfg.Config, cdc *codec.Codec) error {
func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
var chainID string
outDir := viper.GetString(flagOutputDir)
numValidators := viper.GetInt(flagNumValidators)
@ -95,6 +103,9 @@ func initTestnet(config *cfg.Config, cdc *codec.Codec) error {
nodeIDs := make([]string, numValidators)
valPubKeys := make([]crypto.PubKey, numValidators)
gaiaConfig := srvconfig.DefaultConfig()
gaiaConfig.MinGasPrices = viper.GetString(server.FlagMinGasPrices)
var (
accs []app.GenesisAccount
genFiles []string
@ -180,17 +191,17 @@ func initTestnet(config *cfg.Config, cdc *codec.Codec) error {
accs = append(accs, app.GenesisAccount{
Address: addr,
Coins: sdk.Coins{
sdk.NewInt64Coin(fmt.Sprintf("%sToken", nodeDirName), 1000),
sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 150),
sdk.NewInt64Coin(fmt.Sprintf("%stoken", nodeDirName), 1000),
sdk.NewInt64Coin(stakingtypes.DefaultBondDenom, 500),
},
})
msg := stake.NewMsgCreateValidator(
msg := staking.NewMsgCreateValidator(
sdk.ValAddress(addr),
valPubKeys[i],
sdk.NewInt64Coin(stakeTypes.DefaultBondDenom, 100),
stake.NewDescription(nodeDirName, "", "", ""),
stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
sdk.NewInt64Coin(stakingtypes.DefaultBondDenom, 100),
staking.NewDescription(nodeDirName, "", "", ""),
staking.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
)
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo)
txBldr := authtx.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo)
@ -213,6 +224,9 @@ func initTestnet(config *cfg.Config, cdc *codec.Codec) error {
_ = os.RemoveAll(outDir)
return err
}
gaiaConfigFilePath := filepath.Join(nodeDir, "config/gaiad.toml")
srvconfig.WriteConfigFile(gaiaConfigFilePath, gaiaConfig)
}
if err := initGenFiles(cdc, chainID, accs, genFiles, numValidators); err != nil {
@ -261,7 +275,7 @@ func initGenFiles(
}
func collectGenFiles(
cdc *codec.Codec, config *cfg.Config, chainID string,
cdc *codec.Codec, config *tmconfig.Config, chainID string,
monikers, nodeIDs []string, valPubKeys []crypto.PubKey,
numValidators int, outDir, nodeDirPrefix, nodeDaemonHomeName string,
) error {

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"time"
amino "github.com/tendermint/go-amino"
@ -16,6 +17,7 @@ import (
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
)
// ExportGenesisFile creates and writes the genesis configuration to disk. An
@ -58,20 +60,6 @@ func ExportGenesisFileWithTime(
return genDoc.SaveAs(genFile)
}
// read of create the private key file for this config
func ReadOrCreatePrivValidator(privValFile string) crypto.PubKey {
var privValidator *privval.FilePV
if common.FileExists(privValFile) {
privValidator = privval.LoadFilePV(privValFile)
} else {
privValidator = privval.GenFilePV(privValFile)
privValidator.Save()
}
return privValidator.GetPubKey()
}
// InitializeNodeValidatorFiles creates private validator and p2p configuration files.
func InitializeNodeValidatorFiles(
config *cfg.Config) (nodeID string, valPubKey crypto.PubKey, err error,
@ -83,7 +71,19 @@ func InitializeNodeValidatorFiles(
}
nodeID = string(nodeKey.ID())
valPubKey = ReadOrCreatePrivValidator(config.PrivValidatorFile())
server.UpgradeOldPrivValFile(config)
pvKeyFile := config.PrivValidatorKeyFile()
if err := common.EnsureDir(filepath.Dir(pvKeyFile), 0777); err != nil {
return nodeID, valPubKey, nil
}
pvStateFile := config.PrivValidatorStateFile()
if err := common.EnsureDir(filepath.Dir(pvStateFile), 0777); err != nil {
return nodeID, valPubKey, nil
}
valPubKey = privval.LoadOrGenFilePV(pvKeyFile, pvStateFile).GetPubKey()
return nodeID, valPubKey, nil
}

View File

@ -1,110 +0,0 @@
package main
import (
"flag"
"fmt"
"io"
"os"
"strconv"
"strings"
auto "github.com/tendermint/tendermint/libs/autofile"
cmn "github.com/tendermint/tendermint/libs/common"
)
//nolint
const Version = "0.0.2"
const sleepSeconds = 1 // Every second
const readBufferSize = 1024 // 1KB at a time
// Parse command-line options
func parseFlags() (headPath string, chopSize int64, limitSize int64, version bool) {
var flagSet = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
var chopSizeStr, limitSizeStr string
flagSet.StringVar(&headPath, "head", "logjack.out", "Destination (head) file.")
flagSet.StringVar(&chopSizeStr, "chop", "100M", "Move file if greater than this")
flagSet.StringVar(&limitSizeStr, "limit", "10G", "Only keep this much (for each specified file). Remove old files.")
flagSet.BoolVar(&version, "version", false, "Version")
flagSet.Parse(os.Args[1:]) //nolint
chopSize = parseBytesize(chopSizeStr)
limitSize = parseBytesize(limitSizeStr)
return
}
func main() {
// Read options
headPath, chopSize, limitSize, version := parseFlags()
if version {
fmt.Printf("logjack version %v\n", Version)
return
}
// Open Group
group, err := auto.OpenGroup(headPath, auto.GroupHeadSizeLimit(chopSize), auto.GroupTotalSizeLimit(limitSize))
if err != nil {
fmt.Printf("logjack couldn't create output file %v\n", headPath)
os.Exit(1)
}
// TODO: Maybe fix Group to re-allow these mutations.
// group.SetHeadSizeLimit(chopSize)
// group.SetTotalSizeLimit(limitSize)
err = group.Start()
if err != nil {
fmt.Printf("logjack couldn't start with file %v\n", headPath)
os.Exit(1)
}
go func() {
// Forever, read from stdin and write to AutoFile.
buf := make([]byte, readBufferSize)
for {
n, err := os.Stdin.Read(buf)
group.Write(buf[:n]) //nolint
group.Flush() //nolint
if err != nil {
group.Stop() //nolint
if err == io.EOF {
os.Exit(0)
} else {
fmt.Println("logjack errored")
os.Exit(1)
}
}
}
}()
// Trap signal
cmn.TrapSignal(func() {
fmt.Println("logjack shutting down")
})
}
func parseBytesize(chopSize string) int64 {
// Handle suffix multiplier
var multiplier int64 = 1
if strings.HasSuffix(chopSize, "T") {
multiplier = 1042 * 1024 * 1024 * 1024
chopSize = chopSize[:len(chopSize)-1]
}
if strings.HasSuffix(chopSize, "G") {
multiplier = 1042 * 1024 * 1024
chopSize = chopSize[:len(chopSize)-1]
}
if strings.HasSuffix(chopSize, "M") {
multiplier = 1042 * 1024
chopSize = chopSize[:len(chopSize)-1]
}
if strings.HasSuffix(chopSize, "K") {
multiplier = 1042
chopSize = chopSize[:len(chopSize)-1]
}
// Parse the numeric part
chopSizeInt, err := strconv.Atoi(chopSize)
if err != nil {
panic(err)
}
return int64(chopSizeInt) * multiplier
}

View File

@ -19,7 +19,10 @@ module.exports = {
indexName: 'cosmos_network',
debug: false
},
nav: [{ text: "Back to Cosmos", link: "https://cosmos.network" }],
nav: [
{ text: "Back to Cosmos", link: "https://cosmos.network" },
{ text: "RPC", link: "../rpc/" }
],
sidebar: [
{
title: "Overview",
@ -34,6 +37,7 @@ module.exports = {
title: "Gaia",
collapsable: false,
children: [
"/gaia/what-is-gaia"
"/gaia/installation",
"/gaia/join-testnet",
"/gaia/validators/validator-setup",

View File

@ -66,25 +66,25 @@ to send users to the GitHub.
To build and serve the documentation locally, run:
```
```bash
npm install -g vuepress
```
then change the following line in the `config.js`:
```
```js
base: "/docs/",
```
to:
```
```js
base: "/",
```
Finally, go up one directory to the root of the repo and run:
```
```bash
# from root of repo
vuepress build docs
cd dist/docs
@ -110,3 +110,17 @@ We are using [Algolia](https://www.algolia.com) to power full-text search. This
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).
### 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
```
2. Edit API docs
1. Directly Edit API docs manually: `client/lcd/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 `client/lcd/swagger-ui`.
4. Compile gaiacli
```bash
make install
```

View File

@ -1,40 +1,33 @@
# Welcome to the SDK Docs!
# Cosmos SDK Documentation
Welcome to the SDK docs!
## Get Started
- **[SDK Intro](./intro/README.md)**: High-level overview of the Cosmos SDK.
- **[SDK application tutorial](https://github.com/cosmos/sdk-application-tutorial)**: A tutorial to learn the SDK. It showcases how to build an SDK-based blockchain from scratch, and explains the basic principles of the SDK in the process.
![cosmonaut reading the cosmos docs in space](./cosmos-docs.jpg)
## Resources
## Learn the SDK
### SDK Intro
If you are a newcomer and would like to learn more about the Cosmos SDK, this **[intro](./intro/README.md)** is a good starting place.
### SDK tutorial
If you like to learn by doing, you can follow the **[SDK application tutorial](https://github.com/cosmos/sdk-application-tutorial)**. It showcases how to build an SDK-based blockchain from scratch, and teaches you about the basic principles the SDK in the process.
## Use the SDK
The following sections contain the information you need if you want to build a fully-functional SDK-based blockchain:
>*NOTE*: We are currently working on improving the docs. Some info might be missing. If that is the case, try the Cosmos [Forum](https://forum.cosmos.network). Failing that, [open an issue](https://github.com/cosmos/cosmos-sdk/issues/new).
- [Introduction](./intro/README.md): Contains introductory high-level material on the Cosmos SDK.
- [Gaia](./gaia/README.md): Contains all documentation related to the gaia application (current name for the Cosmos-Hub). Also contains info on how to join gaia testnets.
- [Clients](./clients/README.md): Documentation about SDK clients like the SDK Command-Line interface and the SDK Light-client.
- [Specifications](./spec/README.md): Contains SDK and modules specifications.
- [SDK API Reference](https://godoc.org/github.com/cosmos/cosmos-sdk): Godocs of the Cosmos-SDK.
- [REST API spec](https://cosmos.network/rpc/): List of endpoints to interract with a `gaia` full-node through REST.
If you are reading this on the Cosmos Website, please know that you can find more information on [github](https://github.com/cosmos/cosmos-sdk/tree/develop/docs). Also if you find any issues with the documentation please [*open a Pull Request*](https://github.com/cosmos/cosmos-sdk/compare?expand=1), or at least [*open an Issue*](https://github.com/cosmos/cosmos-sdk/issues/new) to update the docs!
- [Specifications](./spec/README.md): Specifications of modules and other parts of the Cosmos SDK.
- [SDK API Reference](https://godoc.org/github.com/cosmos/cosmos-sdk): Godocs of the Cosmos SDK.
- [REST API spec](https://cosmos.network/rpc/): List of endpoints to interact with a `gaia` full-node through REST.
## Cosmos Hub testnet
To install the latest version of the `gaia` application (application of the Cosmos Hub) and join the public testnet, **click [here](./gaia/join-testnet.md)**
- [Join the public testnet](./gaia/join-testnet.md) of the Cosmos Hub.
- [Start your own `gaia` testnet](./gaia/deploy-testnet.md).
To start your own `gaia` testnet, **click [here](./gaia/deploy-testnet.md)**
## Creating a new SDK project
To create a new project, you can either:
- Fork [this repo](https://github.com/cosmos/sdk-application-tutorial/). Do not forget to remove the `nameservice` module from the various files if you don't need it.
- Use community tools like [chainkit](https://github.com/blocklayerhq/chainkit).
## Languages
The Cosmos-SDK is currently written in [Golang](https://golang.org/), though the
framework could be implemented similarly in other languages.
Contact us for information about funding an implementation in another language.
## Contribute
@ -43,4 +36,4 @@ considerations when making changes.
## Version
This documentation is built from the following commit:
This documentation is built from the following commit:

View File

@ -426,7 +426,7 @@ func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp {
app := bapp.NewBaseApp(app1Name, logger, db, tx1Decoder)
// Create a capability key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
keyAccount := sdk.NewKVStoreKey(auth.StoreKey)
// Register message routes.
// Note the handler receives the keyAccount and thus

View File

@ -2,7 +2,7 @@
In the previous app we built a simple bank with one message type `send` for sending
coins and one store for storing accounts.
Here we build `App2`, which expands on `App1` by introducing
Here we build `App2`, which expands on `App1` by introducing
- a new message type for issuing new coins
- a new store for coin metadata (like who can issue coins)
@ -38,7 +38,7 @@ methods for `MsgIssue` are similar to `MsgSend`.
## Handler
We'll need a new handler to support the new message type. It just checks if the
sender of the `MsgIssue` is the correct issuer for the given coin type, as per the information
sender of the `MsgIssue` is the correct issuer for the given coin type, as per the information
in the issuer store:
```go
@ -107,11 +107,11 @@ but that's left as an excercise for the reader :).
## Amino
Now that we have two implementations of `Msg`, we won't know before hand
Now that we have two implementations of `Msg`, we won't know before hand
which type is contained in a serialized `Tx`. Ideally, we would use the
`Msg` interface inside our `Tx` implementation, but the JSON decoder can't
decode into interface types. In fact, there's no standard way to unmarshal
into interfaces in Go. This is one of the primary reasons we built
decode into interface types. In fact, there's no standard way to unmarshal
into interfaces in Go. This is one of the primary reasons we built
[Amino](https://github.com/tendermint/go-amino) :).
While SDK developers can encode transactions and state objects however they
@ -121,7 +121,7 @@ excludes the `oneof` keyword.
While `oneof` provides union types, Amino aims to provide interfaces.
The main difference being that with union types, you have to know all the types
up front. But anyone can implement an interface type whenever and however
up front. But anyone can implement an interface type whenever and however
they like.
To implement interface types, Amino allows any concrete implementation of an
@ -164,7 +164,7 @@ Now that we're using Amino, we can embed the `Msg` interface directly in our
// Simple tx to wrap the Msg.
type app2Tx struct {
sdk.Msg
PubKey crypto.PubKey
Signature []byte
}
@ -189,7 +189,7 @@ func tx2Decoder(cdc *codec.Codec) sdk.TxDecoder {
## AnteHandler
Now that we have an implementation of `Tx` that includes more than just the Msg,
Now that we have an implementation of `Tx` that includes more than just the Msg,
we need to specify how that extra information is validated and processed. This
is the role of the `AnteHandler`. The word `ante` here denotes "before", as the
`AnteHandler` is run before a `Handler`. While an app can have many Handlers,
@ -209,7 +209,7 @@ according to whatever capability keys it was granted. Instead of a `Msg`,
however, it takes a `Tx`.
Like Handler, AnteHandler returns a `Result` type, but it also returns a new
`Context` and an `abort bool`.
`Context` and an `abort bool`.
For `App2`, we simply check if the PubKey matches the Address, and the Signature validates with the PubKey:
@ -259,7 +259,7 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp {
app := bapp.NewBaseApp(app2Name, logger, db, txDecoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
keyAccount := sdk.NewKVStoreKey(auth.StoreKey)
// Create a key for accessing the issue store.
keyIssue := sdk.NewKVStoreKey("issue")

View File

@ -1,8 +1,8 @@
# Modules
In the previous app, we introduced a new `Msg` type and used Amino to encode
transactions. We also introduced additional data to the `Tx`, and used a simple
`AnteHandler` to validate it.
transactions. We also introduced additional data to the `Tx`, and used a simple
`AnteHandler` to validate it.
Here, in `App3`, we introduce two built-in SDK modules to
replace the `Msg`, `Tx`, `Handler`, and `AnteHandler` implementations we've seen
@ -16,11 +16,11 @@ The `x/bank` module implements `Msg` and `Handler` - it has everything we need
to transfer coins between accounts.
Here, we'll introduce the important types from `x/auth` and `x/bank`, and use
them to build `App3`, our shortest app yet. The complete code can be found in
them to build `App3`, our shortest app yet. The complete code can be found in
[app3.go](examples/app3.go), and at the end of this section.
For more details, see the
[x/auth](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth) and
[x/auth](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth) and
[x/bank](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank) API documentation.
## Accounts
@ -74,7 +74,6 @@ The default implementation of `Account` is the `BaseAccount`:
```go
// BaseAccount - base account structure.
// Extend this by embedding this in your AppAccount.
// See the examples/basecoin/types/account.go for an example.
type BaseAccount struct {
Address sdk.AccAddress `json:"address"`
Coins sdk.Coins `json:"coins"`
@ -102,7 +101,7 @@ the `BaseAccount` to store additional data without requiring another lookup from
the store.
Creating an AccountKeeper is easy - we just need to specify a codec, a
capability key, and a prototype of the object being encoded
capability key, and a prototype of the object being encoded
```go
accountKeeper := auth.NewAccountKeeper(cdc, keyAccount, auth.ProtoBaseAccount)
@ -145,7 +144,7 @@ type StdTx struct {
This is the standard form for a transaction in the SDK. Besides the Msgs, it
includes:
- a fee to be paid by the first signer
- a fee to be paid by the first signer
- replay protecting nonces in the signature
- a memo of prunable additional data
@ -166,8 +165,8 @@ type StdSignature struct {
}
```
The signature includes both an `AccountNumber` and a `Sequence`.
The `Sequence` must match the one in the
The signature includes both an `AccountNumber` and a `Sequence`.
The `Sequence` must match the one in the
corresponding account when the transaction is processed, and will increment by
one with every transaction. This prevents the same
transaction from being replayed multiple times, resolving the insecurity that
@ -200,10 +199,10 @@ transaction fee can be paid, and reject the transaction if not.
The `StdTx` supports multiple messages and multiple signers.
To sign the transaction, each signer must collect the following information:
- the ChainID
- the ChainID
- the AccountNumber and Sequence for the given signer's account (from the
blockchain)
- the transaction fee
- the transaction fee
- the list of transaction messages
- an optional memo
@ -244,7 +243,7 @@ Note that validating
signatures requires checking that the correct account number and sequence was
used by each signer, as this information is required in the `StdSignBytes`.
If any of the above are not satisfied, the AnteHandelr returns an error.
If any of the above are not satisfied, the AnteHandelr returns an error.
If all of the above verifications pass, the AnteHandler makes the following
changes to the state:
@ -254,7 +253,7 @@ changes to the state:
- deduct the fee from the first signer's account
Recall that incrementing the `Sequence` prevents "replay attacks" where
the same message could be executed over and over again.
the same message could be executed over and over again.
The PubKey is required for signature verification, but it is only required in
the StdSignature once. From that point on, it will be stored in the account.
@ -267,13 +266,13 @@ Now that we've seen the `auth.AccountKeeper` and how its used to build a
complete AnteHandler, it's time to look at how to build higher-level
abstractions for taking action on accounts.
Earlier, we noted that `Mappers` are abstactions over KVStores that handle
marshalling and unmarshalling data types to and from underlying stores.
We can build another abstraction on top of `Mappers` that we call `Keepers`,
Earlier, we noted that `Mappers` are abstactions over KVStores that handle
marshalling and unmarshalling data types to and from underlying stores.
We can build another abstraction on top of `Mappers` that we call `Keepers`,
which expose only limitted functionality on the underlying types stored by the `Mapper`.
For instance, the `x/bank` module defines the canonical versions of `MsgSend`
and `MsgIssue` for the SDK, as well as a `Handler` for processing them. However,
and `MsgIssue` for the SDK, as well as a `Handler` for processing them. However,
rather than passing a `KVStore` or even an `AccountKeeper` directly to the handler,
we introduce a `bank.Keeper`, which can only be used to transfer coins in and out of accounts.
This allows us to determine up front that the only effect the bank module's
@ -302,21 +301,21 @@ docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#Keeper) for the full
Note we can refine the `bank.Keeper` by restricting it's method set. For
instance, the
[bank.ViewKeeper](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#ViewKeeper)
[bank.ViewKeeper](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#ViewKeeper)
is a read-only version, while the
[bank.SendKeeper](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#SendKeeper)
[bank.SendKeeper](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank#SendKeeper)
only executes transfers of coins from input accounts to output
accounts.
We use this `Keeper` paradigm extensively in the SDK as the way to define what
kind of functionality each module gets access to. In particular, we try to
follow the *principle of least authority*.
Rather than providing full blown access to the `KVStore` or the `AccountKeeper`,
Rather than providing full blown access to the `KVStore` or the `AccountKeeper`,
we restrict access to a small number of functions that do very specific things.
## App3
With the `auth.AccountKeeper` and `bank.Keeper` in hand,
With the `auth.AccountKeeper` and `bank.Keeper` in hand,
we're now ready to build `App3`.
The `x/auth` and `x/bank` modules do all the heavy lifting:
@ -330,8 +329,8 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
app := bapp.NewBaseApp(app3Name, logger, db, auth.DefaultTxDecoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
keyFees := sdk.NewKVStoreKey("fee") // TODO
keyAccount := sdk.NewKVStoreKey(auth.StoreKey)
keyFees := sdk.NewKVStoreKey(auth.FeeStoreKey) // TODO
// Set various mappers/keepers to interact easily with underlying stores
accountKeeper := auth.NewAccountKeeper(cdc, keyAccount, auth.ProtoBaseAccount)
@ -355,8 +354,8 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
}
```
Note we use `bank.NewHandler`, which handles only `bank.MsgSend`,
and receives only the `bank.Keeper`. See the
Note we use `bank.NewHandler`, which handles only `bank.MsgSend`,
and receives only the `bank.Keeper`. See the
[x/bank API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank)
for more details.
@ -366,7 +365,7 @@ We also use the default txDecoder in `x/auth`, which decodes amino-encoded
## Conclusion
Armed with native modules for authentication and coin transfer,
emboldened by the paradigm of mappers and keepers,
and ever invigorated by the desire to build secure state-machines,
emboldened by the paradigm of mappers and keepers,
and ever invigorated by the desire to build secure state-machines,
we find ourselves here with a full-blown, all-checks-in-place, multi-asset
cryptocurrency - the beating heart of the Cosmos-SDK.

View File

@ -9,6 +9,7 @@ import (
bapp "github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
const (
@ -22,7 +23,7 @@ func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp {
app := bapp.NewBaseApp(app1Name, logger, db, tx1Decoder)
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
keyAccount := sdk.NewKVStoreKey(auth.StoreKey)
// Register message routes.
// Note the handler gets access to the account store.

View File

@ -15,6 +15,7 @@ import (
bapp "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
const (
@ -42,7 +43,7 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp {
app := bapp.NewBaseApp(app2Name, logger, db, tx2Decoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
keyAccount := sdk.NewKVStoreKey(auth.StoreKey)
// Create a key for accessing the issue store.
keyIssue := sdk.NewKVStoreKey("issue")

View File

@ -21,7 +21,7 @@ func TestEncoding(t *testing.T) {
sendMsg := MsgSend{
From: addr1,
To: addr2,
Amount: sdk.Coins{sdk.NewCoin("testCoins", sdk.NewInt(100))},
Amount: sdk.Coins{sdk.NewCoin("testcoins", sdk.NewInt(100))},
}
// Construct transaction
@ -55,7 +55,7 @@ func TestEncoding(t *testing.T) {
issueMsg := MsgIssue{
Issuer: addr1,
Receiver: addr2,
Coin: sdk.Coin{"testCoin", sdk.NewInt(100)},
Coin: sdk.NewCoin("testcoin", sdk.NewInt(100)),
}
signBytes = issueMsg.GetSignBytes()

View File

@ -26,8 +26,8 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
app := bapp.NewBaseApp(app3Name, logger, db, auth.DefaultTxDecoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
keyFees := sdk.NewKVStoreKey("fee") // TODO
keyAccount := sdk.NewKVStoreKey(auth.StoreKey)
keyFees := sdk.NewKVStoreKey(auth.FeeStoreKey) // TODO
// Set various mappers/keepers to interact easily with underlying stores
accountKeeper := auth.NewAccountKeeper(cdc, keyAccount, auth.ProtoBaseAccount)

View File

@ -25,14 +25,14 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp {
app := bapp.NewBaseApp(app4Name, logger, db, auth.DefaultTxDecoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
keyAccount := sdk.NewKVStoreKey(auth.StoreKey)
// Set various mappers/keepers to interact easily with underlying stores
accountKeeper := auth.NewAccountKeeper(cdc, keyAccount, auth.ProtoBaseAccount)
bankKeeper := bank.NewBaseKeeper(accountKeeper)
// TODO
keyFees := sdk.NewKVStoreKey("fee")
keyFees := sdk.NewKVStoreKey(auth.FeeStoreKey)
feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees)
app.SetAnteHandler(auth.NewAnteHandler(accountKeeper, feeKeeper))

View File

@ -56,7 +56,7 @@ type SimpleGovApp struct {
Let us do a quick reminder so that it is clear why we need these stores and keepers. Our application is primarily based on the `simple_governance` module. However, we have established in section [Keepers for our app](module-keeper.md) that our module needs access to two other modules: the `bank` module and the `stake` module. We also need the `auth` module for basic account functionalities. Finally, we need access to the main multistore to declare the stores of each of the module we use.
## CLI and Rest server
## CLI and Rest server
We will need to add the newly created commands to our application. To do so, go to the `cmd` folder inside your root directory:
@ -66,7 +66,7 @@ cd cmd
```
`simplegovd` is the folder that stores the command for running the server daemon, whereas `simplegovcli` defines the commands of your application.
### Application CLI
### Application CLI
**File: [`cmd/simplegovcli/maing.go`](https://github.com/cosmos/cosmos-sdk/blob/fedekunze/module_tutorial/examples/simpleGov/cmd/simplegovcli/main.go)**
@ -191,9 +191,9 @@ var cdc = MakeCodec()
var app = &SimpleGovApp{
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
cdc: cdc,
capKeyMainStore: sdk.NewKVStoreKey("main"),
capKeyAccountStore: sdk.NewKVStoreKey("acc"),
capKeyStakingStore: sdk.NewKVStoreKey("stake"),
capKeyMainStore: sdk.NewKVStoreKey(bam.MainStoreKey),
capKeyAccountStore: sdk.NewKVStoreKey(auth.StoreKey),
capKeyStakingStore: sdk.NewKVStoreKey(stake.StoreKey),
capKeySimpleGovStore: sdk.NewKVStoreKey("simpleGov"),
}
```
@ -248,4 +248,4 @@ func MakeCodec() *codec.Codec {
cdc.RegisterConcrete(&types.AppAccount{}, "simpleGov/Account", nil)
return cdc
}
```
```

View File

@ -2,7 +2,7 @@
## Context
There is a need for a scalable structure of the SDK documentation. Current documentation includes a lot of non-related SDK material, is difficult to maintain and hard to follow as a user.
There is a need for a scalable structure of the SDK documentation. Current documentation includes a lot of non-related SDK material, is difficult to maintain and hard to follow as a user.
Ideally, we would have:
- All docs related to dev frameworks or tools live in their respective github repos (sdk repo would contain sdk docs, hub repo would contain hub docs, lotion repo would contain lotion docs, etc.)
@ -34,9 +34,6 @@ docs/
│ │ ├── cli
│ ├── gas
│ └── commands
├── examples/
│ ├── basecoin/
│ └── democoin/
├── clients/
│ ├── lite/
│ ├── service-providers
@ -46,11 +43,10 @@ docs/
The files in each sub-folders do not matter and will likely change. What matters is the sectioning:
- `README`: Landing page of the docs.
- `README`: Landing page of the docs.
- `into`: Introductory material. Goal is to have a short explainer of the SDK and then channel people to the resource they need. The [sdk-tutorial](https://github.com/cosmos/sdk-application-tutorial/) will be highlighted, as well as the `godocs`.
- `gaia`: Contains all docs related to the `gaia` application. Will later be renamed to `cosmos-hub` or `chub` and probably moved to its own repository.
- `concepts`: Contains high-level explanations of the abstractions of the SDK. It does not contain specific code implementation and does not need to be updated often. **It is not an API specification of the interfaces**. API spec is the `godoc`.
- `examples`: Contain a couple examples of sdk application like `basecoin` and `democoin`. Developers need to maintain them up-to-date and make sure they compile as the SDK gets upgraded.
- `concepts`: Contains high-level explanations of the abstractions of the SDK. It does not contain specific code implementation and does not need to be updated often. **It is not an API specification of the interfaces**. API spec is the `godoc`.
- `clients`: Contains specs and info about the various SDK clients.
- `spec`: Contains specs of modules, and others.
- `architecture`: Contains architecture-related docs like the present one.
@ -73,16 +69,16 @@ Accepted
### Positive
- Much clearer organisation of the SDK docs.
- Much clearer organisation of the SDK docs.
- The `/docs` folder now only contains SDK and gaia related material. Later, it will only contain SDK related material.
- Developers only have to update `/docs` folder when they open a PR (and not `/examples` for example).
- Developers only have to update `/docs` folder when they open a PR (and not `/examples` for example).
- Easier for developers to find what they need to update in the docs thanks to reworked architecture.
- Cleaner vuepress build for website docs.
- Cleaner vuepress build for website docs.
- Will help build an executable doc (cf https://github.com/cosmos/cosmos-sdk/issues/2611)
### Neutral
- We need to move a bunch of deprecated stuff to `/_attic` folder.
- We need to move a bunch of deprecated stuff to `/_attic` folder.
- We need to integrate content in `docs/sdk/docs/core` in `concepts`.
- We need to move all the content that currently lives in `docs` and does not fit in new structure (like `lotion`, intro material, whitepaper) to the website repository.
- Update `DOCS_README.md`
@ -91,4 +87,4 @@ Accepted
- https://github.com/cosmos/cosmos-sdk/issues/1460
- https://github.com/cosmos/cosmos-sdk/pull/2695
- https://github.com/cosmos/cosmos-sdk/issues/2611
- https://github.com/cosmos/cosmos-sdk/issues/2611

View File

@ -13,7 +13,7 @@ commitment, only the `DeliverTx` is persisted.
The BaseApp requires stores to be mounted via capabilities keys - handlers can
only access stores they're given the key to. The `baseApp` ensures all stores are
properly loaded, cached, and committed. One mounted store is considered the
"main" - it holds the latest block header, from which we can find and load the
"main" (`baseApp.MainStoreKey`) - it holds the latest block header, from which we can find and load the
most recent state.
The BaseApp distinguishes between two handler types - the `AnteHandler` and the
@ -116,9 +116,9 @@ otherwise a gas meter with `ConsensusParam.BlockSize.MaxGas` is initialized.
Before the transaction logic is run, the `BlockGasMeter` is first checked to
see if any gas remains. If no gas remains, then `DeliverTx` immediately returns
an error.
an error.
After the transaction has been processed, the used gas (up to the transaction
gas limit) is deducted from the BlockGasMeter. If the remaining gas exceeds the
meter's limits, then DeliverTx returns an error and the transaction is not
committed.
committed.

View File

@ -1,320 +0,0 @@
# Basecoin Example
Here we explain how to get started with a basic Basecoin blockchain, how
to send transactions between accounts using the ``basecli`` tool, and
what is happening under the hood.
## Setup and Install
You will need to have go installed on your computer. Please refer to the [cosmos testnet tutorial](https://cosmos.network/validators/tutorial), which will always have the most updated instructions on how to get setup with go and the cosmos repository.
Once you have go installed, run the command:
```
go get github.com/cosmos/cosmos-sdk
```
There will be an error stating `can't load package: package github.com/cosmos/cosmos-sdk: no Go files`, however you can ignore this error, it doesn't affect us. Now change directories to:
```
cd $GOPATH/src/github.com/cosmos/cosmos-sdk
```
And run :
```
make get_tools // run make update_tools if you already had it installed
make get_vendor_deps
make install_examples
```
Then run `make install_examples`, which creates binaries for `basecli` and `basecoind`. You can look at the Makefile if you want to see the details on what these make commands are doing.
## Using basecli and basecoind
Check the versions by running:
```
basecli version
basecoind version
```
They should read something like `0.17.1-5d18d5f`, but the versions will be constantly updating so don't worry if your version is higher that 0.17.1. That's a good thing.
Note that you can always check help in the terminal by running `basecli -h` or `basecoind -h`. It is good to check these out if you are stuck, because updates to the code base might slightly change the commands, and you might find the correct command in there.
Let's start by initializing the basecoind daemon. Run the command
```
basecoind init
```
And you should see something like this:
```
{
"chain_id": "test-chain-z77iHG",
"node_id": "e14c5056212b5736e201dd1d64c89246f3288129",
"app_message": {
"secret": "pluck life bracket worry guilt wink upgrade olive tilt output reform census member trouble around abandon"
}
}
```
This creates the `~/.basecoind folder`, which has config.toml, genesis.json, node_key.json, priv_validator.json. Take some time to review what is contained in these files if you want to understand what is going on at a deeper level.
## Generating keys
The next thing we'll need to do is add the key from priv_validator.json to the gaiacli key manager. For this we need the 16 word seed that represents the private key, and a password. You can also get the 16 word seed from the output seen above, under `"secret"`. Then run the command:
```
basecli keys add alice --recover
```
Which will give you three prompts:
```
Enter a passphrase for your key:
Repeat the passphrase:
Enter your recovery seed phrase:
```
You just created your first locally stored key, under the name alice, and this account is linked to the private key that is running the basecoind validator node. Once you do this, the ~/.basecli folder is created, which will hold the alice key and any other keys you make. Now that you have the key for alice, you can start up the blockchain by running
```
basecoind start
```
You should see blocks being created at a fast rate, with a lot of output in the terminal.
Next we need to make some more keys so we can use the send transaction functionality of basecoin. Open a new terminal, and run the following commands, to make two new accounts, and give each account a password you can remember:
```
basecli keys add bob
basecli keys add charlie
```
You can see your keys with the command:
```
basecli keys list
```
You should now see alice, bob and charlie's account all show up.
```
NAME: ADDRESS: PUBKEY:
alice cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f cosmospub1addwnpepq0w037u5g7y7lvdvsred2dehg90j84k0weyss5ynysf0nnnax74agrsxns6
bob cosmos18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz cosmospub1addwnpepqwe97n8lryxrzvamrvjfj24jys3uzf8wndfvqa2l7mh5nsv4jrvdznvyeg6
charlie cosmos13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q cosmospub1addwnpepqdmtxv35rrmv2dvcr3yhfyxj7dzrd4z4rnhmclksq4g55a4wpl54clvx33l
```
## Send transactions
Lets send bob and charlie some tokens. First, lets query alice's account so we can see what kind of tokens she has:
```
basecli account cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f
```
Where `cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f` is alice's address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some!
The following command will send coins from alice, to bob:
```
basecli send --from=alice --amount=10000mycoin --to=cosmos18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz
--sequence=0 --chain-id=test-chain-AE4XQo
```
Flag Descriptions:
- `from` is the name you gave your key
- `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file
- `sequence` is a tally of how many transactions have been made by this account. Since this is the first tx on this account, it is 0
- `chain-id` is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/genesis.json`
Now if we check bobs account, it should have `10000 mycoin`. You can do so by running :
```
basecli account cosmos18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz
```
Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail:
```
basecli send --from=bob --amount=5000mycoin --to=cosmos13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q
--sequence=0 --chain-id=test-chain-AE4XQo
```
Note how we use the ``--from`` flag to select a different account to send from.
Lets now try to send from bob back to alice:
```
basecli send --from=bob --amount=3000mycoin --to=cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f
--sequence=1 --chain-id=test-chain-AE4XQo
```
Notice that the sequence is now 1, since we have already recorded bobs 1st transaction as `sequence 0`. Also note the ``hash`` value in the response in the terminal - this is the hash of the transaction. We can query for the transaction with this command:
```
basecli tx <INSERT HASH HERE>
```
It will return the details of the transaction hash, such as how many coins were send and to which address, and on what block it occurred.
That is the basic implementation of basecoin!
## Reset the basecoind blockchain and basecli data
**WARNING:** Running these commands will wipe out any existing
information in both the ``~/.basecli`` and ``~/.basecoind`` directories,
including private keys. This should be no problem considering that basecoin
is just an example, but it is always good to pay extra attention when
you are removing private keys, in any scenario involving a blockchain.
To remove all the files created and refresh your environment (e.g., if
starting this tutorial again or trying something new), the following
commands are run:
```
basecoind unsafe-reset-all
rm -rf ~/.basecoind
rm -rf ~/.basecli
```
## Technical Details on how Basecoin Works
This section describes some of the more technical aspects for what is going on under the hood of Basecoin.
## Proof
Even if you don't see it in the UI, the result of every query comes with
a proof. This is a Merkle proof that the result of the query is actually
contained in the state. And the state's Merkle root is contained in a
recent block header. Behind the scenes, ``basecli`` will not only
verify that this state matches the header, but also that the header is
properly signed by the known validator set. It will even update the
validator set as needed, so long as there have not been major changes
and it is secure to do so. So, if you wonder why the query may take a
second... there is a lot of work going on in the background to make sure
even a lying full node can't trick your client.
## Accounts and Transactions
For a better understanding of how to further use the tools, it helps to
understand the underlying data structures, so lets look at accounts and transactions.
### Accounts
The Basecoin state consists entirely of a set of accounts. Each account
contains an address, a public key, a balance in many different coin denominations,
and a strictly increasing sequence number for replay protection. This
type of account was directly inspired by accounts in Ethereum, and is
unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs).
```
type BaseAccount struct {
Address sdk.Address `json:"address"`
Coins sdk.Coins `json:"coins"`
PubKey crypto.PubKey `json:"public_key"`
Sequence int64 `json:"sequence"`
}
```
You can also add more fields to accounts, and basecoin actually does so. Basecoin
adds a Name field in order to show how easily the base account structure can be
modified to suit any applications needs. It takes the `auth.BaseAccount` we see above,
and extends it with `Name`.
```
type AppAccount struct {
auth.BaseAccount
Name string `json:"name"`
}
```
Within accounts, coin balances are stored. Basecoin is a multi-asset cryptocurrency, so each account can have many
different kinds of tokens, which are held in an array.
```
type Coins []Coin
type Coin struct {
Denom string `json:"denom"`
Amount int64 `json:"amount"`
}
```
If you want to add more coins to a blockchain, you can do so manually in
the ``~/.basecoin/genesis.json`` before you start the blockchain for the
first time.
Accounts are serialized and stored in a Merkle tree under the key
``base/a/<address>``, where ``<address>`` is the address of the account.
Typically, the address of the account is the first 20-bytes of the ``sha256`` hash
of the public key, but other formats are acceptable as well, as defined
in the `Tendermint crypto
library <https://github.com/tendermint/tendermint/tree/master/crypto>`__. The Merkle tree
used in Basecoin is a balanced, binary search tree, which we call an
`IAVL tree <https://github.com/tendermint/iavl>`__.
### Transactions
Basecoin defines a transaction type, the `SendTx`, which allows tokens
to be sent to other accounts. The `SendTx` takes a list of inputs and
a list of outputs, and transfers all the tokens listed in the inputs
from their corresponding accounts to the accounts listed in the output.
The `SendTx` is structured as follows:
```
type SendTx struct {
Gas int64 `json:"gas"`
Fee Coin `json:"fee"`
Inputs []TxInput `json:"inputs"`
Outputs []TxOutput `json:"outputs"`
}
type TxInput struct {
Address []byte `json:"address"` // Hash of the PubKey
Coins Coins `json:"coins"` //
Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput
Signature []byte `json:"signature"` // Depends on the PubKey type and the whole Tx
PubKey crypto.PubKey `json:"pub_key"` // Is present iff Sequence == 0
}
type TxOutput struct {
Address []byte `json:"address"` // Hash of the PubKey
Coins Coins `json:"coins"` //
}
```
Note the `SendTx` includes a field for `Gas` and `Fee`. The
`Gas` limits the total amount of computation that can be done by the
transaction, while the `Fee` refers to the total amount paid in fees.
This is slightly different from Ethereum's concept of `Gas` and
`GasPrice`, where `Fee = Gas x GasPrice`. In Basecoin, the `Gas`
and `Fee` are independent, and the `GasPrice` is implicit.
In Basecoin, the `Fee` is meant to be used by the validators to inform
the ordering of transactions, like in Bitcoin. And the `Gas` is meant
to be used by the application plugin to control its execution. There is
currently no means to pass `Fee` information to the Tendermint
validators, but it will come soon... so this version of Basecoin does
not actually fully implement fees and gas, but it still allows us
to send transactions between accounts.
Note also that the `PubKey` only needs to be sent for
`Sequence == 0`. After that, it is stored under the account in the
Merkle tree and subsequent transactions can exclude it, using only the
`Address` to refer to the sender. Ethereum does not require public
keys to be sent in transactions as it uses a different elliptic curve
scheme which enables the public key to be derived from the signature
itself.
Finally, note that the use of multiple inputs and multiple outputs
allows us to send many different types of tokens between many different
accounts at once in an atomic transaction. Thus, the `SendTx` can
serve as a basic unit of decentralized exchange. When using multiple
inputs and outputs, you must make sure that the sum of coins of the
inputs equals the sum of coins of the outputs (no creating money), and
that all accounts that provide inputs have signed the transaction.

View File

@ -1,190 +0,0 @@
package app
import (
"encoding/json"
"os"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/docs/examples/basecoin/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/ibc"
)
const (
appName = "BasecoinApp"
)
// default home directories for expected binaries
var (
DefaultCLIHome = os.ExpandEnv("$HOME/.basecli")
DefaultNodeHome = os.ExpandEnv("$HOME/.basecoind")
)
// BasecoinApp implements an extended ABCI application. It contains a BaseApp,
// a codec for serialization, KVStore keys for multistore state management, and
// various mappers and keepers to manage getting, setting, and serializing the
// integral app types.
type BasecoinApp struct {
*bam.BaseApp
cdc *codec.Codec
// keys to access the multistore
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
keyIBC *sdk.KVStoreKey
// manage getting and setting accounts
accountKeeper auth.AccountKeeper
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
ibcMapper ibc.Mapper
}
// NewBasecoinApp returns a reference to a new BasecoinApp given a logger and
// database. Internally, a codec is created along with all the necessary keys.
// In addition, all necessary mappers and keepers are created, routes
// registered, and finally the stores being mounted along with any necessary
// chain initialization.
func NewBasecoinApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseApp)) *BasecoinApp {
// create and register app-level codec for TXs and accounts
cdc := MakeCodec()
// create your application type
var app = &BasecoinApp{
cdc: cdc,
BaseApp: bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...),
keyMain: sdk.NewKVStoreKey("main"),
keyAccount: sdk.NewKVStoreKey("acc"),
keyIBC: sdk.NewKVStoreKey("ibc"),
}
// define and attach the mappers and keepers
app.accountKeeper = auth.NewAccountKeeper(
cdc,
app.keyAccount, // target store
func() auth.Account {
return &types.AppAccount{}
},
)
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, ibc.DefaultCodespace)
// register message routes
app.Router().
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.bankKeeper))
// perform initialization logic
app.SetInitChainer(app.initChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper))
// mount the multistore and load the latest state
app.MountStores(app.keyMain, app.keyAccount, app.keyIBC)
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())
}
app.Seal()
return app
}
// MakeCodec creates a new codec codec and registers all the necessary types
// with the codec.
func MakeCodec() *codec.Codec {
cdc := codec.New()
codec.RegisterCrypto(cdc)
sdk.RegisterCodec(cdc)
bank.RegisterCodec(cdc)
ibc.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
// register custom type
cdc.RegisterConcrete(&types.AppAccount{}, "basecoin/Account", nil)
cdc.Seal()
return cdc
}
// BeginBlocker reflects logic to run before any TXs application are processed
// by the application.
func (app *BasecoinApp) BeginBlocker(_ sdk.Context, _ abci.RequestBeginBlock) abci.ResponseBeginBlock {
return abci.ResponseBeginBlock{}
}
// EndBlocker reflects logic to run after all TXs are processed by the
// application.
func (app *BasecoinApp) EndBlocker(_ sdk.Context, _ abci.RequestEndBlock) abci.ResponseEndBlock {
return abci.ResponseEndBlock{}
}
// initChainer implements the custom application logic that the BaseApp will
// invoke upon initialization. In this case, it will take the application's
// state provided by 'req' and attempt to deserialize said state. The state
// should contain all the genesis accounts. These accounts will be added to the
// application's account mapper.
func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
genesisState := new(types.GenesisState)
err := app.cdc.UnmarshalJSON(stateJSON, genesisState)
if err != nil {
// TODO: https://github.com/cosmos/cosmos-sdk/issues/468
panic(err)
}
for _, gacc := range genesisState.Accounts {
acc, err := gacc.ToAppAccount()
if err != nil {
// TODO: https://github.com/cosmos/cosmos-sdk/issues/468
panic(err)
}
acc.AccountNumber = app.accountKeeper.GetNextAccountNumber(ctx)
app.accountKeeper.SetAccount(ctx, acc)
}
return abci.ResponseInitChain{}
}
// ExportAppStateAndValidators implements custom application logic that exposes
// various parts of the application's state and set of validators. An error is
// returned if any step getting the state or set of validators fails.
func (app *BasecoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
ctx := app.NewContext(true, abci.Header{})
accounts := []*types.GenesisAccount{}
appendAccountsFn := func(acc auth.Account) bool {
account := &types.GenesisAccount{
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
}
accounts = append(accounts, account)
return false
}
app.accountKeeper.IterateAccounts(ctx, appendAccountsFn)
genState := types.GenesisState{Accounts: accounts}
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
}
return appState, validators, err
}

View File

@ -1,82 +0,0 @@
package app
import (
"os"
"testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/ed25519"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/docs/examples/basecoin/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
func setGenesis(baseApp *BasecoinApp, accounts ...*types.AppAccount) (types.GenesisState, error) {
genAccts := make([]*types.GenesisAccount, len(accounts))
for i, appAct := range accounts {
genAccts[i] = types.NewGenesisAccount(appAct)
}
genesisState := types.GenesisState{Accounts: genAccts}
stateBytes, err := codec.MarshalJSONIndent(baseApp.cdc, genesisState)
if err != nil {
return types.GenesisState{}, err
}
// initialize and commit the chain
baseApp.InitChain(abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{}, AppStateBytes: stateBytes,
})
baseApp.Commit()
return genesisState, nil
}
func TestGenesis(t *testing.T) {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
baseApp := NewBasecoinApp(logger, db)
// construct a pubkey and an address for the test account
pubkey := ed25519.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
// construct some test coins
coins, err := sdk.ParseCoins("77foocoin,99barcoin")
require.Nil(t, err)
// create an auth.BaseAccount for the given test account and set it's coins
baseAcct := auth.NewBaseAccountWithAddress(addr)
err = baseAcct.SetCoins(coins)
require.Nil(t, err)
// create a new test AppAccount with the given auth.BaseAccount
appAcct := types.NewAppAccount("foobar", baseAcct)
genState, err := setGenesis(baseApp, appAcct)
require.Nil(t, err)
// create a context for the BaseApp
ctx := baseApp.BaseApp.NewContext(true, abci.Header{})
res := baseApp.accountKeeper.GetAccount(ctx, baseAcct.Address)
require.Equal(t, appAcct, res)
// reload app and ensure the account is still there
baseApp = NewBasecoinApp(logger, db)
stateBytes, err := codec.MarshalJSONIndent(baseApp.cdc, genState)
require.Nil(t, err)
// initialize the chain with the expected genesis state
baseApp.InitChain(abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{}, AppStateBytes: stateBytes,
})
ctx = baseApp.BaseApp.NewContext(true, abci.Header{})
res = baseApp.accountKeeper.GetAccount(ctx, baseAcct.Address)
require.Equal(t, appAcct, res)
}

View File

@ -1,56 +0,0 @@
package clitest
import (
"encoding/json"
"fmt"
"os"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
)
var (
basecoindHome = ""
basecliHome = ""
)
func init() {
basecoindHome, basecliHome = getTestingHomeDirs()
}
func TestInitStartSequence(t *testing.T) {
os.RemoveAll(basecoindHome)
servAddr, port, err := server.FreeTCPAddr()
require.NoError(t, err)
executeInit(t)
executeStart(t, servAddr, port)
}
func executeInit(t *testing.T) {
var (
chainID string
initRes map[string]json.RawMessage
)
_, stderr := tests.ExecuteT(t, fmt.Sprintf("basecoind --home=%s --home-client=%s init --name=test", basecoindHome, basecliHome), app.DefaultKeyPass)
err := json.Unmarshal([]byte(stderr), &initRes)
require.NoError(t, err)
err = json.Unmarshal(initRes["chain_id"], &chainID)
require.NoError(t, err)
}
func executeStart(t *testing.T, servAddr, port string) {
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("basecoind start --home=%s --rpc.laddr=%v", basecoindHome, servAddr))
defer proc.Stop(false)
tests.WaitForTMStart(port)
}
func getTestingHomeDirs() (string, string) {
tmpDir := os.TempDir()
basecoindHome := fmt.Sprintf("%s%s.test_basecoind", tmpDir, string(os.PathSeparator))
basecliHome := fmt.Sprintf("%s%s.test_basecli", tmpDir, string(os.PathSeparator))
return basecoindHome, basecliHome
}

View File

@ -1,127 +0,0 @@
package main
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/lcd"
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/docs/examples/basecoin/app"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/libs/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
)
const (
storeAcc = "acc"
storeSlashing = "slashing"
storeStake = "stake"
)
// rootCmd is the entry point for this binary
var (
rootCmd = &cobra.Command{
Use: "basecli",
Short: "Basecoin light-client",
}
)
func main() {
// disable sorting
cobra.EnableCommandSorting = false
// get the codec
cdc := app.MakeCodec()
// Setup certain SDK config
config := sdk.GetConfig()
config.SetBech32PrefixForAccount("baseacc", "basepub")
config.SetBech32PrefixForValidator("baseval", "basevalpub")
config.SetBech32PrefixForConsensusNode("basecons", "baseconspub")
config.Seal()
// TODO: Setup keybase, viper object, etc. to be passed into
// the below functions and eliminate global vars, like we do
// with the cdc.
// add standard rpc, and tx commands
rootCmd.AddCommand(
rpc.InitClientCommand(),
rpc.StatusCommand(),
client.LineBreak,
tx.SearchTxCmd(cdc),
tx.QueryTxCmd(cdc),
client.LineBreak,
)
// add query/post commands (custom to binary)
rootCmd.AddCommand(
stakecmd.GetCmdQueryValidator(storeStake, cdc),
stakecmd.GetCmdQueryValidators(storeStake, cdc),
stakecmd.GetCmdQueryValidatorUnbondingDelegations(storeStake, cdc),
stakecmd.GetCmdQueryValidatorRedelegations(storeStake, cdc),
stakecmd.GetCmdQueryDelegation(storeStake, cdc),
stakecmd.GetCmdQueryDelegations(storeStake, cdc),
stakecmd.GetCmdQueryPool(storeStake, cdc),
stakecmd.GetCmdQueryParams(storeStake, cdc),
stakecmd.GetCmdQueryUnbondingDelegation(storeStake, cdc),
stakecmd.GetCmdQueryUnbondingDelegations(storeStake, cdc),
stakecmd.GetCmdQueryRedelegation(storeStake, cdc),
stakecmd.GetCmdQueryRedelegations(storeStake, cdc),
slashingcmd.GetCmdQuerySigningInfo(storeSlashing, cdc),
stakecmd.GetCmdQueryValidatorDelegations(storeStake, cdc),
authcmd.GetAccountCmd(storeAcc, cdc),
)
rootCmd.AddCommand(
bankcmd.SendTxCmd(cdc),
ibccmd.IBCTransferCmd(cdc),
ibccmd.IBCRelayCmd(cdc),
stakecmd.GetCmdCreateValidator(cdc),
stakecmd.GetCmdEditValidator(cdc),
stakecmd.GetCmdDelegate(cdc),
stakecmd.GetCmdUnbond(storeStake, cdc),
stakecmd.GetCmdRedelegate(storeStake, cdc),
slashingcmd.GetCmdUnjail(cdc),
)
// add proxy, version and key info
rootCmd.AddCommand(
client.LineBreak,
lcd.ServeCommand(cdc, registerRoutes),
keys.Commands(),
client.LineBreak,
version.VersionCmd,
)
// prepare and add flags
executor := cli.PrepareMainCmd(rootCmd, "BC", app.DefaultCLIHome)
err := executor.Execute()
if err != nil {
// Note: Handle with #870
panic(err)
}
}
func registerRoutes(rs *lcd.RestServer) {
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, storeAcc)
bank.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
stake.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashing.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
}

View File

@ -1,132 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"github.com/tendermint/tendermint/p2p"
"github.com/cosmos/cosmos-sdk/baseapp"
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
"github.com/spf13/cobra"
"github.com/spf13/viper"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/docs/examples/basecoin/app"
"github.com/cosmos/cosmos-sdk/server"
)
const (
flagClientHome = "home-client"
)
func main() {
cdc := app.MakeCodec()
ctx := server.NewDefaultContext()
rootCmd := &cobra.Command{
Use: "basecoind",
Short: "Basecoin Daemon (server)",
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
}
rootCmd.AddCommand(InitCmd(ctx, cdc))
server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators)
// prepare and add flags
rootDir := os.ExpandEnv("$HOME/.basecoind")
executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir)
err := executor.Execute()
if err != nil {
// Note: Handle with #870
panic(err)
}
}
// get cmd to initialize all files for tendermint and application
// nolint: errcheck
func InitCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
Args: cobra.NoArgs,
RunE: func(_ *cobra.Command, _ []string) error {
config := ctx.Config
config.SetRoot(viper.GetString(cli.HomeFlag))
chainID := viper.GetString(client.FlagChainID)
if chainID == "" {
chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
}
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil {
return err
}
nodeID := string(nodeKey.ID())
pk := gaiaInit.ReadOrCreatePrivValidator(config.PrivValidatorFile())
genTx, appMessage, validator, err := server.SimpleAppGenTx(cdc, pk)
if err != nil {
return err
}
appState, err := server.SimpleAppGenState(
cdc, tmtypes.GenesisDoc{}, []json.RawMessage{genTx})
if err != nil {
return err
}
appStateJSON, err := cdc.MarshalJSON(appState)
if err != nil {
return err
}
toPrint := struct {
ChainID string `json:"chain_id"`
NodeID string `json:"node_id"`
AppMessage json.RawMessage `json:"app_message"`
}{
chainID,
nodeID,
appMessage,
}
out, err := codec.MarshalJSONIndent(cdc, toPrint)
if err != nil {
return err
}
fmt.Fprintf(os.Stderr, "%s\n", string(out))
return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID,
[]tmtypes.GenesisValidator{validator}, appStateJSON)
},
}
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
cmd.Flags().String(client.FlagChainID, "",
"genesis file chain-id, if left blank will be randomly created")
cmd.Flags().String(client.FlagName, "", "validator's moniker")
cmd.MarkFlagRequired(client.FlagName)
return cmd
}
func newApp(logger log.Logger, db dbm.DB, storeTracer io.Writer) abci.Application {
return app.NewBasecoinApp(logger, db, baseapp.SetPruning(viper.GetString("pruning")))
}
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, storeTracer io.Writer, _ int64, _ bool) (
json.RawMessage, []tmtypes.GenesisValidator, error) {
bapp := app.NewBasecoinApp(logger, db)
return bapp.ExportAppStateAndValidators()
}

View File

@ -1,81 +0,0 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
var _ auth.Account = (*AppAccount)(nil)
// AppAccount is a custom extension for this application. It is an example of
// extending auth.BaseAccount with custom fields. It is compatible with the
// stock auth.AccountKeeper, since auth.AccountKeeper uses the flexible go-amino
// library.
type AppAccount struct {
auth.BaseAccount
Name string `json:"name"`
}
// nolint
func (acc AppAccount) GetName() string { return acc.Name }
func (acc *AppAccount) SetName(name string) { acc.Name = name }
// NewAppAccount returns a reference to a new AppAccount given a name and an
// auth.BaseAccount.
func NewAppAccount(name string, baseAcct auth.BaseAccount) *AppAccount {
return &AppAccount{BaseAccount: baseAcct, Name: name}
}
// GetAccountDecoder returns the AccountDecoder function for the custom
// AppAccount.
func GetAccountDecoder(cdc *codec.Codec) auth.AccountDecoder {
return func(accBytes []byte) (auth.Account, error) {
if len(accBytes) == 0 {
return nil, sdk.ErrTxDecode("accBytes are empty")
}
acct := new(AppAccount)
err := cdc.UnmarshalBinaryBare(accBytes, &acct)
if err != nil {
panic(err)
}
return acct, err
}
}
// GenesisState reflects the genesis state of the application.
type GenesisState struct {
Accounts []*GenesisAccount `json:"accounts"`
}
// GenesisAccount reflects a genesis account the application expects in it's
// genesis state.
type GenesisAccount struct {
Name string `json:"name"`
Address sdk.AccAddress `json:"address"`
Coins sdk.Coins `json:"coins"`
}
// NewGenesisAccount returns a reference to a new GenesisAccount given an
// AppAccount.
func NewGenesisAccount(aa *AppAccount) *GenesisAccount {
return &GenesisAccount{
Name: aa.Name,
Address: aa.Address,
Coins: aa.Coins.Sort(),
}
}
// ToAppAccount converts a GenesisAccount to an AppAccount.
func (ga *GenesisAccount) ToAppAccount() (acc *AppAccount, err error) {
return &AppAccount{
Name: ga.Name,
BaseAccount: auth.BaseAccount{
Address: ga.Address,
Coins: ga.Coins.Sort(),
},
}, nil
}

View File

@ -1,197 +0,0 @@
package app
import (
"encoding/json"
"os"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/types"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/cool"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/pow"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/simplestake"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/sketchy"
)
const (
appName = "DemocoinApp"
)
// default home directories for expected binaries
var (
DefaultCLIHome = os.ExpandEnv("$HOME/.democli")
DefaultNodeHome = os.ExpandEnv("$HOME/.democoind")
)
// Extended ABCI application
type DemocoinApp struct {
*bam.BaseApp
cdc *codec.Codec
// keys to access the substores
capKeyMainStore *sdk.KVStoreKey
capKeyAccountStore *sdk.KVStoreKey
capKeyPowStore *sdk.KVStoreKey
capKeyIBCStore *sdk.KVStoreKey
capKeyStakingStore *sdk.KVStoreKey
// keepers
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
coolKeeper cool.Keeper
powKeeper pow.Keeper
ibcMapper ibc.Mapper
stakeKeeper simplestake.Keeper
// Manage getting and setting accounts
accountKeeper auth.AccountKeeper
}
func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
// Create app-level codec for txs and accounts.
var cdc = MakeCodec()
// Create your application object.
var app = &DemocoinApp{
BaseApp: bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc)),
cdc: cdc,
capKeyMainStore: sdk.NewKVStoreKey("main"),
capKeyAccountStore: sdk.NewKVStoreKey("acc"),
capKeyPowStore: sdk.NewKVStoreKey("pow"),
capKeyIBCStore: sdk.NewKVStoreKey("ibc"),
capKeyStakingStore: sdk.NewKVStoreKey("stake"),
}
// Define the accountKeeper.
app.accountKeeper = auth.NewAccountKeeper(
cdc,
app.capKeyAccountStore, // target store
types.ProtoAppAccount, // prototype
)
// Add handlers.
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
app.coolKeeper = cool.NewKeeper(app.capKeyMainStore, app.bankKeeper, cool.DefaultCodespace)
app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), app.bankKeeper, pow.DefaultCodespace)
app.ibcMapper = ibc.NewMapper(app.cdc, app.capKeyIBCStore, ibc.DefaultCodespace)
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper, simplestake.DefaultCodespace)
app.Router().
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("cool", cool.NewHandler(app.coolKeeper)).
AddRoute("pow", app.powKeeper.Handler).
AddRoute("sketchy", sketchy.NewHandler()).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.bankKeeper)).
AddRoute("simplestake", simplestake.NewHandler(app.stakeKeeper))
// Initialize BaseApp.
app.SetInitChainer(app.initChainerFn(app.coolKeeper, app.powKeeper))
app.MountStores(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore)
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper))
err := app.LoadLatestVersion(app.capKeyMainStore)
if err != nil {
cmn.Exit(err.Error())
}
app.Seal()
return app
}
// custom tx codec
func MakeCodec() *codec.Codec {
var cdc = codec.New()
codec.RegisterCrypto(cdc) // Register crypto.
sdk.RegisterCodec(cdc) // Register Msgs
cool.RegisterCodec(cdc)
pow.RegisterCodec(cdc)
bank.RegisterCodec(cdc)
ibc.RegisterCodec(cdc)
simplestake.RegisterCodec(cdc)
// Register AppAccount
cdc.RegisterInterface((*auth.Account)(nil), nil)
cdc.RegisterConcrete(&types.AppAccount{}, "democoin/Account", nil)
cdc.Seal()
return cdc
}
// custom logic for democoin initialization
// nolint: unparam
func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keeper) sdk.InitChainer {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
genesisState := new(types.GenesisState)
err := app.cdc.UnmarshalJSON(stateJSON, genesisState)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
for _, gacc := range genesisState.Accounts {
acc, err := gacc.ToAppAccount()
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
app.accountKeeper.SetAccount(ctx, acc)
}
// Application specific genesis handling
err = cool.InitGenesis(ctx, app.coolKeeper, genesisState.CoolGenesis)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
err = pow.InitGenesis(ctx, app.powKeeper, genesisState.POWGenesis)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
return abci.ResponseInitChain{}
}
}
// Custom logic for state export
func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
ctx := app.NewContext(true, abci.Header{})
// iterate to get the accounts
accounts := []*types.GenesisAccount{}
appendAccount := func(acc auth.Account) (stop bool) {
account := &types.GenesisAccount{
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
}
accounts = append(accounts, account)
return false
}
app.accountKeeper.IterateAccounts(ctx, appendAccount)
genState := types.GenesisState{
Accounts: accounts,
POWGenesis: pow.ExportGenesis(ctx, app.powKeeper),
CoolGenesis: cool.ExportGenesis(ctx, app.coolKeeper),
}
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
}
return appState, validators, nil
}

View File

@ -1,73 +0,0 @@
package app
import (
"os"
"testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/ed25519"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/types"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/cool"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
func setGenesis(bapp *DemocoinApp, trend string, accs ...auth.BaseAccount) error {
genaccs := make([]*types.GenesisAccount, len(accs))
for i, acc := range accs {
genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, "foobart"})
}
genesisState := types.GenesisState{
Accounts: genaccs,
CoolGenesis: cool.Genesis{trend},
}
stateBytes, err := codec.MarshalJSONIndent(bapp.cdc, genesisState)
if err != nil {
return err
}
// Initialize the chain
vals := []abci.ValidatorUpdate{}
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
bapp.Commit()
return nil
}
func TestGenesis(t *testing.T) {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
bapp := NewDemocoinApp(logger, db)
// Construct some genesis bytes to reflect democoin/types/AppAccount
pk := ed25519.GenPrivKey().PubKey()
addr := sdk.AccAddress(pk.Address())
coins, err := sdk.ParseCoins("77foocoin,99barcoin")
require.Nil(t, err)
baseAcc := auth.BaseAccount{
Address: addr,
Coins: coins,
}
acc := &types.AppAccount{baseAcc, "foobart"}
err = setGenesis(bapp, "ice-cold", baseAcc)
require.Nil(t, err)
// A checkTx context
ctx := bapp.BaseApp.NewContext(true, abci.Header{})
res1 := bapp.accountKeeper.GetAccount(ctx, baseAcc.Address)
require.Equal(t, acc, res1)
// reload app and ensure the account is still there
bapp = NewDemocoinApp(logger, db)
bapp.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}")})
ctx = bapp.BaseApp.NewContext(true, abci.Header{})
res1 = bapp.accountKeeper.GetAccount(ctx, baseAcc.Address)
require.Equal(t, acc, res1)
}

View File

@ -1,57 +0,0 @@
package clitest
import (
"encoding/json"
"fmt"
"os"
"testing"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
)
var (
democoindHome = ""
democliHome = ""
)
func init() {
democoindHome, democliHome = getTestingHomeDirs()
}
func TestInitStartSequence(t *testing.T) {
os.RemoveAll(democoindHome)
servAddr, port, err := server.FreeTCPAddr()
require.NoError(t, err)
executeInit(t)
executeStart(t, servAddr, port)
}
func executeInit(t *testing.T) {
var (
chainID string
initRes map[string]json.RawMessage
)
_, stderr := tests.ExecuteT(t, fmt.Sprintf("democoind --home=%s --home-client=%s init --name=test", democoindHome, democliHome), app.DefaultKeyPass)
err := json.Unmarshal([]byte(stderr), &initRes)
require.NoError(t, err)
err = json.Unmarshal(initRes["chain_id"], &chainID)
require.NoError(t, err)
}
func executeStart(t *testing.T, servAddr, port string) {
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("democoind start --home=%s --rpc.laddr=%v", democoindHome, servAddr))
defer proc.Stop(false)
tests.WaitForTMStart(port)
}
func getTestingHomeDirs() (string, string) {
tmpDir := os.TempDir()
democoindHome := fmt.Sprintf("%s%s.test_democoind", tmpDir, string(os.PathSeparator))
democliHome := fmt.Sprintf("%s%s.test_democli", tmpDir, string(os.PathSeparator))
return democoindHome, democliHome
}

View File

@ -1,114 +0,0 @@
package main
import (
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/lcd"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/version"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/app"
coolcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/cool/client/cli"
powcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/pow/client/cli"
simplestakingcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/simplestake/client/cli"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// rootCmd is the entry point for this binary
var (
rootCmd = &cobra.Command{
Use: "democli",
Short: "Democoin light-client",
}
storeAcc = "acc"
)
func main() {
// disable sorting
cobra.EnableCommandSorting = false
// get the codec
cdc := app.MakeCodec()
// Setup certain SDK config
config := sdk.GetConfig()
config.SetBech32PrefixForAccount("demoacc", "demopub")
config.SetBech32PrefixForValidator("demoval", "demovalpub")
config.SetBech32PrefixForConsensusNode("democons", "democonspub")
config.Seal()
// TODO: setup keybase, viper object, etc. to be passed into
// the below functions and eliminate global vars, like we do
// with the cdc
// add standard rpc, and tx commands
rootCmd.AddCommand(
rpc.InitClientCommand(),
rpc.StatusCommand(),
client.LineBreak,
tx.SearchTxCmd(cdc),
tx.QueryTxCmd(cdc),
client.LineBreak,
)
// add query/post commands (custom to binary)
// start with commands common to basecoin
rootCmd.AddCommand(
authcmd.GetAccountCmd(storeAcc, cdc),
)
rootCmd.AddCommand(
bankcmd.SendTxCmd(cdc),
)
rootCmd.AddCommand(
client.PostCommands(
simplestakingcmd.BondTxCmd(cdc),
)...)
rootCmd.AddCommand(
client.PostCommands(
simplestakingcmd.UnbondTxCmd(cdc),
)...)
// and now democoin specific commands
rootCmd.AddCommand(
client.PostCommands(
coolcmd.QuizTxCmd(cdc),
coolcmd.SetTrendTxCmd(cdc),
powcmd.MineCmd(cdc),
)...)
// add proxy, version and key info
rootCmd.AddCommand(
client.LineBreak,
lcd.ServeCommand(cdc, registerRoutes),
keys.Commands(),
client.LineBreak,
version.VersionCmd,
)
// prepare and add flags
executor := cli.PrepareMainCmd(rootCmd, "BC", app.DefaultCLIHome)
err := executor.Execute()
if err != nil {
// handle with #870
panic(err)
}
}
func registerRoutes(rs *lcd.RestServer) {
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, storeAcc)
bank.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
}

View File

@ -1,169 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/p2p"
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/cli"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/app"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
)
const (
flagClientHome = "home-client"
)
// coolGenAppParams sets up the app_state and appends the cool app state
func CoolAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
appState json.RawMessage, err error) {
appState, err = server.SimpleAppGenState(cdc, tmtypes.GenesisDoc{}, appGenTxs)
if err != nil {
return
}
key := "cool"
value := json.RawMessage(`{
"trend": "ice-cold"
}`)
appState, err = server.InsertKeyJSON(cdc, appState, key, value)
if err != nil {
return
}
key = "pow"
value = json.RawMessage(`{
"difficulty": "1",
"count": "0"
}`)
appState, err = server.InsertKeyJSON(cdc, appState, key, value)
return
}
// get cmd to initialize all files for tendermint and application
// nolint: errcheck
func InitCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
Args: cobra.NoArgs,
RunE: func(_ *cobra.Command, _ []string) error {
config := ctx.Config
config.SetRoot(viper.GetString(cli.HomeFlag))
chainID := viper.GetString(client.FlagChainID)
if chainID == "" {
chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
}
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil {
return err
}
nodeID := string(nodeKey.ID())
pk := gaiaInit.ReadOrCreatePrivValidator(config.PrivValidatorFile())
genTx, appMessage, validator, err := server.SimpleAppGenTx(cdc, pk)
if err != nil {
return err
}
appState, err := CoolAppGenState(cdc, tmtypes.GenesisDoc{},
[]json.RawMessage{genTx})
if err != nil {
return err
}
appStateJSON, err := cdc.MarshalJSON(appState)
if err != nil {
return err
}
toPrint := struct {
ChainID string `json:"chain_id"`
NodeID string `json:"node_id"`
AppMessage json.RawMessage `json:"app_message"`
}{
chainID,
nodeID,
appMessage,
}
out, err := codec.MarshalJSONIndent(cdc, toPrint)
if err != nil {
return err
}
fmt.Fprintf(os.Stderr, "%s\n", string(out))
return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID,
[]tmtypes.GenesisValidator{validator}, appStateJSON)
},
}
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
cmd.Flags().String(client.FlagChainID, "",
"genesis file chain-id, if left blank will be randomly created")
cmd.Flags().String(client.FlagName, "", "validator's moniker")
cmd.MarkFlagRequired(client.FlagName)
return cmd
}
func newApp(logger log.Logger, db dbm.DB, _ io.Writer) abci.Application {
return app.NewDemocoinApp(logger, db)
}
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, _ io.Writer, _ int64, _ bool) (
json.RawMessage, []tmtypes.GenesisValidator, error) {
dapp := app.NewDemocoinApp(logger, db)
return dapp.ExportAppStateAndValidators()
}
func main() {
cdc := app.MakeCodec()
// Setup certain SDK config
config := sdk.GetConfig()
config.SetBech32PrefixForAccount("demoacc", "demopub")
config.SetBech32PrefixForValidator("demoval", "demovalpub")
config.SetBech32PrefixForConsensusNode("democons", "democonspub")
config.Seal()
ctx := server.NewDefaultContext()
rootCmd := &cobra.Command{
Use: "democoind",
Short: "Democoin Daemon (server)",
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
}
rootCmd.AddCommand(InitCmd(ctx, cdc))
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc))
server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators)
// prepare and add flags
rootDir := os.ExpandEnv("$HOME/.democoind")
executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir)
err := executor.Execute()
if err != nil {
// handle with #870
panic(err)
}
}

View File

@ -1,163 +0,0 @@
package mock
import (
"bytes"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Validator implements sdk.Validator
type Validator struct {
Address sdk.ValAddress
Power sdk.Dec
}
// Implements sdk.Validator
func (v Validator) GetStatus() sdk.BondStatus {
return sdk.Bonded
}
// Implements sdk.Validator
func (v Validator) GetOperator() sdk.ValAddress {
return v.Address
}
// Implements sdk.Validator
func (v Validator) GetConsPubKey() crypto.PubKey {
return nil
}
// Implements sdk.Validator
func (v Validator) GetConsAddr() sdk.ConsAddress {
return nil
}
// Implements sdk.Validator
func (v Validator) GetTokens() sdk.Dec {
return sdk.ZeroDec()
}
// Implements sdk.Validator
func (v Validator) GetPower() sdk.Dec {
return v.Power
}
// Implements sdk.Validator
func (v Validator) GetDelegatorShares() sdk.Dec {
return sdk.ZeroDec()
}
// Implements sdk.Validator
func (v Validator) GetCommission() sdk.Dec {
return sdk.ZeroDec()
}
// Implements sdk.Validator
func (v Validator) GetJailed() bool {
return false
}
// Implements sdk.Validator
func (v Validator) GetBondHeight() int64 {
return 0
}
// Implements sdk.Validator
func (v Validator) GetMoniker() string {
return ""
}
// Implements sdk.Validator
type ValidatorSet struct {
Validators []Validator
}
// IterateValidators implements sdk.ValidatorSet
func (vs *ValidatorSet) IterateValidators(ctx sdk.Context, fn func(index int64, Validator sdk.Validator) bool) {
for i, val := range vs.Validators {
if fn(int64(i), val) {
break
}
}
}
// IterateBondedValidatorsByPower implements sdk.ValidatorSet
func (vs *ValidatorSet) IterateBondedValidatorsByPower(ctx sdk.Context, fn func(index int64, Validator sdk.Validator) bool) {
vs.IterateValidators(ctx, fn)
}
// IterateLastValidators implements sdk.ValidatorSet
func (vs *ValidatorSet) IterateLastValidators(ctx sdk.Context, fn func(index int64, Validator sdk.Validator) bool) {
vs.IterateValidators(ctx, fn)
}
// Validator implements sdk.ValidatorSet
func (vs *ValidatorSet) Validator(ctx sdk.Context, addr sdk.ValAddress) sdk.Validator {
for _, val := range vs.Validators {
if bytes.Equal(val.Address.Bytes(), addr.Bytes()) {
return val
}
}
return nil
}
// ValidatorByPubKey implements sdk.ValidatorSet
func (vs *ValidatorSet) ValidatorByConsPubKey(_ sdk.Context, _ crypto.PubKey) sdk.Validator {
panic("not implemented")
}
// ValidatorByPubKey implements sdk.ValidatorSet
func (vs *ValidatorSet) ValidatorByConsAddr(_ sdk.Context, _ sdk.ConsAddress) sdk.Validator {
panic("not implemented")
}
// TotalPower implements sdk.ValidatorSet
func (vs *ValidatorSet) TotalPower(ctx sdk.Context) sdk.Dec {
res := sdk.ZeroDec()
for _, val := range vs.Validators {
res = res.Add(val.Power)
}
return res
}
// Helper function for adding new validator
func (vs *ValidatorSet) AddValidator(val Validator) {
vs.Validators = append(vs.Validators, val)
}
// Helper function for removing exsting validator
func (vs *ValidatorSet) RemoveValidator(addr sdk.AccAddress) {
pos := -1
for i, val := range vs.Validators {
if bytes.Equal(val.Address, addr) {
pos = i
break
}
}
if pos == -1 {
return
}
vs.Validators = append(vs.Validators[:pos], vs.Validators[pos+1:]...)
}
// Implements sdk.ValidatorSet
func (vs *ValidatorSet) Slash(_ sdk.Context, _ sdk.ConsAddress, _ int64, _ int64, _ sdk.Dec) {
panic("not implemented")
}
// Implements sdk.ValidatorSet
func (vs *ValidatorSet) Jail(_ sdk.Context, _ sdk.ConsAddress) {
panic("not implemented")
}
// Implements sdk.ValidatorSet
func (vs *ValidatorSet) Unjail(_ sdk.Context, _ sdk.ConsAddress) {
panic("not implemented")
}
// Implements sdk.ValidatorSet
func (vs *ValidatorSet) Delegation(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) sdk.Delegation {
panic("not implemented")
}

View File

@ -1,82 +0,0 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/cool"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/pow"
)
var _ auth.Account = (*AppAccount)(nil)
// Custom extensions for this application. This is just an example of
// extending auth.BaseAccount with custom fields.
//
// This is compatible with the stock auth.AccountStore, since
// auth.AccountStore uses the flexible go-amino library.
type AppAccount struct {
auth.BaseAccount
Name string `json:"name"`
}
// Constructor for AppAccount
func ProtoAppAccount() auth.Account {
return &AppAccount{}
}
// nolint
func (acc AppAccount) GetName() string { return acc.Name }
func (acc *AppAccount) SetName(name string) { acc.Name = name }
// Get the AccountDecoder function for the custom AppAccount
func GetAccountDecoder(cdc *codec.Codec) auth.AccountDecoder {
return func(accBytes []byte) (res auth.Account, err error) {
if len(accBytes) == 0 {
return nil, sdk.ErrTxDecode("accBytes are empty")
}
acct := new(AppAccount)
err = cdc.UnmarshalBinaryBare(accBytes, &acct)
if err != nil {
panic(err)
}
return acct, err
}
}
//___________________________________________________________________________________
// State to Unmarshal
type GenesisState struct {
Accounts []*GenesisAccount `json:"accounts"`
POWGenesis pow.Genesis `json:"pow"`
CoolGenesis cool.Genesis `json:"cool"`
}
// GenesisAccount doesn't need pubkey or sequence
type GenesisAccount struct {
Name string `json:"name"`
Address sdk.AccAddress `json:"address"`
Coins sdk.Coins `json:"coins"`
}
func NewGenesisAccount(aa *AppAccount) *GenesisAccount {
return &GenesisAccount{
Name: aa.Name,
Address: aa.Address,
Coins: aa.Coins.Sort(),
}
}
// convert GenesisAccount to AppAccount
func (ga *GenesisAccount) ToAppAccount() (acc *AppAccount, err error) {
baseAcc := auth.BaseAccount{
Address: ga.Address,
Coins: ga.Coins.Sort(),
}
return &AppAccount{
BaseAccount: baseAcc,
Name: ga.Name,
}, nil
}

View File

@ -1,107 +0,0 @@
package assoc
import (
"bytes"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// ValidatorSet defines
type ValidatorSet struct {
sdk.ValidatorSet
store sdk.KVStore
cdc *codec.Codec
maxAssoc int
addrLen int
}
var _ sdk.ValidatorSet = ValidatorSet{}
// NewValidatorSet returns new ValidatorSet with underlying ValidatorSet
func NewValidatorSet(cdc *codec.Codec, store sdk.KVStore, valset sdk.ValidatorSet, maxAssoc int, addrLen int) ValidatorSet {
if maxAssoc < 0 || addrLen < 0 {
panic("Cannot use negative integer for NewValidatorSet")
}
return ValidatorSet{
ValidatorSet: valset,
store: store,
cdc: cdc,
maxAssoc: maxAssoc,
addrLen: addrLen,
}
}
// Implements sdk.ValidatorSet
func (valset ValidatorSet) Validator(ctx sdk.Context, addr sdk.ValAddress) (res sdk.Validator) {
base := valset.store.Get(GetBaseKey(addr))
res = valset.ValidatorSet.Validator(ctx, base)
if res == nil {
res = valset.ValidatorSet.Validator(ctx, addr)
}
return
}
// GetBaseKey :: sdk.ValAddress -> sdk.ValAddress
func GetBaseKey(addr sdk.ValAddress) []byte {
return append([]byte{0x00}, addr...)
}
// GetAssocPrefix :: sdk.ValAddress -> (sdk.ValAddress -> byte)
func GetAssocPrefix(base sdk.ValAddress) []byte {
return append([]byte{0x01}, base...)
}
// GetAssocKey :: (sdk.ValAddress, sdk.ValAddress) -> byte
func GetAssocKey(base sdk.ValAddress, assoc sdk.ValAddress) []byte {
return append(append([]byte{0x01}, base...), assoc...)
}
// Associate associates new address with validator address
// nolint: unparam
func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
return false
}
// If someone already owns the associated address
if valset.store.Get(GetBaseKey(assoc)) != nil {
return false
}
valset.store.Set(GetBaseKey(assoc), base)
valset.store.Set(GetAssocKey(base, assoc), []byte{0x00})
return true
}
// Dissociate removes association between addresses
// nolint: unparam
func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
return false
}
// No associated address found for given validator
if !bytes.Equal(valset.store.Get(GetBaseKey(assoc)), base) {
return false
}
valset.store.Delete(GetBaseKey(assoc))
valset.store.Delete(GetAssocKey(base, assoc))
return true
}
// Associations returns all associated addresses with a validator
// nolint: unparam
func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.ValAddress) (res []sdk.ValAddress) {
res = make([]sdk.ValAddress, valset.maxAssoc)
iter := sdk.KVStorePrefixIterator(valset.store, GetAssocPrefix(base))
defer iter.Close()
i := 0
for ; iter.Valid(); iter.Next() {
key := iter.Key()
res[i] = key[len(key)-valset.addrLen:]
i++
}
return res[:i]
}

View File

@ -1,71 +0,0 @@
package assoc
import (
"bytes"
"testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/mock"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func defaultContext(key sdk.StoreKey) sdk.Context {
db := dbm.NewMemDB()
cms := store.NewCommitMultiStore(db)
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
cms.LoadLatestVersion()
ctx := sdk.NewContext(cms, abci.Header{}, false, nil)
return ctx
}
func TestValidatorSet(t *testing.T) {
key := sdk.NewKVStoreKey("test")
ctx := defaultContext(key)
addr1 := []byte("addr1")
addr2 := []byte("addr2")
base := &mock.ValidatorSet{[]mock.Validator{
{addr1, sdk.NewDec(1)},
{addr2, sdk.NewDec(2)},
}}
valset := NewValidatorSet(codec.New(), ctx.KVStore(key).Prefix([]byte("assoc")), base, 1, 5)
require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1))
require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2))
assoc1 := []byte("asso1")
assoc2 := []byte("asso2")
require.True(t, valset.Associate(ctx, addr1, assoc1))
require.True(t, valset.Associate(ctx, addr2, assoc2))
require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, assoc1))
require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, assoc2))
require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1))
require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2))
assocs := valset.Associations(ctx, addr1)
require.Equal(t, 1, len(assocs))
require.True(t, bytes.Equal(assoc1, assocs[0]))
require.False(t, valset.Associate(ctx, addr1, assoc2))
require.False(t, valset.Associate(ctx, addr2, assoc1))
valset.Dissociate(ctx, addr1, assoc1)
valset.Dissociate(ctx, addr2, assoc2)
require.Equal(t, base.Validator(ctx, addr1), valset.Validator(ctx, addr1))
require.Equal(t, base.Validator(ctx, addr2), valset.Validator(ctx, addr2))
require.Nil(t, valset.Validator(ctx, assoc1))
require.Nil(t, valset.Validator(ctx, assoc2))
}

View File

@ -1,105 +0,0 @@
package cool
import (
"testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
bank "github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/mock"
)
var (
priv1 = ed25519.GenPrivKey()
pubKey = priv1.PubKey()
addr1 = sdk.AccAddress(pubKey.Address())
quizMsg1 = MsgQuiz{
Sender: addr1,
CoolAnswer: "icecold",
}
quizMsg2 = MsgQuiz{
Sender: addr1,
CoolAnswer: "badvibesonly",
}
setTrendMsg1 = MsgSetTrend{
Sender: addr1,
Cool: "icecold",
}
setTrendMsg2 = MsgSetTrend{
Sender: addr1,
Cool: "badvibesonly",
}
setTrendMsg3 = MsgSetTrend{
Sender: addr1,
Cool: "warmandkind",
}
)
// initialize the mock application for this module
func getMockApp(t *testing.T) *mock.App {
mapp := mock.NewApp()
RegisterCodec(mapp.Cdc)
keyCool := sdk.NewKVStoreKey("cool")
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper)
keeper := NewKeeper(keyCool, bankKeeper, DefaultCodespace)
mapp.Router().AddRoute("cool", NewHandler(keeper))
mapp.SetInitChainer(getInitChainer(mapp, keeper, "ice-cold"))
require.NoError(t, mapp.CompleteSetup(keyCool))
return mapp
}
// overwrite the mock init chainer
func getInitChainer(mapp *mock.App, keeper Keeper, newTrend string) sdk.InitChainer {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
mapp.InitChainer(ctx, req)
keeper.setTrend(ctx, newTrend)
return abci.ResponseInitChain{}
}
}
func TestMsgQuiz(t *testing.T) {
mapp := getMockApp(t)
// Construct genesis state
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: nil,
}
accs := []auth.Account{acc1}
// Initialize the chain (nil)
mock.SetGenesis(mapp, accs)
// A checkTx context (true)
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
res1 := mapp.AccountKeeper.GetAccount(ctxCheck, addr1)
require.Equal(t, acc1, res1)
// Set the trend, submit a really cool quiz and check for reward
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []uint64{0}, []uint64{0}, true, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []uint64{0}, []uint64{1}, true, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(69))})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []uint64{0}, []uint64{2}, false, false, priv1) // result without reward
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(69))})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []uint64{0}, []uint64{3}, true, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(138))})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg2}, []uint64{0}, []uint64{4}, true, true, priv1) // reset the trend
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []uint64{0}, []uint64{5}, false, false, priv1) // the same answer will nolonger do!
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(138))})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []uint64{0}, []uint64{6}, true, true, priv1) // earlier answer now relevant again
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("badvibesonly", sdk.NewInt(69)), sdk.NewCoin("icecold", sdk.NewInt(138))})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg3}, []uint64{0}, []uint64{7}, false, false, priv1) // expect to fail to set the trend to something which is not cool
}

View File

@ -1,60 +0,0 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/cool"
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
// QuizTxCmd invokes the coolness quiz transaction.
func QuizTxCmd(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "cool [answer]",
Short: "What's cooler than being cool?",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithAccountDecoder(cdc)
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
msg := cool.NewMsgQuiz(from, args[0])
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}
// SetTrendTxCmd sends a new cool trend transaction.
func SetTrendTxCmd(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "setcool [answer]",
Short: "You're so cool, tell us what is cool!",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithAccountDecoder(cdc)
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
msg := cool.NewMsgSetTrend(from, args[0])
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}

View File

@ -1,11 +0,0 @@
package cool
import (
"github.com/cosmos/cosmos-sdk/codec"
)
// Register concrete types on codec codec
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(MsgQuiz{}, "cool/Quiz", nil)
cdc.RegisterConcrete(MsgSetTrend{}, "cool/SetTrend", nil)
}

View File

@ -1,20 +0,0 @@
package cool
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Cool errors reserve 400 ~ 499.
const (
DefaultCodespace sdk.CodespaceType = "cool"
// Cool module reserves error 400-499 lawl
CodeIncorrectCoolAnswer sdk.CodeType = 400
)
// ErrIncorrectCoolAnswer - Error returned upon an incorrect guess
func ErrIncorrectCoolAnswer(codespace sdk.CodespaceType, answer string) sdk.Error {
return sdk.NewError(codespace, CodeIncorrectCoolAnswer, fmt.Sprintf("incorrect cool answer: %v", answer))
}

View File

@ -1,57 +0,0 @@
package cool
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// This is just an example to demonstrate a functional custom module
// with full feature set functionality.
//
// /$$$$$$$ /$$$$$$ /$$$$$$ /$$
// /$$_____/ /$$__ $$ /$$__ $$| $$
//| $$ | $$ \ $$| $$ \ $$| $$
//| $$ | $$ | $$| $$ | $$| $$
//| $$$$$$$| $$$$$$/| $$$$$$/| $$$$$$$
// \_______/ \______/ \______/ |______/
// NewHandler returns a handler for "cool" type messages.
func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case MsgSetTrend:
return handleMsgSetTrend(ctx, k, msg)
case MsgQuiz:
return handleMsgQuiz(ctx, k, msg)
default:
errMsg := fmt.Sprintf("Unrecognized cool Msg type: %v", msg.Type())
return sdk.ErrUnknownRequest(errMsg).Result()
}
}
}
// Handle MsgQuiz This is the engine of your module
func handleMsgSetTrend(ctx sdk.Context, k Keeper, msg MsgSetTrend) sdk.Result {
k.setTrend(ctx, msg.Cool)
return sdk.Result{}
}
// Handle MsgQuiz This is the engine of your module
func handleMsgQuiz(ctx sdk.Context, k Keeper, msg MsgQuiz) sdk.Result {
correct := k.CheckTrend(ctx, msg.CoolAnswer)
if !correct {
return ErrIncorrectCoolAnswer(k.codespace, msg.CoolAnswer).Result()
}
bonusCoins := sdk.Coins{sdk.NewInt64Coin(msg.CoolAnswer, 69)}
_, _, err := k.ck.AddCoins(ctx, msg.Sender, bonusCoins)
if err != nil {
return err.Result()
}
return sdk.Result{}
}

View File

@ -1,56 +0,0 @@
package cool
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank"
)
// Keeper - handlers sets/gets of custom variables for your module
type Keeper struct {
ck bank.Keeper
storeKey sdk.StoreKey // The (unexposed) key used to access the store from the Context.
codespace sdk.CodespaceType
}
// NewKeeper - Returns the Keeper
func NewKeeper(key sdk.StoreKey, bankKeeper bank.Keeper, codespace sdk.CodespaceType) Keeper {
return Keeper{bankKeeper, key, codespace}
}
// Key to knowing the trend on the streets!
var trendKey = []byte("TrendKey")
// GetTrend - returns the current cool trend
func (k Keeper) GetTrend(ctx sdk.Context) string {
store := ctx.KVStore(k.storeKey)
bz := store.Get(trendKey)
return string(bz)
}
// Implements sdk.AccountKeeper.
func (k Keeper) setTrend(ctx sdk.Context, newTrend string) {
store := ctx.KVStore(k.storeKey)
store.Set(trendKey, []byte(newTrend))
}
// CheckTrend - Returns true or false based on whether guessedTrend is currently cool or not
func (k Keeper) CheckTrend(ctx sdk.Context, guessedTrend string) bool {
if guessedTrend == k.GetTrend(ctx) {
return true
}
return false
}
// InitGenesis - store the genesis trend
func InitGenesis(ctx sdk.Context, k Keeper, data Genesis) error {
k.setTrend(ctx, data.Trend)
return nil
}
// ExportGenesis - output the genesis trend
func ExportGenesis(ctx sdk.Context, k Keeper) Genesis {
trend := k.GetTrend(ctx)
return Genesis{trend}
}

View File

@ -1,50 +0,0 @@
package cool
import (
"testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
auth "github.com/cosmos/cosmos-sdk/x/auth"
bank "github.com/cosmos/cosmos-sdk/x/bank"
)
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) {
db := dbm.NewMemDB()
capKey := sdk.NewKVStoreKey("capkey")
ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db)
ms.LoadLatestVersion()
return ms, capKey
}
func TestCoolKeeper(t *testing.T) {
ms, capKey := setupMultiStore()
cdc := codec.New()
auth.RegisterBaseAccount(cdc)
am := auth.NewAccountKeeper(cdc, capKey, auth.ProtoBaseAccount)
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
ck := bank.NewBaseKeeper(am)
keeper := NewKeeper(capKey, ck, DefaultCodespace)
err := InitGenesis(ctx, keeper, Genesis{"icy"})
require.Nil(t, err)
genesis := ExportGenesis(ctx, keeper)
require.Nil(t, err)
require.Equal(t, genesis, Genesis{"icy"})
res := keeper.GetTrend(ctx)
require.Equal(t, res, "icy")
keeper.setTrend(ctx, "fiery")
res = keeper.GetTrend(ctx)
require.Equal(t, res, "fiery")
}

View File

@ -1,108 +0,0 @@
package cool
import (
"encoding/json"
"fmt"
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// a really cool msg type, these fields are can be entirely arbitrary and
// custom to your message
type MsgSetTrend struct {
Sender sdk.AccAddress
Cool string
}
// genesis state - specify genesis trend
type Genesis struct {
Trend string `json:"trend"`
}
// new cool message
func NewMsgSetTrend(sender sdk.AccAddress, cool string) MsgSetTrend {
return MsgSetTrend{
Sender: sender,
Cool: cool,
}
}
// enforce the msg type at compile time
var _ sdk.Msg = MsgSetTrend{}
// nolint
func (msg MsgSetTrend) Route() string { return "cool" }
func (msg MsgSetTrend) Type() string { return "set_trend" }
func (msg MsgSetTrend) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Sender} }
func (msg MsgSetTrend) String() string {
return fmt.Sprintf("MsgSetTrend{Sender: %v, Cool: %v}", msg.Sender, msg.Cool)
}
// Validate Basic is used to quickly disqualify obviously invalid messages quickly
func (msg MsgSetTrend) ValidateBasic() sdk.Error {
if len(msg.Sender) == 0 {
return sdk.ErrUnknownAddress(msg.Sender.String()).TraceSDK("")
}
if strings.Contains(msg.Cool, "hot") {
return sdk.ErrUnauthorized("").TraceSDK("hot is not cool")
}
if strings.Contains(msg.Cool, "warm") {
return sdk.ErrUnauthorized("").TraceSDK("warm is not very cool")
}
return nil
}
// Get the bytes for the message signer to sign on
func (msg MsgSetTrend) GetSignBytes() []byte {
b, err := json.Marshal(msg)
if err != nil {
panic(err)
}
return sdk.MustSortJSON(b)
}
//_______________________________________________________________________
// A message type to quiz how cool you are. these fields are can be entirely
// arbitrary and custom to your message
type MsgQuiz struct {
Sender sdk.AccAddress
CoolAnswer string
}
// New cool message
func NewMsgQuiz(sender sdk.AccAddress, coolerthancool string) MsgQuiz {
return MsgQuiz{
Sender: sender,
CoolAnswer: coolerthancool,
}
}
// enforce the msg type at compile time
var _ sdk.Msg = MsgQuiz{}
// nolint
func (msg MsgQuiz) Route() string { return "cool" }
func (msg MsgQuiz) Type() string { return "quiz" }
func (msg MsgQuiz) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Sender} }
func (msg MsgQuiz) String() string {
return fmt.Sprintf("MsgQuiz{Sender: %v, CoolAnswer: %v}", msg.Sender, msg.CoolAnswer)
}
// Validate Basic is used to quickly disqualify obviously invalid messages quickly
func (msg MsgQuiz) ValidateBasic() sdk.Error {
if len(msg.Sender) == 0 {
return sdk.ErrUnknownAddress(msg.Sender.String()).TraceSDK("")
}
return nil
}
// Get the bytes for the message signer to sign on
func (msg MsgQuiz) GetSignBytes() []byte {
b, err := json.Marshal(msg)
if err != nil {
panic(err)
}
return sdk.MustSortJSON(b)
}

View File

@ -1,58 +0,0 @@
# Oracle Module
`x/oracle` provides a way to receive external information(real world price, events from other chains, etc.) with validators' vote. Each validator make transaction which contains those informations, and Oracle aggregates them until the supermajority signed on it. After then, Oracle sends the information to the actual module that processes the information, and prune the votes from the state.
## Integration
See `x/oracle/oracle_test.go` for the code that using Oracle
To use Oracle in your module, first define a `payload`. It should implement `oracle.Payload` and contain nessesary information for your module. Including nonce is recommended.
```go
type MyPayload struct {
Data int
Nonce int
}
```
When you write a payload, its `.Route()` should return same route with your module is registered on the router. It is because `oracle.Msg` inherits `.Route()` from its embedded payload and it should be handled on the user modules.
Then route every incoming `oracle.Msg` to `oracle.Keeper.Handler()` with the function that implements `oracle.Handler`.
```go
func NewHandler(keeper Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case oracle.Msg:
return keeper.oracle.Handle(ctx sdk.Context, p oracle.Payload) sdk.Error {
switch p := p.(type) {
case MyPayload:
return handleMyPayload(ctx, keeper, p)
}
}
}
}
}
```
In the previous example, the keeper has an `oracle.Keeper`. `oracle.Keeper`s are generated by `NewKeeper`.
```go
func NewKeeper(key sdk.StoreKey, cdc *codec.Codec, valset sdk.ValidatorSet, supermaj sdk.Dec, timeout int64) Keeper {
return Keeper {
cdc: cdc,
key: key,
// ValidatorSet to get validators infor
valset: valset,
// The keeper will pass payload
// when more than 2/3 signed on it
supermaj: supermaj,
// The keeper will prune votes after 100 blocks from last sign
timeout: timeout,
}
}
```
Now the validators can send `oracle.Msg`s with `MyPayload` when they want to witness external events.

View File

@ -1,31 +0,0 @@
package oracle
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Oracle errors reserve 1101-1199
const (
CodeNotValidator sdk.CodeType = 1101
CodeAlreadyProcessed sdk.CodeType = 1102
CodeAlreadySigned sdk.CodeType = 1103
CodeUnknownRequest sdk.CodeType = sdk.CodeUnknownRequest
)
// ----------------------------------------
// Error constructors
// ErrNotValidator called when the signer of a Msg is not a validator
func ErrNotValidator(codespace sdk.CodespaceType, address sdk.AccAddress) sdk.Error {
return sdk.NewError(codespace, CodeNotValidator, address.String())
}
// ErrAlreadyProcessed called when a payload is already processed
func ErrAlreadyProcessed(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeAlreadyProcessed, "")
}
// ErrAlreadySigned called when the signer is trying to double signing
func ErrAlreadySigned(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeAlreadySigned, "")
}

View File

@ -1,106 +0,0 @@
package oracle
import (
"bytes"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Handler handles payload after it passes voting process
type Handler func(ctx sdk.Context, p Payload) sdk.Error
func (keeper Keeper) update(ctx sdk.Context, val sdk.Validator, valset sdk.ValidatorSet, p Payload, info Info) Info {
info.Power = info.Power.Add(val.GetPower())
// Return if the voted power is not bigger than required power
totalPower := valset.TotalPower(ctx)
requiredPower := totalPower.Mul(keeper.supermaj)
if !info.Power.GT(requiredPower) {
return info
}
// Check if the validators hash has been changed during the vote process
// and recalculate voted power
hash := ctx.BlockHeader().ValidatorsHash
if !bytes.Equal(hash, info.Hash) {
info.Power = sdk.ZeroDec()
info.Hash = hash
prefix := GetSignPrefix(p, keeper.cdc)
store := ctx.KVStore(keeper.key)
iter := sdk.KVStorePrefixIterator(store, prefix)
defer iter.Close()
for ; iter.Valid(); iter.Next() {
if valset.Validator(ctx, iter.Value()) != nil {
store.Delete(iter.Key())
continue
}
info.Power = info.Power.Add(val.GetPower())
}
if !info.Power.GT(totalPower.Mul(keeper.supermaj)) {
return info
}
}
info.Status = Processed
return info
}
// Handle is used by other modules to handle Msg
func (keeper Keeper) Handle(h Handler, ctx sdk.Context, o Msg, codespace sdk.CodespaceType) sdk.Result {
valset := keeper.valset
signer := o.Signer
payload := o.Payload
// Check the oracle is not in process
info := keeper.Info(ctx, payload)
if info.Status != Pending {
return ErrAlreadyProcessed(codespace).Result()
}
// Check if it is reporting timeout
now := ctx.BlockHeight()
if now > info.LastSigned+keeper.timeout {
info = Info{Status: Timeout}
keeper.setInfo(ctx, payload, info)
keeper.clearSigns(ctx, payload)
return sdk.Result{}
}
info.LastSigned = ctx.BlockHeight()
// check the signer is a validator
val := valset.Validator(ctx, sdk.ValAddress(signer))
if val == nil {
return ErrNotValidator(codespace, signer).Result()
}
// Check double signing
if keeper.signed(ctx, payload, signer) {
return ErrAlreadySigned(codespace).Result()
}
keeper.sign(ctx, payload, signer)
info = keeper.update(ctx, val, valset, payload, info)
if info.Status == Processed {
info = Info{Status: Processed}
}
keeper.setInfo(ctx, payload, info)
if info.Status == Processed {
keeper.clearSigns(ctx, payload)
cctx, write := ctx.CacheContext()
err := h(cctx, payload)
if err != nil {
return sdk.Result{
Code: sdk.CodeOK,
Log: err.ABCILog(),
}
}
write()
}
return sdk.Result{}
}

View File

@ -1,111 +0,0 @@
package oracle
import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Keeper of the oracle store
type Keeper struct {
key sdk.StoreKey
cdc *codec.Codec
valset sdk.ValidatorSet
supermaj sdk.Dec
timeout int64
}
// NewKeeper constructs a new keeper
func NewKeeper(key sdk.StoreKey, cdc *codec.Codec, valset sdk.ValidatorSet, supermaj sdk.Dec, timeout int64) Keeper {
if timeout < 0 {
panic("Timeout should not be negative")
}
return Keeper{
key: key,
cdc: cdc,
valset: valset,
supermaj: supermaj,
timeout: timeout,
}
}
// InfoStatus - current status of an Info
type InfoStatus int8
// Define InfoStatus
const (
Pending = InfoStatus(iota)
Processed
Timeout
)
// Info for each payload
type Info struct {
Power sdk.Dec
Hash []byte
LastSigned int64
Status InfoStatus
}
// EmptyInfo construct an empty Info
func EmptyInfo(ctx sdk.Context) Info {
return Info{
Power: sdk.ZeroDec(),
Hash: ctx.BlockHeader().ValidatorsHash,
LastSigned: ctx.BlockHeight(),
Status: Pending,
}
}
// Info returns the information about a payload
func (keeper Keeper) Info(ctx sdk.Context, p Payload) (res Info) {
store := ctx.KVStore(keeper.key)
key := GetInfoKey(p, keeper.cdc)
bz := store.Get(key)
if bz == nil {
return EmptyInfo(ctx)
}
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &res)
return
}
func (keeper Keeper) setInfo(ctx sdk.Context, p Payload, info Info) {
store := ctx.KVStore(keeper.key)
key := GetInfoKey(p, keeper.cdc)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(info)
store.Set(key, bz)
}
func (keeper Keeper) sign(ctx sdk.Context, p Payload, signer sdk.AccAddress) {
store := ctx.KVStore(keeper.key)
key := GetSignKey(p, signer, keeper.cdc)
store.Set(key, signer)
}
func (keeper Keeper) signed(ctx sdk.Context, p Payload, signer sdk.AccAddress) bool {
store := ctx.KVStore(keeper.key)
key := GetSignKey(p, signer, keeper.cdc)
return store.Has(key)
}
func (keeper Keeper) clearSigns(ctx sdk.Context, p Payload) {
store := ctx.KVStore(keeper.key)
prefix := GetSignPrefix(p, keeper.cdc)
iter := sdk.KVStorePrefixIterator(store, prefix)
for ; iter.Valid(); iter.Next() {
store.Delete(iter.Key())
}
iter.Close()
}

Some files were not shown because too many files have changed in this diff Show More