commit
e003c5ebe0
@ -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
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
client/lcd/swagger-ui/* linguist-vendored
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@ -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
|
||||
|
||||
152
CHANGELOG.md
152
CHANGELOG.md
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
11
Gopkg.lock
generated
@ -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",
|
||||
|
||||
@ -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"
|
||||
|
||||
79
Makefile
79
Makefile
@ -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 \
|
||||
|
||||
@ -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
2
Vagrantfile
vendored
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
142
client/lcd/swagger-ui/swagger.yaml
vendored
142
client/lcd/swagger-ui/swagger.yaml
vendored
@ -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:
|
||||
|
||||
@ -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), ¶ms)
|
||||
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)
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/cmd/cosmos-sdk-cli/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@ -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),
|
||||
}
|
||||
|
||||
|
||||
@ -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))
|
||||
}
|
||||
|
||||
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
51
cmd/gaia/cli_test/README.md
Normal file
51
cmd/gaia/cli_test/README.md
Normal 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
591
cmd/gaia/cli_test/test_helpers.go
Normal file
591
cmd/gaia/cli_test/test_helpers.go
Normal 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), ¶ms)
|
||||
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), ¶ms)
|
||||
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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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",
|
||||
|
||||
@ -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
|
||||
```
|
||||
|
||||
@ -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.
|
||||
|
||||

|
||||
## 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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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")
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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")
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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")
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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]
|
||||
}
|
||||
@ -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))
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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})
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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))
|
||||
}
|
||||
@ -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{}
|
||||
}
|
||||
@ -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}
|
||||
}
|
||||
@ -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")
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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.
|
||||
@ -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, "")
|
||||
}
|
||||
@ -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{}
|
||||
}
|
||||
@ -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
Loading…
Reference in New Issue
Block a user