Merge PR #4036: Release v0.34.0
This commit is contained in:
commit
7cb34220af
|
@ -3,7 +3,7 @@ version: 2
|
||||||
defaults: &linux_defaults
|
defaults: &linux_defaults
|
||||||
working_directory: /go/src/github.com/cosmos/cosmos-sdk
|
working_directory: /go/src/github.com/cosmos/cosmos-sdk
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/golang:1.11.5
|
- image: circleci/golang:1.12.1
|
||||||
environment:
|
environment:
|
||||||
GOBIN: /tmp/workspace/bin
|
GOBIN: /tmp/workspace/bin
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ macos_config: &macos_defaults
|
||||||
xcode: "10.1.0"
|
xcode: "10.1.0"
|
||||||
working_directory: /Users/distiller/project/src/github.com/cosmos/cosmos-sdk
|
working_directory: /Users/distiller/project/src/github.com/cosmos/cosmos-sdk
|
||||||
environment:
|
environment:
|
||||||
GO_VERSION: "1.11.5"
|
GO_VERSION: "1.12.1"
|
||||||
|
|
||||||
set_macos_env: &macos_env
|
set_macos_env: &macos_env
|
||||||
run:
|
run:
|
||||||
|
@ -27,6 +27,7 @@ set_macos_env: &macos_env
|
||||||
echo 'export GOPATH=$HOME/project' >> $BASH_ENV
|
echo 'export GOPATH=$HOME/project' >> $BASH_ENV
|
||||||
echo 'export GOBIN=$GOPATH/bin' >> $BASH_ENV
|
echo 'export GOBIN=$GOPATH/bin' >> $BASH_ENV
|
||||||
echo 'export PATH=$PATH:$HOME/go/bin:$GOBIN' >> $BASH_ENV
|
echo 'export PATH=$PATH:$HOME/go/bin:$GOBIN' >> $BASH_ENV
|
||||||
|
echo 'export GO111MODULE=on'
|
||||||
|
|
||||||
############
|
############
|
||||||
#
|
#
|
||||||
|
@ -35,7 +36,7 @@ set_macos_env: &macos_env
|
||||||
docs_update: &docs_deploy
|
docs_update: &docs_deploy
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
docker:
|
docker:
|
||||||
- image: tendermint/docs_deployment
|
- image: tendermintdev/jq_curl
|
||||||
environment:
|
environment:
|
||||||
AWS_REGION: us-east-1
|
AWS_REGION: us-east-1
|
||||||
|
|
||||||
|
@ -44,7 +45,6 @@ deps: &dependencies
|
||||||
name: dependencies
|
name: dependencies
|
||||||
command: |
|
command: |
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
make vendor-deps
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup_dependencies:
|
setup_dependencies:
|
||||||
|
@ -53,6 +53,9 @@ jobs:
|
||||||
- run: mkdir -p /tmp/workspace/bin
|
- run: mkdir -p /tmp/workspace/bin
|
||||||
- run: mkdir -p /tmp/workspace/profiles
|
- run: mkdir -p /tmp/workspace/profiles
|
||||||
- checkout
|
- checkout
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
- run:
|
- run:
|
||||||
name: tools
|
name: tools
|
||||||
command: |
|
command: |
|
||||||
|
@ -63,7 +66,12 @@ jobs:
|
||||||
name: binaries
|
name: binaries
|
||||||
command: |
|
command: |
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
|
make go-mod-cache
|
||||||
make install
|
make install
|
||||||
|
- save_cache:
|
||||||
|
key: go-mod-v1-{{ checksum "go.sum" }}
|
||||||
|
paths:
|
||||||
|
- "/go/pkg/mod"
|
||||||
- persist_to_workspace:
|
- persist_to_workspace:
|
||||||
root: /tmp/workspace
|
root: /tmp/workspace
|
||||||
paths:
|
paths:
|
||||||
|
@ -78,17 +86,14 @@ jobs:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- checkout
|
- checkout
|
||||||
- *dependencies
|
- *dependencies
|
||||||
- run:
|
- restore_cache:
|
||||||
name: Get metalinter
|
keys:
|
||||||
command: |
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
export PATH="$GOBIN:$PATH"
|
|
||||||
make devtools-clean
|
|
||||||
make devtools
|
|
||||||
- run:
|
- run:
|
||||||
name: Lint source
|
name: Lint source
|
||||||
command: |
|
command: |
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
make test_lint
|
make ci-lint
|
||||||
|
|
||||||
integration_tests:
|
integration_tests:
|
||||||
<<: *linux_defaults
|
<<: *linux_defaults
|
||||||
|
@ -98,6 +103,9 @@ jobs:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- checkout
|
- checkout
|
||||||
- *dependencies
|
- *dependencies
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
- run:
|
- run:
|
||||||
name: Test cli
|
name: Test cli
|
||||||
command: |
|
command: |
|
||||||
|
@ -112,6 +120,9 @@ jobs:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- checkout
|
- checkout
|
||||||
- *dependencies
|
- *dependencies
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
- run:
|
- run:
|
||||||
name: Test individual module simulations
|
name: Test individual module simulations
|
||||||
command: |
|
command: |
|
||||||
|
@ -126,6 +137,9 @@ jobs:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- checkout
|
- checkout
|
||||||
- *dependencies
|
- *dependencies
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
- run:
|
- run:
|
||||||
name: Test full Gaia simulation
|
name: Test full Gaia simulation
|
||||||
command: |
|
command: |
|
||||||
|
@ -140,6 +154,9 @@ jobs:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- checkout
|
- checkout
|
||||||
- *dependencies
|
- *dependencies
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
- run:
|
- run:
|
||||||
name: Test Gaia import/export simulation
|
name: Test Gaia import/export simulation
|
||||||
command: |
|
command: |
|
||||||
|
@ -154,6 +171,9 @@ jobs:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- checkout
|
- checkout
|
||||||
- *dependencies
|
- *dependencies
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
- run:
|
- run:
|
||||||
name: Test Gaia import/export simulation
|
name: Test Gaia import/export simulation
|
||||||
command: |
|
command: |
|
||||||
|
@ -168,10 +188,14 @@ jobs:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- checkout
|
- checkout
|
||||||
- *dependencies
|
- *dependencies
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
- run:
|
- run:
|
||||||
name: Test multi-seed Gaia simulation long
|
name: Test multi-seed Gaia simulation long
|
||||||
command: |
|
command: |
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
|
export GO111MODULE=on
|
||||||
scripts/multisim.sh 500 50 TestFullGaiaSimulation
|
scripts/multisim.sh 500 50 TestFullGaiaSimulation
|
||||||
|
|
||||||
test_sim_gaia_multi_seed:
|
test_sim_gaia_multi_seed:
|
||||||
|
@ -182,10 +206,14 @@ jobs:
|
||||||
at: /tmp/workspace
|
at: /tmp/workspace
|
||||||
- checkout
|
- checkout
|
||||||
- *dependencies
|
- *dependencies
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
- run:
|
- run:
|
||||||
name: Test multi-seed Gaia simulation short
|
name: Test multi-seed Gaia simulation short
|
||||||
command: |
|
command: |
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
|
export GO111MODULE=on
|
||||||
scripts/multisim.sh 50 10 TestFullGaiaSimulation
|
scripts/multisim.sh 50 10 TestFullGaiaSimulation
|
||||||
|
|
||||||
test_cover:
|
test_cover:
|
||||||
|
@ -197,14 +225,18 @@ jobs:
|
||||||
- checkout
|
- checkout
|
||||||
- *dependencies
|
- *dependencies
|
||||||
- run: mkdir -p /tmp/logs
|
- run: mkdir -p /tmp/logs
|
||||||
|
- restore_cache:
|
||||||
|
keys:
|
||||||
|
- go-mod-v1-{{ checksum "go.sum" }}
|
||||||
- run:
|
- run:
|
||||||
name: Run tests
|
name: Run tests
|
||||||
command: |
|
command: |
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
export VERSION="$(git describe --tags --long | sed 's/v\(.*\)/\1/')"
|
export VERSION="$(git describe --tags --long | sed 's/v\(.*\)/\1/')"
|
||||||
|
export GO111MODULE=on
|
||||||
for pkg in $(go list ./... | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | grep -v '/simulation' | circleci tests split --split-by=timings); do
|
for pkg in $(go list ./... | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | grep -v '/simulation' | circleci tests split --split-by=timings); do
|
||||||
id=$(echo "$pkg" | sed 's|[/.]|_|g')
|
id=$(echo "$pkg" | sed 's|[/.]|_|g')
|
||||||
GOCACHE=off go test -timeout 8m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic -tags='ledger test_ledger_mock' "$pkg" | tee "/tmp/logs/$id-$RANDOM.log"
|
go test -mod=readonly -timeout 8m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic -tags='ledger test_ledger_mock' "$pkg" | tee "/tmp/logs/$id-$RANDOM.log"
|
||||||
done
|
done
|
||||||
- persist_to_workspace:
|
- persist_to_workspace:
|
||||||
root: /tmp/workspace
|
root: /tmp/workspace
|
||||||
|
@ -253,7 +285,7 @@ jobs:
|
||||||
GOPATH: /home/circleci/.go_workspace/
|
GOPATH: /home/circleci/.go_workspace/
|
||||||
GOOS: linux
|
GOOS: linux
|
||||||
GOARCH: amd64
|
GOARCH: amd64
|
||||||
GO_VERSION: "1.11.5"
|
GO_VERSION: "1.12.1"
|
||||||
parallelism: 1
|
parallelism: 1
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
|
@ -268,7 +300,6 @@ jobs:
|
||||||
popd
|
popd
|
||||||
set -x
|
set -x
|
||||||
make tools
|
make tools
|
||||||
make vendor-deps
|
|
||||||
make build-linux
|
make build-linux
|
||||||
make localnet-start
|
make localnet-start
|
||||||
./scripts/localnet-blocks-test.sh 40 5 10 localhost
|
./scripts/localnet-blocks-test.sh 40 5 10 localhost
|
||||||
|
@ -280,7 +311,22 @@ jobs:
|
||||||
- run:
|
- run:
|
||||||
name: Trigger website build
|
name: Trigger website build
|
||||||
command: |
|
command: |
|
||||||
chamber exec cosmos-sdk -- start_website_build
|
curl --silent \
|
||||||
|
--show-error \
|
||||||
|
-X POST \
|
||||||
|
--header "Content-Type: application/json" \
|
||||||
|
-d "{\"branch\": \"$CIRCLE_BRANCH\"}" \
|
||||||
|
"https://circleci.com/api/v1.1/project/github/$CIRCLE_PROJECT_USERNAME/$WEBSITE_REPO_NAME/build?circle-token=$TENDERBOT_API_TOKEN" > response.json
|
||||||
|
|
||||||
|
RESULT=`jq -r '.status' response.json`
|
||||||
|
MESSAGE=`jq -r '.message' response.json`
|
||||||
|
|
||||||
|
if [[ ${RESULT} == "null" ]] || [[ ${RESULT} -ne "200" ]]; then
|
||||||
|
echo "CircleCI API call failed: $MESSAGE"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Website build started"
|
||||||
|
fi
|
||||||
|
|
||||||
macos_ci:
|
macos_ci:
|
||||||
<<: *macos_defaults
|
<<: *macos_defaults
|
||||||
|
@ -300,7 +346,6 @@ jobs:
|
||||||
command: |
|
command: |
|
||||||
source $BASH_ENV
|
source $BASH_ENV
|
||||||
make tools
|
make tools
|
||||||
make vendor-deps
|
|
||||||
make install
|
make install
|
||||||
- run:
|
- run:
|
||||||
name: Integration tests
|
name: Integration tests
|
||||||
|
@ -322,14 +367,19 @@ jobs:
|
||||||
- setup_remote_docker:
|
- setup_remote_docker:
|
||||||
docker_layer_caching: true
|
docker_layer_caching: true
|
||||||
- run: |
|
- run: |
|
||||||
if [ "${CIRCLE_BRANCH}" == "master" ]; then
|
GAIAD_VERSION=''
|
||||||
|
if [ "${CIRCLE_BRANCH}" = "master" ]; then
|
||||||
GAIAD_VERSION="stable"
|
GAIAD_VERSION="stable"
|
||||||
elif [ "${CIRCLE_BRANCH}" == "develop" ]; then
|
elif [ "${CIRCLE_BRANCH}" = "develop" ]; then
|
||||||
GAIAD_VERSION="develop"
|
GAIAD_VERSION="develop"
|
||||||
fi
|
fi
|
||||||
docker build -t tendermint/gaia:$GAIAD_VERSION .
|
if [ -z "${GAIAD_VERSION}" ]; then
|
||||||
docker login -u $DOCKER_USER -p $DOCKER_PASS
|
docker build .
|
||||||
docker push tendermint/gaia:$GAIAD_VERSION
|
else
|
||||||
|
docker build -t tendermint/gaia:$GAIAD_VERSION .
|
||||||
|
docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
|
docker push tendermint/gaia:$GAIAD_VERSION
|
||||||
|
fi
|
||||||
|
|
||||||
docker_tagged:
|
docker_tagged:
|
||||||
<<: *linux_defaults
|
<<: *linux_defaults
|
||||||
|
@ -349,11 +399,6 @@ workflows:
|
||||||
test-suite:
|
test-suite:
|
||||||
jobs:
|
jobs:
|
||||||
- docker_image:
|
- docker_image:
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
- develop
|
|
||||||
requires:
|
requires:
|
||||||
- setup_dependencies
|
- setup_dependencies
|
||||||
- docker_tagged:
|
- docker_tagged:
|
||||||
|
@ -378,7 +423,12 @@ workflows:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
- setup_dependencies
|
- setup_dependencies:
|
||||||
|
# filters here are needed to enable this job also for tags
|
||||||
|
filters:
|
||||||
|
tags:
|
||||||
|
only:
|
||||||
|
- /^v.*/
|
||||||
- lint:
|
- lint:
|
||||||
requires:
|
requires:
|
||||||
- setup_dependencies
|
- setup_dependencies
|
||||||
|
|
|
@ -9,7 +9,7 @@ v If a checkbox is n/a - please still include it but + a little note why
|
||||||
- [ ] Linked to github-issue with discussion and accepted design OR link to spec that describes this work.
|
- [ ] Linked to github-issue with discussion and accepted design OR link to spec that describes this work.
|
||||||
- [ ] Wrote tests
|
- [ ] Wrote tests
|
||||||
- [ ] Updated relevant documentation (`docs/`)
|
- [ ] Updated relevant documentation (`docs/`)
|
||||||
- [ ] Added entries in `PENDING.md` with issue #
|
- [ ] Added a relevant changelog entry: `sdkch add [section] [stanza] [message]`
|
||||||
- [ ] rereviewed `Files changed` in the github PR explorer
|
- [ ] rereviewed `Files changed` in the github PR explorer
|
||||||
|
|
||||||
______
|
______
|
||||||
|
|
|
@ -7,18 +7,17 @@
|
||||||
*.swn
|
*.swn
|
||||||
.vscode
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
|
*.pyc
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
vendor
|
vendor
|
||||||
vendor-deps
|
|
||||||
.vendor-new
|
|
||||||
build
|
build
|
||||||
tools/bin/*
|
tools/bin/*
|
||||||
examples/build/*
|
examples/build/*
|
||||||
docs/_build
|
docs/_build
|
||||||
docs/tutorial
|
docs/tutorial
|
||||||
dist
|
dist
|
||||||
devtools-stamp
|
tools-stamp
|
||||||
|
|
||||||
# Data - ideally these don't exist
|
# Data - ideally these don't exist
|
||||||
baseapp/data/*
|
baseapp/data/*
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
linters:
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- errcheck
|
||||||
|
- golint
|
||||||
|
- ineffassign
|
||||||
|
- unconvert
|
||||||
|
- misspell
|
||||||
|
linters-settings:
|
||||||
|
gocyclo:
|
||||||
|
min-complexity: 11
|
||||||
|
errcheck:
|
||||||
|
ignore: fmt:.*,io/ioutil:^Read.*,github.com/spf13/cobra:MarkFlagRequired,github.com/spf13/viper:BindPFlag
|
||||||
|
golint:
|
||||||
|
min-confidence: 1.1
|
||||||
|
run:
|
||||||
|
tests: false
|
148
CHANGELOG.md
148
CHANGELOG.md
|
@ -1,5 +1,153 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
* [0.34.0](#0340)
|
||||||
|
* [Breaking Changes](#breaking-changes)
|
||||||
|
* [Gaia](#gaia)
|
||||||
|
* [Gaia CLI](#gaia-cli)
|
||||||
|
* [SDK](#sdk)
|
||||||
|
* [Tendermint](#tendermint)
|
||||||
|
* [New features](#new-features)
|
||||||
|
* [SDK](#sdk-1)
|
||||||
|
* [Gaia](#gaia-1)
|
||||||
|
* [Gaia CLI](#gaia-cli-1)
|
||||||
|
* [Gaia REST API](#gaia-rest-api)
|
||||||
|
* [Improvements](#improvements)
|
||||||
|
* [Gaia](#gaia-2)
|
||||||
|
* [Gaia CLI](#gaia-cli-2)
|
||||||
|
* [SDK](#sdk-2)
|
||||||
|
* [Bug Fixes](#bug-fixes)
|
||||||
|
* [Gaia](#gaia-3)
|
||||||
|
* [Gaia CLI](#gaia-cli-3)
|
||||||
|
* [SDK](#sdk-3)
|
||||||
|
* [0.33.2](#0332)
|
||||||
|
* [Improvements](#improvements-1)
|
||||||
|
* [Tendermint](#tendermint-1)
|
||||||
|
* [0.33.1](#0331)
|
||||||
|
* [Bug Fixes](#bug-fixes-1)
|
||||||
|
* [Gaia](#gaia-4)
|
||||||
|
|
||||||
|
## 0.34.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
#### Gaia
|
||||||
|
|
||||||
|
* [\#3463](https://github.com/cosmos/cosmos-sdk/issues/3463) Revert bank module handler fork (re-enables transfers)
|
||||||
|
* [\#3875](https://github.com/cosmos/cosmos-sdk/issues/3875) Replace `async` flag with `--broadcast-mode` flag where the default
|
||||||
|
value is `sync`. The `block` mode should not be used. The REST client now
|
||||||
|
uses `mode` parameter instead of the `return` parameter.
|
||||||
|
|
||||||
|
#### Gaia CLI
|
||||||
|
|
||||||
|
* [\#3938](https://github.com/cosmos/cosmos-sdk/issues/3938) Remove REST server's SSL support altogether.
|
||||||
|
|
||||||
|
#### SDK
|
||||||
|
|
||||||
|
* [\#3245](https://github.com/cosmos/cosmos-sdk/issues/3245) Rename validator.GetJailed() to validator.IsJailed()
|
||||||
|
* [\#3516](https://github.com/cosmos/cosmos-sdk/issues/3516) Remove concept of shares from staking unbonding and redelegation UX;
|
||||||
|
replaced by direct coin amount.
|
||||||
|
|
||||||
|
#### Tendermint
|
||||||
|
|
||||||
|
* [\#4029](https://github.com/cosmos/cosmos-sdk/issues/4029) Upgrade Tendermint to v0.31.3
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
#### SDK
|
||||||
|
|
||||||
|
* [\#2935](https://github.com/cosmos/cosmos-sdk/issues/2935) New module Crisis which can test broken invariant with messages
|
||||||
|
* [\#3813](https://github.com/cosmos/cosmos-sdk/issues/3813) New sdk.NewCoins safe constructor to replace bare sdk.Coins{} declarations.
|
||||||
|
* [\#3858](https://github.com/cosmos/cosmos-sdk/issues/3858) add website, details and identity to gentx cli command
|
||||||
|
* Implement coin conversion and denomination registration utilities
|
||||||
|
|
||||||
|
#### Gaia
|
||||||
|
|
||||||
|
* [\#2935](https://github.com/cosmos/cosmos-sdk/issues/2935) Optionally assert invariants on a blockly basis using `gaiad --assert-invariants-blockly`
|
||||||
|
* [\#3886](https://github.com/cosmos/cosmos-sdk/issues/3886) Implement minting module querier and CLI/REST clients.
|
||||||
|
|
||||||
|
#### Gaia CLI
|
||||||
|
|
||||||
|
* [\#3937](https://github.com/cosmos/cosmos-sdk/issues/3937) Add command to query community-pool
|
||||||
|
|
||||||
|
#### Gaia REST API
|
||||||
|
|
||||||
|
* [\#3937](https://github.com/cosmos/cosmos-sdk/issues/3937) Add route to fetch community-pool
|
||||||
|
* [\#3949](https://github.com/cosmos/cosmos-sdk/issues/3949) added /slashing/signing_infos to get signing_info for all validators
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
#### Gaia
|
||||||
|
|
||||||
|
* [\#3808](https://github.com/cosmos/cosmos-sdk/issues/3808) `gaiad` and `gaiacli` integration tests use ./build/ binaries.
|
||||||
|
* \[\#3819](https://github.com/cosmos/cosmos-sdk/issues/3819) Simulation refactor, log output now stored in ~/.gaiad/simulation/
|
||||||
|
* Simulation moved to its own module (not a part of mock)
|
||||||
|
* Logger type instead of passing function variables everywhere
|
||||||
|
* Logger json output (for reloadable simulation running)
|
||||||
|
* Cleanup bank simulation messages / remove dup code in bank simulation
|
||||||
|
* Simulations saved in `~/.gaiad/simulations/`
|
||||||
|
* "Lean" simulation output option to exclude No-ops and !ok functions (`--SimulationLean` flag)
|
||||||
|
* [\#3893](https://github.com/cosmos/cosmos-sdk/issues/3893) Improve `gaiacli tx sign` command
|
||||||
|
* Add shorthand flags -a and -s for the account and sequence numbers respectively
|
||||||
|
* Mark the account and sequence numbers required during "offline" mode
|
||||||
|
* Always do an RPC query for account and sequence number during "online" mode
|
||||||
|
* [\#4018](https://github.com/cosmos/cosmos-sdk/issues/4018) create genesis port script for release v.0.34.0
|
||||||
|
|
||||||
|
#### Gaia CLI
|
||||||
|
|
||||||
|
* [\#3833](https://github.com/cosmos/cosmos-sdk/issues/3833) Modify stake to atom in gaia's doc.
|
||||||
|
* [\#3841](https://github.com/cosmos/cosmos-sdk/issues/3841) Add indent to JSON of `gaiacli keys [add|show|list]`
|
||||||
|
* [\#3859](https://github.com/cosmos/cosmos-sdk/issues/3859) Add newline to echo of `gaiacli keys ...`
|
||||||
|
* [\#3959](https://github.com/cosmos/cosmos-sdk/issues/3959) Improving error messages when signing with ledger devices fails
|
||||||
|
|
||||||
|
#### SDK
|
||||||
|
|
||||||
|
* [\#3238](https://github.com/cosmos/cosmos-sdk/issues/3238) Add block time to tx responses when querying for
|
||||||
|
txs by tags or hash.
|
||||||
|
* \[\#3752](https://github.com/cosmos/cosmos-sdk/issues/3752) Explanatory docs for minting mechanism (`docs/spec/mint/01_concepts.md`)
|
||||||
|
* [\#3801](https://github.com/cosmos/cosmos-sdk/issues/3801) `baseapp` safety improvements
|
||||||
|
* [\#3820](https://github.com/cosmos/cosmos-sdk/issues/3820) Make Coins.IsAllGT() more robust and consistent.
|
||||||
|
* [\#3828](https://github.com/cosmos/cosmos-sdk/issues/3828) New sdkch tool to maintain changelogs
|
||||||
|
* [\#3864](https://github.com/cosmos/cosmos-sdk/issues/3864) Make Coins.IsAllGTE() more consistent.
|
||||||
|
* [\#3907](https://github.com/cosmos/cosmos-sdk/issues/3907): dep -> go mod migration
|
||||||
|
* Drop dep in favor of go modules.
|
||||||
|
* Upgrade to Go 1.12.1.
|
||||||
|
* [\#3917](https://github.com/cosmos/cosmos-sdk/issues/3917) Allow arbitrary decreases to validator commission rates.
|
||||||
|
* [\#3937](https://github.com/cosmos/cosmos-sdk/issues/3937) Implement community pool querier.
|
||||||
|
* [\#3940](https://github.com/cosmos/cosmos-sdk/issues/3940) Codespace should be lowercase.
|
||||||
|
* [\#3986](https://github.com/cosmos/cosmos-sdk/issues/3986) Update the Stringer implementation of the Proposal type.
|
||||||
|
* [\#926](https://github.com/cosmos/cosmos-sdk/issues/926) circuit breaker high level explanation
|
||||||
|
* [\#3896](https://github.com/cosmos/cosmos-sdk/issues/3896) Fixed various linters warnings in the context of the gometalinter -> golangci-lint migration
|
||||||
|
* [\#3916](https://github.com/cosmos/cosmos-sdk/issues/3916) Hex encode data in tx responses
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
#### Gaia
|
||||||
|
|
||||||
|
* [\#3825](https://github.com/cosmos/cosmos-sdk/issues/3825) Validate genesis before running gentx
|
||||||
|
* [\#3889](https://github.com/cosmos/cosmos-sdk/issues/3889) When `--generate-only` is provided, the Keybase is not used and as a result
|
||||||
|
the `--from` value must be a valid Bech32 cosmos address.
|
||||||
|
* 3974 Fix go env setting in installation.md
|
||||||
|
* 3996 Change 'make get_tools' to 'make tools' in DOCS_README.md.
|
||||||
|
|
||||||
|
#### Gaia CLI
|
||||||
|
|
||||||
|
* [\#3883](https://github.com/cosmos/cosmos-sdk/issues/3883) Remove Height Flag from CLI Queries
|
||||||
|
* [\#3899](https://github.com/cosmos/cosmos-sdk/issues/3899) Using 'gaiacli config node' breaks ~/config/config.toml
|
||||||
|
|
||||||
|
#### SDK
|
||||||
|
|
||||||
|
* [\#3837](https://github.com/cosmos/cosmos-sdk/issues/3837) Fix `WithdrawValidatorCommission` to properly set the validator's remaining commission.
|
||||||
|
* [\#3870](https://github.com/cosmos/cosmos-sdk/issues/3870) Fix DecCoins#TruncateDecimal to never return zero coins in
|
||||||
|
either the truncated coins or the change coins.
|
||||||
|
* [\#3915](https://github.com/cosmos/cosmos-sdk/issues/3915) Remove ';' delimiting support from ParseDecCoins
|
||||||
|
* [\#3977](https://github.com/cosmos/cosmos-sdk/issues/3977) Fix docker image build
|
||||||
|
* [\#4020](https://github.com/cosmos/cosmos-sdk/issues/4020) Fix queryDelegationRewards by returning an error
|
||||||
|
when the validator or delegation do not exist.
|
||||||
|
* [\#4050](https://github.com/cosmos/cosmos-sdk/issues/4050) Fix DecCoins APIs
|
||||||
|
where rounding or truncation could result in zero decimal coins.
|
||||||
|
* [\#4088](https://github.com/cosmos/cosmos-sdk/issues/4088) Fix `calculateDelegationRewards`
|
||||||
|
by accounting for rounding errors when multiplying stake by slashing fractions.
|
||||||
|
|
||||||
## 0.33.2
|
## 0.33.2
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
|
@ -100,21 +100,15 @@ Please don't make Pull Requests to `master`.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
We use [dep](https://github.com/golang/dep) to manage dependencies.
|
We use [Go 1.11 Modules](https://github.com/golang/go/wiki/Modules) to manage
|
||||||
|
dependency versions.
|
||||||
|
|
||||||
That said, the master branch of every Cosmos repository should just build
|
The master branch of every Cosmos repository should just build with `go get`,
|
||||||
with `go get`, which means they should be kept up-to-date with their
|
which means they should be kept up-to-date with their dependencies so we can
|
||||||
dependencies so we can get away with telling people they can just `go get` our
|
get away with telling people they can just `go get` our software.
|
||||||
software.
|
|
||||||
|
|
||||||
Since some dependencies are not under our control, a third party may break our
|
Since some dependencies are not under our control, a third party may break our
|
||||||
build, in which case we can fall back on `dep ensure` (or `make
|
build, in which case we can fall back on `go mod tidy -v`.
|
||||||
get_vendor_deps`). Even for dependencies under our control, dep helps us to
|
|
||||||
keep multiple repos in sync as they evolve. Anything with an executable, such
|
|
||||||
as apps, tools, and the core, should use dep.
|
|
||||||
|
|
||||||
Run `dep status` to get a list of vendor dependencies that may not be
|
|
||||||
up-to-date.
|
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
|
@ -171,7 +165,7 @@ only pull requests targeted directly against master.
|
||||||
### Development Procedure:
|
### Development Procedure:
|
||||||
- the latest state of development is on `develop`
|
- the latest state of development is on `develop`
|
||||||
- `develop` must never fail `make test` or `make test_cli`
|
- `develop` must never fail `make test` or `make test_cli`
|
||||||
- `develop` should not fail `make test_lint`
|
- `develop` should not fail `make lint`
|
||||||
- no --force onto `develop` (except when reverting a broken commit, which should seldom happen)
|
- no --force onto `develop` (except when reverting a broken commit, which should seldom happen)
|
||||||
- create a development branch either on github.com/cosmos/cosmos-sdk, or your fork (using `git remote add origin`)
|
- create a development branch either on github.com/cosmos/cosmos-sdk, or your fork (using `git remote add origin`)
|
||||||
- before submitting a pull request, begin `git rebase` on top of `develop`
|
- before submitting a pull request, begin `git rebase` on top of `develop`
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
FROM golang:alpine AS build-env
|
FROM golang:alpine AS build-env
|
||||||
|
|
||||||
# Set up dependencies
|
# Set up dependencies
|
||||||
ENV PACKAGES make git libc-dev bash gcc linux-headers eudev-dev
|
ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev
|
||||||
|
|
||||||
# Set working directory for the build
|
# Set working directory for the build
|
||||||
WORKDIR /go/src/github.com/cosmos/cosmos-sdk
|
WORKDIR /go/src/github.com/cosmos/cosmos-sdk
|
||||||
|
@ -16,8 +16,6 @@ COPY . .
|
||||||
# Install minimum necessary dependencies, build Cosmos SDK, remove packages
|
# Install minimum necessary dependencies, build Cosmos SDK, remove packages
|
||||||
RUN apk add --no-cache $PACKAGES && \
|
RUN apk add --no-cache $PACKAGES && \
|
||||||
make tools && \
|
make tools && \
|
||||||
make vendor-deps && \
|
|
||||||
make build && \
|
|
||||||
make install
|
make install
|
||||||
|
|
||||||
# Final image
|
# Final image
|
||||||
|
|
|
@ -1,725 +0,0 @@
|
||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
|
||||||
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:09a7f74eb6bb3c0f14d8926610c87f569c5cff68e978d30e9a3540aeb626fdf0"
|
|
||||||
name = "github.com/bartekn/go-bip39"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "a05967ea095d81c8fe4833776774cfaff8e5036c"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
|
|
||||||
name = "github.com/beorn7/perks"
|
|
||||||
packages = ["quantile"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:1343a2963481a305ca4d051e84bc2abd16b601ee22ed324f8d605de1adb291b0"
|
|
||||||
name = "github.com/bgentry/speakeasy"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd"
|
|
||||||
version = "v0.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:093bf93a65962e8191e3e8cd8fc6c363f83d43caca9739c906531ba7210a9904"
|
|
||||||
name = "github.com/btcsuite/btcd"
|
|
||||||
packages = ["btcec"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "ed77733ec07dfc8a513741138419b8d9d3de9d2d"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:386de157f7d19259a7f9c81f26ce011223ce0f090353c1152ffdf730d7d10ac2"
|
|
||||||
name = "github.com/btcsuite/btcutil"
|
|
||||||
packages = ["bech32"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:e8a3550c8786316675ff54ad6f09d265d129c9d986919af7f541afba50d87ce2"
|
|
||||||
name = "github.com/cosmos/go-bip39"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "52158e4697b87de16ed390e1bdaf813e581008fa"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:a2b34d1436ac24a0db176f84c015d80438602eeec12f2f8358bb72749711ab52"
|
|
||||||
name = "github.com/cosmos/ledger-cosmos-go"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "e2f595b3b7b222e1cbe9daf89e73e4dcab02d54c"
|
|
||||||
version = "v0.9.8"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
|
|
||||||
name = "github.com/davecgh/go-spew"
|
|
||||||
packages = ["spew"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
|
||||||
version = "v1.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:fed20bf7f0da387c96d4cfc140a95572e5aba4bb984beb7de910e090ae39849b"
|
|
||||||
name = "github.com/ethereum/go-ethereum"
|
|
||||||
packages = ["crypto/secp256k1"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "c942700427557e3ff6de3aaf6b916e2f056c1ec2"
|
|
||||||
version = "v1.8.23"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd"
|
|
||||||
name = "github.com/fsnotify/fsnotify"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
|
||||||
version = "v1.4.7"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:fdf5169073fb0ad6dc12a70c249145e30f4058647bea25f0abd48b6d9f228a11"
|
|
||||||
name = "github.com/go-kit/kit"
|
|
||||||
packages = [
|
|
||||||
"log",
|
|
||||||
"log/level",
|
|
||||||
"log/term",
|
|
||||||
"metrics",
|
|
||||||
"metrics/discard",
|
|
||||||
"metrics/internal/lv",
|
|
||||||
"metrics/prometheus",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "4dc7be5d2d12881735283bcab7352178e190fc71"
|
|
||||||
version = "v0.6.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:4062bc6de62d73e2be342243cf138cf499b34d558876db8d9430e2149388a4d8"
|
|
||||||
name = "github.com/go-logfmt/logfmt"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "07c9b44f60d7ffdfb7d8efe1ad539965737836dc"
|
|
||||||
version = "v0.4.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d"
|
|
||||||
name = "github.com/go-stack/stack"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a"
|
|
||||||
version = "v1.8.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:35621fe20f140f05a0c4ef662c26c0ab4ee50bca78aa30fe87d33120bd28165e"
|
|
||||||
name = "github.com/gogo/protobuf"
|
|
||||||
packages = [
|
|
||||||
"gogoproto",
|
|
||||||
"jsonpb",
|
|
||||||
"proto",
|
|
||||||
"protoc-gen-gogo/descriptor",
|
|
||||||
"sortkeys",
|
|
||||||
"types",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "636bf0302bc95575d69441b25a2603156ffdddf1"
|
|
||||||
version = "v1.1.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:17fe264ee908afc795734e8c4e63db2accabaf57326dbf21763a7d6b86096260"
|
|
||||||
name = "github.com/golang/protobuf"
|
|
||||||
packages = [
|
|
||||||
"proto",
|
|
||||||
"ptypes",
|
|
||||||
"ptypes/any",
|
|
||||||
"ptypes/duration",
|
|
||||||
"ptypes/timestamp",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
|
||||||
version = "v1.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:e4f5819333ac698d294fe04dbf640f84719658d5c7ce195b10060cc37292ce79"
|
|
||||||
name = "github.com/golang/snappy"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "2a8bb927dd31d8daada140a5d09578521ce5c36a"
|
|
||||||
version = "v0.0.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:ca59b1175189b3f0e9f1793d2c350114be36eaabbe5b9f554b35edee1de50aea"
|
|
||||||
name = "github.com/gorilla/mux"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "a7962380ca08b5a188038c69871b8d3fbdf31e89"
|
|
||||||
version = "v1.7.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
|
|
||||||
name = "github.com/gorilla/websocket"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
|
|
||||||
version = "v1.4.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10"
|
|
||||||
name = "github.com/hashicorp/hcl"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"hcl/ast",
|
|
||||||
"hcl/parser",
|
|
||||||
"hcl/printer",
|
|
||||||
"hcl/scanner",
|
|
||||||
"hcl/strconv",
|
|
||||||
"hcl/token",
|
|
||||||
"json/parser",
|
|
||||||
"json/scanner",
|
|
||||||
"json/token",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241"
|
|
||||||
version = "v1.0.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
|
||||||
name = "github.com/inconshreveable/mousetrap"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
|
||||||
version = "v1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:a74b5a8e34ee5843cd6e65f698f3e75614f812ff170c2243425d75bc091e9af2"
|
|
||||||
name = "github.com/jmhodges/levigo"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "853d788c5c416eaaee5b044570784a96c7a26975"
|
|
||||||
version = "v1.0.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:a64e323dc06b73892e5bb5d040ced475c4645d456038333883f58934abbf6f72"
|
|
||||||
name = "github.com/kr/logfmt"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7"
|
|
||||||
name = "github.com/magiconair/properties"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
|
||||||
version = "v1.8.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:3bb9c8451d199650bfd303e0068d86f135952fead374ad87c09a9b8a2cc4bd7c"
|
|
||||||
name = "github.com/mattn/go-isatty"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "369ecd8cea9851e459abb67eb171853e3986591e"
|
|
||||||
version = "v0.0.6"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
|
|
||||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
|
||||||
packages = ["pbutil"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
|
||||||
version = "v1.0.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318"
|
|
||||||
name = "github.com/mitchellh/mapstructure"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe"
|
|
||||||
version = "v1.1.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:6d4d9067e639d96a804ee9a30fa89c7233c5c5edbfe736072ff00d48c97bccc4"
|
|
||||||
name = "github.com/otiai10/copy"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "7e9a647135a142c2669943d4a4d29be015ce9392"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
|
|
||||||
name = "github.com/pelletier/go-toml"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
|
||||||
version = "v1.2.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
|
|
||||||
name = "github.com/pkg/errors"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
|
||||||
version = "v0.8.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
|
|
||||||
name = "github.com/pmezard/go-difflib"
|
|
||||||
packages = ["difflib"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
|
||||||
version = "v1.0.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:93a746f1060a8acbcf69344862b2ceced80f854170e1caae089b2834c5fbf7f4"
|
|
||||||
name = "github.com/prometheus/client_golang"
|
|
||||||
packages = [
|
|
||||||
"prometheus",
|
|
||||||
"prometheus/internal",
|
|
||||||
"prometheus/promhttp",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "505eaef017263e299324067d40ca2c48f6a2cf50"
|
|
||||||
version = "v0.9.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
|
|
||||||
name = "github.com/prometheus/client_model"
|
|
||||||
packages = ["go"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:35cf6bdf68db765988baa9c4f10cc5d7dda1126a54bd62e252dbcd0b1fc8da90"
|
|
||||||
name = "github.com/prometheus/common"
|
|
||||||
packages = [
|
|
||||||
"expfmt",
|
|
||||||
"internal/bitbucket.org/ww/goautoneg",
|
|
||||||
"model",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250"
|
|
||||||
version = "v0.2.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:bfc66a1fd78dc8f14d419fd52a5a42db1d572e887ebcc80b98c1a515a8f2d837"
|
|
||||||
name = "github.com/prometheus/procfs"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"internal/util",
|
|
||||||
"iostats",
|
|
||||||
"nfs",
|
|
||||||
"xfs",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "bbced9601137e764853b2fad7ec3e2dc4c504e02"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:ea0700160aca4ef099f4e06686a665a87691f4248dddd40796925eda2e46bd64"
|
|
||||||
name = "github.com/rakyll/statik"
|
|
||||||
packages = ["fs"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "aa8a7b1baecd0f31a436bf7956fcdcc609a83035"
|
|
||||||
version = "v0.1.4"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:c4556a44e350b50a490544d9b06e9fba9c286c21d6c0e47f54f3a9214597298c"
|
|
||||||
name = "github.com/rcrowley/go-metrics"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "e2704e165165ec55d062f5919b4b29494e9fa790"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:b0c25f00bad20d783d259af2af8666969e2fc343fa0dc9efe52936bbd67fb758"
|
|
||||||
name = "github.com/rs/cors"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "9a47f48565a795472d43519dd49aac781f3034fb"
|
|
||||||
version = "v1.6.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:3e39bafd6c2f4bf3c76c3bfd16a2e09e016510ad5db90dc02b88e2f565d6d595"
|
|
||||||
name = "github.com/spf13/afero"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"mem",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "f4711e4db9e9a1d3887343acb72b2bbfc2f686f5"
|
|
||||||
version = "v1.2.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:08d65904057412fc0270fc4812a1c90c594186819243160dc779a402d4b6d0bc"
|
|
||||||
name = "github.com/spf13/cast"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "8c9545af88b134710ab1cd196795e7f2388358d7"
|
|
||||||
version = "v1.3.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939"
|
|
||||||
name = "github.com/spf13/cobra"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
|
||||||
version = "v0.0.3"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:1b753ec16506f5864d26a28b43703c58831255059644351bbcb019b843950900"
|
|
||||||
name = "github.com/spf13/jwalterweatherman"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "94f6ae3ed3bceceafa716478c5fbf8d29ca601a1"
|
|
||||||
version = "v1.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
|
|
||||||
name = "github.com/spf13/pflag"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
|
||||||
version = "v1.0.3"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:ba07ec7953d565ac57a11b123a3bf0c8e848f2c7f637fccb0f9ce4f9e489d69a"
|
|
||||||
name = "github.com/spf13/viper"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "a1b837276271029e31f796ae5d03ba9ffb017244"
|
|
||||||
version = "v1.0.3"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:7e8d267900c7fa7f35129a2a37596e38ed0f11ca746d6d9ba727980ee138f9f6"
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
packages = [
|
|
||||||
"assert",
|
|
||||||
"require",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
|
||||||
version = "v1.2.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:b3cfb8d82b1601a846417c3f31c03a7961862cb2c98dcf0959c473843e6d9a2b"
|
|
||||||
name = "github.com/syndtr/goleveldb"
|
|
||||||
packages = [
|
|
||||||
"leveldb",
|
|
||||||
"leveldb/cache",
|
|
||||||
"leveldb/comparer",
|
|
||||||
"leveldb/errors",
|
|
||||||
"leveldb/filter",
|
|
||||||
"leveldb/iterator",
|
|
||||||
"leveldb/journal",
|
|
||||||
"leveldb/memdb",
|
|
||||||
"leveldb/opt",
|
|
||||||
"leveldb/storage",
|
|
||||||
"leveldb/table",
|
|
||||||
"leveldb/util",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:83f5e189eea2baad419a6a410984514266ff690075759c87e9ede596809bd0b8"
|
|
||||||
name = "github.com/tendermint/btcd"
|
|
||||||
packages = ["btcec"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "80daadac05d1cd29571fccf27002d79667a88b58"
|
|
||||||
version = "v0.1.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:ad9c4c1a4e7875330b1f62906f2830f043a23edb5db997e3a5ac5d3e6eadf80a"
|
|
||||||
name = "github.com/tendermint/go-amino"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "dc14acf9ef15f85828bfbc561ed9dd9d2a284885"
|
|
||||||
version = "v0.14.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:1bb088f6291e5426e3874a60bca0e481a91a5633395d7e0c427ec3e49b626e7b"
|
|
||||||
name = "github.com/tendermint/iavl"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "ac7c35c12e8633a1e9fd0b52a00b900b40f32cd3"
|
|
||||||
version = "v0.12.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:97ded93050176418272057abf9819a3dea92713a40327e9906ba6deb92896e9d"
|
|
||||||
name = "github.com/tendermint/tendermint"
|
|
||||||
packages = [
|
|
||||||
"abci/client",
|
|
||||||
"abci/example/code",
|
|
||||||
"abci/example/counter",
|
|
||||||
"abci/example/kvstore",
|
|
||||||
"abci/server",
|
|
||||||
"abci/types",
|
|
||||||
"blockchain",
|
|
||||||
"cmd/tendermint/commands",
|
|
||||||
"config",
|
|
||||||
"consensus",
|
|
||||||
"consensus/types",
|
|
||||||
"crypto",
|
|
||||||
"crypto/armor",
|
|
||||||
"crypto/ed25519",
|
|
||||||
"crypto/encoding/amino",
|
|
||||||
"crypto/merkle",
|
|
||||||
"crypto/multisig",
|
|
||||||
"crypto/multisig/bitarray",
|
|
||||||
"crypto/secp256k1",
|
|
||||||
"crypto/tmhash",
|
|
||||||
"crypto/xsalsa20symmetric",
|
|
||||||
"evidence",
|
|
||||||
"libs/autofile",
|
|
||||||
"libs/bech32",
|
|
||||||
"libs/cli",
|
|
||||||
"libs/cli/flags",
|
|
||||||
"libs/clist",
|
|
||||||
"libs/common",
|
|
||||||
"libs/db",
|
|
||||||
"libs/events",
|
|
||||||
"libs/fail",
|
|
||||||
"libs/flowrate",
|
|
||||||
"libs/log",
|
|
||||||
"libs/pubsub",
|
|
||||||
"libs/pubsub/query",
|
|
||||||
"lite",
|
|
||||||
"lite/client",
|
|
||||||
"lite/errors",
|
|
||||||
"lite/proxy",
|
|
||||||
"mempool",
|
|
||||||
"node",
|
|
||||||
"p2p",
|
|
||||||
"p2p/conn",
|
|
||||||
"p2p/pex",
|
|
||||||
"p2p/upnp",
|
|
||||||
"privval",
|
|
||||||
"proxy",
|
|
||||||
"rpc/client",
|
|
||||||
"rpc/core",
|
|
||||||
"rpc/core/types",
|
|
||||||
"rpc/grpc",
|
|
||||||
"rpc/lib/client",
|
|
||||||
"rpc/lib/server",
|
|
||||||
"rpc/lib/types",
|
|
||||||
"state",
|
|
||||||
"state/txindex",
|
|
||||||
"state/txindex/kv",
|
|
||||||
"state/txindex/null",
|
|
||||||
"types",
|
|
||||||
"types/time",
|
|
||||||
"version",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "v0.31.0-dev0-fix0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:b73f5e117bc7c6e8fc47128f20db48a873324ad5cfeeebfc505e85c58682b5e4"
|
|
||||||
name = "github.com/zondax/hid"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "T"
|
|
||||||
revision = "302fd402163c34626286195dfa9adac758334acc"
|
|
||||||
version = "v0.9.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:f8e4c0b959174a1fa5946b12f1f2ac7ea5651bef20a9e4a8dac55dbffcaa6cd6"
|
|
||||||
name = "github.com/zondax/ledger-go"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "69c15f1333a9b6866e5f66096561c7d138894bc5"
|
|
||||||
version = "v0.8.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:6f6dc6060c4e9ba73cf28aa88f12a69a030d3d19d518ef8e931879eaa099628d"
|
|
||||||
name = "golang.org/x/crypto"
|
|
||||||
packages = [
|
|
||||||
"bcrypt",
|
|
||||||
"blowfish",
|
|
||||||
"chacha20poly1305",
|
|
||||||
"curve25519",
|
|
||||||
"ed25519",
|
|
||||||
"ed25519/internal/edwards25519",
|
|
||||||
"hkdf",
|
|
||||||
"internal/chacha20",
|
|
||||||
"internal/subtle",
|
|
||||||
"nacl/box",
|
|
||||||
"nacl/secretbox",
|
|
||||||
"openpgp/armor",
|
|
||||||
"openpgp/errors",
|
|
||||||
"pbkdf2",
|
|
||||||
"poly1305",
|
|
||||||
"ripemd160",
|
|
||||||
"salsa20/salsa",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "3764759f34a542a3aef74d6b02e35be7ab893bba"
|
|
||||||
source = "https://github.com/tendermint/crypto"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1"
|
|
||||||
name = "golang.org/x/net"
|
|
||||||
packages = [
|
|
||||||
"context",
|
|
||||||
"http/httpguts",
|
|
||||||
"http2",
|
|
||||||
"http2/hpack",
|
|
||||||
"idna",
|
|
||||||
"internal/timeseries",
|
|
||||||
"netutil",
|
|
||||||
"trace",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "292b43bbf7cb8d35ddf40f8d5100ef3837cced3f"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:4bd75b1a219bc590b05c976bbebf47f4e993314ebb5c7cbf2efe05a09a184d54"
|
|
||||||
name = "golang.org/x/sys"
|
|
||||||
packages = [
|
|
||||||
"cpu",
|
|
||||||
"unix",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "4e1fef5609515ec7a2cee7b5de30ba6d9b438cbf"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
|
|
||||||
name = "golang.org/x/text"
|
|
||||||
packages = [
|
|
||||||
"collate",
|
|
||||||
"collate/build",
|
|
||||||
"internal/colltab",
|
|
||||||
"internal/gen",
|
|
||||||
"internal/tag",
|
|
||||||
"internal/triegen",
|
|
||||||
"internal/ucd",
|
|
||||||
"language",
|
|
||||||
"secure/bidirule",
|
|
||||||
"transform",
|
|
||||||
"unicode/bidi",
|
|
||||||
"unicode/cldr",
|
|
||||||
"unicode/norm",
|
|
||||||
"unicode/rangetable",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
|
||||||
version = "v0.3.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c"
|
|
||||||
name = "google.golang.org/genproto"
|
|
||||||
packages = ["googleapis/rpc/status"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "383e8b2c3b9e36c4076b235b32537292176bae20"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:cbc746de4662c66fd24a037501bd65aa0f8ad0bfca0c92576e0abb88864e3741"
|
|
||||||
name = "google.golang.org/grpc"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"balancer",
|
|
||||||
"balancer/base",
|
|
||||||
"balancer/roundrobin",
|
|
||||||
"binarylog/grpc_binarylog_v1",
|
|
||||||
"codes",
|
|
||||||
"connectivity",
|
|
||||||
"credentials",
|
|
||||||
"credentials/internal",
|
|
||||||
"encoding",
|
|
||||||
"encoding/proto",
|
|
||||||
"grpclog",
|
|
||||||
"internal",
|
|
||||||
"internal/backoff",
|
|
||||||
"internal/binarylog",
|
|
||||||
"internal/channelz",
|
|
||||||
"internal/envconfig",
|
|
||||||
"internal/grpcrand",
|
|
||||||
"internal/grpcsync",
|
|
||||||
"internal/syscall",
|
|
||||||
"internal/transport",
|
|
||||||
"keepalive",
|
|
||||||
"metadata",
|
|
||||||
"naming",
|
|
||||||
"peer",
|
|
||||||
"resolver",
|
|
||||||
"resolver/dns",
|
|
||||||
"resolver/passthrough",
|
|
||||||
"stats",
|
|
||||||
"status",
|
|
||||||
"tap",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "2fdaae294f38ed9a121193c51ec99fecd3b13eb7"
|
|
||||||
version = "v1.19.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
|
|
||||||
name = "gopkg.in/yaml.v2"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
|
|
||||||
version = "v2.2.2"
|
|
||||||
|
|
||||||
[solve-meta]
|
|
||||||
analyzer-name = "dep"
|
|
||||||
analyzer-version = 1
|
|
||||||
input-imports = [
|
|
||||||
"github.com/bartekn/go-bip39",
|
|
||||||
"github.com/bgentry/speakeasy",
|
|
||||||
"github.com/btcsuite/btcd/btcec",
|
|
||||||
"github.com/cosmos/go-bip39",
|
|
||||||
"github.com/cosmos/ledger-cosmos-go",
|
|
||||||
"github.com/gogo/protobuf/proto",
|
|
||||||
"github.com/golang/protobuf/proto",
|
|
||||||
"github.com/gorilla/mux",
|
|
||||||
"github.com/mattn/go-isatty",
|
|
||||||
"github.com/otiai10/copy",
|
|
||||||
"github.com/pelletier/go-toml",
|
|
||||||
"github.com/pkg/errors",
|
|
||||||
"github.com/rakyll/statik/fs",
|
|
||||||
"github.com/spf13/cobra",
|
|
||||||
"github.com/spf13/pflag",
|
|
||||||
"github.com/spf13/viper",
|
|
||||||
"github.com/stretchr/testify/assert",
|
|
||||||
"github.com/stretchr/testify/require",
|
|
||||||
"github.com/tendermint/btcd/btcec",
|
|
||||||
"github.com/tendermint/go-amino",
|
|
||||||
"github.com/tendermint/iavl",
|
|
||||||
"github.com/tendermint/tendermint/abci/server",
|
|
||||||
"github.com/tendermint/tendermint/abci/types",
|
|
||||||
"github.com/tendermint/tendermint/blockchain",
|
|
||||||
"github.com/tendermint/tendermint/cmd/tendermint/commands",
|
|
||||||
"github.com/tendermint/tendermint/config",
|
|
||||||
"github.com/tendermint/tendermint/crypto",
|
|
||||||
"github.com/tendermint/tendermint/crypto/armor",
|
|
||||||
"github.com/tendermint/tendermint/crypto/ed25519",
|
|
||||||
"github.com/tendermint/tendermint/crypto/encoding/amino",
|
|
||||||
"github.com/tendermint/tendermint/crypto/merkle",
|
|
||||||
"github.com/tendermint/tendermint/crypto/multisig",
|
|
||||||
"github.com/tendermint/tendermint/crypto/secp256k1",
|
|
||||||
"github.com/tendermint/tendermint/crypto/tmhash",
|
|
||||||
"github.com/tendermint/tendermint/crypto/xsalsa20symmetric",
|
|
||||||
"github.com/tendermint/tendermint/libs/bech32",
|
|
||||||
"github.com/tendermint/tendermint/libs/cli",
|
|
||||||
"github.com/tendermint/tendermint/libs/cli/flags",
|
|
||||||
"github.com/tendermint/tendermint/libs/common",
|
|
||||||
"github.com/tendermint/tendermint/libs/db",
|
|
||||||
"github.com/tendermint/tendermint/libs/log",
|
|
||||||
"github.com/tendermint/tendermint/lite",
|
|
||||||
"github.com/tendermint/tendermint/lite/errors",
|
|
||||||
"github.com/tendermint/tendermint/lite/proxy",
|
|
||||||
"github.com/tendermint/tendermint/node",
|
|
||||||
"github.com/tendermint/tendermint/p2p",
|
|
||||||
"github.com/tendermint/tendermint/privval",
|
|
||||||
"github.com/tendermint/tendermint/proxy",
|
|
||||||
"github.com/tendermint/tendermint/rpc/client",
|
|
||||||
"github.com/tendermint/tendermint/rpc/core/types",
|
|
||||||
"github.com/tendermint/tendermint/rpc/lib/client",
|
|
||||||
"github.com/tendermint/tendermint/rpc/lib/server",
|
|
||||||
"github.com/tendermint/tendermint/state",
|
|
||||||
"github.com/tendermint/tendermint/types",
|
|
||||||
"github.com/tendermint/tendermint/types/time",
|
|
||||||
"github.com/tendermint/tendermint/version",
|
|
||||||
"golang.org/x/crypto/bcrypt",
|
|
||||||
]
|
|
||||||
solver-name = "gps-cdcl"
|
|
||||||
solver-version = 1
|
|
93
Gopkg.toml
93
Gopkg.toml
|
@ -1,93 +0,0 @@
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/bgentry/speakeasy"
|
|
||||||
version = "~0.1.0"
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "github.com/golang/protobuf"
|
|
||||||
version = "=1.1.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/mattn/go-isatty"
|
|
||||||
version = "~0.0.3"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/spf13/cobra"
|
|
||||||
version = "~0.0.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/spf13/viper"
|
|
||||||
version = "~1.0.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/pkg/errors"
|
|
||||||
version = "=0.8.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
version = "=1.2.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/otiai10/copy"
|
|
||||||
revision = "7e9a647135a142c2669943d4a4d29be015ce9392"
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "github.com/tendermint/go-amino"
|
|
||||||
version = "v0.14.1"
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "github.com/tendermint/iavl"
|
|
||||||
version = "~v0.12.0"
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "github.com/tendermint/tendermint"
|
|
||||||
revision = "v0.31.0-dev0-fix0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/cosmos/ledger-cosmos-go"
|
|
||||||
version = "=v0.9.8"
|
|
||||||
|
|
||||||
## deps without releases:
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/btcsuite/btcd"
|
|
||||||
revision = "ed77733ec07dfc8a513741138419b8d9d3de9d2d"
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "golang.org/x/crypto"
|
|
||||||
source = "https://github.com/tendermint/crypto"
|
|
||||||
revision = "3764759f34a542a3aef74d6b02e35be7ab893bba"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/cosmos/go-bip39"
|
|
||||||
revision = "52158e4697b87de16ed390e1bdaf813e581008fa"
|
|
||||||
|
|
||||||
## transitive deps, with releases:
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "github.com/davecgh/go-spew"
|
|
||||||
version = "=v1.1.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/rakyll/statik"
|
|
||||||
version = "=v0.1.4"
|
|
||||||
|
|
||||||
## transitive deps, without releases:
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "github.com/syndtr/goleveldb"
|
|
||||||
revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445"
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "golang.org/x/sys"
|
|
||||||
revision = "4e1fef5609515ec7a2cee7b5de30ba6d9b438cbf"
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "google.golang.org/genproto"
|
|
||||||
revision = "383e8b2c3b9e36c4076b235b32537292176bae20"
|
|
||||||
|
|
||||||
[prune]
|
|
||||||
go-tests = true
|
|
||||||
unused-packages = true
|
|
||||||
[[prune.project]]
|
|
||||||
name = "github.com/zondax/hid"
|
|
||||||
unused-packages = false
|
|
131
Makefile
131
Makefile
|
@ -4,11 +4,10 @@ VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//')
|
||||||
COMMIT := $(shell git log -1 --format='%H')
|
COMMIT := $(shell git log -1 --format='%H')
|
||||||
CAT := $(if $(filter $(OS),Windows_NT),type,cat)
|
CAT := $(if $(filter $(OS),Windows_NT),type,cat)
|
||||||
LEDGER_ENABLED ?= true
|
LEDGER_ENABLED ?= true
|
||||||
GOTOOLS = \
|
|
||||||
github.com/golang/dep/cmd/dep \
|
|
||||||
github.com/alecthomas/gometalinter \
|
|
||||||
github.com/rakyll/statik
|
|
||||||
GOBIN ?= $(GOPATH)/bin
|
GOBIN ?= $(GOPATH)/bin
|
||||||
|
GOSUM := $(shell which gosum)
|
||||||
|
|
||||||
|
export GO111MODULE = on
|
||||||
|
|
||||||
# process build tags
|
# process build tags
|
||||||
|
|
||||||
|
@ -46,9 +45,12 @@ build_tags := $(strip $(build_tags))
|
||||||
|
|
||||||
ldflags = -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
|
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.Commit=$(COMMIT) \
|
||||||
-X github.com/cosmos/cosmos-sdk/version.VendorDirHash=$(shell $(CAT) vendor-deps) \
|
|
||||||
-X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags)"
|
-X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags)"
|
||||||
|
|
||||||
|
ifneq ($(GOSUM),)
|
||||||
|
ldflags += -X github.com/cosmos/cosmos-sdk/version.VendorDirHash=$(shell $(GOSUM) go.sum)
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(WITH_CLEVELDB),yes)
|
ifeq ($(WITH_CLEVELDB),yes)
|
||||||
ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=cleveldb
|
ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=cleveldb
|
||||||
endif
|
endif
|
||||||
|
@ -57,7 +59,7 @@ ldflags := $(strip $(ldflags))
|
||||||
|
|
||||||
BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
|
BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
|
||||||
|
|
||||||
all: devtools vendor-deps install test_lint test
|
all: tools install lint test
|
||||||
|
|
||||||
# The below include contains the tools target.
|
# The below include contains the tools target.
|
||||||
include scripts/Makefile
|
include scripts/Makefile
|
||||||
|
@ -65,36 +67,36 @@ include scripts/Makefile
|
||||||
########################################
|
########################################
|
||||||
### CI
|
### CI
|
||||||
|
|
||||||
ci: devtools vendor-deps install test_cover test_lint test
|
ci: tools install test_cover lint test
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
### Build/Install
|
### Build/Install
|
||||||
|
|
||||||
build:
|
build: go.sum
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaia/cmd/gaiad
|
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaia/cmd/gaiad
|
||||||
go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaia/cmd/gaiacli
|
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaia/cmd/gaiacli
|
||||||
else
|
else
|
||||||
go build $(BUILD_FLAGS) -o build/gaiad ./cmd/gaia/cmd/gaiad
|
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiad ./cmd/gaia/cmd/gaiad
|
||||||
go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli
|
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli
|
||||||
go build $(BUILD_FLAGS) -o build/gaiareplay ./cmd/gaia/cmd/gaiareplay
|
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiareplay ./cmd/gaia/cmd/gaiareplay
|
||||||
go build $(BUILD_FLAGS) -o build/gaiakeyutil ./cmd/gaia/cmd/gaiakeyutil
|
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiakeyutil ./cmd/gaia/cmd/gaiakeyutil
|
||||||
endif
|
endif
|
||||||
|
|
||||||
build-linux: vendor-deps
|
build-linux: go.sum
|
||||||
LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build
|
LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build
|
||||||
|
|
||||||
update_gaia_lite_docs:
|
update_gaia_lite_docs:
|
||||||
@statik -src=client/lcd/swagger-ui -dest=client/lcd -f
|
@statik -src=client/lcd/swagger-ui -dest=client/lcd -f
|
||||||
|
|
||||||
install: vendor-deps check-ledger update_gaia_lite_docs
|
install: go.sum check-ledger update_gaia_lite_docs
|
||||||
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad
|
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad
|
||||||
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli
|
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli
|
||||||
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiareplay
|
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiareplay
|
||||||
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiakeyutil
|
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiakeyutil
|
||||||
|
|
||||||
install_debug:
|
install_debug: go.sum
|
||||||
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiadebug
|
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiadebug
|
||||||
|
|
||||||
dist:
|
dist:
|
||||||
@bash publish/dist.sh
|
@bash publish/dist.sh
|
||||||
|
@ -103,38 +105,13 @@ dist:
|
||||||
########################################
|
########################################
|
||||||
### Tools & dependencies
|
### Tools & dependencies
|
||||||
|
|
||||||
check_tools:
|
go-mod-cache: go.sum
|
||||||
@# https://stackoverflow.com/a/25668869
|
@echo "--> Download go modules to local cache"
|
||||||
@echo "Found tools: $(foreach tool,$(notdir $(GOTOOLS)),\
|
@go mod download
|
||||||
$(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))"
|
|
||||||
|
|
||||||
update_tools:
|
go.sum: tools go.mod
|
||||||
@echo "--> Updating tools to correct version"
|
@echo "--> Ensure dependencies have not been modified"
|
||||||
$(MAKE) --always-make tools
|
@go mod verify
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
devtools: devtools-stamp
|
|
||||||
devtools-clean: tools-clean
|
|
||||||
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 $@
|
|
||||||
|
|
||||||
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: tools
|
|
||||||
@echo "--> Running dep ensure"
|
|
||||||
@rm -rf .vendor-new
|
|
||||||
@dep ensure -v
|
|
||||||
|
|
||||||
draw_deps: tools
|
draw_deps: tools
|
||||||
@# requires brew install graphviz or apt-get install graphviz
|
@# requires brew install graphviz or apt-get install graphviz
|
||||||
|
@ -142,7 +119,7 @@ draw_deps: tools
|
||||||
@goviz -i github.com/cosmos/cosmos-sdk/cmd/gaia/cmd/gaiad -d 2 | dot -Tpng -o dependency-graph.png
|
@goviz -i github.com/cosmos/cosmos-sdk/cmd/gaia/cmd/gaiad -d 2 | dot -Tpng -o dependency-graph.png
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f devtools-stamp vendor-deps snapcraft-local.yaml
|
rm -rf snapcraft-local.yaml build/
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -rf vendor/
|
rm -rf vendor/
|
||||||
|
@ -160,34 +137,34 @@ godocs:
|
||||||
|
|
||||||
test: test_unit
|
test: test_unit
|
||||||
|
|
||||||
test_cli:
|
test_cli: build
|
||||||
@go test -p 4 `go list github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test` -tags=cli_test
|
@go test -mod=readonly -p 4 `go list ./cmd/gaia/cli_test/...` -tags=cli_test
|
||||||
|
|
||||||
test_ledger:
|
test_ledger:
|
||||||
# First test with mock
|
# First test with mock
|
||||||
@go test `go list github.com/cosmos/cosmos-sdk/crypto` -tags='cgo ledger test_ledger_mock'
|
@go test -mod=readonly `go list github.com/cosmos/cosmos-sdk/crypto` -tags='cgo ledger test_ledger_mock'
|
||||||
# Now test with a real device
|
# Now test with a real device
|
||||||
@go test -v `go list github.com/cosmos/cosmos-sdk/crypto` -tags='cgo ledger'
|
@go test -mod=readonly -v `go list github.com/cosmos/cosmos-sdk/crypto` -tags='cgo ledger'
|
||||||
|
|
||||||
test_unit:
|
test_unit:
|
||||||
@VERSION=$(VERSION) go test $(PACKAGES_NOSIMULATION) -tags='ledger test_ledger_mock'
|
@VERSION=$(VERSION) go test -mod=readonly $(PACKAGES_NOSIMULATION) -tags='ledger test_ledger_mock'
|
||||||
|
|
||||||
test_race:
|
test_race:
|
||||||
@VERSION=$(VERSION) go test -race $(PACKAGES_NOSIMULATION)
|
@VERSION=$(VERSION) go test -mod=readonly -race $(PACKAGES_NOSIMULATION)
|
||||||
|
|
||||||
test_sim_gaia_nondeterminism:
|
test_sim_gaia_nondeterminism:
|
||||||
@echo "Running nondeterminism test..."
|
@echo "Running nondeterminism test..."
|
||||||
@go test ./cmd/gaia/app -run TestAppStateDeterminism -SimulationEnabled=true -v -timeout 10m
|
@go test -mod=readonly ./cmd/gaia/app -run TestAppStateDeterminism -SimulationEnabled=true -v -timeout 10m
|
||||||
|
|
||||||
test_sim_gaia_custom_genesis_fast:
|
test_sim_gaia_custom_genesis_fast:
|
||||||
@echo "Running custom genesis simulation..."
|
@echo "Running custom genesis simulation..."
|
||||||
@echo "By default, ${HOME}/.gaiad/config/genesis.json will be used."
|
@echo "By default, ${HOME}/.gaiad/config/genesis.json will be used."
|
||||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationGenesis=${HOME}/.gaiad/config/genesis.json \
|
@go test -mod=readonly ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationGenesis=${HOME}/.gaiad/config/genesis.json \
|
||||||
-SimulationEnabled=true -SimulationNumBlocks=100 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -SimulationPeriod=5 -v -timeout 24h
|
-SimulationEnabled=true -SimulationNumBlocks=100 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -SimulationPeriod=5 -v -timeout 24h
|
||||||
|
|
||||||
test_sim_gaia_fast:
|
test_sim_gaia_fast:
|
||||||
@echo "Running quick Gaia simulation. This may take several minutes..."
|
@echo "Running quick Gaia simulation. This may take several minutes..."
|
||||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=100 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -SimulationPeriod=5 -v -timeout 24h
|
@go test -mod=readonly ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=100 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=99 -SimulationPeriod=5 -v -timeout 24h
|
||||||
|
|
||||||
test_sim_gaia_import_export:
|
test_sim_gaia_import_export:
|
||||||
@echo "Running Gaia import/export simulation. This may take several minutes..."
|
@echo "Running Gaia import/export simulation. This may take several minutes..."
|
||||||
|
@ -211,31 +188,31 @@ SIM_BLOCK_SIZE ?= 200
|
||||||
SIM_COMMIT ?= true
|
SIM_COMMIT ?= true
|
||||||
test_sim_gaia_benchmark:
|
test_sim_gaia_benchmark:
|
||||||
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
|
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
|
||||||
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ \
|
@go test -mod=readonly -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ \
|
||||||
-SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h
|
-SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h
|
||||||
|
|
||||||
test_sim_gaia_profile:
|
test_sim_gaia_profile:
|
||||||
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
|
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
|
||||||
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ \
|
@go test -mod=readonly -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ \
|
||||||
-SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out
|
-SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out
|
||||||
|
|
||||||
test_cover:
|
test_cover:
|
||||||
@export VERSION=$(VERSION); bash -x tests/test_cover.sh
|
@export VERSION=$(VERSION); bash -x tests/test_cover.sh
|
||||||
|
|
||||||
test_lint:
|
lint: tools ci-lint
|
||||||
gometalinter --config=tools/gometalinter.json ./...
|
ci-lint:
|
||||||
!(gometalinter --exclude /usr/lib/go/src/ --exclude client/lcd/statik/statik.go --exclude 'vendor/*' --disable-all --enable='errcheck' --vendor ./... | grep -v "client/")
|
golangci-lint run
|
||||||
|
go vet -composites=false -tests=false ./...
|
||||||
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s
|
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s
|
||||||
dep status >> /dev/null
|
go mod verify
|
||||||
!(grep -n branch Gopkg.toml)
|
|
||||||
|
|
||||||
format:
|
format: tools
|
||||||
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs gofmt -w -s
|
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs gofmt -w -s
|
||||||
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs misspell -w
|
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs misspell -w
|
||||||
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs goimports -w -local github.com/cosmos/cosmos-sdk
|
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs goimports -w -local github.com/cosmos/cosmos-sdk
|
||||||
|
|
||||||
benchmark:
|
benchmark:
|
||||||
@go test -bench=. $(PACKAGES_NOSIMULATION)
|
@go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION)
|
||||||
|
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
@ -287,11 +264,11 @@ snapcraft-local.yaml: snapcraft-local.yaml.in
|
||||||
# To avoid unintended conflicts with file names, always add to .PHONY
|
# To avoid unintended conflicts with file names, always add to .PHONY
|
||||||
# unless there is a reason not to.
|
# unless there is a reason not to.
|
||||||
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
||||||
.PHONY: build install install_debug dist clean distclean \
|
.PHONY: install install_debug dist clean distclean \
|
||||||
check_tools check_dev_tools get_vendor_deps draw_deps test test_cli test_unit \
|
draw_deps test test_cli test_unit \
|
||||||
test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
|
test_cover lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
|
||||||
build-linux build-docker-gaiadnode localnet-start localnet-stop \
|
build-linux build-docker-gaiadnode localnet-start localnet-stop \
|
||||||
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast \
|
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast \
|
||||||
test_sim_gaia_custom_genesis_fast test_sim_gaia_custom_genesis_multi_seed \
|
test_sim_gaia_custom_genesis_fast test_sim_gaia_custom_genesis_multi_seed \
|
||||||
test_sim_gaia_multi_seed test_sim_gaia_import_export update_tools update_dev_tools \
|
test_sim_gaia_multi_seed test_sim_gaia_import_export \
|
||||||
devtools-clean
|
go-mod-cache
|
||||||
|
|
57
PENDING.md
57
PENDING.md
|
@ -1,57 +0,0 @@
|
||||||
# PENDING CHANGELOG
|
|
||||||
|
|
||||||
<!----------------------------- BREAKING CHANGES ----------------------------->
|
|
||||||
|
|
||||||
## BREAKING CHANGES
|
|
||||||
|
|
||||||
### Gaia REST API
|
|
||||||
|
|
||||||
### Gaia CLI
|
|
||||||
|
|
||||||
### Gaia
|
|
||||||
|
|
||||||
### SDK
|
|
||||||
|
|
||||||
### Tendermint
|
|
||||||
|
|
||||||
<!--------------------------------- FEATURES --------------------------------->
|
|
||||||
|
|
||||||
## FEATURES
|
|
||||||
|
|
||||||
### Gaia REST API
|
|
||||||
|
|
||||||
### Gaia CLI
|
|
||||||
|
|
||||||
### Gaia
|
|
||||||
|
|
||||||
### SDK
|
|
||||||
|
|
||||||
### Tendermint
|
|
||||||
|
|
||||||
<!------------------------------- IMPROVEMENTS ------------------------------->
|
|
||||||
|
|
||||||
## IMPROVEMENTS
|
|
||||||
|
|
||||||
### Gaia REST API
|
|
||||||
|
|
||||||
### Gaia CLI
|
|
||||||
|
|
||||||
### Gaia
|
|
||||||
|
|
||||||
### SDK
|
|
||||||
|
|
||||||
### Tendermint
|
|
||||||
|
|
||||||
<!--------------------------------- BUG FIXES -------------------------------->
|
|
||||||
|
|
||||||
## BUG FIXES
|
|
||||||
|
|
||||||
### Gaia REST API
|
|
||||||
|
|
||||||
### Gaia CLI
|
|
||||||
|
|
||||||
### Gaia
|
|
||||||
|
|
||||||
### SDK
|
|
||||||
|
|
||||||
### Tendermint
|
|
|
@ -18,7 +18,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
|
**WARNING**: The SDK has mostly stabilized, but we are still making some
|
||||||
breaking changes.
|
breaking changes.
|
||||||
|
|
||||||
**Note**: Requires [Go 1.11.5+](https://golang.org/dl/)
|
**Note**: Requires [Go 1.12.1+](https://golang.org/dl/)
|
||||||
|
|
||||||
## Cosmos Hub Mainnet
|
## Cosmos Hub Mainnet
|
||||||
|
|
||||||
|
|
|
@ -287,12 +287,25 @@ func (app *BaseApp) storeConsensusParams(consensusParams *abci.ConsensusParams)
|
||||||
mainStore.Set(mainConsensusParamsKey, consensusParamsBz)
|
mainStore.Set(mainConsensusParamsKey, consensusParamsBz)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMaximumBlockGas gets the maximum gas from the consensus params.
|
// getMaximumBlockGas gets the maximum gas from the consensus params. It panics
|
||||||
func (app *BaseApp) getMaximumBlockGas() (maxGas uint64) {
|
// if maximum block gas is less than negative one and returns zero if negative
|
||||||
if app.consensusParams == nil || app.consensusParams.BlockSize == nil {
|
// one.
|
||||||
|
func (app *BaseApp) getMaximumBlockGas() uint64 {
|
||||||
|
if app.consensusParams == nil || app.consensusParams.Block == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return uint64(app.consensusParams.BlockSize.MaxGas)
|
|
||||||
|
maxGas := app.consensusParams.Block.MaxGas
|
||||||
|
switch {
|
||||||
|
case maxGas < -1:
|
||||||
|
panic(fmt.Sprintf("invalid maximum block gas: %d", maxGas))
|
||||||
|
|
||||||
|
case maxGas == -1:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
default:
|
||||||
|
return uint64(maxGas)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -510,6 +523,19 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *BaseApp) validateHeight(req abci.RequestBeginBlock) error {
|
||||||
|
if req.Header.Height < 1 {
|
||||||
|
return fmt.Errorf("invalid height: %d", req.Header.Height)
|
||||||
|
}
|
||||||
|
|
||||||
|
prevHeight := app.LastBlockHeight()
|
||||||
|
if req.Header.Height != prevHeight+1 {
|
||||||
|
return fmt.Errorf("invalid height: %d; expected: %d", req.Header.Height, prevHeight+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// BeginBlock implements the ABCI application interface.
|
// BeginBlock implements the ABCI application interface.
|
||||||
func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) {
|
func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) {
|
||||||
if app.cms.TracingEnabled() {
|
if app.cms.TracingEnabled() {
|
||||||
|
@ -518,6 +544,10 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := app.validateHeight(req); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the DeliverTx state. If this is the first block, it should
|
// Initialize the DeliverTx state. If this is the first block, it should
|
||||||
// already be initialized in InitChain. Otherwise app.deliverState will be
|
// already be initialized in InitChain. Otherwise app.deliverState will be
|
||||||
// nil, since it is reset on Commit.
|
// nil, since it is reset on Commit.
|
||||||
|
@ -631,7 +661,7 @@ func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) (ctx sdk.Con
|
||||||
|
|
||||||
// runMsgs iterates through all the messages and executes them.
|
// runMsgs iterates through all the messages and executes them.
|
||||||
func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (result sdk.Result) {
|
func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (result sdk.Result) {
|
||||||
idxlogs := make([]sdk.ABCIMessageLog, 0, len(msgs)) // a list of JSON-encoded logs with msg index
|
idxLogs := make([]sdk.ABCIMessageLog, 0, len(msgs)) // a list of JSON-encoded logs with msg index
|
||||||
|
|
||||||
var data []byte // NOTE: we just append them all (?!)
|
var data []byte // NOTE: we just append them all (?!)
|
||||||
var tags sdk.Tags // also just append them all
|
var tags sdk.Tags // also just append them all
|
||||||
|
@ -665,7 +695,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
||||||
// stop execution and return on first failed message
|
// stop execution and return on first failed message
|
||||||
if !msgResult.IsOK() {
|
if !msgResult.IsOK() {
|
||||||
idxLog.Success = false
|
idxLog.Success = false
|
||||||
idxlogs = append(idxlogs, idxLog)
|
idxLogs = append(idxLogs, idxLog)
|
||||||
|
|
||||||
code = msgResult.Code
|
code = msgResult.Code
|
||||||
codespace = msgResult.Codespace
|
codespace = msgResult.Codespace
|
||||||
|
@ -673,10 +703,10 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
||||||
}
|
}
|
||||||
|
|
||||||
idxLog.Success = true
|
idxLog.Success = true
|
||||||
idxlogs = append(idxlogs, idxLog)
|
idxLogs = append(idxLogs, idxLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
logJSON := codec.Cdc.MustMarshalJSON(idxlogs)
|
logJSON := codec.Cdc.MustMarshalJSON(idxLogs)
|
||||||
result = sdk.Result{
|
result = sdk.Result{
|
||||||
Code: code,
|
Code: code,
|
||||||
Codespace: codespace,
|
Codespace: codespace,
|
||||||
|
@ -689,7 +719,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the applicantion's deliverState if app is in runTxModeDeliver,
|
// Returns the applications's deliverState if app is in runTxModeDeliver,
|
||||||
// otherwise it returns the application's checkstate.
|
// otherwise it returns the application's checkstate.
|
||||||
func (app *BaseApp) getState(mode runTxMode) *state {
|
func (app *BaseApp) getState(mode runTxMode) *state {
|
||||||
if mode == runTxModeCheck || mode == runTxModeSimulate {
|
if mode == runTxModeCheck || mode == runTxModeSimulate {
|
||||||
|
@ -799,7 +829,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
|
||||||
// performance benefits, but it'll be more difficult to get right.
|
// performance benefits, but it'll be more difficult to get right.
|
||||||
anteCtx, msCache = app.cacheTxContext(ctx, txBytes)
|
anteCtx, msCache = app.cacheTxContext(ctx, txBytes)
|
||||||
|
|
||||||
newCtx, result, abort := app.anteHandler(anteCtx, tx, (mode == runTxModeSimulate))
|
newCtx, result, abort := app.anteHandler(anteCtx, tx, mode == runTxModeSimulate)
|
||||||
if !newCtx.IsZero() {
|
if !newCtx.IsZero() {
|
||||||
// At this point, newCtx.MultiStore() is cache-wrapped, or something else
|
// At this point, newCtx.MultiStore() is cache-wrapped, or something else
|
||||||
// replaced by the ante handler. We want the original multistore, not one
|
// replaced by the ante handler. We want the original multistore, not one
|
||||||
|
|
|
@ -296,6 +296,7 @@ func TestInitChainer(t *testing.T) {
|
||||||
// stores are mounted and private members are set - sealing baseapp
|
// stores are mounted and private members are set - sealing baseapp
|
||||||
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, int64(0), app.LastBlockHeight())
|
||||||
|
|
||||||
app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}"), ChainId: "test-chain-id"}) // must have valid JSON genesis file, even if empty
|
app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}"), ChainId: "test-chain-id"}) // must have valid JSON genesis file, even if empty
|
||||||
|
|
||||||
|
@ -308,6 +309,7 @@ func TestInitChainer(t *testing.T) {
|
||||||
|
|
||||||
app.Commit()
|
app.Commit()
|
||||||
res = app.Query(query)
|
res = app.Query(query)
|
||||||
|
require.Equal(t, int64(1), app.LastBlockHeight())
|
||||||
require.Equal(t, value, res.Value)
|
require.Equal(t, value, res.Value)
|
||||||
|
|
||||||
// reload app
|
// reload app
|
||||||
|
@ -316,14 +318,17 @@ func TestInitChainer(t *testing.T) {
|
||||||
app.MountStores(capKey, capKey2)
|
app.MountStores(capKey, capKey2)
|
||||||
err = app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
err = app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, int64(1), app.LastBlockHeight())
|
||||||
|
|
||||||
// ensure we can still query after reloading
|
// ensure we can still query after reloading
|
||||||
res = app.Query(query)
|
res = app.Query(query)
|
||||||
require.Equal(t, value, res.Value)
|
require.Equal(t, value, res.Value)
|
||||||
|
|
||||||
// commit and ensure we can still query
|
// commit and ensure we can still query
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
header := abci.Header{Height: app.LastBlockHeight() + 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
app.Commit()
|
app.Commit()
|
||||||
|
|
||||||
res = app.Query(query)
|
res = app.Query(query)
|
||||||
require.Equal(t, value, res.Value)
|
require.Equal(t, value, res.Value)
|
||||||
}
|
}
|
||||||
|
@ -514,7 +519,6 @@ func TestCheckTx(t *testing.T) {
|
||||||
app := setupBaseApp(t, anteOpt, routerOpt)
|
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||||
|
|
||||||
nTxs := int64(5)
|
nTxs := int64(5)
|
||||||
|
|
||||||
app.InitChain(abci.RequestInitChain{})
|
app.InitChain(abci.RequestInitChain{})
|
||||||
|
|
||||||
// Create same codec used in txDecoder
|
// Create same codec used in txDecoder
|
||||||
|
@ -536,7 +540,8 @@ func TestCheckTx(t *testing.T) {
|
||||||
require.Equal(t, nTxs, storedCounter)
|
require.Equal(t, nTxs, storedCounter)
|
||||||
|
|
||||||
// If a block is committed, CheckTx state should be reset.
|
// If a block is committed, CheckTx state should be reset.
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
header := abci.Header{Height: 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
app.EndBlock(abci.RequestEndBlock{})
|
app.EndBlock(abci.RequestEndBlock{})
|
||||||
app.Commit()
|
app.Commit()
|
||||||
|
|
||||||
|
@ -567,16 +572,22 @@ func TestDeliverTx(t *testing.T) {
|
||||||
|
|
||||||
nBlocks := 3
|
nBlocks := 3
|
||||||
txPerHeight := 5
|
txPerHeight := 5
|
||||||
|
|
||||||
for blockN := 0; blockN < nBlocks; blockN++ {
|
for blockN := 0; blockN < nBlocks; blockN++ {
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
header := abci.Header{Height: int64(blockN) + 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
|
||||||
for i := 0; i < txPerHeight; i++ {
|
for i := 0; i < txPerHeight; i++ {
|
||||||
counter := int64(blockN*txPerHeight + i)
|
counter := int64(blockN*txPerHeight + i)
|
||||||
tx := newTxCounter(counter, counter)
|
tx := newTxCounter(counter, counter)
|
||||||
|
|
||||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
res := app.DeliverTx(txBytes)
|
res := app.DeliverTx(txBytes)
|
||||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||||
}
|
}
|
||||||
|
|
||||||
app.EndBlock(abci.RequestEndBlock{})
|
app.EndBlock(abci.RequestEndBlock{})
|
||||||
app.Commit()
|
app.Commit()
|
||||||
}
|
}
|
||||||
|
@ -610,48 +621,47 @@ func TestMultiMsgDeliverTx(t *testing.T) {
|
||||||
|
|
||||||
// run a multi-msg tx
|
// run a multi-msg tx
|
||||||
// with all msgs the same route
|
// with all msgs the same route
|
||||||
{
|
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
tx := newTxCounter(0, 0, 1, 2)
|
|
||||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
res := app.DeliverTx(txBytes)
|
|
||||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
|
||||||
|
|
||||||
store := app.deliverState.ctx.KVStore(capKey1)
|
header := abci.Header{Height: 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
tx := newTxCounter(0, 0, 1, 2)
|
||||||
|
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
res := app.DeliverTx(txBytes)
|
||||||
|
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||||
|
|
||||||
// tx counter only incremented once
|
store := app.deliverState.ctx.KVStore(capKey1)
|
||||||
txCounter := getIntFromStore(store, anteKey)
|
|
||||||
require.Equal(t, int64(1), txCounter)
|
|
||||||
|
|
||||||
// msg counter incremented three times
|
// tx counter only incremented once
|
||||||
msgCounter := getIntFromStore(store, deliverKey)
|
txCounter := getIntFromStore(store, anteKey)
|
||||||
require.Equal(t, int64(3), msgCounter)
|
require.Equal(t, int64(1), txCounter)
|
||||||
}
|
|
||||||
|
// msg counter incremented three times
|
||||||
|
msgCounter := getIntFromStore(store, deliverKey)
|
||||||
|
require.Equal(t, int64(3), msgCounter)
|
||||||
|
|
||||||
// replace the second message with a msgCounter2
|
// replace the second message with a msgCounter2
|
||||||
{
|
|
||||||
tx := newTxCounter(1, 3)
|
|
||||||
tx.Msgs = append(tx.Msgs, msgCounter2{0})
|
|
||||||
tx.Msgs = append(tx.Msgs, msgCounter2{1})
|
|
||||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
res := app.DeliverTx(txBytes)
|
|
||||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
|
||||||
|
|
||||||
store := app.deliverState.ctx.KVStore(capKey1)
|
tx = newTxCounter(1, 3)
|
||||||
|
tx.Msgs = append(tx.Msgs, msgCounter2{0})
|
||||||
|
tx.Msgs = append(tx.Msgs, msgCounter2{1})
|
||||||
|
txBytes, err = codec.MarshalBinaryLengthPrefixed(tx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
res = app.DeliverTx(txBytes)
|
||||||
|
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||||
|
|
||||||
// tx counter only incremented once
|
store = app.deliverState.ctx.KVStore(capKey1)
|
||||||
txCounter := getIntFromStore(store, anteKey)
|
|
||||||
require.Equal(t, int64(2), txCounter)
|
|
||||||
|
|
||||||
// original counter increments by one
|
// tx counter only incremented once
|
||||||
// new counter increments by two
|
txCounter = getIntFromStore(store, anteKey)
|
||||||
msgCounter := getIntFromStore(store, deliverKey)
|
require.Equal(t, int64(2), txCounter)
|
||||||
require.Equal(t, int64(4), msgCounter)
|
|
||||||
msgCounter2 := getIntFromStore(store, deliverKey2)
|
// original counter increments by one
|
||||||
require.Equal(t, int64(2), msgCounter2)
|
// new counter increments by two
|
||||||
}
|
msgCounter = getIntFromStore(store, deliverKey)
|
||||||
|
require.Equal(t, int64(4), msgCounter)
|
||||||
|
msgCounter2 := getIntFromStore(store, deliverKey2)
|
||||||
|
require.Equal(t, int64(2), msgCounter2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interleave calls to Check and Deliver and ensure
|
// Interleave calls to Check and Deliver and ensure
|
||||||
|
@ -692,7 +702,8 @@ func TestSimulateTx(t *testing.T) {
|
||||||
nBlocks := 3
|
nBlocks := 3
|
||||||
for blockN := 0; blockN < nBlocks; blockN++ {
|
for blockN := 0; blockN < nBlocks; blockN++ {
|
||||||
count := int64(blockN + 1)
|
count := int64(blockN + 1)
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
header := abci.Header{Height: count}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
|
||||||
tx := newTxCounter(count, count)
|
tx := newTxCounter(count, count)
|
||||||
txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx)
|
txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx)
|
||||||
|
@ -737,7 +748,9 @@ func TestRunInvalidTransaction(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
app := setupBaseApp(t, anteOpt, routerOpt)
|
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
|
header := abci.Header{Height: 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
|
||||||
// Transaction with no messages
|
// Transaction with no messages
|
||||||
{
|
{
|
||||||
|
@ -847,7 +860,8 @@ func TestTxGasLimits(t *testing.T) {
|
||||||
|
|
||||||
app := setupBaseApp(t, anteOpt, routerOpt)
|
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||||
|
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
header := abci.Header{Height: 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
tx *txTest
|
tx *txTest
|
||||||
|
@ -932,7 +946,7 @@ func TestMaxBlockGasLimits(t *testing.T) {
|
||||||
app := setupBaseApp(t, anteOpt, routerOpt)
|
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||||
app.InitChain(abci.RequestInitChain{
|
app.InitChain(abci.RequestInitChain{
|
||||||
ConsensusParams: &abci.ConsensusParams{
|
ConsensusParams: &abci.ConsensusParams{
|
||||||
BlockSize: &abci.BlockSizeParams{
|
Block: &abci.BlockParams{
|
||||||
MaxGas: 100,
|
MaxGas: 100,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -962,7 +976,8 @@ func TestMaxBlockGasLimits(t *testing.T) {
|
||||||
tx := tc.tx
|
tx := tc.tx
|
||||||
|
|
||||||
// reset the block gas
|
// reset the block gas
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
header := abci.Header{Height: app.LastBlockHeight() + 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
|
||||||
// execute the transaction multiple times
|
// execute the transaction multiple times
|
||||||
for j := 0; j < tc.numDelivers; j++ {
|
for j := 0; j < tc.numDelivers; j++ {
|
||||||
|
@ -1005,7 +1020,9 @@ func TestBaseAppAnteHandler(t *testing.T) {
|
||||||
|
|
||||||
app.InitChain(abci.RequestInitChain{})
|
app.InitChain(abci.RequestInitChain{})
|
||||||
registerTestCodec(cdc)
|
registerTestCodec(cdc)
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
|
header := abci.Header{Height: app.LastBlockHeight() + 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
|
||||||
// execute a tx that will fail ante handler execution
|
// execute a tx that will fail ante handler execution
|
||||||
//
|
//
|
||||||
|
@ -1105,14 +1122,16 @@ func TestGasConsumptionBadTx(t *testing.T) {
|
||||||
app := setupBaseApp(t, anteOpt, routerOpt)
|
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||||
app.InitChain(abci.RequestInitChain{
|
app.InitChain(abci.RequestInitChain{
|
||||||
ConsensusParams: &abci.ConsensusParams{
|
ConsensusParams: &abci.ConsensusParams{
|
||||||
BlockSize: &abci.BlockSizeParams{
|
Block: &abci.BlockParams{
|
||||||
MaxGas: 9,
|
MaxGas: 9,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
app.InitChain(abci.RequestInitChain{})
|
app.InitChain(abci.RequestInitChain{})
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
|
header := abci.Header{Height: app.LastBlockHeight() + 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
|
||||||
tx := newTxCounter(5, 0)
|
tx := newTxCounter(5, 0)
|
||||||
tx.setFailOnAnte(true)
|
tx.setFailOnAnte(true)
|
||||||
|
@ -1174,7 +1193,9 @@ func TestQuery(t *testing.T) {
|
||||||
require.Equal(t, 0, len(res.Value))
|
require.Equal(t, 0, len(res.Value))
|
||||||
|
|
||||||
// query is still empty after a DeliverTx before we commit
|
// query is still empty after a DeliverTx before we commit
|
||||||
app.BeginBlock(abci.RequestBeginBlock{})
|
header := abci.Header{Height: app.LastBlockHeight() + 1}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
|
||||||
resTx = app.Deliver(tx)
|
resTx = app.Deliver(tx)
|
||||||
require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
|
require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
|
||||||
res = app.Query(query)
|
res = app.Query(query)
|
||||||
|
@ -1216,3 +1237,19 @@ func TestP2PQuery(t *testing.T) {
|
||||||
res = app.Query(idQuery)
|
res = app.Query(idQuery)
|
||||||
require.Equal(t, uint32(4), res.Code)
|
require.Equal(t, uint32(4), res.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetMaximumBlockGas(t *testing.T) {
|
||||||
|
app := setupBaseApp(t)
|
||||||
|
|
||||||
|
app.setConsensusParams(&abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: 0}})
|
||||||
|
require.Equal(t, uint64(0), app.getMaximumBlockGas())
|
||||||
|
|
||||||
|
app.setConsensusParams(&abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: -1}})
|
||||||
|
require.Equal(t, uint64(0), app.getMaximumBlockGas())
|
||||||
|
|
||||||
|
app.setConsensusParams(&abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: 5000000}})
|
||||||
|
require.Equal(t, uint64(5000000), app.getMaximumBlockGas())
|
||||||
|
|
||||||
|
app.setConsensusParams(&abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: -5000000}})
|
||||||
|
require.Panics(t, func() { app.getMaximumBlockGas() })
|
||||||
|
}
|
||||||
|
|
|
@ -18,14 +18,11 @@ const (
|
||||||
flagGet = "get"
|
flagGet = "get"
|
||||||
)
|
)
|
||||||
|
|
||||||
var configDefaults map[string]string
|
var configDefaults = map[string]string{
|
||||||
|
"chain-id": "",
|
||||||
func init() {
|
"output": "text",
|
||||||
configDefaults = map[string]string{
|
"node": "tcp://localhost:26657",
|
||||||
"chain-id": "",
|
"broadcast-mode": "sync",
|
||||||
"output": "text",
|
|
||||||
"node": "tcp://localhost:26657",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigCmd returns a CLI command to interactively create a
|
// ConfigCmd returns a CLI command to interactively create a
|
||||||
|
@ -56,13 +53,13 @@ func runConfigCmd(cmd *cobra.Command, args []string) error {
|
||||||
return fmt.Errorf("wrong number of arguments")
|
return fmt.Errorf("wrong number of arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load configuration
|
// load configuration
|
||||||
tree, err := loadConfigFile(cfgFile)
|
tree, err := loadConfigFile(cfgFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the config and exit
|
// print the config and exit
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
s, err := tree.ToTomlString()
|
s, err := tree.ToTomlString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -73,45 +70,54 @@ func runConfigCmd(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
key := args[0]
|
key := args[0]
|
||||||
// Get value action
|
|
||||||
|
// get config value for a given key
|
||||||
if getAction {
|
if getAction {
|
||||||
switch key {
|
switch key {
|
||||||
case "trace", "trust-node", "indent":
|
case "trace", "trust-node", "indent":
|
||||||
fmt.Println(tree.GetDefault(key, false).(bool))
|
fmt.Println(tree.GetDefault(key, false).(bool))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if defaultValue, ok := configDefaults[key]; ok {
|
if defaultValue, ok := configDefaults[key]; ok {
|
||||||
fmt.Println(tree.GetDefault(key, defaultValue).(string))
|
fmt.Println(tree.GetDefault(key, defaultValue).(string))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return errUnknownConfigKey(key)
|
return errUnknownConfigKey(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set value action
|
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
return fmt.Errorf("wrong number of arguments")
|
return fmt.Errorf("wrong number of arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
value := args[1]
|
value := args[1]
|
||||||
|
|
||||||
|
// set config value for a given key
|
||||||
switch key {
|
switch key {
|
||||||
case "chain-id", "output", "node":
|
case "chain-id", "output", "node", "broadcast-mode":
|
||||||
tree.Set(key, value)
|
tree.Set(key, value)
|
||||||
|
|
||||||
case "trace", "trust-node", "indent":
|
case "trace", "trust-node", "indent":
|
||||||
boolVal, err := strconv.ParseBool(value)
|
boolVal, err := strconv.ParseBool(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tree.Set(key, boolVal)
|
tree.Set(key, boolVal)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return errUnknownConfigKey(key)
|
return errUnknownConfigKey(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save configuration to disk
|
// save configuration to disk
|
||||||
if err := saveConfigFile(cfgFile, tree); err != nil {
|
if err := saveConfigFile(cfgFile, tree); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "configuration saved to %s\n", cfgFile)
|
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "configuration saved to %s\n", cfgFile)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +150,7 @@ func loadConfigFile(cfgFile string) (*toml.Tree, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveConfigFile(cfgFile string, tree *toml.Tree) error {
|
func saveConfigFile(cfgFile string, tree *toml.Tree) error {
|
||||||
fp, err := os.OpenFile(cfgFile, os.O_WRONLY|os.O_CREATE, 0644)
|
fp, err := os.OpenFile(cfgFile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// For https://github.com/cosmos/cosmos-sdk/issues/3899
|
||||||
|
func Test_runConfigCmdTwiceWithShorterNodeValue(t *testing.T) {
|
||||||
|
// Prepare environment
|
||||||
|
t.Parallel()
|
||||||
|
configHome, cleanup := tmpDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
_ = os.RemoveAll(filepath.Join(configHome, "config"))
|
||||||
|
viper.Set(cli.HomeFlag, configHome)
|
||||||
|
|
||||||
|
// Init command config
|
||||||
|
cmd := ConfigCmd(configHome)
|
||||||
|
assert.NotNil(t, cmd)
|
||||||
|
|
||||||
|
err := cmd.RunE(cmd, []string{"node", "tcp://localhost:26657"})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
err = cmd.RunE(cmd, []string{"node", "--get"})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
err = cmd.RunE(cmd, []string{"node", "tcp://local:26657"})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
err = cmd.RunE(cmd, []string{"node", "--get"})
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tmpDir(t *testing.T) (string, func()) {
|
||||||
|
dir, err := ioutil.TempDir("", t.Name()+"_")
|
||||||
|
require.NoError(t, err)
|
||||||
|
return dir, func() { _ = os.RemoveAll(dir) }
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package context
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,29 +12,36 @@ import (
|
||||||
// an intermediate structure which is logged if the context has a logger
|
// an intermediate structure which is logged if the context has a logger
|
||||||
// defined.
|
// defined.
|
||||||
func (ctx CLIContext) BroadcastTx(txBytes []byte) (res sdk.TxResponse, err error) {
|
func (ctx CLIContext) BroadcastTx(txBytes []byte) (res sdk.TxResponse, err error) {
|
||||||
if ctx.Async {
|
switch ctx.BroadcastMode {
|
||||||
if res, err = ctx.BroadcastTxAsync(txBytes); err != nil {
|
case client.BroadcastSync:
|
||||||
return
|
res, err = ctx.BroadcastTxSync(txBytes)
|
||||||
}
|
|
||||||
return
|
case client.BroadcastAsync:
|
||||||
|
res, err = ctx.BroadcastTxAsync(txBytes)
|
||||||
|
|
||||||
|
case client.BroadcastBlock:
|
||||||
|
res, err = ctx.BroadcastTxCommit(txBytes)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return sdk.TxResponse{}, fmt.Errorf("unsupported return type %s; supported types: sync, async, block", ctx.BroadcastMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if res, err = ctx.BroadcastTxAndAwaitCommit(txBytes); err != nil {
|
return res, err
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BroadcastTxAndAwaitCommit broadcasts transaction bytes to a Tendermint node
|
// BroadcastTxCommit broadcasts transaction bytes to a Tendermint node and
|
||||||
// and waits for a commit.
|
// waits for a commit.
|
||||||
func (ctx CLIContext) BroadcastTxAndAwaitCommit(tx []byte) (sdk.TxResponse, error) {
|
//
|
||||||
|
// NOTE: This should ideally not be used as the request may timeout but the tx
|
||||||
|
// may still be included in a block. Use BroadcastTxAsync or BroadcastTxSync
|
||||||
|
// instead.
|
||||||
|
func (ctx CLIContext) BroadcastTxCommit(txBytes []byte) (sdk.TxResponse, error) {
|
||||||
node, err := ctx.GetNode()
|
node, err := ctx.GetNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.TxResponse{}, err
|
return sdk.TxResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := node.BroadcastTxCommit(tx)
|
res, err := node.BroadcastTxCommit(txBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.NewResponseFormatBroadcastTxCommit(res), err
|
return sdk.NewResponseFormatBroadcastTxCommit(res), err
|
||||||
}
|
}
|
||||||
|
@ -46,35 +54,29 @@ func (ctx CLIContext) BroadcastTxAndAwaitCommit(tx []byte) (sdk.TxResponse, erro
|
||||||
return sdk.NewResponseFormatBroadcastTxCommit(res), fmt.Errorf(res.DeliverTx.Log)
|
return sdk.NewResponseFormatBroadcastTxCommit(res), fmt.Errorf(res.DeliverTx.Log)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sdk.NewResponseFormatBroadcastTxCommit(res), err
|
return sdk.NewResponseFormatBroadcastTxCommit(res), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BroadcastTxSync broadcasts transaction bytes to a Tendermint node synchronously.
|
// BroadcastTxSync broadcasts transaction bytes to a Tendermint node
|
||||||
func (ctx CLIContext) BroadcastTxSync(tx []byte) (sdk.TxResponse, error) {
|
// synchronously (i.e. returns after CheckTx execution).
|
||||||
|
func (ctx CLIContext) BroadcastTxSync(txBytes []byte) (sdk.TxResponse, error) {
|
||||||
node, err := ctx.GetNode()
|
node, err := ctx.GetNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.TxResponse{}, err
|
return sdk.TxResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := node.BroadcastTxSync(tx)
|
res, err := node.BroadcastTxSync(txBytes)
|
||||||
if err != nil {
|
|
||||||
return sdk.NewResponseFormatBroadcastTx(res), err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sdk.NewResponseFormatBroadcastTx(res), err
|
return sdk.NewResponseFormatBroadcastTx(res), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node asynchronously.
|
// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node
|
||||||
func (ctx CLIContext) BroadcastTxAsync(tx []byte) (sdk.TxResponse, error) {
|
// asynchronously (i.e. returns immediately).
|
||||||
|
func (ctx CLIContext) BroadcastTxAsync(txBytes []byte) (sdk.TxResponse, error) {
|
||||||
node, err := ctx.GetNode()
|
node, err := ctx.GetNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.TxResponse{}, err
|
return sdk.TxResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := node.BroadcastTxAsync(tx)
|
res, err := node.BroadcastTxAsync(txBytes)
|
||||||
if err != nil {
|
|
||||||
return sdk.NewResponseFormatBroadcastTx(res), err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sdk.NewResponseFormatBroadcastTx(res), err
|
return sdk.NewResponseFormatBroadcastTx(res), err
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ type CLIContext struct {
|
||||||
AccountStore string
|
AccountStore string
|
||||||
TrustNode bool
|
TrustNode bool
|
||||||
UseLedger bool
|
UseLedger bool
|
||||||
Async bool
|
BroadcastMode string
|
||||||
PrintResponse bool
|
PrintResponse bool
|
||||||
Verifier tmlite.Verifier
|
Verifier tmlite.Verifier
|
||||||
VerifierHome string
|
VerifierHome string
|
||||||
|
@ -67,7 +67,8 @@ func NewCLIContext() CLIContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
from := viper.GetString(client.FlagFrom)
|
from := viper.GetString(client.FlagFrom)
|
||||||
fromAddress, fromName, err := GetFromFields(from)
|
genOnly := viper.GetBool(client.FlagGenerateOnly)
|
||||||
|
fromAddress, fromName, err := GetFromFields(from, genOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to get from fields: %v", err)
|
fmt.Printf("failed to get from fields: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -89,11 +90,11 @@ func NewCLIContext() CLIContext {
|
||||||
Height: viper.GetInt64(client.FlagHeight),
|
Height: viper.GetInt64(client.FlagHeight),
|
||||||
TrustNode: viper.GetBool(client.FlagTrustNode),
|
TrustNode: viper.GetBool(client.FlagTrustNode),
|
||||||
UseLedger: viper.GetBool(client.FlagUseLedger),
|
UseLedger: viper.GetBool(client.FlagUseLedger),
|
||||||
Async: viper.GetBool(client.FlagAsync),
|
BroadcastMode: viper.GetString(client.FlagBroadcastMode),
|
||||||
PrintResponse: viper.GetBool(client.FlagPrintResponse),
|
PrintResponse: viper.GetBool(client.FlagPrintResponse),
|
||||||
Verifier: verifier,
|
Verifier: verifier,
|
||||||
Simulate: viper.GetBool(client.FlagDryRun),
|
Simulate: viper.GetBool(client.FlagDryRun),
|
||||||
GenerateOnly: viper.GetBool(client.FlagGenerateOnly),
|
GenerateOnly: genOnly,
|
||||||
FromAddress: fromAddress,
|
FromAddress: fromAddress,
|
||||||
FromName: fromName,
|
FromName: fromName,
|
||||||
Indent: viper.GetBool(client.FlagIndentResponse),
|
Indent: viper.GetBool(client.FlagIndentResponse),
|
||||||
|
@ -247,6 +248,13 @@ func (ctx CLIContext) WithFromAddress(addr sdk.AccAddress) CLIContext {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithBroadcastMode returns a copy of the context with an updated broadcast
|
||||||
|
// mode.
|
||||||
|
func (ctx CLIContext) WithBroadcastMode(mode string) CLIContext {
|
||||||
|
ctx.BroadcastMode = mode
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
// PrintOutput prints output while respecting output and indent flags
|
// PrintOutput prints output while respecting output and indent flags
|
||||||
// NOTE: pass in marshalled structs that have been unmarshaled
|
// NOTE: pass in marshalled structs that have been unmarshaled
|
||||||
// because this function will panic on marshaling errors
|
// because this function will panic on marshaling errors
|
||||||
|
@ -259,7 +267,7 @@ func (ctx CLIContext) PrintOutput(toPrint fmt.Stringer) (err error) {
|
||||||
|
|
||||||
case "json":
|
case "json":
|
||||||
if ctx.Indent {
|
if ctx.Indent {
|
||||||
out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ")
|
out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ")
|
||||||
} else {
|
} else {
|
||||||
out, err = ctx.Codec.MarshalJSON(toPrint)
|
out, err = ctx.Codec.MarshalJSON(toPrint)
|
||||||
}
|
}
|
||||||
|
@ -274,12 +282,22 @@ func (ctx CLIContext) PrintOutput(toPrint fmt.Stringer) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFromFields returns a from account address and Keybase name given either
|
// GetFromFields returns a from account address and Keybase name given either
|
||||||
// an address or key name.
|
// an address or key name. If genOnly is true, only a valid Bech32 cosmos
|
||||||
func GetFromFields(from string) (sdk.AccAddress, string, error) {
|
// address is returned.
|
||||||
|
func GetFromFields(from string, genOnly bool) (sdk.AccAddress, string, error) {
|
||||||
if from == "" {
|
if from == "" {
|
||||||
return nil, "", nil
|
return nil, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if genOnly {
|
||||||
|
addr, err := sdk.AccAddressFromBech32(from)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
keybase, err := keys.NewKeyBaseFromHomeFlag()
|
keybase, err := keys.NewKeyBaseFromHomeFlag()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
|
@ -18,11 +18,20 @@ const (
|
||||||
DefaultGasLimit = 200000
|
DefaultGasLimit = 200000
|
||||||
GasFlagAuto = "auto"
|
GasFlagAuto = "auto"
|
||||||
|
|
||||||
|
// BroadcastBlock defines a tx broadcasting mode where the client waits for
|
||||||
|
// the tx to be committed in a block.
|
||||||
|
BroadcastBlock = "block"
|
||||||
|
// BroadcastSync defines a tx broadcasting mode where the client waits for
|
||||||
|
// a CheckTx execution response only.
|
||||||
|
BroadcastSync = "sync"
|
||||||
|
// BroadcastAsync defines a tx broadcasting mode where the client returns
|
||||||
|
// immediately.
|
||||||
|
BroadcastAsync = "async"
|
||||||
|
|
||||||
FlagUseLedger = "ledger"
|
FlagUseLedger = "ledger"
|
||||||
FlagChainID = "chain-id"
|
FlagChainID = "chain-id"
|
||||||
FlagNode = "node"
|
FlagNode = "node"
|
||||||
FlagHeight = "height"
|
FlagHeight = "height"
|
||||||
FlagGas = "gas"
|
|
||||||
FlagGasAdjustment = "gas-adjustment"
|
FlagGasAdjustment = "gas-adjustment"
|
||||||
FlagTrustNode = "trust-node"
|
FlagTrustNode = "trust-node"
|
||||||
FlagFrom = "from"
|
FlagFrom = "from"
|
||||||
|
@ -32,7 +41,7 @@ const (
|
||||||
FlagMemo = "memo"
|
FlagMemo = "memo"
|
||||||
FlagFees = "fees"
|
FlagFees = "fees"
|
||||||
FlagGasPrices = "gas-prices"
|
FlagGasPrices = "gas-prices"
|
||||||
FlagAsync = "async"
|
FlagBroadcastMode = "broadcast-mode"
|
||||||
FlagPrintResponse = "print-response"
|
FlagPrintResponse = "print-response"
|
||||||
FlagDryRun = "dry-run"
|
FlagDryRun = "dry-run"
|
||||||
FlagGenerateOnly = "generate-only"
|
FlagGenerateOnly = "generate-only"
|
||||||
|
@ -40,10 +49,6 @@ const (
|
||||||
FlagListenAddr = "laddr"
|
FlagListenAddr = "laddr"
|
||||||
FlagCORS = "cors"
|
FlagCORS = "cors"
|
||||||
FlagMaxOpenConnections = "max-open"
|
FlagMaxOpenConnections = "max-open"
|
||||||
FlagTLS = "tls"
|
|
||||||
FlagSSLHosts = "ssl-hosts"
|
|
||||||
FlagSSLCertFile = "ssl-certfile"
|
|
||||||
FlagSSLKeyFile = "ssl-keyfile"
|
|
||||||
FlagOutputDocument = "output-document" // inspired by wget -O
|
FlagOutputDocument = "output-document" // inspired by wget -O
|
||||||
FlagSkipConfirmation = "yes"
|
FlagSkipConfirmation = "yes"
|
||||||
)
|
)
|
||||||
|
@ -62,7 +67,6 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
c.Flags().Bool(FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
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().Bool(FlagUseLedger, false, "Use a connected Ledger device")
|
||||||
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
|
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(FlagTrustNode, c.Flags().Lookup(FlagTrustNode))
|
||||||
viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger))
|
viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger))
|
||||||
viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode))
|
viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode))
|
||||||
|
@ -77,15 +81,15 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
for _, c := range cmds {
|
for _, c := range cmds {
|
||||||
c.Flags().Bool(FlagIndentResponse, false, "Add indent to JSON response")
|
c.Flags().Bool(FlagIndentResponse, false, "Add indent to JSON response")
|
||||||
c.Flags().String(FlagFrom, "", "Name or address of private key with which to sign")
|
c.Flags().String(FlagFrom, "", "Name or address of private key with which to sign")
|
||||||
c.Flags().Uint64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
|
c.Flags().Uint64P(FlagAccountNumber, "a", 0, "The account number of the signing account (offline mode only)")
|
||||||
c.Flags().Uint64(FlagSequence, 0, "Sequence number to sign the tx")
|
c.Flags().Uint64P(FlagSequence, "s", 0, "The sequence number of the signing account (offline mode only)")
|
||||||
c.Flags().String(FlagMemo, "", "Memo to send along with transaction")
|
c.Flags().String(FlagMemo, "", "Memo to send along with transaction")
|
||||||
c.Flags().String(FlagFees, "", "Fees to pay along with transaction; eg: 10stake,1atom")
|
c.Flags().String(FlagFees, "", "Fees to pay along with transaction; eg: 10uatom")
|
||||||
c.Flags().String(FlagGasPrices, "", "Gas prices to determine the transaction fee (e.g. 0.00001stake)")
|
c.Flags().String(FlagGasPrices, "", "Gas prices to determine the transaction fee (e.g. 10uatom)")
|
||||||
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
|
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().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().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().StringP(FlagBroadcastMode, "b", BroadcastSync, "Transaction broadcasting mode (sync|async|block)")
|
||||||
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
|
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(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(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
|
||||||
|
@ -111,10 +115,6 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
func RegisterRestServerFlags(cmd *cobra.Command) *cobra.Command {
|
func RegisterRestServerFlags(cmd *cobra.Command) *cobra.Command {
|
||||||
cmd = GetCommands(cmd)[0]
|
cmd = GetCommands(cmd)[0]
|
||||||
cmd.Flags().String(FlagListenAddr, "tcp://localhost:1317", "The address for the server to listen on")
|
cmd.Flags().String(FlagListenAddr, "tcp://localhost:1317", "The address for the server to listen on")
|
||||||
cmd.Flags().Bool(FlagTLS, false, "Enable SSL/TLS layer")
|
|
||||||
cmd.Flags().String(FlagSSLHosts, "", "Comma-separated hostnames and IPs to generate a certificate for")
|
|
||||||
cmd.Flags().String(FlagSSLCertFile, "", "Path to a SSL certificate file. If not supplied, a self-signed certificate will be generated.")
|
|
||||||
cmd.Flags().String(FlagSSLKeyFile, "", "Path to a key file; ignored if a certificate file is not supplied.")
|
|
||||||
cmd.Flags().String(FlagCORS, "", "Set the domains that can make CORS requests (* for all)")
|
cmd.Flags().String(FlagCORS, "", "Set the domains that can make CORS requests (* for all)")
|
||||||
cmd.Flags().Int(FlagMaxOpenConnections, 1000, "The number of maximum open connections")
|
cmd.Flags().Int(FlagMaxOpenConnections, 1000, "The number of maximum open connections")
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ the flag --nosort is set.
|
||||||
cmd.Flags().Bool(flagDryRun, false, "Perform action, but don't add key to local keystore")
|
cmd.Flags().Bool(flagDryRun, false, "Perform action, but don't add key to local keystore")
|
||||||
cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation")
|
cmd.Flags().Uint32(flagAccount, 0, "Account number for HD derivation")
|
||||||
cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation")
|
cmd.Flags().Uint32(flagIndex, 0, "Address index number for HD derivation")
|
||||||
|
cmd.Flags().Bool(client.FlagIndentResponse, false, "Add indent to JSON response")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +147,7 @@ func runAddCmd(_ *cobra.Command, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "Key %q saved to disk.", name)
|
fmt.Fprintf(os.Stderr, "Key %q saved to disk.\n", name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +217,7 @@ func runAddCmd(_ *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bip39.IsMnemonicValid(mnemonic) {
|
if !bip39.IsMnemonicValid(mnemonic) {
|
||||||
fmt.Fprintf(os.Stderr, "Error: Mnemonic is not valid")
|
fmt.Fprintf(os.Stderr, "Error: Mnemonic is not valid.\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
package keys
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func listKeysCmd() *cobra.Command {
|
func listKeysCmd() *cobra.Command {
|
||||||
return &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "list",
|
Use: "list",
|
||||||
Short: "List all keys",
|
Short: "List all keys",
|
||||||
Long: `Return a list of all public keys stored by this key manager
|
Long: `Return a list of all public keys stored by this key manager
|
||||||
along with their associated name and address.`,
|
along with their associated name and address.`,
|
||||||
RunE: runListCmd,
|
RunE: runListCmd,
|
||||||
}
|
}
|
||||||
|
cmd.Flags().Bool(client.FlagIndentResponse, false, "Add indent to JSON response")
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runListCmd(cmd *cobra.Command, args []string) error {
|
func runListCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package keys
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto"
|
"github.com/cosmos/cosmos-sdk/crypto"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
|
@ -49,6 +50,7 @@ consisting of all the keys provided by name and multisig threshold.`,
|
||||||
cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in the device")
|
cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in the device")
|
||||||
cmd.Flags().Uint(flagMultiSigThreshold, 1, "K out of N required signatures")
|
cmd.Flags().Uint(flagMultiSigThreshold, 1, "K out of N required signatures")
|
||||||
cmd.Flags().BoolP(flagShowMultiSig, "m", false, "Output multisig pubkey constituents, threshold, and weights")
|
cmd.Flags().BoolP(flagShowMultiSig, "m", false, "Output multisig pubkey constituents, threshold, and weights")
|
||||||
|
cmd.Flags().Bool(client.FlagIndentResponse, false, "Add indent to JSON response")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,17 @@ type AddNewKey struct {
|
||||||
Index int `json:"index,string,omitempty"`
|
Index int `json:"index,string,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAddNewKey constructs a new AddNewKey request structure.
|
||||||
|
func NewAddNewKey(name, password, mnemonic string, account, index int) AddNewKey {
|
||||||
|
return AddNewKey{
|
||||||
|
Name: name,
|
||||||
|
Password: password,
|
||||||
|
Mnemonic: mnemonic,
|
||||||
|
Account: account,
|
||||||
|
Index: index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// RecoverKeyBody recovers a key
|
// RecoverKeyBody recovers a key
|
||||||
type RecoverKey struct {
|
type RecoverKey struct {
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
@ -19,13 +30,26 @@ type RecoverKey struct {
|
||||||
Index int `json:"index,string,omitempty"`
|
Index int `json:"index,string,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewRecoverKey constructs a new RecoverKey request structure.
|
||||||
|
func NewRecoverKey(password, mnemonic string, account, index int) RecoverKey {
|
||||||
|
return RecoverKey{Password: password, Mnemonic: mnemonic, Account: account, Index: index}
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateKeyReq requests updating a key
|
// UpdateKeyReq requests updating a key
|
||||||
type UpdateKeyReq struct {
|
type UpdateKeyReq struct {
|
||||||
OldPassword string `json:"old_password"`
|
OldPassword string `json:"old_password"`
|
||||||
NewPassword string `json:"new_password"`
|
NewPassword string `json:"new_password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewUpdateKeyReq constructs a new UpdateKeyReq structure.
|
||||||
|
func NewUpdateKeyReq(old, new string) UpdateKeyReq {
|
||||||
|
return UpdateKeyReq{OldPassword: old, NewPassword: new}
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteKeyReq requests deleting a key
|
// DeleteKeyReq requests deleting a key
|
||||||
type DeleteKeyReq struct {
|
type DeleteKeyReq struct {
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDeleteKeyReq constructs a new DeleteKeyReq structure.
|
||||||
|
func NewDeleteKeyReq(password string) DeleteKeyReq { return DeleteKeyReq{Password: password} }
|
||||||
|
|
|
@ -118,8 +118,14 @@ func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) {
|
||||||
printKeyTextHeader()
|
printKeyTextHeader()
|
||||||
printKeyOutput(ko)
|
printKeyOutput(ko)
|
||||||
|
|
||||||
case "json":
|
case OutputFormatJSON:
|
||||||
out, err := MarshalJSON(ko)
|
var out []byte
|
||||||
|
var err error
|
||||||
|
if viper.GetBool(client.FlagIndentResponse) {
|
||||||
|
out, err = cdc.MarshalJSONIndent(ko, "", " ")
|
||||||
|
} else {
|
||||||
|
out, err = cdc.MarshalJSON(ko)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -142,11 +148,18 @@ func printInfos(infos []keys.Info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case OutputFormatJSON:
|
case OutputFormatJSON:
|
||||||
out, err := MarshalJSON(kos)
|
var out []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if viper.GetBool(client.FlagIndentResponse) {
|
||||||
|
out, err = cdc.MarshalJSONIndent(kos, "", " ")
|
||||||
|
} else {
|
||||||
|
out, err = cdc.MarshalJSON(kos)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
package lcd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/x509"
|
|
||||||
"crypto/x509/pkix"
|
|
||||||
"encoding/pem"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// default: 30 days
|
|
||||||
const defaultValidFor = 30 * 24 * time.Hour
|
|
||||||
|
|
||||||
func generateSelfSignedCert(host string) (certBytes []byte, priv *ecdsa.PrivateKey, err error) {
|
|
||||||
priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
||||||
notBefore := time.Now()
|
|
||||||
notAfter := notBefore.Add(defaultValidFor)
|
|
||||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
|
||||||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("failed to generate serial number: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
template := x509.Certificate{
|
|
||||||
SerialNumber: serialNumber,
|
|
||||||
Subject: pkix.Name{
|
|
||||||
Organization: []string{"Gaia Lite"},
|
|
||||||
},
|
|
||||||
DNSNames: []string{"localhost"},
|
|
||||||
NotBefore: notBefore,
|
|
||||||
NotAfter: notAfter,
|
|
||||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
||||||
BasicConstraintsValid: true,
|
|
||||||
IsCA: true,
|
|
||||||
}
|
|
||||||
hosts := strings.Split(host, ",")
|
|
||||||
for _, h := range hosts {
|
|
||||||
if ip := net.ParseIP(h); ip != nil {
|
|
||||||
template.IPAddresses = append(template.IPAddresses, ip)
|
|
||||||
} else {
|
|
||||||
template.DNSNames = append(template.DNSNames, h)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
certBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("couldn't create certificate: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeCertAndPrivKey(certBytes []byte, priv *ecdsa.PrivateKey) (certFile string, keyFile string, err error) {
|
|
||||||
if priv == nil {
|
|
||||||
err = errors.New("private key is nil")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
certFile, err = writeCertificateFile(certBytes)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
keyFile, err = writeKeyFile(priv)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeCertificateFile(certBytes []byte) (filename string, err error) {
|
|
||||||
f, err := ioutil.TempFile("", "cert_")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
filename = f.Name()
|
|
||||||
if err := pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}); err != nil {
|
|
||||||
return filename, fmt.Errorf("failed to write data to %s: %s", filename, err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeKeyFile(priv *ecdsa.PrivateKey) (filename string, err error) {
|
|
||||||
f, err := ioutil.TempFile("", "key_")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
filename = f.Name()
|
|
||||||
block, err := pemBlockForKey(priv)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := pem.Encode(f, block); err != nil {
|
|
||||||
return filename, fmt.Errorf("failed to write data to %s: %s", filename, err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func pemBlockForKey(priv *ecdsa.PrivateKey) (*pem.Block, error) {
|
|
||||||
b, err := x509.MarshalECPrivateKey(priv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to marshal ECDSA private key: %v", err)
|
|
||||||
}
|
|
||||||
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func genCertKeyFilesAndReturnFingerprint(sslHosts string) (certFile, keyFile string, fingerprint string, err error) {
|
|
||||||
certBytes, priv, err := generateSelfSignedCert(sslHosts)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
certFile, keyFile, err = writeCertAndPrivKey(certBytes, priv)
|
|
||||||
cleanupFunc := func() {
|
|
||||||
os.Remove(certFile)
|
|
||||||
os.Remove(keyFile)
|
|
||||||
}
|
|
||||||
// Either of the files could have been written already,
|
|
||||||
// thus clean up regardless of the error.
|
|
||||||
if err != nil {
|
|
||||||
defer cleanupFunc()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fingerprint, err = fingerprintForCertificate(certBytes)
|
|
||||||
if err != nil {
|
|
||||||
defer cleanupFunc()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func fingerprintForCertificate(certBytes []byte) (string, error) {
|
|
||||||
cert, err := x509.ParseCertificate(certBytes)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write(cert.Raw)
|
|
||||||
fingerprintBytes := h.Sum(nil)
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for i, b := range fingerprintBytes {
|
|
||||||
if i > 0 {
|
|
||||||
fmt.Fprintf(&buf, ":")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(&buf, "%02X", b)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("SHA256 Fingerprint=%s", buf.String()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func fingerprintFromFile(certFile string) (string, error) {
|
|
||||||
f, err := os.Open(certFile)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
data, err := ioutil.ReadAll(f)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
block, _ := pem.Decode(data)
|
|
||||||
if block == nil {
|
|
||||||
return "", fmt.Errorf("couldn't find PEM data in %s", certFile)
|
|
||||||
}
|
|
||||||
return fingerprintForCertificate(block.Bytes)
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
package lcd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/x509"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGenerateSelfSignedCert(t *testing.T) {
|
|
||||||
host := "127.0.0.1,localhost,::1"
|
|
||||||
certBytes, _, err := generateSelfSignedCert(host)
|
|
||||||
require.Nil(t, err)
|
|
||||||
cert, err := x509.ParseCertificate(certBytes)
|
|
||||||
require.Nil(t, err)
|
|
||||||
require.Equal(t, 2, len(cert.IPAddresses))
|
|
||||||
require.Equal(t, 2, len(cert.DNSNames))
|
|
||||||
require.True(t, cert.IsCA)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWriteCertAndPrivKey(t *testing.T) {
|
|
||||||
expectedPerm := "-rw-------"
|
|
||||||
derBytes, priv, err := generateSelfSignedCert("localhost")
|
|
||||||
require.Nil(t, err)
|
|
||||||
type args struct {
|
|
||||||
certBytes []byte
|
|
||||||
priv *ecdsa.PrivateKey
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{"valid certificate", args{derBytes, priv}, false},
|
|
||||||
{"garbage", args{[]byte("some garbage"), nil}, true},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
gotCertFile, gotKeyFile, err := writeCertAndPrivKey(tt.args.certBytes, tt.args.priv)
|
|
||||||
defer os.Remove(gotCertFile)
|
|
||||||
defer os.Remove(gotKeyFile)
|
|
||||||
if tt.wantErr {
|
|
||||||
require.NotNil(t, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
require.Nil(t, err)
|
|
||||||
info, err := os.Stat(gotCertFile)
|
|
||||||
require.Nil(t, err)
|
|
||||||
require.True(t, info.Mode().IsRegular())
|
|
||||||
require.Equal(t, expectedPerm, info.Mode().String())
|
|
||||||
info, err = os.Stat(gotKeyFile)
|
|
||||||
require.Nil(t, err)
|
|
||||||
require.True(t, info.Mode().IsRegular())
|
|
||||||
require.Equal(t, expectedPerm, info.Mode().String())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFingerprintFromFile(t *testing.T) {
|
|
||||||
cert := `-----BEGIN CERTIFICATE-----
|
|
||||||
MIIBbDCCARGgAwIBAgIQSuFKYv/22v+cxtVgMUrQADAKBggqhkjOPQQDAjASMRAw
|
|
||||||
DgYDVQQKEwdBY21lIENvMB4XDTE4MDkyMDIzNDQyNloXDTE5MDkyMDIzNDQyNlow
|
|
||||||
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDIo
|
|
||||||
ujAesRczcPVAWiLhpeV1B7hS/RI2LJaGj3QjyJ8hiUthJTPIamr8m7LuS/U5fS0o
|
|
||||||
hY297YeTIGo9YkxClICjSTBHMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
|
|
||||||
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MA8GA1UdEQQIMAaHBH8AAAEwCgYIKoZI
|
|
||||||
zj0EAwIDSQAwRgIhAKnwbhX9FrGG1otCVLwhClQ3RaLxnNpCgIGTqSimb34cAiEA
|
|
||||||
stMN+IqMCKWlZyGqxGIiyksMLMEU3lRqKNQn2EoAZJY=
|
|
||||||
-----END CERTIFICATE-----`
|
|
||||||
wantFingerprint := `SHA256 Fingerprint=0B:ED:9A:AA:A2:D1:7E:B2:53:56:F6:FC:C0:E6:1A:69:70:21:A2:B0:90:FC:AF:BB:EF:AE:2C:78:52:AB:68:40`
|
|
||||||
certFile, err := ioutil.TempFile("", "test_cert_")
|
|
||||||
require.Nil(t, err)
|
|
||||||
_, err = certFile.Write([]byte(cert))
|
|
||||||
require.Nil(t, err)
|
|
||||||
err = certFile.Close()
|
|
||||||
require.Nil(t, err)
|
|
||||||
defer os.Remove(certFile.Name())
|
|
||||||
fingerprint, err := fingerprintFromFile(certFile.Name())
|
|
||||||
require.Nil(t, err)
|
|
||||||
require.Equal(t, wantFingerprint, fingerprint)
|
|
||||||
|
|
||||||
// test failure
|
|
||||||
emptyFile, err := ioutil.TempFile("", "test_cert_")
|
|
||||||
require.Nil(t, err)
|
|
||||||
err = emptyFile.Close()
|
|
||||||
require.Nil(t, err)
|
|
||||||
defer os.Remove(emptyFile.Name())
|
|
||||||
_, err = fingerprintFromFile(emptyFile.Name())
|
|
||||||
require.NotNil(t, err)
|
|
||||||
}
|
|
|
@ -11,6 +11,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
@ -520,9 +522,18 @@ func TestBonding(t *testing.T) {
|
||||||
// test redelegation
|
// test redelegation
|
||||||
rdTokens := sdk.TokensFromTendermintPower(30)
|
rdTokens := sdk.TokensFromTendermintPower(30)
|
||||||
resultTx = doBeginRedelegation(t, port, name1, pw, addr, operAddrs[0], operAddrs[1], rdTokens, fees)
|
resultTx = doBeginRedelegation(t, port, name1, pw, addr, operAddrs[0], operAddrs[1], rdTokens, fees)
|
||||||
|
require.Equal(t, uint32(0), resultTx.Code)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
require.Equal(t, uint32(0), resultTx.Code)
|
// query delegations, unbondings and redelegations from validator and delegator
|
||||||
|
delegatorDels = getDelegatorDelegations(t, port, addr)
|
||||||
|
require.Len(t, delegatorDels, 1)
|
||||||
|
require.Equal(t, operAddrs[1], delegatorDels[0].ValidatorAddress)
|
||||||
|
|
||||||
|
// TODO uncomment once all validators actually sign in the lcd tests
|
||||||
|
//validator2 := getValidator(t, port, operAddrs[1])
|
||||||
|
//delTokensAfterRedelegation := validator2.ShareTokens(delegatorDels[0].GetShares())
|
||||||
|
//require.Equal(t, rdTokens.ToDec(), delTokensAfterRedelegation)
|
||||||
|
|
||||||
// verify balance after paying fees
|
// verify balance after paying fees
|
||||||
acc = getAccount(t, port, addr)
|
acc = getAccount(t, port, addr)
|
||||||
|
@ -542,20 +553,6 @@ func TestBonding(t *testing.T) {
|
||||||
require.Len(t, txs, 1)
|
require.Len(t, txs, 1)
|
||||||
require.Equal(t, resultTx.Height, txs[0].Height)
|
require.Equal(t, resultTx.Height, txs[0].Height)
|
||||||
|
|
||||||
// query delegations, unbondings and redelegations from validator and delegator
|
|
||||||
delegatorDels = getDelegatorDelegations(t, port, addr)
|
|
||||||
require.Len(t, delegatorDels, 1)
|
|
||||||
require.Equal(t, operAddrs[1], delegatorDels[0].ValidatorAddress)
|
|
||||||
|
|
||||||
// because the second validator never signs during these tests, if this
|
|
||||||
// this test takes a long time to run, eventually this second validator
|
|
||||||
// will get slashed, meaning that it's exchange rate is no-longer 1-to-1,
|
|
||||||
// hence we utilize the exchange rate in the following test
|
|
||||||
|
|
||||||
validator2 := getValidator(t, port, operAddrs[1])
|
|
||||||
delTokensAfterRedelegation := validator2.ShareTokens(delegatorDels[0].GetShares())
|
|
||||||
require.Equal(t, rdTokens.ToDec(), delTokensAfterRedelegation)
|
|
||||||
|
|
||||||
redelegation := getRedelegations(t, port, addr, operAddrs[0], operAddrs[1])
|
redelegation := getRedelegations(t, port, addr, operAddrs[0], operAddrs[1])
|
||||||
require.Len(t, redelegation, 1)
|
require.Len(t, redelegation, 1)
|
||||||
require.Len(t, redelegation[0].Entries, 1)
|
require.Len(t, redelegation[0].Entries, 1)
|
||||||
|
@ -614,7 +611,9 @@ func TestSubmitProposal(t *testing.T) {
|
||||||
require.Equal(t, uint32(0), resultTx.Code)
|
require.Equal(t, uint32(0), resultTx.Code)
|
||||||
|
|
||||||
var proposalID uint64
|
var proposalID uint64
|
||||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.Data, &proposalID)
|
bz, err := hex.DecodeString(resultTx.Data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
|
||||||
|
|
||||||
// verify balance
|
// verify balance
|
||||||
acc = getAccount(t, port, addr)
|
acc = getAccount(t, port, addr)
|
||||||
|
@ -649,7 +648,9 @@ func TestDeposit(t *testing.T) {
|
||||||
require.Equal(t, uint32(0), resultTx.Code)
|
require.Equal(t, uint32(0), resultTx.Code)
|
||||||
|
|
||||||
var proposalID uint64
|
var proposalID uint64
|
||||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.Data, &proposalID)
|
bz, err := hex.DecodeString(resultTx.Data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
|
||||||
|
|
||||||
// verify balance
|
// verify balance
|
||||||
acc = getAccount(t, port, addr)
|
acc = getAccount(t, port, addr)
|
||||||
|
@ -680,7 +681,7 @@ func TestDeposit(t *testing.T) {
|
||||||
// query proposal
|
// query proposal
|
||||||
totalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(10))}
|
totalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(10))}
|
||||||
proposal = getProposal(t, port, proposalID)
|
proposal = getProposal(t, port, proposalID)
|
||||||
require.True(t, proposal.GetTotalDeposit().IsEqual(totalCoins))
|
require.True(t, proposal.TotalDeposit.IsEqual(totalCoins))
|
||||||
|
|
||||||
// query deposit
|
// query deposit
|
||||||
deposit := getDeposit(t, port, proposalID, addr)
|
deposit := getDeposit(t, port, proposalID, addr)
|
||||||
|
@ -706,7 +707,9 @@ func TestVote(t *testing.T) {
|
||||||
require.Equal(t, uint32(0), resultTx.Code)
|
require.Equal(t, uint32(0), resultTx.Code)
|
||||||
|
|
||||||
var proposalID uint64
|
var proposalID uint64
|
||||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.Data, &proposalID)
|
bz, err := hex.DecodeString(resultTx.Data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
|
||||||
|
|
||||||
// verify balance
|
// verify balance
|
||||||
acc = getAccount(t, port, addr)
|
acc = getAccount(t, port, addr)
|
||||||
|
@ -718,7 +721,7 @@ func TestVote(t *testing.T) {
|
||||||
// query proposal
|
// query proposal
|
||||||
proposal := getProposal(t, port, proposalID)
|
proposal := getProposal(t, port, proposalID)
|
||||||
require.Equal(t, "Test", proposal.GetTitle())
|
require.Equal(t, "Test", proposal.GetTitle())
|
||||||
require.Equal(t, gov.StatusVotingPeriod, proposal.GetStatus())
|
require.Equal(t, gov.StatusVotingPeriod, proposal.Status)
|
||||||
|
|
||||||
// vote
|
// vote
|
||||||
resultTx = doVote(t, port, seed, name1, pw, addr, proposalID, "Yes", fees)
|
resultTx = doVote(t, port, seed, name1, pw, addr, proposalID, "Yes", fees)
|
||||||
|
@ -787,6 +790,8 @@ func TestUnjail(t *testing.T) {
|
||||||
require.Equal(t, true, signingInfo.IndexOffset > 0)
|
require.Equal(t, true, signingInfo.IndexOffset > 0)
|
||||||
require.Equal(t, time.Unix(0, 0).UTC(), signingInfo.JailedUntil)
|
require.Equal(t, time.Unix(0, 0).UTC(), signingInfo.JailedUntil)
|
||||||
require.Equal(t, true, signingInfo.MissedBlocksCounter == 0)
|
require.Equal(t, true, signingInfo.MissedBlocksCounter == 0)
|
||||||
|
signingInfoList := getSigningInfoList(t, port)
|
||||||
|
require.NotZero(t, len(signingInfoList))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProposalsQuery(t *testing.T) {
|
func TestProposalsQuery(t *testing.T) {
|
||||||
|
@ -805,18 +810,24 @@ func TestProposalsQuery(t *testing.T) {
|
||||||
// Addr1 proposes (and deposits) proposals #1 and #2
|
// Addr1 proposes (and deposits) proposals #1 and #2
|
||||||
resultTx := doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit, fees)
|
resultTx := doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit, fees)
|
||||||
var proposalID1 uint64
|
var proposalID1 uint64
|
||||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.Data, &proposalID1)
|
bz, err := hex.DecodeString(resultTx.Data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID1)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
resultTx = doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit, fees)
|
resultTx = doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit, fees)
|
||||||
var proposalID2 uint64
|
var proposalID2 uint64
|
||||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.Data, &proposalID2)
|
bz, err = hex.DecodeString(resultTx.Data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID2)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// Addr2 proposes (and deposits) proposals #3
|
// Addr2 proposes (and deposits) proposals #3
|
||||||
resultTx = doSubmitProposal(t, port, seeds[1], names[1], passwords[1], addrs[1], halfMinDeposit, fees)
|
resultTx = doSubmitProposal(t, port, seeds[1], names[1], passwords[1], addrs[1], halfMinDeposit, fees)
|
||||||
var proposalID3 uint64
|
var proposalID3 uint64
|
||||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.Data, &proposalID3)
|
bz, err = hex.DecodeString(resultTx.Data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID3)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// Addr2 deposits on proposals #2 & #3
|
// Addr2 deposits on proposals #2 & #3
|
||||||
|
@ -855,13 +866,13 @@ func TestProposalsQuery(t *testing.T) {
|
||||||
// Only proposals #1 should be in Deposit Period
|
// Only proposals #1 should be in Deposit Period
|
||||||
proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod)
|
proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod)
|
||||||
require.Len(t, proposals, 1)
|
require.Len(t, proposals, 1)
|
||||||
require.Equal(t, proposalID1, proposals[0].GetProposalID())
|
require.Equal(t, proposalID1, proposals[0].ProposalID)
|
||||||
|
|
||||||
// Only proposals #2 and #3 should be in Voting Period
|
// Only proposals #2 and #3 should be in Voting Period
|
||||||
proposals = getProposalsFilterStatus(t, port, gov.StatusVotingPeriod)
|
proposals = getProposalsFilterStatus(t, port, gov.StatusVotingPeriod)
|
||||||
require.Len(t, proposals, 2)
|
require.Len(t, proposals, 2)
|
||||||
require.Equal(t, proposalID2, proposals[0].GetProposalID())
|
require.Equal(t, proposalID2, proposals[0].ProposalID)
|
||||||
require.Equal(t, proposalID3, proposals[1].GetProposalID())
|
require.Equal(t, proposalID3, proposals[1].ProposalID)
|
||||||
|
|
||||||
// Addr1 votes on proposals #2 & #3
|
// Addr1 votes on proposals #2 & #3
|
||||||
resultTx = doVote(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID2, "Yes", fees)
|
resultTx = doVote(t, port, seeds[0], names[0], passwords[0], addrs[0], proposalID2, "Yes", fees)
|
||||||
|
@ -875,31 +886,31 @@ func TestProposalsQuery(t *testing.T) {
|
||||||
|
|
||||||
// Test query all proposals
|
// Test query all proposals
|
||||||
proposals = getProposalsAll(t, port)
|
proposals = getProposalsAll(t, port)
|
||||||
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID1, (proposals[0]).ProposalID)
|
||||||
require.Equal(t, proposalID2, (proposals[1]).GetProposalID())
|
require.Equal(t, proposalID2, (proposals[1]).ProposalID)
|
||||||
require.Equal(t, proposalID3, (proposals[2]).GetProposalID())
|
require.Equal(t, proposalID3, (proposals[2]).ProposalID)
|
||||||
|
|
||||||
// Test query deposited by addr1
|
// Test query deposited by addr1
|
||||||
proposals = getProposalsFilterDepositor(t, port, addrs[0])
|
proposals = getProposalsFilterDepositor(t, port, addrs[0])
|
||||||
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID1, (proposals[0]).ProposalID)
|
||||||
|
|
||||||
// Test query deposited by addr2
|
// Test query deposited by addr2
|
||||||
proposals = getProposalsFilterDepositor(t, port, addrs[1])
|
proposals = getProposalsFilterDepositor(t, port, addrs[1])
|
||||||
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
|
||||||
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
|
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
|
||||||
|
|
||||||
// Test query voted by addr1
|
// Test query voted by addr1
|
||||||
proposals = getProposalsFilterVoter(t, port, addrs[0])
|
proposals = getProposalsFilterVoter(t, port, addrs[0])
|
||||||
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
|
||||||
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
|
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
|
||||||
|
|
||||||
// Test query voted by addr2
|
// Test query voted by addr2
|
||||||
proposals = getProposalsFilterVoter(t, port, addrs[1])
|
proposals = getProposalsFilterVoter(t, port, addrs[1])
|
||||||
require.Equal(t, proposalID3, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID3, (proposals[0]).ProposalID)
|
||||||
|
|
||||||
// Test query voted and deposited by addr1
|
// Test query voted and deposited by addr1
|
||||||
proposals = getProposalsFilterVoterDepositor(t, port, addrs[0], addrs[0])
|
proposals = getProposalsFilterVoterDepositor(t, port, addrs[0], addrs[0])
|
||||||
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
|
||||||
|
|
||||||
// Test query votes on Proposal 2
|
// Test query votes on Proposal 2
|
||||||
votes := getVotes(t, port, proposalID2)
|
votes := getVotes(t, port, proposalID2)
|
||||||
|
@ -1008,3 +1019,29 @@ func TestDistributionFlow(t *testing.T) {
|
||||||
resultTx = doWithdrawDelegatorAllRewards(t, port, seed, name1, pw, addr, fees)
|
resultTx = doWithdrawDelegatorAllRewards(t, port, seed, name1, pw, addr, fees)
|
||||||
require.Equal(t, uint32(0), resultTx.Code)
|
require.Equal(t, uint32(0), resultTx.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMintingQueries(t *testing.T) {
|
||||||
|
kb, err := keys.NewKeyBaseFromDir(InitClientHome(t, ""))
|
||||||
|
require.NoError(t, err)
|
||||||
|
addr, _ := CreateAddr(t, name1, pw, kb)
|
||||||
|
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
res, body := Request(t, port, "GET", "/minting/parameters", nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
var params mint.Params
|
||||||
|
require.NoError(t, cdc.UnmarshalJSON([]byte(body), ¶ms))
|
||||||
|
|
||||||
|
res, body = Request(t, port, "GET", "/minting/inflation", nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
var inflation sdk.Dec
|
||||||
|
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &inflation))
|
||||||
|
|
||||||
|
res, body = Request(t, port, "GET", "/minting/annual-provisions", nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
var annualProvisions sdk.Dec
|
||||||
|
require.NoError(t, cdc.UnmarshalJSON([]byte(body), &annualProvisions))
|
||||||
|
}
|
||||||
|
|
|
@ -52,61 +52,27 @@ func NewRestServer(cdc *codec.Codec) *RestServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the rest server
|
// Start starts the rest server
|
||||||
func (rs *RestServer) Start(listenAddr string, sslHosts string,
|
func (rs *RestServer) Start(listenAddr string, maxOpen int) (err error) {
|
||||||
certFile string, keyFile string, maxOpen int, secure bool) (err error) {
|
|
||||||
|
|
||||||
server.TrapSignal(func() {
|
server.TrapSignal(func() {
|
||||||
err := rs.listener.Close()
|
err := rs.listener.Close()
|
||||||
rs.log.Error("error closing listener", "err", err)
|
rs.log.Error("error closing listener", "err", err)
|
||||||
})
|
})
|
||||||
|
|
||||||
rs.listener, err = rpcserver.Listen(
|
cfg := rpcserver.DefaultConfig()
|
||||||
listenAddr,
|
cfg.MaxOpenConnections = maxOpen
|
||||||
rpcserver.Config{MaxOpenConnections: maxOpen},
|
|
||||||
)
|
rs.listener, err = rpcserver.Listen(listenAddr, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rs.log.Info(fmt.Sprintf("Starting Gaia Lite REST service (chain-id: %q)...",
|
rs.log.Info(
|
||||||
viper.GetString(client.FlagChainID)))
|
fmt.Sprintf(
|
||||||
|
"Starting Gaia Lite REST service (chain-id: %q)...",
|
||||||
// launch rest-server in insecure mode
|
viper.GetString(client.FlagChainID),
|
||||||
if !secure {
|
),
|
||||||
return rpcserver.StartHTTPServer(rs.listener, rs.Mux, rs.log)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle certificates
|
|
||||||
if certFile != "" {
|
|
||||||
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
|
|
||||||
if err := validateCertKeyFiles(certFile, keyFile); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
rs.log.Info(rs.fingerprint)
|
|
||||||
return rpcserver.StartHTTPAndTLSServer(
|
|
||||||
rs.listener,
|
|
||||||
rs.Mux,
|
|
||||||
certFile, keyFile,
|
|
||||||
rs.log,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return rpcserver.StartHTTPServer(rs.listener, rs.Mux, rs.log, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeCommand will start a Gaia Lite REST service as a blocking process. It
|
// ServeCommand will start a Gaia Lite REST service as a blocking process. It
|
||||||
|
@ -122,13 +88,8 @@ func ServeCommand(cdc *codec.Codec, registerRoutesFn func(*RestServer)) *cobra.C
|
||||||
registerRoutesFn(rs)
|
registerRoutesFn(rs)
|
||||||
|
|
||||||
// Start the rest server and return error if one exists
|
// Start the rest server and return error if one exists
|
||||||
err = rs.Start(
|
err = rs.Start(viper.GetString(client.FlagListenAddr),
|
||||||
viper.GetString(client.FlagListenAddr),
|
viper.GetInt(client.FlagMaxOpenConnections))
|
||||||
viper.GetString(client.FlagSSLHosts),
|
|
||||||
viper.GetString(client.FlagSSLCertFile),
|
|
||||||
viper.GetString(client.FlagSSLKeyFile),
|
|
||||||
viper.GetInt(client.FlagMaxOpenConnections),
|
|
||||||
viper.GetBool(client.FlagTLS))
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,7 +21,7 @@ tags:
|
||||||
description: Query app version
|
description: Query app version
|
||||||
schemes:
|
schemes:
|
||||||
- https
|
- https
|
||||||
host: fabo.interblock.io:1317
|
host: stargate.cosmos.network
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
kms:
|
kms:
|
||||||
type: basic
|
type: basic
|
||||||
|
@ -65,6 +65,17 @@ paths:
|
||||||
moniker:
|
moniker:
|
||||||
type: string
|
type: string
|
||||||
example: validator-name
|
example: validator-name
|
||||||
|
protocol_version:
|
||||||
|
properties:
|
||||||
|
p2p:
|
||||||
|
type: string
|
||||||
|
example: 7
|
||||||
|
block:
|
||||||
|
type: string
|
||||||
|
example: 10
|
||||||
|
app:
|
||||||
|
type: string
|
||||||
|
example: 0
|
||||||
network:
|
network:
|
||||||
type: string
|
type: string
|
||||||
example: gaia-2
|
example: gaia-2
|
||||||
|
@ -79,9 +90,14 @@ paths:
|
||||||
example: 0.15.0
|
example: 0.15.0
|
||||||
other:
|
other:
|
||||||
description: more information on versions
|
description: more information on versions
|
||||||
type: array
|
type: object
|
||||||
items:
|
properties:
|
||||||
type: string
|
tx_index:
|
||||||
|
type: string
|
||||||
|
example: on
|
||||||
|
rpc_address:
|
||||||
|
type: string
|
||||||
|
example: tcp://0.0.0.0:26657
|
||||||
500:
|
500:
|
||||||
description: Failed to query node status
|
description: Failed to query node status
|
||||||
/syncing:
|
/syncing:
|
||||||
|
@ -122,6 +138,7 @@ paths:
|
||||||
description: Block height
|
description: Block height
|
||||||
required: true
|
required: true
|
||||||
type: number
|
type: number
|
||||||
|
x-example: 1
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: The block at a specific height
|
description: The block at a specific height
|
||||||
|
@ -167,6 +184,7 @@ paths:
|
||||||
description: Block height
|
description: Block height
|
||||||
required: true
|
required: true
|
||||||
type: number
|
type: number
|
||||||
|
x-example: 1
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: The validator set at a specific block height
|
description: The validator set at a specific block height
|
||||||
|
@ -198,6 +216,7 @@ paths:
|
||||||
description: Tx hash
|
description: Tx hash
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: 88D6B85EAB87D43CDF50F39C22FC2237A37FEDC4CE723200AD0AF48CBEDBC317
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Tx with the provided hash
|
description: Tx with the provided hash
|
||||||
|
@ -219,14 +238,17 @@ paths:
|
||||||
type: string
|
type: string
|
||||||
description: "transaction tags such as 'action=submit-proposal' and 'proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc' which results in the following endpoint: 'GET /txs?action=submit-proposal&proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc'"
|
description: "transaction tags such as 'action=submit-proposal' and 'proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc' which results in the following endpoint: 'GET /txs?action=submit-proposal&proposer=cosmos1g9ahr6xhht5rmqven628nklxluzyv8z9jqjcmc'"
|
||||||
required: true
|
required: true
|
||||||
|
x-example: 'TODO'
|
||||||
- in: query
|
- in: query
|
||||||
name: page
|
name: page
|
||||||
description: Pagination page
|
description: Page number
|
||||||
type: integer
|
type: integer
|
||||||
|
x-example: 1
|
||||||
- in: query
|
- in: query
|
||||||
name: size
|
name: limit
|
||||||
description: Pagination size
|
description: Maximum number of items per page
|
||||||
type: integer
|
type: integer
|
||||||
|
x-example: 1
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: All txs matching the provided tags
|
description: All txs matching the provided tags
|
||||||
|
@ -250,14 +272,14 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- in: body
|
- in: body
|
||||||
name: txBroadcast
|
name: txBroadcast
|
||||||
description: The tx must be a signed StdTx. The supported return types includes `"block"`(return after tx commit), `"sync"`(return afer CheckTx) and `"async"`(return right away).
|
description: The tx must be a signed StdTx. The supported broadcast modes include `"block"`(return after tx commit), `"sync"`(return afer CheckTx) and `"async"`(return right away).
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
tx:
|
tx:
|
||||||
$ref: "#/definitions/StdTx"
|
$ref: "#/definitions/StdTx"
|
||||||
return:
|
mode:
|
||||||
type: string
|
type: string
|
||||||
example: block
|
example: block
|
||||||
responses:
|
responses:
|
||||||
|
@ -313,6 +335,7 @@ paths:
|
||||||
description: Account address in bech32 format
|
description: Account address in bech32 format
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos16gdxm24ht2mxtpz9cma6tr6a6d47x63hlq4pxt
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Account balances
|
description: Account balances
|
||||||
|
@ -339,6 +362,7 @@ paths:
|
||||||
description: Account address in bech32 format
|
description: Account address in bech32 format
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos16gdxm24ht2mxtpz9cma6tr6a6d47x63hlq4pxt
|
||||||
- in: body
|
- in: body
|
||||||
name: account
|
name: account
|
||||||
description: The sender and tx information
|
description: The sender and tx information
|
||||||
|
@ -374,6 +398,7 @@ paths:
|
||||||
description: Account address
|
description: Account address
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos16gdxm24ht2mxtpz9cma6tr6a6d47x63hlq4pxt
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Account information on the blockchain
|
description: Account information on the blockchain
|
||||||
|
@ -408,6 +433,7 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
get:
|
get:
|
||||||
summary: Get all delegations from a delegator
|
summary: Get all delegations from a delegator
|
||||||
tags:
|
tags:
|
||||||
|
@ -466,11 +492,13 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
- in: path
|
- in: path
|
||||||
name: validatorAddr
|
name: validatorAddr
|
||||||
description: Bech32 OperatorAddress of validator
|
description: Bech32 OperatorAddress of validator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Query the current delegation between a delegator and a validator
|
summary: Query the current delegation between a delegator and a validator
|
||||||
tags:
|
tags:
|
||||||
|
@ -493,6 +521,7 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
get:
|
get:
|
||||||
summary: Get all unbonding delegations from a delegator
|
summary: Get all unbonding delegations from a delegator
|
||||||
tags:
|
tags:
|
||||||
|
@ -552,11 +581,13 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
- in: path
|
- in: path
|
||||||
name: validatorAddr
|
name: validatorAddr
|
||||||
description: Bech32 OperatorAddress of validator
|
description: Bech32 OperatorAddress of validator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Query all unbonding delegations between a delegator and a validator
|
summary: Query all unbonding delegations between a delegator and a validator
|
||||||
tags:
|
tags:
|
||||||
|
@ -613,6 +644,7 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
post:
|
post:
|
||||||
summary: Submit a redelegation
|
summary: Submit a redelegation
|
||||||
parameters:
|
parameters:
|
||||||
|
@ -655,6 +687,7 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
get:
|
get:
|
||||||
summary: Query all validators that a delegator is bonded to
|
summary: Query all validators that a delegator is bonded to
|
||||||
tags:
|
tags:
|
||||||
|
@ -679,11 +712,13 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
- in: path
|
- in: path
|
||||||
name: validatorAddr
|
name: validatorAddr
|
||||||
description: Bech32 ValAddress of Delegator
|
description: Bech32 ValAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Query a validator that a delegator is bonded to
|
summary: Query a validator that a delegator is bonded to
|
||||||
tags:
|
tags:
|
||||||
|
@ -706,6 +741,7 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
get:
|
get:
|
||||||
summary: Get all staking txs (i.e msgs) from a delegator
|
summary: Get all staking txs (i.e msgs) from a delegator
|
||||||
tags:
|
tags:
|
||||||
|
@ -748,6 +784,7 @@ paths:
|
||||||
description: Bech32 OperatorAddress of validator
|
description: Bech32 OperatorAddress of validator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Query the information from a single validator
|
summary: Query the information from a single validator
|
||||||
tags:
|
tags:
|
||||||
|
@ -770,6 +807,7 @@ paths:
|
||||||
description: Bech32 OperatorAddress of validator
|
description: Bech32 OperatorAddress of validator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Get all delegations from a validator
|
summary: Get all delegations from a validator
|
||||||
tags:
|
tags:
|
||||||
|
@ -794,6 +832,7 @@ paths:
|
||||||
description: Bech32 OperatorAddress of validator
|
description: Bech32 OperatorAddress of validator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Get all unbonding delegations from a validator
|
summary: Get all unbonding delegations from a validator
|
||||||
tags:
|
tags:
|
||||||
|
@ -881,26 +920,52 @@ paths:
|
||||||
name: validatorPubKey
|
name: validatorPubKey
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: cosmosvalconspub1zcjduepq7mft6gfls57a0a42d7uhx656cckhfvtrlmw744jv4q0mvlv0dypskehfk8
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
type: object
|
$ref: "#/definitions/SigningInfo"
|
||||||
properties:
|
|
||||||
start_height:
|
|
||||||
type: string
|
|
||||||
index_offset:
|
|
||||||
type: string
|
|
||||||
jailed_until:
|
|
||||||
type: string
|
|
||||||
missed_blocks_counter:
|
|
||||||
type: string
|
|
||||||
204:
|
204:
|
||||||
description: No sign info of this validator
|
description: No sign info of this validator
|
||||||
400:
|
400:
|
||||||
description: Invalid validator public key
|
description: Invalid validator public key
|
||||||
500:
|
500:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
|
/slashing/signing_infos:
|
||||||
|
get:
|
||||||
|
summary: Get sign info of given all validators
|
||||||
|
description: Get sign info of all validators
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
tags:
|
||||||
|
- ICS23
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: page
|
||||||
|
description: Page number
|
||||||
|
type: integer
|
||||||
|
required: true
|
||||||
|
x-example: 1
|
||||||
|
- in: query
|
||||||
|
name: limit
|
||||||
|
description: Maximum number of items per page
|
||||||
|
type: integer
|
||||||
|
required: true
|
||||||
|
x-example: 5
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/SigningInfo"
|
||||||
|
204:
|
||||||
|
description: No validators with sign info
|
||||||
|
400:
|
||||||
|
description: Invalid validator public key for one of the validators
|
||||||
|
500:
|
||||||
|
description: Internal Server Error
|
||||||
/slashing/validators/{validatorAddr}/unjail:
|
/slashing/validators/{validatorAddr}/unjail:
|
||||||
post:
|
post:
|
||||||
summary: Unjail a jailed validator
|
summary: Unjail a jailed validator
|
||||||
|
@ -917,6 +982,7 @@ paths:
|
||||||
name: validatorAddr
|
name: validatorAddr
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
- description: ""
|
- description: ""
|
||||||
name: UnjailBody
|
name: UnjailBody
|
||||||
in: body
|
in: body
|
||||||
|
@ -1053,6 +1119,7 @@ paths:
|
||||||
name: proposalId
|
name: proposalId
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: '1'
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -1075,6 +1142,7 @@ paths:
|
||||||
name: proposalId
|
name: proposalId
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: '1'
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -1097,6 +1165,7 @@ paths:
|
||||||
name: proposalId
|
name: proposalId
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: '1'
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -1123,6 +1192,7 @@ paths:
|
||||||
name: proposalId
|
name: proposalId
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: '1'
|
||||||
- description: ""
|
- description: ""
|
||||||
name: post_deposit_body
|
name: post_deposit_body
|
||||||
in: body
|
in: body
|
||||||
|
@ -1163,11 +1233,13 @@ paths:
|
||||||
name: proposalId
|
name: proposalId
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: '1'
|
||||||
- type: string
|
- type: string
|
||||||
description: Bech32 depositor address
|
description: Bech32 depositor address
|
||||||
name: depositor
|
name: depositor
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: cosmos1xl6453f6q6dv5770c9ue6hspdc0vxfuqtudkhz
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -1193,6 +1265,7 @@ paths:
|
||||||
name: proposalId
|
name: proposalId
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: '1'
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -1219,6 +1292,7 @@ paths:
|
||||||
name: proposalId
|
name: proposalId
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: '1'
|
||||||
- description: valid value of `"option"` field can be `"yes"`, `"no"`, `"no_with_veto"` and `"abstain"`
|
- description: valid value of `"option"` field can be `"yes"`, `"no"`, `"no_with_veto"` and `"abstain"`
|
||||||
name: post_vote_body
|
name: post_vote_body
|
||||||
in: body
|
in: body
|
||||||
|
@ -1258,11 +1332,13 @@ paths:
|
||||||
name: proposalId
|
name: proposalId
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: '1'
|
||||||
- type: string
|
- type: string
|
||||||
description: Bech32 voter address
|
description: Bech32 voter address
|
||||||
name: voter
|
name: voter
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: cosmos1qwl879nx9t6kef4supyazayf7vjhennyjqwjgr
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -1288,6 +1364,7 @@ paths:
|
||||||
name: proposalId
|
name: proposalId
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
|
x-example: '1'
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -1381,6 +1458,7 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
get:
|
get:
|
||||||
summary: Get the total rewards balance from all delegations
|
summary: Get the total rewards balance from all delegations
|
||||||
description: Get the sum of all the rewards earned by delegations by a single delegator
|
description: Get the sum of all the rewards earned by delegations by a single delegator
|
||||||
|
@ -1433,11 +1511,13 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
- in: path
|
- in: path
|
||||||
name: validatorAddr
|
name: validatorAddr
|
||||||
description: Bech32 OperatorAddress of validator
|
description: Bech32 OperatorAddress of validator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Query a delegation reward
|
summary: Query a delegation reward
|
||||||
description: Query a single delegation reward by a delegator
|
description: Query a single delegation reward by a delegator
|
||||||
|
@ -1490,6 +1570,7 @@ paths:
|
||||||
description: Bech32 AccAddress of Delegator
|
description: Bech32 AccAddress of Delegator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
|
||||||
get:
|
get:
|
||||||
summary: Get the rewards withdrawal address
|
summary: Get the rewards withdrawal address
|
||||||
description: Get the delegations' rewards withdrawal address. This is the address in which the user will receive the reward funds
|
description: Get the delegations' rewards withdrawal address. This is the address in which the user will receive the reward funds
|
||||||
|
@ -1542,6 +1623,7 @@ paths:
|
||||||
description: Bech32 OperatorAddress of validator
|
description: Bech32 OperatorAddress of validator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Validator distribution information
|
summary: Validator distribution information
|
||||||
description: Query the distribution information of a single validator
|
description: Query the distribution information of a single validator
|
||||||
|
@ -1565,21 +1647,22 @@ paths:
|
||||||
description: Bech32 OperatorAddress of validator
|
description: Bech32 OperatorAddress of validator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Fee distribution outstanding rewards of a single validator
|
summary: Fee distribution outstanding rewards of a single validator
|
||||||
tags:
|
tags:
|
||||||
- ICS24
|
- ICS24
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/Coin"
|
$ref: "#/definitions/Coin"
|
||||||
500:
|
500:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
/distribution/validators/{validatorAddr}/rewards:
|
/distribution/validators/{validatorAddr}/rewards:
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
|
@ -1587,6 +1670,7 @@ paths:
|
||||||
description: Bech32 OperatorAddress of validator
|
description: Bech32 OperatorAddress of validator
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
|
||||||
get:
|
get:
|
||||||
summary: Commission and self-delegation rewards of a single validator
|
summary: Commission and self-delegation rewards of a single validator
|
||||||
description: Query the commission and self-delegation rewards of validator.
|
description: Query the commission and self-delegation rewards of validator.
|
||||||
|
@ -1632,6 +1716,22 @@ paths:
|
||||||
description: Key password is wrong
|
description: Key password is wrong
|
||||||
500:
|
500:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
|
/distribution/community_pool:
|
||||||
|
get:
|
||||||
|
summary: Community pool parameters
|
||||||
|
tags:
|
||||||
|
- ICS24
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/Coin"
|
||||||
|
500:
|
||||||
|
description: Internal Server Error
|
||||||
/distribution/parameters:
|
/distribution/parameters:
|
||||||
get:
|
get:
|
||||||
summary: Fee distribution parameters
|
summary: Fee distribution parameters
|
||||||
|
@ -1652,6 +1752,54 @@ paths:
|
||||||
type: string
|
type: string
|
||||||
500:
|
500:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
|
/minting/parameters:
|
||||||
|
get:
|
||||||
|
summary: Minting module parameters
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
mint_denom:
|
||||||
|
type: string
|
||||||
|
inflation_rate_change:
|
||||||
|
type: string
|
||||||
|
inflation_max:
|
||||||
|
type: string
|
||||||
|
inflation_min:
|
||||||
|
type: string
|
||||||
|
goal_bonded:
|
||||||
|
type: string
|
||||||
|
blocks_per_year:
|
||||||
|
type: integer
|
||||||
|
500:
|
||||||
|
description: Internal Server Error
|
||||||
|
/minting/inflation:
|
||||||
|
get:
|
||||||
|
summary: Current minting inflation value
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
500:
|
||||||
|
description: Internal Server Error
|
||||||
|
/minting/annual-provisions:
|
||||||
|
get:
|
||||||
|
summary: Current minting annual provisions value
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
500:
|
||||||
|
description: Internal Server Error
|
||||||
definitions:
|
definitions:
|
||||||
CheckTxResult:
|
CheckTxResult:
|
||||||
type: object
|
type: object
|
||||||
|
@ -1744,7 +1892,7 @@ definitions:
|
||||||
properties:
|
properties:
|
||||||
denom:
|
denom:
|
||||||
type: string
|
type: string
|
||||||
example: steak
|
example: stake
|
||||||
amount:
|
amount:
|
||||||
type: string
|
type: string
|
||||||
example: "50"
|
example: "50"
|
||||||
|
@ -1882,6 +2030,15 @@ definitions:
|
||||||
$ref: "#/definitions/Hash"
|
$ref: "#/definitions/Hash"
|
||||||
proposer_address:
|
proposer_address:
|
||||||
$ref: "#/definitions/Address"
|
$ref: "#/definitions/Address"
|
||||||
|
version:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
block:
|
||||||
|
type: string
|
||||||
|
example: 10
|
||||||
|
app:
|
||||||
|
type: string
|
||||||
|
example: 0
|
||||||
Block:
|
Block:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -1980,7 +2137,7 @@ definitions:
|
||||||
pub_key:
|
pub_key:
|
||||||
type: string
|
type: string
|
||||||
example: cosmosvalconspub1zcjduepq7sjfglw7ra4mjxpw4ph7dtdhdheh7nz8dfgl6t8u2n5szuuql9mqsrwquu
|
example: cosmosvalconspub1zcjduepq7sjfglw7ra4mjxpw4ph7dtdhdheh7nz8dfgl6t8u2n5szuuql9mqsrwquu
|
||||||
power:
|
voting_power:
|
||||||
type: string
|
type: string
|
||||||
example: "1000"
|
example: "1000"
|
||||||
proposer_priority:
|
proposer_priority:
|
||||||
|
@ -2165,3 +2322,14 @@ definitions:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/Coin"
|
$ref: "#/definitions/Coin"
|
||||||
|
SigningInfo:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
start_height:
|
||||||
|
type: string
|
||||||
|
index_offset:
|
||||||
|
type: string
|
||||||
|
jailed_until:
|
||||||
|
type: string
|
||||||
|
missed_blocks_counter:
|
||||||
|
type: string
|
||||||
|
|
|
@ -42,6 +42,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
||||||
gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
|
gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
|
||||||
|
mintrest "github.com/cosmos/cosmos-sdk/x/mint/client/rest"
|
||||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
slashingrest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
|
slashingrest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
|
||||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||||
|
@ -198,7 +199,7 @@ func InitClientHome(t *testing.T, dir string) string {
|
||||||
// TODO: Make InitializeTestLCD safe to call in multiple tests at the same time
|
// TODO: Make InitializeTestLCD safe to call in multiple tests at the same time
|
||||||
// InitializeTestLCD starts Tendermint and the LCD in process, listening on
|
// InitializeTestLCD starts Tendermint and the LCD in process, listening on
|
||||||
// their respective sockets where nValidators is the total number of validators
|
// their respective sockets where nValidators is the total number of validators
|
||||||
// and initAddrs are the accounts to initialize with some steak tokens. It
|
// and initAddrs are the accounts to initialize with some stake tokens. It
|
||||||
// returns a cleanup function, a set of validator public keys, and a port.
|
// returns a cleanup function, a set of validator public keys, and a port.
|
||||||
func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress, minting bool) (
|
func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress, minting bool) (
|
||||||
cleanup func(), valConsPubKeys []crypto.PubKey, valOperAddrs []sdk.ValAddress, port string) {
|
cleanup func(), valConsPubKeys []crypto.PubKey, valOperAddrs []sdk.ValAddress, port string) {
|
||||||
|
@ -220,14 +221,14 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
||||||
privVal.Reset()
|
privVal.Reset()
|
||||||
|
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
app := gapp.NewGaiaApp(logger, db, nil, true)
|
app := gapp.NewGaiaApp(logger, db, nil, true, false)
|
||||||
cdc = gapp.MakeCodec()
|
cdc = gapp.MakeCodec()
|
||||||
|
|
||||||
genesisFile := config.GenesisFile()
|
genesisFile := config.GenesisFile()
|
||||||
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
genDoc.Validators = nil
|
genDoc.Validators = nil
|
||||||
genDoc.SaveAs(genesisFile)
|
require.NoError(t, genDoc.SaveAs(genesisFile))
|
||||||
genTxs := []json.RawMessage{}
|
genTxs := []json.RawMessage{}
|
||||||
|
|
||||||
// append any additional (non-proposing) validators
|
// append any additional (non-proposing) validators
|
||||||
|
@ -299,6 +300,9 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
||||||
genesisState.MintData.Minter.Inflation = inflationMin
|
genesisState.MintData.Minter.Inflation = inflationMin
|
||||||
genesisState.MintData.Params.InflationMin = inflationMin
|
genesisState.MintData.Params.InflationMin = inflationMin
|
||||||
|
|
||||||
|
// initialize crisis data
|
||||||
|
genesisState.CrisisData.ConstantFee = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000)
|
||||||
|
|
||||||
// double check inflation is set according to the minting boolean flag
|
// double check inflation is set according to the minting boolean flag
|
||||||
if minting {
|
if minting {
|
||||||
require.Equal(t, sdk.MustNewDecFromStr("15000.0"),
|
require.Equal(t, sdk.MustNewDecFromStr("15000.0"),
|
||||||
|
@ -337,7 +341,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
||||||
|
|
||||||
cleanup = func() {
|
cleanup = func() {
|
||||||
logger.Debug("cleaning up LCD initialization")
|
logger.Debug("cleaning up LCD initialization")
|
||||||
node.Stop()
|
node.Stop() //nolint:errcheck
|
||||||
node.Wait()
|
node.Wait()
|
||||||
lcd.Close()
|
lcd.Close()
|
||||||
}
|
}
|
||||||
|
@ -390,11 +394,11 @@ func startTM(
|
||||||
func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing.T) (net.Listener, error) {
|
func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing.T) (net.Listener, error) {
|
||||||
rs := NewRestServer(cdc)
|
rs := NewRestServer(cdc)
|
||||||
registerRoutes(rs)
|
registerRoutes(rs)
|
||||||
listener, err := tmrpc.Listen(listenAddr, tmrpc.Config{})
|
listener, err := tmrpc.Listen(listenAddr, tmrpc.DefaultConfig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
go tmrpc.StartHTTPServer(listener, rs.Mux, logger)
|
go tmrpc.StartHTTPServer(listener, rs.Mux, logger, tmrpc.DefaultConfig()) //nolint:errcheck
|
||||||
return listener, nil
|
return listener, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,6 +412,7 @@ func registerRoutes(rs *RestServer) {
|
||||||
stakingrest.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)
|
slashingrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
govrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
govrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
|
mintrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request makes a test LCD test request. It returns a response object and a
|
// Request makes a test LCD test request. It returns a response object and a
|
||||||
|
@ -559,7 +564,7 @@ func getKeys(t *testing.T, port string) []keys.KeyOutput {
|
||||||
|
|
||||||
// POST /keys Create a new account locally
|
// POST /keys Create a new account locally
|
||||||
func doKeysPost(t *testing.T, port, name, password, mnemonic string, account int, index int) keys.KeyOutput {
|
func doKeysPost(t *testing.T, port, name, password, mnemonic string, account int, index int) keys.KeyOutput {
|
||||||
pk := clientkeys.AddNewKey{name, password, mnemonic, account, index}
|
pk := clientkeys.NewAddNewKey(name, password, mnemonic, account, index)
|
||||||
req, err := cdc.MarshalJSON(pk)
|
req, err := cdc.MarshalJSON(pk)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -585,7 +590,7 @@ func getKeysSeed(t *testing.T, port string) string {
|
||||||
|
|
||||||
// POST /keys/{name}/recove Recover a account from a seed
|
// POST /keys/{name}/recove Recover a account from a seed
|
||||||
func doRecoverKey(t *testing.T, port, recoverName, recoverPassword, mnemonic string, account uint32, index uint32) {
|
func doRecoverKey(t *testing.T, port, recoverName, recoverPassword, mnemonic string, account uint32, index uint32) {
|
||||||
pk := clientkeys.RecoverKey{recoverPassword, mnemonic, int(account), int(index)}
|
pk := clientkeys.NewRecoverKey(recoverPassword, mnemonic, int(account), int(index))
|
||||||
req, err := cdc.MarshalJSON(pk)
|
req, err := cdc.MarshalJSON(pk)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -613,7 +618,7 @@ func getKey(t *testing.T, port, name string) keys.KeyOutput {
|
||||||
|
|
||||||
// PUT /keys/{name} Update the password for this account in the KMS
|
// PUT /keys/{name} Update the password for this account in the KMS
|
||||||
func updateKey(t *testing.T, port, name, oldPassword, newPassword string, fail bool) {
|
func updateKey(t *testing.T, port, name, oldPassword, newPassword string, fail bool) {
|
||||||
kr := clientkeys.UpdateKeyReq{oldPassword, newPassword}
|
kr := clientkeys.NewUpdateKeyReq(oldPassword, newPassword)
|
||||||
req, err := cdc.MarshalJSON(kr)
|
req, err := cdc.MarshalJSON(kr)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
keyEndpoint := fmt.Sprintf("/keys/%s", name)
|
keyEndpoint := fmt.Sprintf("/keys/%s", name)
|
||||||
|
@ -627,7 +632,7 @@ func updateKey(t *testing.T, port, name, oldPassword, newPassword string, fail b
|
||||||
|
|
||||||
// DELETE /keys/{name} Remove an account
|
// DELETE /keys/{name} Remove an account
|
||||||
func deleteKey(t *testing.T, port, name, password string) {
|
func deleteKey(t *testing.T, port, name, password string) {
|
||||||
dk := clientkeys.DeleteKeyReq{password}
|
dk := clientkeys.NewDeleteKeyReq(password)
|
||||||
req, err := cdc.MarshalJSON(dk)
|
req, err := cdc.MarshalJSON(dk)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
keyEndpoint := fmt.Sprintf("/keys/%s", name)
|
keyEndpoint := fmt.Sprintf("/keys/%s", name)
|
||||||
|
@ -651,7 +656,7 @@ func getAccount(t *testing.T, port string, addr sdk.AccAddress) auth.Account {
|
||||||
|
|
||||||
// POST /tx/broadcast Send a signed Tx
|
// POST /tx/broadcast Send a signed Tx
|
||||||
func doBroadcast(t *testing.T, port string, tx auth.StdTx) (*http.Response, string) {
|
func doBroadcast(t *testing.T, port string, tx auth.StdTx) (*http.Response, string) {
|
||||||
txReq := clienttx.BroadcastReq{Tx: tx, Return: "block"}
|
txReq := clienttx.BroadcastReq{Tx: tx, Mode: "block"}
|
||||||
|
|
||||||
req, err := cdc.MarshalJSON(txReq)
|
req, err := cdc.MarshalJSON(txReq)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
@ -668,7 +673,7 @@ func doTransfer(
|
||||||
resp, body, recvAddr := doTransferWithGas(
|
resp, body, recvAddr := doTransferWithGas(
|
||||||
t, port, seed, name, memo, pwd, addr, "", 1.0, false, true, fees,
|
t, port, seed, name, memo, pwd, addr, "", 1.0, false, true, fees,
|
||||||
)
|
)
|
||||||
require.Equal(t, http.StatusOK, resp.StatusCode, resp)
|
require.Equal(t, http.StatusOK, resp.StatusCode, body)
|
||||||
|
|
||||||
var txResp sdk.TxResponse
|
var txResp sdk.TxResponse
|
||||||
err := cdc.UnmarshalJSON([]byte(body), &txResp)
|
err := cdc.UnmarshalJSON([]byte(body), &txResp)
|
||||||
|
@ -815,11 +820,11 @@ func doDelegate(
|
||||||
from := acc.GetAddress().String()
|
from := acc.GetAddress().String()
|
||||||
|
|
||||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||||
msg := msgDelegationsInput{
|
msg := stakingrest.DelegateRequest{
|
||||||
BaseReq: baseReq,
|
BaseReq: baseReq,
|
||||||
DelegatorAddress: delAddr,
|
DelegatorAddress: delAddr,
|
||||||
ValidatorAddress: valAddr,
|
ValidatorAddress: valAddr,
|
||||||
Delegation: sdk.NewCoin(sdk.DefaultBondDenom, amount),
|
Amount: sdk.NewCoin(sdk.DefaultBondDenom, amount),
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := cdc.MarshalJSON(msg)
|
req, err := cdc.MarshalJSON(msg)
|
||||||
|
@ -839,13 +844,6 @@ func doDelegate(
|
||||||
return txResp
|
return txResp
|
||||||
}
|
}
|
||||||
|
|
||||||
type msgDelegationsInput struct {
|
|
||||||
BaseReq rest.BaseReq `json:"base_req"`
|
|
||||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"` // in bech32
|
|
||||||
ValidatorAddress sdk.ValAddress `json:"validator_address"` // in bech32
|
|
||||||
Delegation sdk.Coin `json:"delegation"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
|
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
|
||||||
func doUndelegate(
|
func doUndelegate(
|
||||||
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress,
|
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress,
|
||||||
|
@ -859,11 +857,11 @@ func doUndelegate(
|
||||||
from := acc.GetAddress().String()
|
from := acc.GetAddress().String()
|
||||||
|
|
||||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||||
msg := msgUndelegateInput{
|
msg := stakingrest.UndelegateRequest{
|
||||||
BaseReq: baseReq,
|
BaseReq: baseReq,
|
||||||
DelegatorAddress: delAddr,
|
DelegatorAddress: delAddr,
|
||||||
ValidatorAddress: valAddr,
|
ValidatorAddress: valAddr,
|
||||||
SharesAmount: amount.ToDec(),
|
Amount: sdk.NewCoin(sdk.DefaultBondDenom, amount),
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := cdc.MarshalJSON(msg)
|
req, err := cdc.MarshalJSON(msg)
|
||||||
|
@ -882,13 +880,6 @@ func doUndelegate(
|
||||||
return txResp
|
return txResp
|
||||||
}
|
}
|
||||||
|
|
||||||
type msgUndelegateInput struct {
|
|
||||||
BaseReq rest.BaseReq `json:"base_req"`
|
|
||||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"` // in bech32
|
|
||||||
ValidatorAddress sdk.ValAddress `json:"validator_address"` // in bech32
|
|
||||||
SharesAmount sdk.Dec `json:"shares"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
|
// POST /staking/delegators/{delegatorAddr}/delegations Submit delegation
|
||||||
func doBeginRedelegation(
|
func doBeginRedelegation(
|
||||||
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress, valSrcAddr,
|
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress, valSrcAddr,
|
||||||
|
@ -902,12 +893,12 @@ func doBeginRedelegation(
|
||||||
from := acc.GetAddress().String()
|
from := acc.GetAddress().String()
|
||||||
|
|
||||||
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
|
||||||
msg := stakingrest.MsgBeginRedelegateInput{
|
msg := stakingrest.RedelegateRequest{
|
||||||
BaseReq: baseReq,
|
BaseReq: baseReq,
|
||||||
DelegatorAddress: delAddr,
|
DelegatorAddress: delAddr,
|
||||||
ValidatorSrcAddress: valSrcAddr,
|
ValidatorSrcAddress: valSrcAddr,
|
||||||
ValidatorDstAddress: valDstAddr,
|
ValidatorDstAddress: valDstAddr,
|
||||||
SharesAmount: amount.ToDec(),
|
Amount: sdk.NewCoin(sdk.DefaultBondDenom, amount),
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := cdc.MarshalJSON(msg)
|
req, err := cdc.MarshalJSON(msg)
|
||||||
|
@ -926,14 +917,6 @@ func doBeginRedelegation(
|
||||||
return txResp
|
return txResp
|
||||||
}
|
}
|
||||||
|
|
||||||
type msgBeginRedelegateInput struct {
|
|
||||||
BaseReq rest.BaseReq `json:"base_req"`
|
|
||||||
DelegatorAddress sdk.AccAddress `json:"delegator_address"` // in bech32
|
|
||||||
ValidatorSrcAddress sdk.ValAddress `json:"validator_src_address"` // in bech32
|
|
||||||
ValidatorDstAddress sdk.ValAddress `json:"validator_dst_address"` // in bech32
|
|
||||||
SharesAmount sdk.Dec `json:"shares"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET /staking/delegators/{delegatorAddr}/delegations Get all delegations from a delegator
|
// GET /staking/delegators/{delegatorAddr}/delegations Get all delegations from a delegator
|
||||||
func getDelegatorDelegations(t *testing.T, port string, delegatorAddr sdk.AccAddress) []staking.Delegation {
|
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)
|
res, body := Request(t, port, "GET", fmt.Sprintf("/staking/delegators/%s/delegations", delegatorAddr), nil)
|
||||||
|
@ -1414,6 +1397,21 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.
|
||||||
return signingInfo
|
return signingInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// ICS 23 - SlashingList
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// GET /slashing/signing_infos Get sign info of all validators with pagination
|
||||||
|
func getSigningInfoList(t *testing.T, port string) []slashing.ValidatorSigningInfo {
|
||||||
|
res, body := Request(t, port, "GET", "/slashing/signing_infos?page=1&limit=1", nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
var signingInfo []slashing.ValidatorSigningInfo
|
||||||
|
err := cdc.UnmarshalJSON([]byte(body), &signingInfo)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
return signingInfo
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Test this functionality, it is not currently in any of the tests
|
// TODO: Test this functionality, it is not currently in any of the tests
|
||||||
// POST /slashing/validators/{validatorAddr}/unjail Unjail a jailed validator
|
// POST /slashing/validators/{validatorAddr}/unjail Unjail a jailed validator
|
||||||
func doUnjail(
|
func doUnjail(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package rest
|
package rest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
@ -67,6 +68,8 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec,
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write(output)
|
if _, err := w.Write(output); err != nil {
|
||||||
|
log.Printf("could not write response: %v", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,20 +115,19 @@ func BlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
height, err := strconv.ParseInt(vars["height"], 10, 64)
|
height, err := strconv.ParseInt(vars["height"], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
rest.WriteErrorResponse(w, http.StatusBadRequest,
|
||||||
w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/block/{height}'."))
|
"ERROR: Couldn't parse block height. Assumed format is '/block/{height}'.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chainHeight, err := GetChainHeight(cliCtx)
|
chainHeight, err := GetChainHeight(cliCtx)
|
||||||
if height > chainHeight {
|
if height > chainHeight {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
rest.WriteErrorResponse(w, http.StatusNotFound,
|
||||||
w.Write([]byte("ERROR: Requested block height is bigger then the chain length."))
|
"ERROR: Requested block height is bigger then the chain length.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
output, err := getBlock(cliCtx, &height)
|
output, err := getBlock(cliCtx, &height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
||||||
|
@ -140,14 +139,12 @@ func LatestBlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
height, err := GetChainHeight(cliCtx)
|
height, err := GetChainHeight(cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
output, err := getBlock(cliCtx, &height)
|
output, err := getBlock(cliCtx, &height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
@ -26,7 +27,9 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||||
// cli version REST handler endpoint
|
// cli version REST handler endpoint
|
||||||
func CLIVersionRequestHandler(w http.ResponseWriter, r *http.Request) {
|
func CLIVersionRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(fmt.Sprintf("{\"version\": \"%s\"}", version.Version)))
|
if _, err := w.Write([]byte(fmt.Sprintf("{\"version\": \"%s\"}", version.Version))); err != nil {
|
||||||
|
log.Printf("could not write response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// connected node version REST handler endpoint
|
// connected node version REST handler endpoint
|
||||||
|
@ -39,6 +42,8 @@ func NodeVersionRequestHandler(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write(version)
|
if _, err := w.Write(version); err != nil {
|
||||||
|
log.Printf("could not write response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
@ -71,8 +72,7 @@ func NodeInfoRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
status, err := getNodeStatus(cliCtx)
|
status, err := getNodeStatus(cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,18 +86,18 @@ func NodeSyncingRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
status, err := getNodeStatus(cliCtx)
|
status, err := getNodeStatus(cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
syncing := status.SyncInfo.CatchingUp
|
syncing := status.SyncInfo.CatchingUp
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write([]byte(strconv.FormatBool(syncing)))
|
if _, err := w.Write([]byte(strconv.FormatBool(syncing))); err != nil {
|
||||||
|
log.Printf("could not write response: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ func ValidatorCommand(cdc *codec.Codec) *cobra.Command {
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
|
||||||
result, err := getValidators(cliCtx, height)
|
result, err := GetValidators(cliCtx, height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getValidators(cliCtx context.CLIContext, height *int64) (ResultValidatorsOutput, error) {
|
func GetValidators(cliCtx context.CLIContext, height *int64) (ResultValidatorsOutput, error) {
|
||||||
// get the node
|
// get the node
|
||||||
node, err := cliCtx.GetNode()
|
node, err := cliCtx.GetNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -160,22 +160,19 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
|
|
||||||
height, err := strconv.ParseInt(vars["height"], 10, 64)
|
height, err := strconv.ParseInt(vars["height"], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
rest.WriteErrorResponse(w, http.StatusBadRequest, "ERROR: Couldn't parse block height. Assumed format is '/validatorsets/{height}'.")
|
||||||
w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/validatorsets/{height}'."))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
chainHeight, err := GetChainHeight(cliCtx)
|
chainHeight, err := GetChainHeight(cliCtx)
|
||||||
if height > chainHeight {
|
if height > chainHeight {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
rest.WriteErrorResponse(w, http.StatusNotFound, "ERROR: Requested block height is bigger then the chain length.")
|
||||||
w.Write([]byte("ERROR: Requested block height is bigger then the chain length."))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := getValidators(cliCtx, &height)
|
output, err := GetValidators(cliCtx, &height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
||||||
|
@ -187,15 +184,13 @@ func LatestValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerF
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
height, err := GetChainHeight(cliCtx)
|
height, err := GetChainHeight(cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := getValidators(cliCtx, &height)
|
output, err := GetValidators(cliCtx, &height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)
|
||||||
|
|
|
@ -18,19 +18,10 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// Returns with the response from CheckTx.
|
|
||||||
flagSync = "sync"
|
|
||||||
// Returns right away, with no response
|
|
||||||
flagAsync = "async"
|
|
||||||
// Only returns error if mempool.BroadcastTx errs (ie. problem with the app) or if we timeout waiting for tx to commit.
|
|
||||||
flagBlock = "block"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BroadcastReq defines a tx broadcasting request.
|
// BroadcastReq defines a tx broadcasting request.
|
||||||
type BroadcastReq struct {
|
type BroadcastReq struct {
|
||||||
Tx auth.StdTx `json:"tx"`
|
Tx auth.StdTx `json:"tx"`
|
||||||
Return string `json:"return"`
|
Mode string `json:"mode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BroadcastTxRequest implements a tx broadcasting handler that is responsible
|
// BroadcastTxRequest implements a tx broadcasting handler that is responsible
|
||||||
|
@ -58,23 +49,9 @@ func BroadcastTxRequest(cliCtx context.CLIContext, cdc *codec.Codec) http.Handle
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var res interface{}
|
cliCtx = cliCtx.WithBroadcastMode(req.Mode)
|
||||||
switch req.Return {
|
|
||||||
case flagBlock:
|
|
||||||
res, err = cliCtx.BroadcastTx(txBytes)
|
|
||||||
|
|
||||||
case flagSync:
|
|
||||||
res, err = cliCtx.BroadcastTxSync(txBytes)
|
|
||||||
|
|
||||||
case flagAsync:
|
|
||||||
res, err = cliCtx.BroadcastTxAsync(txBytes)
|
|
||||||
|
|
||||||
default:
|
|
||||||
rest.WriteErrorResponse(w, http.StatusInternalServerError,
|
|
||||||
"unsupported return type. supported types: block, sync, async")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
res, err := cliCtx.BroadcastTx(txBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
|
@ -110,7 +87,7 @@ $ gaiacli tx broadcast ./mytxn.json
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := cliCtx.BroadcastTx(txBytes)
|
res, err := cliCtx.BroadcastTx(txBytes)
|
||||||
cliCtx.PrintOutput(res)
|
cliCtx.PrintOutput(res) // nolint:errcheck
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ If you supply a dash (-) argument in place of an input filename, the command rea
|
||||||
txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes)
|
txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes)
|
||||||
|
|
||||||
response := txEncodeRespStr(txBytesBase64)
|
response := txEncodeRespStr(txBytesBase64)
|
||||||
cliCtx.PrintOutput(response)
|
cliCtx.PrintOutput(response) // nolint:errcheck
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
package tx
|
package tx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
@ -17,14 +16,100 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
flagTags = "tags"
|
||||||
|
flagPage = "page"
|
||||||
|
flagLimit = "limit"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// CLI
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// SearchTxCmd returns a command to search through tagged transactions.
|
||||||
|
func SearchTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "txs",
|
||||||
|
Short: "Search for paginated transactions that match a set of tags",
|
||||||
|
Long: strings.TrimSpace(`
|
||||||
|
Search for transactions that match the exact given tags where results are paginated.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
$ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>' --page 1 --limit 30
|
||||||
|
`),
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
tagsStr := viper.GetString(flagTags)
|
||||||
|
tagsStr = strings.Trim(tagsStr, "'")
|
||||||
|
|
||||||
|
var tags []string
|
||||||
|
if strings.Contains(tagsStr, "&") {
|
||||||
|
tags = strings.Split(tagsStr, "&")
|
||||||
|
} else {
|
||||||
|
tags = append(tags, tagsStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmTags []string
|
||||||
|
for _, tag := range tags {
|
||||||
|
if !strings.Contains(tag, ":") {
|
||||||
|
return fmt.Errorf("%s should be of the format <key>:<value>", tagsStr)
|
||||||
|
} else if strings.Count(tag, ":") > 1 {
|
||||||
|
return fmt.Errorf("%s should only contain one <key>:<value> pair", tagsStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
keyValue := strings.Split(tag, ":")
|
||||||
|
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, page, limit)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var output []byte
|
||||||
|
if cliCtx.Indent {
|
||||||
|
output, err = cdc.MarshalJSONIndent(txs, "", " ")
|
||||||
|
} else {
|
||||||
|
output, err = cdc.MarshalJSON(txs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(output))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||||
|
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(flagTags, "", "tag:value list of tags that must match")
|
||||||
|
cmd.Flags().Uint32(flagPage, rest.DefaultPage, "Query a specific page of paginated results")
|
||||||
|
cmd.Flags().Uint32(flagLimit, rest.DefaultLimit, "Query number of transactions results per page returned")
|
||||||
|
cmd.MarkFlagRequired(flagTags)
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
// QueryTxCmd implements the default command for a tx query.
|
// QueryTxCmd implements the default command for a tx query.
|
||||||
func QueryTxCmd(cdc *codec.Codec) *cobra.Command {
|
func QueryTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "tx [hash]",
|
Use: "tx [hash]",
|
||||||
Short: "Matches this txhash over all committed blocks",
|
Short: "Find a transaction by hash in a committed block.",
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
@ -46,76 +131,55 @@ func QueryTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
|
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)")
|
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))
|
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryTx(cdc *codec.Codec, cliCtx context.CLIContext, hashHexStr string) (out sdk.TxResponse, err error) {
|
// ----------------------------------------------------------------------------
|
||||||
hash, err := hex.DecodeString(hashHexStr)
|
|
||||||
if err != nil {
|
|
||||||
return out, err
|
|
||||||
}
|
|
||||||
|
|
||||||
node, err := cliCtx.GetNode()
|
|
||||||
if err != nil {
|
|
||||||
return out, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := node.Tx(hash, !cliCtx.TrustNode)
|
|
||||||
if err != nil {
|
|
||||||
return out, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cliCtx.TrustNode {
|
|
||||||
if err = ValidateTxResult(cliCtx, res); err != nil {
|
|
||||||
return out, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if out, err = formatTxResult(cdc, res); err != nil {
|
|
||||||
return out, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateTxResult performs transaction verification
|
|
||||||
func ValidateTxResult(cliCtx context.CLIContext, res *ctypes.ResultTx) error {
|
|
||||||
if !cliCtx.TrustNode {
|
|
||||||
check, err := cliCtx.Verify(res.Height)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = res.Proof.Validate(check.Header.DataHash)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatTxResult(cdc *codec.Codec, res *ctypes.ResultTx) (sdk.TxResponse, error) {
|
|
||||||
tx, err := parseTx(cdc, res.Tx)
|
|
||||||
if err != nil {
|
|
||||||
return sdk.TxResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return sdk.NewResponseResultTx(res, tx), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseTx(cdc *codec.Codec, txBytes []byte) (sdk.Tx, error) {
|
|
||||||
var tx auth.StdTx
|
|
||||||
|
|
||||||
err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tx, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// REST
|
// REST
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// QueryTxRequestHandlerFn transaction query REST handler
|
// QueryTxsByTagsRequestHandlerFn implements a REST handler that searches for
|
||||||
|
// transactions by tags.
|
||||||
|
func QueryTxsByTagsRequestHandlerFn(cliCtx context.CLIContext, cdc *codec.Codec) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var (
|
||||||
|
tags []string
|
||||||
|
txs []sdk.TxResponse
|
||||||
|
page, limit int
|
||||||
|
)
|
||||||
|
|
||||||
|
err := r.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusBadRequest,
|
||||||
|
sdk.AppendMsgToErr("could not parse query parameters", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.Form) == 0 {
|
||||||
|
rest.PostProcessResponse(w, cdc, txs, cliCtx.Indent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, page, limit, err = rest.ParseHTTPArgs(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
txs, err = SearchTxs(cliCtx, cdc, tags, page, limit)
|
||||||
|
if err != nil {
|
||||||
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rest.PostProcessResponse(w, cdc, txs, cliCtx.Indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryTxRequestHandlerFn implements a REST handler that queries a transaction
|
||||||
|
// by hash in a committed block.
|
||||||
func QueryTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
func QueryTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
// register REST routes
|
// register REST routes
|
||||||
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec) {
|
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec) {
|
||||||
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, cliCtx)).Methods("GET")
|
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, cliCtx)).Methods("GET")
|
||||||
r.HandleFunc("/txs", SearchTxRequestHandlerFn(cliCtx, cdc)).Methods("GET")
|
r.HandleFunc("/txs", QueryTxsByTagsRequestHandlerFn(cliCtx, cdc)).Methods("GET")
|
||||||
r.HandleFunc("/txs", BroadcastTxRequest(cliCtx, cdc)).Methods("POST")
|
r.HandleFunc("/txs", BroadcastTxRequest(cliCtx, cdc)).Methods("POST")
|
||||||
r.HandleFunc("/txs/encode", EncodeTxRequestHandlerFn(cdc, cliCtx)).Methods("POST")
|
r.HandleFunc("/txs/encode", EncodeTxRequestHandlerFn(cdc, cliCtx)).Methods("POST")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,250 +0,0 @@
|
||||||
package tx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
|
||||||
"github.com/tendermint/tendermint/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
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
|
|
||||||
func SearchTxCmd(cdc *codec.Codec) *cobra.Command {
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "txs",
|
|
||||||
Short: "Search for all transactions that match the given tags.",
|
|
||||||
Long: strings.TrimSpace(`
|
|
||||||
Search for transactions that match exactly the given tags. For example:
|
|
||||||
|
|
||||||
$ gaiacli query txs --tags '<tag1>:<value1>&<tag2>:<value2>' --page 1 --limit 30
|
|
||||||
`),
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
tagsStr := viper.GetString(flagTags)
|
|
||||||
tagsStr = strings.Trim(tagsStr, "'")
|
|
||||||
var tags []string
|
|
||||||
if strings.Contains(tagsStr, "&") {
|
|
||||||
tags = strings.Split(tagsStr, "&")
|
|
||||||
} else {
|
|
||||||
tags = append(tags, tagsStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
var tmTags []string
|
|
||||||
for _, tag := range tags {
|
|
||||||
if !strings.Contains(tag, ":") {
|
|
||||||
return fmt.Errorf("%s should be of the format <key>:<value>", tagsStr)
|
|
||||||
} else if strings.Count(tag, ":") > 1 {
|
|
||||||
return fmt.Errorf("%s should only contain one <key>:<value> pair", tagsStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyValue := strings.Split(tag, ":")
|
|
||||||
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, page, limit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var output []byte
|
|
||||||
if cliCtx.Indent {
|
|
||||||
output, err = cdc.MarshalJSONIndent(txs, "", " ")
|
|
||||||
} else {
|
|
||||||
output, err = cdc.MarshalJSON(txs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(string(output))
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
|
||||||
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(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, page, limit int) ([]sdk.TxResponse, 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 ")
|
|
||||||
|
|
||||||
// get the node
|
|
||||||
node, err := cliCtx.GetNode()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
prove := !cliCtx.TrustNode
|
|
||||||
|
|
||||||
res, err := node.TxSearch(query, prove, page, limit)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if prove {
|
|
||||||
for _, tx := range res.Txs {
|
|
||||||
err := ValidateTxResult(cliCtx, tx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := FormatTxResults(cdc, res.Txs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the indexed txs into an array of Info
|
|
||||||
func FormatTxResults(cdc *codec.Codec, res []*ctypes.ResultTx) ([]sdk.TxResponse, error) {
|
|
||||||
var err error
|
|
||||||
out := make([]sdk.TxResponse, len(res))
|
|
||||||
for i := range res {
|
|
||||||
out[i], err = formatTxResult(cdc, res[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////
|
|
||||||
// REST
|
|
||||||
|
|
||||||
// Search Tx REST Handler
|
|
||||||
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 []sdk.TxResponse
|
|
||||||
err := r.ParseForm()
|
|
||||||
if err != nil {
|
|
||||||
rest.WriteErrorResponse(w, http.StatusBadRequest,
|
|
||||||
sdk.AppendMsgToErr("could not parse query parameters", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(r.Form) == 0 {
|
|
||||||
rest.PostProcessResponse(w, cdc, txs, cliCtx.Indent)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tags, page, limit, err = parseHTTPArgs(r)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
txs, err = SearchTxs(cliCtx, cdc, tags, page, limit)
|
|
||||||
if err != nil {
|
|
||||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rest.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
|
|
||||||
}
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
package tx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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, page, limit int) ([]sdk.TxResponse, 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 ")
|
||||||
|
|
||||||
|
node, err := cliCtx.GetNode()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
prove := !cliCtx.TrustNode
|
||||||
|
|
||||||
|
resTxs, err := node.TxSearch(query, prove, page, limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if prove {
|
||||||
|
for _, tx := range resTxs.Txs {
|
||||||
|
err := ValidateTxResult(cliCtx, tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resBlocks, err := getBlocksForTxResults(cliCtx, resTxs.Txs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
txs, err := formatTxResults(cdc, resTxs.Txs, resBlocks)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return txs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatTxResults parses the indexed txs into a slice of TxResponse objects.
|
||||||
|
func formatTxResults(cdc *codec.Codec, resTxs []*ctypes.ResultTx, resBlocks map[int64]*ctypes.ResultBlock) ([]sdk.TxResponse, error) {
|
||||||
|
var err error
|
||||||
|
out := make([]sdk.TxResponse, len(resTxs))
|
||||||
|
for i := range resTxs {
|
||||||
|
out[i], err = formatTxResult(cdc, resTxs[i], resBlocks[resTxs[i].Height])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateTxResult performs transaction verification.
|
||||||
|
func ValidateTxResult(cliCtx context.CLIContext, resTx *ctypes.ResultTx) error {
|
||||||
|
if !cliCtx.TrustNode {
|
||||||
|
check, err := cliCtx.Verify(resTx.Height)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = resTx.Proof.Validate(check.Header.DataHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBlocksForTxResults(cliCtx context.CLIContext, resTxs []*ctypes.ResultTx) (map[int64]*ctypes.ResultBlock, error) {
|
||||||
|
node, err := cliCtx.GetNode()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resBlocks := make(map[int64]*ctypes.ResultBlock)
|
||||||
|
|
||||||
|
for _, resTx := range resTxs {
|
||||||
|
if _, ok := resBlocks[resTx.Height]; !ok {
|
||||||
|
resBlock, err := node.Block(&resTx.Height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resBlocks[resTx.Height] = resBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resBlocks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatTxResult(cdc *codec.Codec, resTx *ctypes.ResultTx, resBlock *ctypes.ResultBlock) (sdk.TxResponse, error) {
|
||||||
|
tx, err := parseTx(cdc, resTx.Tx)
|
||||||
|
if err != nil {
|
||||||
|
return sdk.TxResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sdk.NewResponseResultTx(resTx, tx, resBlock.Block.Time.Format(time.RFC3339)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTx(cdc *codec.Codec, txBytes []byte) (sdk.Tx, error) {
|
||||||
|
var tx auth.StdTx
|
||||||
|
|
||||||
|
err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryTx(cdc *codec.Codec, cliCtx context.CLIContext, hashHexStr string) (sdk.TxResponse, error) {
|
||||||
|
hash, err := hex.DecodeString(hashHexStr)
|
||||||
|
if err != nil {
|
||||||
|
return sdk.TxResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := cliCtx.GetNode()
|
||||||
|
if err != nil {
|
||||||
|
return sdk.TxResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resTx, err := node.Tx(hash, !cliCtx.TrustNode)
|
||||||
|
if err != nil {
|
||||||
|
return sdk.TxResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cliCtx.TrustNode {
|
||||||
|
if err = ValidateTxResult(cliCtx, resTx); err != nil {
|
||||||
|
return sdk.TxResponse{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resBlocks, err := getBlocksForTxResults(cliCtx, []*ctypes.ResultTx{resTx})
|
||||||
|
if err != nil {
|
||||||
|
return sdk.TxResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := formatTxResult(cdc, resTx, resBlocks[resTx.Height])
|
||||||
|
if err != nil {
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
|
||||||
|
@ -69,7 +71,17 @@ func CompleteAndBroadcastTxCLI(txBldr authtxb.TxBuilder, cliCtx context.CLIConte
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n\n", cliCtx.Codec.MustMarshalJSON(stdSignMsg))
|
var json []byte
|
||||||
|
if viper.GetBool(client.FlagIndentResponse) {
|
||||||
|
json, err = cliCtx.Codec.MarshalJSONIndent(stdSignMsg, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
json = cliCtx.Codec.MustMarshalJSON(stdSignMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n\n", json)
|
||||||
|
|
||||||
buf := client.BufferStdin()
|
buf := client.BufferStdin()
|
||||||
ok, err := client.GetConfirmation("confirm transaction before signing and broadcasting", buf)
|
ok, err := client.GetConfirmation("confirm transaction before signing and broadcasting", buf)
|
||||||
|
@ -92,8 +104,11 @@ func CompleteAndBroadcastTxCLI(txBldr authtxb.TxBuilder, cliCtx context.CLIConte
|
||||||
|
|
||||||
// broadcast to a Tendermint node
|
// broadcast to a Tendermint node
|
||||||
res, err := cliCtx.BroadcastTx(txBytes)
|
res, err := cliCtx.BroadcastTx(txBytes)
|
||||||
cliCtx.PrintOutput(res)
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cliCtx.PrintOutput(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnrichWithGas calculates the gas estimate that would be consumed by the
|
// EnrichWithGas calculates the gas estimate that would be consumed by the
|
||||||
|
@ -108,7 +123,9 @@ func EnrichWithGas(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []s
|
||||||
|
|
||||||
// CalculateGas simulates the execution of a transaction and returns
|
// CalculateGas simulates the execution of a transaction and returns
|
||||||
// both the estimate obtained by the query and the adjusted amount.
|
// both the estimate obtained by the query and the adjusted amount.
|
||||||
func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *amino.Codec, txBytes []byte, adjustment float64) (estimate, adjusted uint64, err error) {
|
func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error),
|
||||||
|
cdc *amino.Codec, txBytes []byte, adjustment float64) (estimate, adjusted uint64, err error) {
|
||||||
|
|
||||||
// run a simulation (via /app/simulate query) to
|
// run a simulation (via /app/simulate query) to
|
||||||
// estimate gas and update TxBuilder accordingly
|
// estimate gas and update TxBuilder accordingly
|
||||||
rawRes, err := queryFunc("/app/simulate", txBytes)
|
rawRes, err := queryFunc("/app/simulate", txBytes)
|
||||||
|
@ -149,15 +166,17 @@ func PrintUnsignedStdTx(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignStdTx appends a signature to a StdTx and returns a copy of a it. If appendSig
|
// SignStdTx appends a signature to a StdTx and returns a copy of it. If appendSig
|
||||||
// is false, it replaces the signatures already attached with the new signature.
|
// is false, it replaces the signatures already attached with the new signature.
|
||||||
// Don't perform online validation or lookups if offline is true.
|
// Don't perform online validation or lookups if offline is true.
|
||||||
func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, stdTx auth.StdTx, appendSig bool, offline bool) (auth.StdTx, error) {
|
func SignStdTx(
|
||||||
|
txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
|
||||||
|
stdTx auth.StdTx, appendSig bool, offline bool,
|
||||||
|
) (auth.StdTx, error) {
|
||||||
|
|
||||||
var signedStdTx auth.StdTx
|
var signedStdTx auth.StdTx
|
||||||
|
|
||||||
keybase := txBldr.Keybase()
|
info, err := txBldr.Keybase().Get(name)
|
||||||
|
|
||||||
info, err := keybase.Get(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return signedStdTx, err
|
return signedStdTx, err
|
||||||
}
|
}
|
||||||
|
@ -170,8 +189,7 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !offline {
|
if !offline {
|
||||||
txBldr, err = populateAccountFromState(
|
txBldr, err = populateAccountFromState(txBldr, cliCtx, sdk.AccAddress(addr))
|
||||||
txBldr, cliCtx, sdk.AccAddress(addr))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return signedStdTx, err
|
return signedStdTx, err
|
||||||
}
|
}
|
||||||
|
@ -229,25 +247,21 @@ func ReadStdTxFromFile(cdc *amino.Codec, filename string) (stdTx auth.StdTx, err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func populateAccountFromState(txBldr authtxb.TxBuilder, cliCtx context.CLIContext,
|
func populateAccountFromState(
|
||||||
addr sdk.AccAddress) (authtxb.TxBuilder, error) {
|
txBldr authtxb.TxBuilder, cliCtx context.CLIContext, addr sdk.AccAddress,
|
||||||
if txBldr.AccountNumber() == 0 {
|
) (authtxb.TxBuilder, error) {
|
||||||
accNum, err := cliCtx.GetAccountNumber(addr)
|
|
||||||
if err != nil {
|
accNum, err := cliCtx.GetAccountNumber(addr)
|
||||||
return txBldr, err
|
if err != nil {
|
||||||
}
|
return txBldr, err
|
||||||
txBldr = txBldr.WithAccountNumber(accNum)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if txBldr.Sequence() == 0 {
|
accSeq, err := cliCtx.GetAccountSequence(addr)
|
||||||
accSeq, err := cliCtx.GetAccountSequence(addr)
|
if err != nil {
|
||||||
if err != nil {
|
return txBldr, err
|
||||||
return txBldr, err
|
|
||||||
}
|
|
||||||
txBldr = txBldr.WithSequence(accSeq)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return txBldr, nil
|
return txBldr.WithAccountNumber(accNum).WithSequence(accSeq), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTxEncoder return tx encoder from global sdk configuration if ones is defined.
|
// GetTxEncoder return tx encoder from global sdk configuration if ones is defined.
|
||||||
|
|
|
@ -11,14 +11,12 @@ import (
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
|
|
||||||
// TODO: Remove once transfers are enabled.
|
|
||||||
gaiabank "github.com/cosmos/cosmos-sdk/cmd/gaia/app/x/bank"
|
|
||||||
|
|
||||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
|
@ -44,6 +42,8 @@ type GaiaApp struct {
|
||||||
*bam.BaseApp
|
*bam.BaseApp
|
||||||
cdc *codec.Codec
|
cdc *codec.Codec
|
||||||
|
|
||||||
|
assertInvariantsBlockly bool
|
||||||
|
|
||||||
// keys to access the substores
|
// keys to access the substores
|
||||||
keyMain *sdk.KVStoreKey
|
keyMain *sdk.KVStoreKey
|
||||||
keyAccount *sdk.KVStoreKey
|
keyAccount *sdk.KVStoreKey
|
||||||
|
@ -67,11 +67,14 @@ type GaiaApp struct {
|
||||||
mintKeeper mint.Keeper
|
mintKeeper mint.Keeper
|
||||||
distrKeeper distr.Keeper
|
distrKeeper distr.Keeper
|
||||||
govKeeper gov.Keeper
|
govKeeper gov.Keeper
|
||||||
|
crisisKeeper crisis.Keeper
|
||||||
paramsKeeper params.Keeper
|
paramsKeeper params.Keeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGaiaApp returns a reference to an initialized GaiaApp.
|
// NewGaiaApp returns a reference to an initialized GaiaApp.
|
||||||
func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
|
func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest, assertInvariantsBlockly bool,
|
||||||
|
baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
|
||||||
|
|
||||||
cdc := MakeCodec()
|
cdc := MakeCodec()
|
||||||
|
|
||||||
bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...)
|
bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...)
|
||||||
|
@ -143,6 +146,12 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
|
||||||
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakingKeeper,
|
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakingKeeper,
|
||||||
gov.DefaultCodespace,
|
gov.DefaultCodespace,
|
||||||
)
|
)
|
||||||
|
app.crisisKeeper = crisis.NewKeeper(
|
||||||
|
app.paramsKeeper.Subspace(crisis.DefaultParamspace),
|
||||||
|
app.distrKeeper,
|
||||||
|
app.bankKeeper,
|
||||||
|
app.feeCollectionKeeper,
|
||||||
|
)
|
||||||
|
|
||||||
// register the staking hooks
|
// register the staking hooks
|
||||||
// NOTE: The stakingKeeper above is passed by reference, so that it can be
|
// NOTE: The stakingKeeper above is passed by reference, so that it can be
|
||||||
|
@ -151,22 +160,27 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
|
||||||
NewStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()),
|
NewStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// register the crisis routes
|
||||||
|
bank.RegisterInvariants(&app.crisisKeeper, app.accountKeeper)
|
||||||
|
distr.RegisterInvariants(&app.crisisKeeper, app.distrKeeper, app.stakingKeeper)
|
||||||
|
staking.RegisterInvariants(&app.crisisKeeper, app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper)
|
||||||
|
|
||||||
// register message routes
|
// register message routes
|
||||||
//
|
|
||||||
// TODO: Use standard bank router once transfers are enabled.
|
|
||||||
app.Router().
|
app.Router().
|
||||||
AddRoute(bank.RouterKey, gaiabank.NewHandler(app.bankKeeper)).
|
AddRoute(bank.RouterKey, bank.NewHandler(app.bankKeeper)).
|
||||||
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)).
|
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)).
|
||||||
AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)).
|
AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)).
|
||||||
AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)).
|
AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)).
|
||||||
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper))
|
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper)).
|
||||||
|
AddRoute(crisis.RouterKey, crisis.NewHandler(app.crisisKeeper))
|
||||||
|
|
||||||
app.QueryRouter().
|
app.QueryRouter().
|
||||||
AddRoute(auth.QuerierRoute, auth.NewQuerier(app.accountKeeper)).
|
AddRoute(auth.QuerierRoute, auth.NewQuerier(app.accountKeeper)).
|
||||||
AddRoute(distr.QuerierRoute, distr.NewQuerier(app.distrKeeper)).
|
AddRoute(distr.QuerierRoute, distr.NewQuerier(app.distrKeeper)).
|
||||||
AddRoute(gov.QuerierRoute, gov.NewQuerier(app.govKeeper)).
|
AddRoute(gov.QuerierRoute, gov.NewQuerier(app.govKeeper)).
|
||||||
AddRoute(slashing.QuerierRoute, slashing.NewQuerier(app.slashingKeeper, app.cdc)).
|
AddRoute(slashing.QuerierRoute, slashing.NewQuerier(app.slashingKeeper, app.cdc)).
|
||||||
AddRoute(staking.QuerierRoute, staking.NewQuerier(app.stakingKeeper, app.cdc))
|
AddRoute(staking.QuerierRoute, staking.NewQuerier(app.stakingKeeper, app.cdc)).
|
||||||
|
AddRoute(mint.QuerierRoute, mint.NewQuerier(app.mintKeeper))
|
||||||
|
|
||||||
// initialize BaseApp
|
// initialize BaseApp
|
||||||
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint, app.keyDistr,
|
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint, app.keyDistr,
|
||||||
|
@ -197,6 +211,7 @@ func MakeCodec() *codec.Codec {
|
||||||
slashing.RegisterCodec(cdc)
|
slashing.RegisterCodec(cdc)
|
||||||
gov.RegisterCodec(cdc)
|
gov.RegisterCodec(cdc)
|
||||||
auth.RegisterCodec(cdc)
|
auth.RegisterCodec(cdc)
|
||||||
|
crisis.RegisterCodec(cdc)
|
||||||
sdk.RegisterCodec(cdc)
|
sdk.RegisterCodec(cdc)
|
||||||
codec.RegisterCrypto(cdc)
|
codec.RegisterCrypto(cdc)
|
||||||
return cdc
|
return cdc
|
||||||
|
@ -229,7 +244,9 @@ func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.R
|
||||||
validatorUpdates, endBlockerTags := staking.EndBlocker(ctx, app.stakingKeeper)
|
validatorUpdates, endBlockerTags := staking.EndBlocker(ctx, app.stakingKeeper)
|
||||||
tags = append(tags, endBlockerTags...)
|
tags = append(tags, endBlockerTags...)
|
||||||
|
|
||||||
app.assertRuntimeInvariants()
|
if app.assertInvariantsBlockly {
|
||||||
|
app.assertRuntimeInvariants()
|
||||||
|
}
|
||||||
|
|
||||||
return abci.ResponseEndBlock{
|
return abci.ResponseEndBlock{
|
||||||
ValidatorUpdates: validatorUpdates,
|
ValidatorUpdates: validatorUpdates,
|
||||||
|
@ -262,6 +279,7 @@ func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisSt
|
||||||
bank.InitGenesis(ctx, app.bankKeeper, genesisState.BankData)
|
bank.InitGenesis(ctx, app.bankKeeper, genesisState.BankData)
|
||||||
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakingData.Validators.ToSDKValidators())
|
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakingData.Validators.ToSDKValidators())
|
||||||
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
||||||
|
crisis.InitGenesis(ctx, app.crisisKeeper, genesisState.CrisisData)
|
||||||
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
|
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
|
||||||
|
|
||||||
// validate genesis state
|
// validate genesis state
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/tendermint/tendermint/libs/db"
|
"github.com/tendermint/tendermint/libs/db"
|
||||||
|
@ -35,6 +36,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
||||||
mint.DefaultGenesisState(),
|
mint.DefaultGenesisState(),
|
||||||
distr.DefaultGenesisState(),
|
distr.DefaultGenesisState(),
|
||||||
gov.DefaultGenesisState(),
|
gov.DefaultGenesisState(),
|
||||||
|
crisis.DefaultGenesisState(),
|
||||||
slashing.DefaultGenesisState(),
|
slashing.DefaultGenesisState(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,11 +55,11 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
||||||
|
|
||||||
func TestGaiadExport(t *testing.T) {
|
func TestGaiadExport(t *testing.T) {
|
||||||
db := db.NewMemDB()
|
db := db.NewMemDB()
|
||||||
gapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true)
|
gapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, false)
|
||||||
setGenesis(gapp)
|
setGenesis(gapp)
|
||||||
|
|
||||||
// Making a new app object with the db, so that initchain hasn't been called
|
// Making a new app object with the db, so that initchain hasn't been called
|
||||||
newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true)
|
newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, false)
|
||||||
_, _, err := newGapp.ExportAppStateAndValidators(false, []string{})
|
_, _, err := newGapp.ExportAppStateAndValidators(false, []string{})
|
||||||
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
|
@ -46,6 +47,7 @@ func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteLis
|
||||||
mint.ExportGenesis(ctx, app.mintKeeper),
|
mint.ExportGenesis(ctx, app.mintKeeper),
|
||||||
distr.ExportGenesis(ctx, app.distrKeeper),
|
distr.ExportGenesis(ctx, app.distrKeeper),
|
||||||
gov.ExportGenesis(ctx, app.govKeeper),
|
gov.ExportGenesis(ctx, app.govKeeper),
|
||||||
|
crisis.ExportGenesis(ctx, app.crisisKeeper),
|
||||||
slashing.ExportGenesis(ctx, app.slashingKeeper),
|
slashing.ExportGenesis(ctx, app.slashingKeeper),
|
||||||
)
|
)
|
||||||
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
|
@ -39,6 +40,7 @@ type GenesisState struct {
|
||||||
MintData mint.GenesisState `json:"mint"`
|
MintData mint.GenesisState `json:"mint"`
|
||||||
DistrData distr.GenesisState `json:"distr"`
|
DistrData distr.GenesisState `json:"distr"`
|
||||||
GovData gov.GenesisState `json:"gov"`
|
GovData gov.GenesisState `json:"gov"`
|
||||||
|
CrisisData crisis.GenesisState `json:"crisis"`
|
||||||
SlashingData slashing.GenesisState `json:"slashing"`
|
SlashingData slashing.GenesisState `json:"slashing"`
|
||||||
GenTxs []json.RawMessage `json:"gentxs"`
|
GenTxs []json.RawMessage `json:"gentxs"`
|
||||||
}
|
}
|
||||||
|
@ -46,7 +48,7 @@ type GenesisState struct {
|
||||||
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
|
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
|
||||||
bankData bank.GenesisState,
|
bankData bank.GenesisState,
|
||||||
stakingData staking.GenesisState, mintData mint.GenesisState,
|
stakingData staking.GenesisState, mintData mint.GenesisState,
|
||||||
distrData distr.GenesisState, govData gov.GenesisState,
|
distrData distr.GenesisState, govData gov.GenesisState, crisisData crisis.GenesisState,
|
||||||
slashingData slashing.GenesisState) GenesisState {
|
slashingData slashing.GenesisState) GenesisState {
|
||||||
|
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
|
@ -57,6 +59,7 @@ func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
|
||||||
MintData: mintData,
|
MintData: mintData,
|
||||||
DistrData: distrData,
|
DistrData: distrData,
|
||||||
GovData: govData,
|
GovData: govData,
|
||||||
|
CrisisData: crisisData,
|
||||||
SlashingData: slashingData,
|
SlashingData: slashingData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,6 +212,7 @@ func NewDefaultGenesisState() GenesisState {
|
||||||
MintData: mint.DefaultGenesisState(),
|
MintData: mint.DefaultGenesisState(),
|
||||||
DistrData: distr.DefaultGenesisState(),
|
DistrData: distr.DefaultGenesisState(),
|
||||||
GovData: gov.DefaultGenesisState(),
|
GovData: gov.DefaultGenesisState(),
|
||||||
|
CrisisData: crisis.DefaultGenesisState(),
|
||||||
SlashingData: slashing.DefaultGenesisState(),
|
SlashingData: slashing.DefaultGenesisState(),
|
||||||
GenTxs: nil,
|
GenTxs: nil,
|
||||||
}
|
}
|
||||||
|
@ -246,6 +250,9 @@ func GaiaValidateGenesisState(genesisState GenesisState) error {
|
||||||
if err := gov.ValidateGenesis(genesisState.GovData); err != nil {
|
if err := gov.ValidateGenesis(genesisState.GovData); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := crisis.ValidateGenesis(genesisState.CrisisData); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return slashing.ValidateGenesis(genesisState.SlashingData)
|
return slashing.ValidateGenesis(genesisState.SlashingData)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
|
||||||
msg := msgs[0].(staking.MsgCreateValidator)
|
msg := msgs[0].(staking.MsgCreateValidator)
|
||||||
|
|
||||||
acc := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddress))
|
acc := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddress))
|
||||||
acc.Coins = sdk.Coins{sdk.NewInt64Coin(defaultBondDenom, 150)}
|
acc.Coins = sdk.NewCoins(sdk.NewInt64Coin(defaultBondDenom, 150))
|
||||||
genAccs[i] = NewGenesisAccount(&acc)
|
genAccs[i] = NewGenesisAccount(&acc)
|
||||||
stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.Add(sdk.NewInt(150)) // increase the supply
|
stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.Add(sdk.NewInt(150)) // increase the supply
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ func TestToAccount(t *testing.T) {
|
||||||
priv := ed25519.GenPrivKey()
|
priv := ed25519.GenPrivKey()
|
||||||
addr := sdk.AccAddress(priv.PubKey().Address())
|
addr := sdk.AccAddress(priv.PubKey().Address())
|
||||||
authAcc := auth.NewBaseAccountWithAddress(addr)
|
authAcc := auth.NewBaseAccountWithAddress(addr)
|
||||||
authAcc.SetCoins(sdk.Coins{sdk.NewInt64Coin(defaultBondDenom, 150)})
|
authAcc.SetCoins(sdk.NewCoins(sdk.NewInt64Coin(defaultBondDenom, 150)))
|
||||||
genAcc := NewGenesisAccount(&authAcc)
|
genAcc := NewGenesisAccount(&authAcc)
|
||||||
acc := genAcc.ToAccount()
|
acc := genAcc.ToAccount()
|
||||||
require.IsType(t, &auth.BaseAccount{}, acc)
|
require.IsType(t, &auth.BaseAccount{}, acc)
|
||||||
|
|
|
@ -7,20 +7,8 @@ import (
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
|
|
||||||
distrsim "github.com/cosmos/cosmos-sdk/x/distribution/simulation"
|
|
||||||
stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (app *GaiaApp) runtimeInvariants() []sdk.Invariant {
|
|
||||||
return []sdk.Invariant{
|
|
||||||
banksim.NonnegativeBalanceInvariant(app.accountKeeper),
|
|
||||||
distrsim.NonNegativeOutstandingInvariant(app.distrKeeper),
|
|
||||||
stakingsim.SupplyInvariants(app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper),
|
|
||||||
stakingsim.NonNegativePowerInvariant(app.stakingKeeper),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (app *GaiaApp) assertRuntimeInvariants() {
|
func (app *GaiaApp) assertRuntimeInvariants() {
|
||||||
ctx := app.NewContext(false, abci.Header{Height: app.LastBlockHeight() + 1})
|
ctx := app.NewContext(false, abci.Header{Height: app.LastBlockHeight() + 1})
|
||||||
app.assertRuntimeInvariantsOnContext(ctx)
|
app.assertRuntimeInvariantsOnContext(ctx)
|
||||||
|
@ -28,10 +16,12 @@ func (app *GaiaApp) assertRuntimeInvariants() {
|
||||||
|
|
||||||
func (app *GaiaApp) assertRuntimeInvariantsOnContext(ctx sdk.Context) {
|
func (app *GaiaApp) assertRuntimeInvariantsOnContext(ctx sdk.Context) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
invariants := app.runtimeInvariants()
|
invarRoutes := app.crisisKeeper.Routes()
|
||||||
for _, inv := range invariants {
|
for _, ir := range invarRoutes {
|
||||||
if err := inv(ctx); err != nil {
|
if err := ir.Invar(ctx); err != nil {
|
||||||
panic(fmt.Errorf("invariant broken: %s", err))
|
panic(fmt.Errorf("invariant broken: %s\n"+
|
||||||
|
"\tCRITICAL please submit the following transaction:\n"+
|
||||||
|
"\t\t gaiacli tx crisis invariant-broken %v %v", err, ir.ModuleName, ir.Route))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end := time.Now()
|
end := time.Now()
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||||
|
@ -43,19 +43,30 @@ var (
|
||||||
blockSize int
|
blockSize int
|
||||||
enabled bool
|
enabled bool
|
||||||
verbose bool
|
verbose bool
|
||||||
|
lean bool
|
||||||
commit bool
|
commit bool
|
||||||
period int
|
period int
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&genesisFile, "SimulationGenesis", "", "Custom simulation genesis file")
|
flag.StringVar(&genesisFile, "SimulationGenesis", "", "custom simulation genesis file")
|
||||||
flag.Int64Var(&seed, "SimulationSeed", 42, "Simulation random seed")
|
flag.Int64Var(&seed, "SimulationSeed", 42, "simulation random seed")
|
||||||
flag.IntVar(&numBlocks, "SimulationNumBlocks", 500, "Number of blocks")
|
flag.IntVar(&numBlocks, "SimulationNumBlocks", 500, "number of blocks")
|
||||||
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "Operations per block")
|
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "operations per block")
|
||||||
flag.BoolVar(&enabled, "SimulationEnabled", false, "Enable the simulation")
|
flag.BoolVar(&enabled, "SimulationEnabled", false, "enable the simulation")
|
||||||
flag.BoolVar(&verbose, "SimulationVerbose", false, "Verbose log output")
|
flag.BoolVar(&verbose, "SimulationVerbose", false, "verbose log output")
|
||||||
flag.BoolVar(&commit, "SimulationCommit", false, "Have the simulation commit")
|
flag.BoolVar(&lean, "SimulationLean", false, "lean simulation log output")
|
||||||
flag.IntVar(&period, "SimulationPeriod", 1, "Run slow invariants only once every period assertions")
|
flag.BoolVar(&commit, "SimulationCommit", false, "have the simulation commit")
|
||||||
|
flag.IntVar(&period, "SimulationPeriod", 1, "run slow invariants only once every period assertions")
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function for populating input for SimulateFromSeed
|
||||||
|
func getSimulateFromSeedInput(tb testing.TB, app *GaiaApp) (
|
||||||
|
testing.TB, *baseapp.BaseApp, simulation.AppStateFn, int64,
|
||||||
|
simulation.WeightedOperations, sdk.Invariants, int, int, bool, bool) {
|
||||||
|
|
||||||
|
return tb, app.BaseApp, appStateFn, seed,
|
||||||
|
testAndRunTxs(app), invariants(app), numBlocks, blockSize, commit, lean
|
||||||
}
|
}
|
||||||
|
|
||||||
func appStateFromGenesisFileFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
|
func appStateFromGenesisFileFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
|
||||||
|
@ -92,7 +103,7 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
|
||||||
numInitiallyBonded = numAccs
|
numInitiallyBonded = numAccs
|
||||||
}
|
}
|
||||||
fmt.Printf("Selected randomly generated parameters for simulated genesis:\n"+
|
fmt.Printf("Selected randomly generated parameters for simulated genesis:\n"+
|
||||||
"\t{amount of steak per account: %v, initially bonded validators: %v}\n",
|
"\t{amount of stake per account: %v, initially bonded validators: %v}\n",
|
||||||
amount, numInitiallyBonded)
|
amount, numInitiallyBonded)
|
||||||
|
|
||||||
// randomly generate some genesis accounts
|
// randomly generate some genesis accounts
|
||||||
|
@ -265,8 +276,8 @@ func randIntBetween(r *rand.Rand, min, max int) int {
|
||||||
func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
|
func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
|
||||||
return []simulation.WeightedOperation{
|
return []simulation.WeightedOperation{
|
||||||
{5, authsim.SimulateDeductFee(app.accountKeeper, app.feeCollectionKeeper)},
|
{5, authsim.SimulateDeductFee(app.accountKeeper, app.feeCollectionKeeper)},
|
||||||
{100, banksim.SendMsg(app.accountKeeper, app.bankKeeper)},
|
{100, banksim.SimulateMsgSend(app.accountKeeper, app.bankKeeper)},
|
||||||
{10, banksim.SingleInputMsgMultiSend(app.accountKeeper, app.bankKeeper)},
|
{10, banksim.SimulateSingleInputMsgMultiSend(app.accountKeeper, app.bankKeeper)},
|
||||||
{50, distrsim.SimulateMsgSetWithdrawAddress(app.accountKeeper, app.distrKeeper)},
|
{50, distrsim.SimulateMsgSetWithdrawAddress(app.accountKeeper, app.distrKeeper)},
|
||||||
{50, distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper)},
|
{50, distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper)},
|
||||||
{50, distrsim.SimulateMsgWithdrawValidatorCommission(app.accountKeeper, app.distrKeeper)},
|
{50, distrsim.SimulateMsgWithdrawValidatorCommission(app.accountKeeper, app.distrKeeper)},
|
||||||
|
@ -283,12 +294,10 @@ func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
|
||||||
|
|
||||||
func invariants(app *GaiaApp) []sdk.Invariant {
|
func invariants(app *GaiaApp) []sdk.Invariant {
|
||||||
return []sdk.Invariant{
|
return []sdk.Invariant{
|
||||||
simulation.PeriodicInvariant(banksim.NonnegativeBalanceInvariant(app.accountKeeper), period, 0),
|
simulation.PeriodicInvariant(bank.NonnegativeBalanceInvariant(app.accountKeeper), period, 0),
|
||||||
simulation.PeriodicInvariant(govsim.AllInvariants(), period, 0),
|
simulation.PeriodicInvariant(distr.AllInvariants(app.distrKeeper, app.stakingKeeper), period, 0),
|
||||||
simulation.PeriodicInvariant(distrsim.AllInvariants(app.distrKeeper, app.stakingKeeper), period, 0),
|
simulation.PeriodicInvariant(staking.AllInvariants(app.stakingKeeper, app.feeCollectionKeeper,
|
||||||
simulation.PeriodicInvariant(stakingsim.AllInvariants(app.stakingKeeper, app.feeCollectionKeeper,
|
|
||||||
app.distrKeeper, app.accountKeeper), period, 0),
|
app.distrKeeper, app.accountKeeper), period, 0),
|
||||||
simulation.PeriodicInvariant(slashingsim.AllInvariants(), period, 0),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,18 +319,11 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {
|
||||||
db.Close()
|
db.Close()
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
}()
|
}()
|
||||||
app := NewGaiaApp(logger, db, nil, true)
|
app := NewGaiaApp(logger, db, nil, true, false)
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
// TODO parameterize numbers, save for a later PR
|
// TODO parameterize numbers, save for a later PR
|
||||||
_, err := simulation.SimulateFromSeed(
|
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(b, app))
|
||||||
b, app.BaseApp, appStateFn, seed,
|
|
||||||
testAndRunTxs(app),
|
|
||||||
invariants(app), // these shouldn't get ran
|
|
||||||
numBlocks,
|
|
||||||
blockSize,
|
|
||||||
commit,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
b.Fail()
|
b.Fail()
|
||||||
|
@ -352,18 +354,11 @@ func TestFullGaiaSimulation(t *testing.T) {
|
||||||
db.Close()
|
db.Close()
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
}()
|
}()
|
||||||
app := NewGaiaApp(logger, db, nil, true, fauxMerkleModeOpt)
|
app := NewGaiaApp(logger, db, nil, true, false, fauxMerkleModeOpt)
|
||||||
require.Equal(t, "GaiaApp", app.Name())
|
require.Equal(t, "GaiaApp", app.Name())
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
_, err := simulation.SimulateFromSeed(
|
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
|
||||||
t, app.BaseApp, appStateFn, seed,
|
|
||||||
testAndRunTxs(app),
|
|
||||||
invariants(app),
|
|
||||||
numBlocks,
|
|
||||||
blockSize,
|
|
||||||
commit,
|
|
||||||
)
|
|
||||||
if commit {
|
if commit {
|
||||||
// for memdb:
|
// for memdb:
|
||||||
// fmt.Println("Database Size", db.Stats()["database.size"])
|
// fmt.Println("Database Size", db.Stats()["database.size"])
|
||||||
|
@ -393,18 +388,12 @@ func TestGaiaImportExport(t *testing.T) {
|
||||||
db.Close()
|
db.Close()
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
}()
|
}()
|
||||||
app := NewGaiaApp(logger, db, nil, true, fauxMerkleModeOpt)
|
app := NewGaiaApp(logger, db, nil, true, false, fauxMerkleModeOpt)
|
||||||
require.Equal(t, "GaiaApp", app.Name())
|
require.Equal(t, "GaiaApp", app.Name())
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
_, err := simulation.SimulateFromSeed(
|
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
|
||||||
t, app.BaseApp, appStateFn, seed,
|
|
||||||
testAndRunTxs(app),
|
|
||||||
invariants(app),
|
|
||||||
numBlocks,
|
|
||||||
blockSize,
|
|
||||||
commit,
|
|
||||||
)
|
|
||||||
if commit {
|
if commit {
|
||||||
// for memdb:
|
// for memdb:
|
||||||
// fmt.Println("Database Size", db.Stats()["database.size"])
|
// fmt.Println("Database Size", db.Stats()["database.size"])
|
||||||
|
@ -426,7 +415,7 @@ func TestGaiaImportExport(t *testing.T) {
|
||||||
newDB.Close()
|
newDB.Close()
|
||||||
os.RemoveAll(newDir)
|
os.RemoveAll(newDir)
|
||||||
}()
|
}()
|
||||||
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, fauxMerkleModeOpt)
|
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, false, fauxMerkleModeOpt)
|
||||||
require.Equal(t, "GaiaApp", newApp.Name())
|
require.Equal(t, "GaiaApp", newApp.Name())
|
||||||
var genesisState GenesisState
|
var genesisState GenesisState
|
||||||
err = app.cdc.UnmarshalJSON(appState, &genesisState)
|
err = app.cdc.UnmarshalJSON(appState, &genesisState)
|
||||||
|
@ -446,7 +435,8 @@ func TestGaiaImportExport(t *testing.T) {
|
||||||
storeKeysPrefixes := []StoreKeysPrefixes{
|
storeKeysPrefixes := []StoreKeysPrefixes{
|
||||||
{app.keyMain, newApp.keyMain, [][]byte{}},
|
{app.keyMain, newApp.keyMain, [][]byte{}},
|
||||||
{app.keyAccount, newApp.keyAccount, [][]byte{}},
|
{app.keyAccount, newApp.keyAccount, [][]byte{}},
|
||||||
{app.keyStaking, newApp.keyStaking, [][]byte{staking.UnbondingQueueKey, staking.RedelegationQueueKey, staking.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.keySlashing, newApp.keySlashing, [][]byte{}},
|
||||||
{app.keyMint, newApp.keyMint, [][]byte{}},
|
{app.keyMint, newApp.keyMint, [][]byte{}},
|
||||||
{app.keyDistr, newApp.keyDistr, [][]byte{}},
|
{app.keyDistr, newApp.keyDistr, [][]byte{}},
|
||||||
|
@ -488,18 +478,12 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
|
||||||
db.Close()
|
db.Close()
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
}()
|
}()
|
||||||
app := NewGaiaApp(logger, db, nil, true, fauxMerkleModeOpt)
|
app := NewGaiaApp(logger, db, nil, true, false, fauxMerkleModeOpt)
|
||||||
require.Equal(t, "GaiaApp", app.Name())
|
require.Equal(t, "GaiaApp", app.Name())
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
stopEarly, err := simulation.SimulateFromSeed(
|
stopEarly, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
|
||||||
t, app.BaseApp, appStateFn, seed,
|
|
||||||
testAndRunTxs(app),
|
|
||||||
invariants(app),
|
|
||||||
numBlocks,
|
|
||||||
blockSize,
|
|
||||||
commit,
|
|
||||||
)
|
|
||||||
if commit {
|
if commit {
|
||||||
// for memdb:
|
// for memdb:
|
||||||
// fmt.Println("Database Size", db.Stats()["database.size"])
|
// fmt.Println("Database Size", db.Stats()["database.size"])
|
||||||
|
@ -530,21 +514,14 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
|
||||||
newDB.Close()
|
newDB.Close()
|
||||||
os.RemoveAll(newDir)
|
os.RemoveAll(newDir)
|
||||||
}()
|
}()
|
||||||
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, fauxMerkleModeOpt)
|
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, false, fauxMerkleModeOpt)
|
||||||
require.Equal(t, "GaiaApp", newApp.Name())
|
require.Equal(t, "GaiaApp", newApp.Name())
|
||||||
newApp.InitChain(abci.RequestInitChain{
|
newApp.InitChain(abci.RequestInitChain{
|
||||||
AppStateBytes: appState,
|
AppStateBytes: appState,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Run randomized simulation on imported app
|
// Run randomized simulation on imported app
|
||||||
_, err = simulation.SimulateFromSeed(
|
_, err = simulation.SimulateFromSeed(getSimulateFromSeedInput(t, newApp))
|
||||||
t, newApp.BaseApp, appStateFn, seed,
|
|
||||||
testAndRunTxs(newApp),
|
|
||||||
invariants(newApp),
|
|
||||||
numBlocks,
|
|
||||||
blockSize,
|
|
||||||
commit,
|
|
||||||
)
|
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -565,7 +542,7 @@ func TestAppStateDeterminism(t *testing.T) {
|
||||||
for j := 0; j < numTimesToRunPerSeed; j++ {
|
for j := 0; j < numTimesToRunPerSeed; j++ {
|
||||||
logger := log.NewNopLogger()
|
logger := log.NewNopLogger()
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
app := NewGaiaApp(logger, db, nil, true)
|
app := NewGaiaApp(logger, db, nil, true, false)
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
simulation.SimulateFromSeed(
|
simulation.SimulateFromSeed(
|
||||||
|
@ -575,6 +552,7 @@ func TestAppStateDeterminism(t *testing.T) {
|
||||||
50,
|
50,
|
||||||
100,
|
100,
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
appHash := app.LastCommitID().Hash
|
appHash := app.LastCommitID().Hash
|
||||||
appHashList[j] = appHash
|
appHashList[j] = appHash
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
// Package bank contains a forked version of the bank module. It only contains
|
|
||||||
// a modified message handler to support a very limited form of transfers during
|
|
||||||
// mainnet launch -- MsgMultiSend messages.
|
|
||||||
//
|
|
||||||
// NOTE: This fork should be removed entirely once transfers are enabled and
|
|
||||||
// the Gaia router should be reset to using the original bank module handler.
|
|
||||||
package bank
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
uatomDenom = "uatom"
|
|
||||||
atomsToUatoms = int64(1000000)
|
|
||||||
|
|
||||||
// BurnedCoinsAccAddr represents the burn account address used for
|
|
||||||
// MsgMultiSend message during the period for which transfers are disabled.
|
|
||||||
// Its Bech32 address is cosmos1x4p90uuy63fqzsheamn48vq88q3eusykf0a69v.
|
|
||||||
BurnedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("bankBurnedCoins")))
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewHandler returns a handler for "bank" type messages.
|
|
||||||
func NewHandler(k bank.Keeper) sdk.Handler {
|
|
||||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case bank.MsgSend:
|
|
||||||
return handleMsgSend(ctx, k, msg)
|
|
||||||
|
|
||||||
case bank.MsgMultiSend:
|
|
||||||
return handleMsgMultiSend(ctx, k, msg)
|
|
||||||
|
|
||||||
default:
|
|
||||||
errMsg := "Unrecognized bank Msg type: %s" + msg.Type()
|
|
||||||
return sdk.ErrUnknownRequest(errMsg).Result()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleMsgSend implements a MsgSend message handler. It operates no differently
|
|
||||||
// than the standard bank module MsgSend message handler in that it transfers
|
|
||||||
// an amount from one account to another under the condition of transfers being
|
|
||||||
// enabled.
|
|
||||||
func handleMsgSend(ctx sdk.Context, k bank.Keeper, msg bank.MsgSend) sdk.Result {
|
|
||||||
// No need to modify handleMsgSend as the forked module requires no changes,
|
|
||||||
// so we can just call the standard bank modules handleMsgSend since we know
|
|
||||||
// the message is of type MsgSend.
|
|
||||||
return bank.NewHandler(k)(ctx, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleMsgMultiSend implements a modified forked version of a MsgMultiSend
|
|
||||||
// message handler. If transfers are disabled, a modified version of MsgMultiSend
|
|
||||||
// is allowed where there must be a single input and only two outputs. The first
|
|
||||||
// of the two outputs must be to a specific burn address defined by
|
|
||||||
// burnedCoinsAccAddr. In addition, the output amounts must be of 9atom and
|
|
||||||
// 1uatom respectively.
|
|
||||||
func handleMsgMultiSend(ctx sdk.Context, k bank.Keeper, msg bank.MsgMultiSend) sdk.Result {
|
|
||||||
// NOTE: totalIn == totalOut should already have been checked
|
|
||||||
if !k.GetSendEnabled(ctx) {
|
|
||||||
if !validateMultiSendTransfersDisabled(msg) {
|
|
||||||
return bank.ErrSendDisabled(k.Codespace()).Result()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tags, err := k.InputOutputCoins(ctx, msg.Inputs, msg.Outputs)
|
|
||||||
if err != nil {
|
|
||||||
return err.Result()
|
|
||||||
}
|
|
||||||
|
|
||||||
return sdk.Result{
|
|
||||||
Tags: tags,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateMultiSendTransfersDisabled(msg bank.MsgMultiSend) bool {
|
|
||||||
nineAtoms := sdk.Coins{sdk.NewInt64Coin(uatomDenom, 9*atomsToUatoms)}
|
|
||||||
oneAtom := sdk.Coins{sdk.NewInt64Coin(uatomDenom, 1*atomsToUatoms)}
|
|
||||||
|
|
||||||
if len(msg.Inputs) != 1 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(msg.Outputs) != 2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !msg.Outputs[0].Address.Equals(BurnedCoinsAccAddr) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !msg.Outputs[0].Coins.IsEqual(nineAtoms) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !msg.Outputs[1].Coins.IsEqual(oneAtom) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
|
@ -1,216 +0,0 @@
|
||||||
package bank
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
|
||||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
"github.com/cosmos/cosmos-sdk/store"
|
|
||||||
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/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
addrs = []sdk.AccAddress{
|
|
||||||
sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()),
|
|
||||||
sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()),
|
|
||||||
sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()),
|
|
||||||
}
|
|
||||||
|
|
||||||
initAmt = sdk.NewInt(atomsToUatoms * 100)
|
|
||||||
)
|
|
||||||
|
|
||||||
type testInput struct {
|
|
||||||
ctx sdk.Context
|
|
||||||
accKeeper auth.AccountKeeper
|
|
||||||
bankKeeper bank.Keeper
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTestCodec() *codec.Codec {
|
|
||||||
cdc := codec.New()
|
|
||||||
|
|
||||||
bank.RegisterCodec(cdc)
|
|
||||||
auth.RegisterCodec(cdc)
|
|
||||||
sdk.RegisterCodec(cdc)
|
|
||||||
codec.RegisterCrypto(cdc)
|
|
||||||
|
|
||||||
return cdc
|
|
||||||
}
|
|
||||||
|
|
||||||
func createTestInput(t *testing.T) testInput {
|
|
||||||
keyAcc := sdk.NewKVStoreKey(auth.StoreKey)
|
|
||||||
keyParams := sdk.NewKVStoreKey(params.StoreKey)
|
|
||||||
tKeyParams := sdk.NewTransientStoreKey(params.TStoreKey)
|
|
||||||
|
|
||||||
cdc := newTestCodec()
|
|
||||||
db := dbm.NewMemDB()
|
|
||||||
ms := store.NewCommitMultiStore(db)
|
|
||||||
ctx := sdk.NewContext(ms, abci.Header{Time: time.Now().UTC()}, false, log.NewNopLogger())
|
|
||||||
|
|
||||||
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
|
|
||||||
ms.MountStoreWithDB(tKeyParams, sdk.StoreTypeTransient, db)
|
|
||||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
|
||||||
|
|
||||||
require.NoError(t, ms.LoadLatestVersion())
|
|
||||||
|
|
||||||
paramsKeeper := params.NewKeeper(cdc, keyParams, tKeyParams)
|
|
||||||
accKeeper := auth.NewAccountKeeper(
|
|
||||||
cdc,
|
|
||||||
keyAcc,
|
|
||||||
paramsKeeper.Subspace(auth.DefaultParamspace),
|
|
||||||
auth.ProtoBaseAccount,
|
|
||||||
)
|
|
||||||
|
|
||||||
bankKeeper := bank.NewBaseKeeper(
|
|
||||||
accKeeper,
|
|
||||||
paramsKeeper.Subspace(bank.DefaultParamspace),
|
|
||||||
bank.DefaultCodespace,
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, addr := range addrs {
|
|
||||||
_, _, err := bankKeeper.AddCoins(ctx, addr, sdk.Coins{sdk.NewCoin(uatomDenom, initAmt)})
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return testInput{ctx, accKeeper, bankKeeper}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHandlerMsgSendTransfersDisabled(t *testing.T) {
|
|
||||||
input := createTestInput(t)
|
|
||||||
input.bankKeeper.SetSendEnabled(input.ctx, false)
|
|
||||||
|
|
||||||
handler := NewHandler(input.bankKeeper)
|
|
||||||
amt := sdk.NewInt(atomsToUatoms * 5)
|
|
||||||
msg := bank.NewMsgSend(addrs[0], addrs[1], sdk.Coins{sdk.NewCoin(uatomDenom, amt)})
|
|
||||||
|
|
||||||
res := handler(input.ctx, msg)
|
|
||||||
require.False(t, res.IsOK(), "expected failed message execution: %v", res.Log)
|
|
||||||
|
|
||||||
from := input.accKeeper.GetAccount(input.ctx, addrs[0])
|
|
||||||
require.Equal(t, from.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, initAmt)})
|
|
||||||
|
|
||||||
to := input.accKeeper.GetAccount(input.ctx, addrs[1])
|
|
||||||
require.Equal(t, to.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, initAmt)})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHandlerMsgSendTransfersEnabled(t *testing.T) {
|
|
||||||
input := createTestInput(t)
|
|
||||||
input.bankKeeper.SetSendEnabled(input.ctx, true)
|
|
||||||
|
|
||||||
handler := NewHandler(input.bankKeeper)
|
|
||||||
amt := sdk.NewInt(atomsToUatoms * 5)
|
|
||||||
msg := bank.NewMsgSend(addrs[0], addrs[1], sdk.Coins{sdk.NewCoin(uatomDenom, amt)})
|
|
||||||
|
|
||||||
res := handler(input.ctx, msg)
|
|
||||||
require.True(t, res.IsOK(), "expected successful message execution: %v", res.Log)
|
|
||||||
|
|
||||||
from := input.accKeeper.GetAccount(input.ctx, addrs[0])
|
|
||||||
balance := initAmt.Sub(amt)
|
|
||||||
require.Equal(t, from.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, balance)})
|
|
||||||
|
|
||||||
to := input.accKeeper.GetAccount(input.ctx, addrs[1])
|
|
||||||
balance = initAmt.Add(amt)
|
|
||||||
require.Equal(t, to.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, balance)})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHandlerMsgMultiSendTransfersDisabledBurn(t *testing.T) {
|
|
||||||
input := createTestInput(t)
|
|
||||||
input.bankKeeper.SetSendEnabled(input.ctx, false)
|
|
||||||
|
|
||||||
handler := NewHandler(input.bankKeeper)
|
|
||||||
totalAmt := sdk.NewInt(10 * atomsToUatoms)
|
|
||||||
burnAmt := sdk.NewInt(9 * atomsToUatoms)
|
|
||||||
transAmt := sdk.NewInt(1 * atomsToUatoms)
|
|
||||||
msg := bank.NewMsgMultiSend(
|
|
||||||
[]bank.Input{
|
|
||||||
bank.NewInput(addrs[0], sdk.Coins{sdk.NewCoin(uatomDenom, totalAmt)}),
|
|
||||||
},
|
|
||||||
[]bank.Output{
|
|
||||||
bank.NewOutput(BurnedCoinsAccAddr, sdk.Coins{sdk.NewCoin(uatomDenom, burnAmt)}),
|
|
||||||
bank.NewOutput(addrs[1], sdk.Coins{sdk.NewCoin(uatomDenom, transAmt)}),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
res := handler(input.ctx, msg)
|
|
||||||
require.True(t, res.IsOK(), "expected successful message execution: %v", res.Log)
|
|
||||||
|
|
||||||
from := input.accKeeper.GetAccount(input.ctx, addrs[0])
|
|
||||||
balance := initAmt.Sub(totalAmt)
|
|
||||||
require.Equal(t, from.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, balance)})
|
|
||||||
|
|
||||||
to := input.accKeeper.GetAccount(input.ctx, addrs[1])
|
|
||||||
balance = initAmt.Add(transAmt)
|
|
||||||
require.Equal(t, to.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, balance)})
|
|
||||||
|
|
||||||
burn := input.accKeeper.GetAccount(input.ctx, BurnedCoinsAccAddr)
|
|
||||||
require.Equal(t, burn.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, burnAmt)})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHandlerMsgMultiSendTransfersDisabledInvalidBurn(t *testing.T) {
|
|
||||||
input := createTestInput(t)
|
|
||||||
input.bankKeeper.SetSendEnabled(input.ctx, false)
|
|
||||||
|
|
||||||
handler := NewHandler(input.bankKeeper)
|
|
||||||
totalAmt := sdk.NewInt(15 * atomsToUatoms)
|
|
||||||
burnAmt := sdk.NewInt(10 * atomsToUatoms)
|
|
||||||
transAmt := sdk.NewInt(5 * atomsToUatoms)
|
|
||||||
msg := bank.NewMsgMultiSend(
|
|
||||||
[]bank.Input{
|
|
||||||
bank.NewInput(addrs[0], sdk.Coins{sdk.NewCoin(uatomDenom, totalAmt)}),
|
|
||||||
},
|
|
||||||
[]bank.Output{
|
|
||||||
bank.NewOutput(BurnedCoinsAccAddr, sdk.Coins{sdk.NewCoin(uatomDenom, burnAmt)}),
|
|
||||||
bank.NewOutput(addrs[1], sdk.Coins{sdk.NewCoin(uatomDenom, transAmt)}),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
res := handler(input.ctx, msg)
|
|
||||||
require.False(t, res.IsOK(), "expected failed message execution: %v", res.Log)
|
|
||||||
|
|
||||||
from := input.accKeeper.GetAccount(input.ctx, addrs[0])
|
|
||||||
require.Equal(t, from.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, initAmt)})
|
|
||||||
|
|
||||||
to := input.accKeeper.GetAccount(input.ctx, addrs[1])
|
|
||||||
require.Equal(t, to.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, initAmt)})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHandlerMsgMultiSendTransfersEnabled(t *testing.T) {
|
|
||||||
input := createTestInput(t)
|
|
||||||
input.bankKeeper.SetSendEnabled(input.ctx, true)
|
|
||||||
|
|
||||||
handler := NewHandler(input.bankKeeper)
|
|
||||||
totalAmt := sdk.NewInt(10 * atomsToUatoms)
|
|
||||||
outAmt := sdk.NewInt(5 * atomsToUatoms)
|
|
||||||
msg := bank.NewMsgMultiSend(
|
|
||||||
[]bank.Input{
|
|
||||||
bank.NewInput(addrs[0], sdk.Coins{sdk.NewCoin(uatomDenom, totalAmt)}),
|
|
||||||
},
|
|
||||||
[]bank.Output{
|
|
||||||
bank.NewOutput(addrs[1], sdk.Coins{sdk.NewCoin(uatomDenom, outAmt)}),
|
|
||||||
bank.NewOutput(addrs[2], sdk.Coins{sdk.NewCoin(uatomDenom, outAmt)}),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
res := handler(input.ctx, msg)
|
|
||||||
require.True(t, res.IsOK(), "expected successful message execution: %v", res.Log)
|
|
||||||
|
|
||||||
from := input.accKeeper.GetAccount(input.ctx, addrs[0])
|
|
||||||
balance := initAmt.Sub(totalAmt)
|
|
||||||
require.Equal(t, from.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, balance)})
|
|
||||||
|
|
||||||
out1 := input.accKeeper.GetAccount(input.ctx, addrs[1])
|
|
||||||
balance = initAmt.Add(outAmt)
|
|
||||||
require.Equal(t, out1.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, balance)})
|
|
||||||
|
|
||||||
out2 := input.accKeeper.GetAccount(input.ctx, addrs[2])
|
|
||||||
balance = initAmt.Add(outAmt)
|
|
||||||
require.Equal(t, out2.GetCoins(), sdk.Coins{sdk.NewCoin(uatomDenom, balance)})
|
|
||||||
}
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build cli_test
|
||||||
|
|
||||||
package clitest
|
package clitest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -361,7 +363,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
||||||
require.Equal(t, sendTokens, barAcc.GetCoins().AmountOf(denom))
|
require.Equal(t, sendTokens, barAcc.GetCoins().AmountOf(denom))
|
||||||
|
|
||||||
// Generate a create validator transaction and ensure correctness
|
// Generate a create validator transaction and ensure correctness
|
||||||
success, stdout, stderr := f.TxStakingCreateValidator(keyBar, consPubKey, sdk.NewInt64Coin(denom, 2), "--generate-only")
|
success, stdout, stderr := f.TxStakingCreateValidator(barAddr.String(), consPubKey, sdk.NewInt64Coin(denom, 2), "--generate-only")
|
||||||
|
|
||||||
require.True(f.T, success)
|
require.True(f.T, success)
|
||||||
require.Empty(f.T, stderr)
|
require.Empty(f.T, stderr)
|
||||||
|
@ -394,13 +396,13 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
||||||
require.NotZero(t, validatorDelegations[0].Shares)
|
require.NotZero(t, validatorDelegations[0].Shares)
|
||||||
|
|
||||||
// unbond a single share
|
// unbond a single share
|
||||||
unbondTokens := sdk.TokensFromTendermintPower(1)
|
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(1))
|
||||||
success = f.TxStakingUnbond(keyBar, unbondTokens.String(), barVal, "-y")
|
success = f.TxStakingUnbond(keyBar, unbondAmt.String(), barVal, "-y")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
tests.WaitForNextNBlocksTM(1, f.Port)
|
tests.WaitForNextNBlocksTM(1, f.Port)
|
||||||
|
|
||||||
// Ensure bonded staking is correct
|
// Ensure bonded staking is correct
|
||||||
remainingTokens := newValTokens.Sub(unbondTokens)
|
remainingTokens := newValTokens.Sub(unbondAmt.Amount)
|
||||||
validator = f.QueryStakingValidator(barVal)
|
validator = f.QueryStakingValidator(barVal)
|
||||||
require.Equal(t, remainingTokens, validator.Tokens)
|
require.Equal(t, remainingTokens, validator.Tokens)
|
||||||
|
|
||||||
|
@ -437,7 +439,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
// Test submit generate only for submit proposal
|
// Test submit generate only for submit proposal
|
||||||
proposalTokens := sdk.TokensFromTendermintPower(5)
|
proposalTokens := sdk.TokensFromTendermintPower(5)
|
||||||
success, stdout, stderr := f.TxGovSubmitProposal(
|
success, stdout, stderr := f.TxGovSubmitProposal(
|
||||||
keyFoo, "Text", "Test", "test", sdk.NewCoin(denom, proposalTokens), "--generate-only", "-y")
|
fooAddr.String(), "Text", "Test", "test", sdk.NewCoin(denom, proposalTokens), "--generate-only", "-y")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
msg := unmarshalStdTx(t, stdout)
|
msg := unmarshalStdTx(t, stdout)
|
||||||
|
@ -463,12 +465,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
|
|
||||||
// Ensure propsal is directly queryable
|
// Ensure propsal is directly queryable
|
||||||
proposal1 := f.QueryGovProposal(1)
|
proposal1 := f.QueryGovProposal(1)
|
||||||
require.Equal(t, uint64(1), proposal1.GetProposalID())
|
require.Equal(t, uint64(1), proposal1.ProposalID)
|
||||||
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
|
require.Equal(t, gov.StatusDepositPeriod, proposal1.Status)
|
||||||
|
|
||||||
// Ensure query proposals returns properly
|
// Ensure query proposals returns properly
|
||||||
proposalsQuery = f.QueryGovProposals()
|
proposalsQuery = f.QueryGovProposals()
|
||||||
require.Equal(t, uint64(1), proposalsQuery[0].GetProposalID())
|
require.Equal(t, uint64(1), proposalsQuery[0].ProposalID)
|
||||||
|
|
||||||
// Query the deposits on the proposal
|
// Query the deposits on the proposal
|
||||||
deposit := f.QueryGovDeposit(1, fooAddr)
|
deposit := f.QueryGovDeposit(1, fooAddr)
|
||||||
|
@ -476,7 +478,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
|
|
||||||
// Test deposit generate only
|
// Test deposit generate only
|
||||||
depositTokens := sdk.TokensFromTendermintPower(10)
|
depositTokens := sdk.TokensFromTendermintPower(10)
|
||||||
success, stdout, stderr = f.TxGovDeposit(1, keyFoo, sdk.NewCoin(denom, depositTokens), "--generate-only")
|
success, stdout, stderr = f.TxGovDeposit(1, fooAddr.String(), sdk.NewCoin(denom, depositTokens), "--generate-only")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
msg = unmarshalStdTx(t, stdout)
|
msg = unmarshalStdTx(t, stdout)
|
||||||
|
@ -507,11 +509,11 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
|
|
||||||
// Fetch the proposal and ensure it is now in the voting period
|
// Fetch the proposal and ensure it is now in the voting period
|
||||||
proposal1 = f.QueryGovProposal(1)
|
proposal1 = f.QueryGovProposal(1)
|
||||||
require.Equal(t, uint64(1), proposal1.GetProposalID())
|
require.Equal(t, uint64(1), proposal1.ProposalID)
|
||||||
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
|
require.Equal(t, gov.StatusVotingPeriod, proposal1.Status)
|
||||||
|
|
||||||
// Test vote generate only
|
// Test vote generate only
|
||||||
success, stdout, stderr = f.TxGovVote(1, gov.OptionYes, keyFoo, "--generate-only")
|
success, stdout, stderr = f.TxGovVote(1, gov.OptionYes, fooAddr.String(), "--generate-only")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
msg = unmarshalStdTx(t, stdout)
|
msg = unmarshalStdTx(t, stdout)
|
||||||
|
@ -544,7 +546,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
|
|
||||||
// Ensure the proposal returns as in the voting period
|
// Ensure the proposal returns as in the voting period
|
||||||
proposalsQuery = f.QueryGovProposals("--status=VotingPeriod")
|
proposalsQuery = f.QueryGovProposals("--status=VotingPeriod")
|
||||||
require.Equal(t, uint64(1), proposalsQuery[0].GetProposalID())
|
require.Equal(t, uint64(1), proposalsQuery[0].ProposalID)
|
||||||
|
|
||||||
// submit a second test proposal
|
// submit a second test proposal
|
||||||
f.TxGovSubmitProposal(keyFoo, "Text", "Apples", "test", sdk.NewCoin(denom, proposalTokens), "-y")
|
f.TxGovSubmitProposal(keyFoo, "Text", "Apples", "test", sdk.NewCoin(denom, proposalTokens), "-y")
|
||||||
|
@ -552,7 +554,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
|
|
||||||
// Test limit on proposals query
|
// Test limit on proposals query
|
||||||
proposalsQuery = f.QueryGovProposals("--limit=1")
|
proposalsQuery = f.QueryGovProposals("--limit=1")
|
||||||
require.Equal(t, uint64(2), proposalsQuery[0].GetProposalID())
|
require.Equal(t, uint64(2), proposalsQuery[0].ProposalID)
|
||||||
|
|
||||||
f.Cleanup()
|
f.Cleanup()
|
||||||
}
|
}
|
||||||
|
@ -618,7 +620,7 @@ func TestGaiaCLIValidateSignatures(t *testing.T) {
|
||||||
barAddr := f.KeyAddress(keyBar)
|
barAddr := f.KeyAddress(keyBar)
|
||||||
|
|
||||||
// generate sendTx with default gas
|
// generate sendTx with default gas
|
||||||
success, stdout, stderr := f.TxSend(keyFoo, barAddr, sdk.NewInt64Coin(denom, 10), "--generate-only")
|
success, stdout, stderr := f.TxSend(fooAddr.String(), barAddr, sdk.NewInt64Coin(denom, 10), "--generate-only")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
|
|
||||||
|
@ -669,7 +671,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
||||||
|
|
||||||
// Test generate sendTx with default gas
|
// Test generate sendTx with default gas
|
||||||
sendTokens := sdk.TokensFromTendermintPower(10)
|
sendTokens := sdk.TokensFromTendermintPower(10)
|
||||||
success, stdout, stderr := f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--generate-only")
|
success, stdout, stderr := f.TxSend(fooAddr.String(), barAddr, sdk.NewCoin(denom, sendTokens), "--generate-only")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
msg := unmarshalStdTx(t, stdout)
|
msg := unmarshalStdTx(t, stdout)
|
||||||
|
@ -678,7 +680,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
||||||
require.Equal(t, 0, len(msg.GetSignatures()))
|
require.Equal(t, 0, len(msg.GetSignatures()))
|
||||||
|
|
||||||
// Test generate sendTx with --gas=$amount
|
// Test generate sendTx with --gas=$amount
|
||||||
success, stdout, stderr = f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--gas=100", "--generate-only")
|
success, stdout, stderr = f.TxSend(fooAddr.String(), barAddr, sdk.NewCoin(denom, sendTokens), "--gas=100", "--generate-only")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
msg = unmarshalStdTx(t, stdout)
|
msg = unmarshalStdTx(t, stdout)
|
||||||
|
@ -687,7 +689,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
||||||
require.Equal(t, 0, len(msg.GetSignatures()))
|
require.Equal(t, 0, len(msg.GetSignatures()))
|
||||||
|
|
||||||
// Test generate sendTx, estimate gas
|
// Test generate sendTx, estimate gas
|
||||||
success, stdout, stderr = f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--gas=auto", "--generate-only")
|
success, stdout, stderr = f.TxSend(fooAddr.String(), barAddr, sdk.NewCoin(denom, sendTokens), "--gas=auto", "--generate-only")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.NotEmpty(t, stderr)
|
require.NotEmpty(t, stderr)
|
||||||
msg = unmarshalStdTx(t, stdout)
|
msg = unmarshalStdTx(t, stdout)
|
||||||
|
@ -764,7 +766,7 @@ func TestGaiaCLIMultisignInsufficientCosigners(t *testing.T) {
|
||||||
tests.WaitForNextNBlocksTM(1, f.Port)
|
tests.WaitForNextNBlocksTM(1, f.Port)
|
||||||
|
|
||||||
// Test generate sendTx with multisig
|
// Test generate sendTx with multisig
|
||||||
success, stdout, _ := f.TxSend(keyFooBarBaz, barAddr, sdk.NewInt64Coin(denom, 5), "--generate-only")
|
success, stdout, _ := f.TxSend(fooBarBazAddr.String(), barAddr, sdk.NewInt64Coin(denom, 5), "--generate-only")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
|
|
||||||
// Write the output to disk
|
// Write the output to disk
|
||||||
|
@ -808,8 +810,10 @@ func TestGaiaCLIEncode(t *testing.T) {
|
||||||
|
|
||||||
// Build a testing transaction and write it to disk
|
// Build a testing transaction and write it to disk
|
||||||
barAddr := f.KeyAddress(keyBar)
|
barAddr := f.KeyAddress(keyBar)
|
||||||
|
keyAddr := f.KeyAddress(keyFoo)
|
||||||
|
|
||||||
sendTokens := sdk.TokensFromTendermintPower(10)
|
sendTokens := sdk.TokensFromTendermintPower(10)
|
||||||
success, stdout, stderr := f.TxSend(keyFoo, barAddr, sdk.NewCoin(denom, sendTokens), "--generate-only", "--memo", "deadbeef")
|
success, stdout, stderr := f.TxSend(keyAddr.String(), barAddr, sdk.NewCoin(denom, sendTokens), "--generate-only", "--memo", "deadbeef")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
|
|
||||||
|
@ -853,7 +857,7 @@ func TestGaiaCLIMultisignSortSignatures(t *testing.T) {
|
||||||
require.Equal(t, int64(10), fooBarBazAcc.GetCoins().AmountOf(denom).Int64())
|
require.Equal(t, int64(10), fooBarBazAcc.GetCoins().AmountOf(denom).Int64())
|
||||||
|
|
||||||
// Test generate sendTx with multisig
|
// Test generate sendTx with multisig
|
||||||
success, stdout, _ := f.TxSend(keyFooBarBaz, barAddr, sdk.NewInt64Coin(denom, 5), "--generate-only")
|
success, stdout, _ := f.TxSend(fooBarBazAddr.String(), barAddr, sdk.NewInt64Coin(denom, 5), "--generate-only")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
|
|
||||||
// Write the output to disk
|
// Write the output to disk
|
||||||
|
@ -915,7 +919,7 @@ func TestGaiaCLIMultisign(t *testing.T) {
|
||||||
require.Equal(t, int64(10), fooBarBazAcc.GetCoins().AmountOf(denom).Int64())
|
require.Equal(t, int64(10), fooBarBazAcc.GetCoins().AmountOf(denom).Int64())
|
||||||
|
|
||||||
// Test generate sendTx with multisig
|
// Test generate sendTx with multisig
|
||||||
success, stdout, stderr := f.TxSend(keyFooBarBaz, bazAddr, sdk.NewInt64Coin(denom, 10), "--generate-only")
|
success, stdout, stderr := f.TxSend(fooBarBazAddr.String(), bazAddr, sdk.NewInt64Coin(denom, 10), "--generate-only")
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
|
|
||||||
|
@ -963,6 +967,7 @@ func TestGaiaCLIConfig(t *testing.T) {
|
||||||
node := fmt.Sprintf("%s:%s", f.RPCAddr, f.Port)
|
node := fmt.Sprintf("%s:%s", f.RPCAddr, f.Port)
|
||||||
|
|
||||||
// Set available configuration options
|
// Set available configuration options
|
||||||
|
f.CLIConfig("broadcast-mode", "block")
|
||||||
f.CLIConfig("node", node)
|
f.CLIConfig("node", node)
|
||||||
f.CLIConfig("output", "text")
|
f.CLIConfig("output", "text")
|
||||||
f.CLIConfig("trust-node", "true")
|
f.CLIConfig("trust-node", "true")
|
||||||
|
@ -972,7 +977,8 @@ func TestGaiaCLIConfig(t *testing.T) {
|
||||||
|
|
||||||
config, err := ioutil.ReadFile(path.Join(f.GCLIHome, "config", "config.toml"))
|
config, err := ioutil.ReadFile(path.Join(f.GCLIHome, "config", "config.toml"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
expectedConfig := fmt.Sprintf(`chain-id = "%s"
|
expectedConfig := fmt.Sprintf(`broadcast-mode = "block"
|
||||||
|
chain-id = "%s"
|
||||||
indent = true
|
indent = true
|
||||||
node = "%s"
|
node = "%s"
|
||||||
output = "text"
|
output = "text"
|
||||||
|
|
|
@ -104,15 +104,15 @@ func (f Fixtures) GenesisState() app.GenesisState {
|
||||||
return appState
|
return appState
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitFixtures is called at the beginning of a test
|
// InitFixtures is called at the beginning of a test and initializes a chain
|
||||||
// and initializes a chain with 1 validator
|
// with 1 validator.
|
||||||
func InitFixtures(t *testing.T) (f *Fixtures) {
|
func InitFixtures(t *testing.T) (f *Fixtures) {
|
||||||
f = NewFixtures(t)
|
f = NewFixtures(t)
|
||||||
|
|
||||||
// Reset test state
|
// reset test state
|
||||||
f.UnsafeResetAll()
|
f.UnsafeResetAll()
|
||||||
|
|
||||||
// Ensure keystore has foo and bar keys
|
// ensure keystore has foo and bar keys
|
||||||
f.KeysDelete(keyFoo)
|
f.KeysDelete(keyFoo)
|
||||||
f.KeysDelete(keyBar)
|
f.KeysDelete(keyBar)
|
||||||
f.KeysDelete(keyBar)
|
f.KeysDelete(keyBar)
|
||||||
|
@ -124,14 +124,16 @@ func InitFixtures(t *testing.T) (f *Fixtures) {
|
||||||
f.KeysAdd(keyFooBarBaz, "--multisig-threshold=2", fmt.Sprintf(
|
f.KeysAdd(keyFooBarBaz, "--multisig-threshold=2", fmt.Sprintf(
|
||||||
"--multisig=%s,%s,%s", keyFoo, keyBar, keyBaz))
|
"--multisig=%s,%s,%s", keyFoo, keyBar, keyBaz))
|
||||||
|
|
||||||
// Ensure that CLI output is in JSON format
|
// ensure that CLI output is in JSON format
|
||||||
f.CLIConfig("output", "json")
|
f.CLIConfig("output", "json")
|
||||||
|
|
||||||
// NOTE: GDInit sets the ChainID
|
// NOTE: GDInit sets the ChainID
|
||||||
f.GDInit(keyFoo)
|
f.GDInit(keyFoo)
|
||||||
f.CLIConfig("chain-id", f.ChainID)
|
|
||||||
|
|
||||||
// Start an account with tokens
|
f.CLIConfig("chain-id", f.ChainID)
|
||||||
|
f.CLIConfig("broadcast-mode", "block")
|
||||||
|
|
||||||
|
// start an account with tokens
|
||||||
f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins)
|
f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins)
|
||||||
f.AddGenesisAccount(
|
f.AddGenesisAccount(
|
||||||
f.KeyAddress(keyVesting), startCoins,
|
f.KeyAddress(keyVesting), startCoins,
|
||||||
|
@ -139,8 +141,10 @@ func InitFixtures(t *testing.T) (f *Fixtures) {
|
||||||
fmt.Sprintf("--vesting-start-time=%d", time.Now().UTC().UnixNano()),
|
fmt.Sprintf("--vesting-start-time=%d", time.Now().UTC().UnixNano()),
|
||||||
fmt.Sprintf("--vesting-end-time=%d", time.Now().Add(60*time.Second).UTC().UnixNano()),
|
fmt.Sprintf("--vesting-end-time=%d", time.Now().Add(60*time.Second).UTC().UnixNano()),
|
||||||
)
|
)
|
||||||
|
|
||||||
f.GenTx(keyFoo)
|
f.GenTx(keyFoo)
|
||||||
f.CollectGenTxs()
|
f.CollectGenTxs()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +167,7 @@ func (f *Fixtures) Flags() string {
|
||||||
|
|
||||||
// UnsafeResetAll is gaiad unsafe-reset-all
|
// UnsafeResetAll is gaiad unsafe-reset-all
|
||||||
func (f *Fixtures) UnsafeResetAll(flags ...string) {
|
func (f *Fixtures) UnsafeResetAll(flags ...string) {
|
||||||
cmd := fmt.Sprintf("gaiad --home=%s unsafe-reset-all", f.GDHome)
|
cmd := fmt.Sprintf("../../../build/gaiad --home=%s unsafe-reset-all", f.GDHome)
|
||||||
executeWrite(f.T, addFlags(cmd, flags))
|
executeWrite(f.T, addFlags(cmd, flags))
|
||||||
err := os.RemoveAll(filepath.Join(f.GDHome, "config", "gentx"))
|
err := os.RemoveAll(filepath.Join(f.GDHome, "config", "gentx"))
|
||||||
require.NoError(f.T, err)
|
require.NoError(f.T, err)
|
||||||
|
@ -172,7 +176,7 @@ func (f *Fixtures) UnsafeResetAll(flags ...string) {
|
||||||
// GDInit is gaiad init
|
// GDInit is gaiad init
|
||||||
// NOTE: GDInit sets the ChainID for the Fixtures instance
|
// NOTE: GDInit sets the ChainID for the Fixtures instance
|
||||||
func (f *Fixtures) GDInit(moniker string, flags ...string) {
|
func (f *Fixtures) GDInit(moniker string, flags ...string) {
|
||||||
cmd := fmt.Sprintf("gaiad init -o --home=%s %s", f.GDHome, moniker)
|
cmd := fmt.Sprintf("../../../build/gaiad init -o --home=%s %s", f.GDHome, moniker)
|
||||||
_, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
_, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
|
|
||||||
var chainID string
|
var chainID string
|
||||||
|
@ -189,25 +193,25 @@ func (f *Fixtures) GDInit(moniker string, flags ...string) {
|
||||||
|
|
||||||
// AddGenesisAccount is gaiad add-genesis-account
|
// AddGenesisAccount is gaiad add-genesis-account
|
||||||
func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, flags ...string) {
|
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)
|
cmd := fmt.Sprintf("../../../build/gaiad add-genesis-account %s %s --home=%s", address, coins, f.GDHome)
|
||||||
executeWriteCheckErr(f.T, addFlags(cmd, flags))
|
executeWriteCheckErr(f.T, addFlags(cmd, flags))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenTx is gaiad gentx
|
// GenTx is gaiad gentx
|
||||||
func (f *Fixtures) GenTx(name string, flags ...string) {
|
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)
|
cmd := fmt.Sprintf("../../../build/gaiad gentx --name=%s --home=%s --home-client=%s", name, f.GDHome, f.GCLIHome)
|
||||||
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CollectGenTxs is gaiad collect-gentxs
|
// CollectGenTxs is gaiad collect-gentxs
|
||||||
func (f *Fixtures) CollectGenTxs(flags ...string) {
|
func (f *Fixtures) CollectGenTxs(flags ...string) {
|
||||||
cmd := fmt.Sprintf("gaiad collect-gentxs --home=%s", f.GDHome)
|
cmd := fmt.Sprintf("../../../build/gaiad collect-gentxs --home=%s", f.GDHome)
|
||||||
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GDStart runs gaiad start with the appropriate flags and returns a process
|
// GDStart runs gaiad start with the appropriate flags and returns a process
|
||||||
func (f *Fixtures) GDStart(flags ...string) *tests.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)
|
cmd := fmt.Sprintf("../../../build/gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", f.GDHome, f.RPCAddr, f.P2PAddr)
|
||||||
proc := tests.GoExecuteTWithStdout(f.T, addFlags(cmd, flags))
|
proc := tests.GoExecuteTWithStdout(f.T, addFlags(cmd, flags))
|
||||||
tests.WaitForTMStart(f.Port)
|
tests.WaitForTMStart(f.Port)
|
||||||
tests.WaitForNextNBlocksTM(1, f.Port)
|
tests.WaitForNextNBlocksTM(1, f.Port)
|
||||||
|
@ -216,7 +220,7 @@ func (f *Fixtures) GDStart(flags ...string) *tests.Process {
|
||||||
|
|
||||||
// GDTendermint returns the results of gaiad tendermint [query]
|
// GDTendermint returns the results of gaiad tendermint [query]
|
||||||
func (f *Fixtures) GDTendermint(query string) string {
|
func (f *Fixtures) GDTendermint(query string) string {
|
||||||
cmd := fmt.Sprintf("gaiad tendermint %s --home=%s", query, f.GDHome)
|
cmd := fmt.Sprintf("../../../build/gaiad tendermint %s --home=%s", query, f.GDHome)
|
||||||
success, stdout, stderr := executeWriteRetStdStreams(f.T, cmd)
|
success, stdout, stderr := executeWriteRetStdStreams(f.T, cmd)
|
||||||
require.Empty(f.T, stderr)
|
require.Empty(f.T, stderr)
|
||||||
require.True(f.T, success)
|
require.True(f.T, success)
|
||||||
|
@ -225,7 +229,7 @@ func (f *Fixtures) GDTendermint(query string) string {
|
||||||
|
|
||||||
// ValidateGenesis runs gaiad validate-genesis
|
// ValidateGenesis runs gaiad validate-genesis
|
||||||
func (f *Fixtures) ValidateGenesis() {
|
func (f *Fixtures) ValidateGenesis() {
|
||||||
cmd := fmt.Sprintf("gaiad validate-genesis --home=%s", f.GDHome)
|
cmd := fmt.Sprintf("../../../build/gaiad validate-genesis --home=%s", f.GDHome)
|
||||||
executeWriteCheckErr(f.T, cmd)
|
executeWriteCheckErr(f.T, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,31 +238,31 @@ func (f *Fixtures) ValidateGenesis() {
|
||||||
|
|
||||||
// KeysDelete is gaiacli keys delete
|
// KeysDelete is gaiacli keys delete
|
||||||
func (f *Fixtures) KeysDelete(name string, flags ...string) {
|
func (f *Fixtures) KeysDelete(name string, flags ...string) {
|
||||||
cmd := fmt.Sprintf("gaiacli keys delete --home=%s %s", f.GCLIHome, name)
|
cmd := fmt.Sprintf("../../../build/gaiacli keys delete --home=%s %s", f.GCLIHome, name)
|
||||||
executeWrite(f.T, addFlags(cmd, append(append(flags, "-y"), "-f")))
|
executeWrite(f.T, addFlags(cmd, append(append(flags, "-y"), "-f")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeysAdd is gaiacli keys add
|
// KeysAdd is gaiacli keys add
|
||||||
func (f *Fixtures) KeysAdd(name string, flags ...string) {
|
func (f *Fixtures) KeysAdd(name string, flags ...string) {
|
||||||
cmd := fmt.Sprintf("gaiacli keys add --home=%s %s", f.GCLIHome, name)
|
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s %s", f.GCLIHome, name)
|
||||||
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeysAddRecover prepares gaiacli keys add --recover
|
// KeysAddRecover prepares gaiacli keys add --recover
|
||||||
func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) {
|
func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) {
|
||||||
cmd := fmt.Sprintf("gaiacli keys add --home=%s --recover %s", f.GCLIHome, name)
|
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s --recover %s", f.GCLIHome, name)
|
||||||
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic)
|
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeysAddRecoverHDPath prepares gaiacli keys add --recover --account --index
|
// KeysAddRecoverHDPath prepares gaiacli keys add --recover --account --index
|
||||||
func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) {
|
func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) {
|
||||||
cmd := fmt.Sprintf("gaiacli keys add --home=%s --recover %s --account %d --index %d", f.GCLIHome, name, account, index)
|
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s --recover %s --account %d --index %d", f.GCLIHome, name, account, index)
|
||||||
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic)
|
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeysShow is gaiacli keys show
|
// KeysShow is gaiacli keys show
|
||||||
func (f *Fixtures) KeysShow(name string, flags ...string) keys.KeyOutput {
|
func (f *Fixtures) KeysShow(name string, flags ...string) keys.KeyOutput {
|
||||||
cmd := fmt.Sprintf("gaiacli keys show --home=%s %s", f.GCLIHome, name)
|
cmd := fmt.Sprintf("../../../build/gaiacli keys show --home=%s %s", f.GCLIHome, name)
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var ko keys.KeyOutput
|
var ko keys.KeyOutput
|
||||||
err := clientkeys.UnmarshalJSON([]byte(out), &ko)
|
err := clientkeys.UnmarshalJSON([]byte(out), &ko)
|
||||||
|
@ -279,7 +283,7 @@ func (f *Fixtures) KeyAddress(name string) sdk.AccAddress {
|
||||||
|
|
||||||
// CLIConfig is gaiacli config
|
// CLIConfig is gaiacli config
|
||||||
func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
|
func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
|
||||||
cmd := fmt.Sprintf("gaiacli config --home=%s %s %s", f.GCLIHome, key, value)
|
cmd := fmt.Sprintf("../../../build/gaiacli config --home=%s %s %s", f.GCLIHome, key, value)
|
||||||
executeWriteCheckErr(f.T, addFlags(cmd, flags))
|
executeWriteCheckErr(f.T, addFlags(cmd, flags))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +292,7 @@ func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
|
||||||
|
|
||||||
// TxSend is gaiacli tx send
|
// TxSend is gaiacli tx send
|
||||||
func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) {
|
func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) {
|
||||||
cmd := fmt.Sprintf("gaiacli tx send %s %s %v --from=%s", to, amount, f.Flags(), from)
|
cmd := fmt.Sprintf("../../../build/gaiacli tx send %s %s %v --from=%s", to, amount, f.Flags(), from)
|
||||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,25 +300,25 @@ func (f *Fixtures) txSendWithConfirm(
|
||||||
from string, to sdk.AccAddress, amount sdk.Coin, confirm string, flags ...string,
|
from string, to sdk.AccAddress, amount sdk.Coin, confirm string, flags ...string,
|
||||||
) (bool, string, string) {
|
) (bool, string, string) {
|
||||||
|
|
||||||
cmd := fmt.Sprintf("gaiacli tx send %s %s %v --from=%s", to, amount, f.Flags(), from)
|
cmd := fmt.Sprintf("../../../build/gaiacli tx send %s %s %v --from=%s", to, amount, f.Flags(), from)
|
||||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), confirm, app.DefaultKeyPass)
|
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), confirm, app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxSign is gaiacli tx sign
|
// TxSign is gaiacli tx sign
|
||||||
func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) {
|
func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) {
|
||||||
cmd := fmt.Sprintf("gaiacli tx sign %v --from=%s %v", f.Flags(), signer, fileName)
|
cmd := fmt.Sprintf("../../../build/gaiacli tx sign %v --from=%s %v", f.Flags(), signer, fileName)
|
||||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxBroadcast is gaiacli tx broadcast
|
// TxBroadcast is gaiacli tx broadcast
|
||||||
func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) {
|
func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) {
|
||||||
cmd := fmt.Sprintf("gaiacli tx broadcast %v %v", f.Flags(), fileName)
|
cmd := fmt.Sprintf("../../../build/gaiacli tx broadcast %v %v", f.Flags(), fileName)
|
||||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxEncode is gaiacli tx encode
|
// TxEncode is gaiacli tx encode
|
||||||
func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) {
|
func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) {
|
||||||
cmd := fmt.Sprintf("gaiacli tx encode %v %v", f.Flags(), fileName)
|
cmd := fmt.Sprintf("../../../build/gaiacli tx encode %v %v", f.Flags(), fileName)
|
||||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +326,7 @@ func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, str
|
||||||
func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string,
|
func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string,
|
||||||
flags ...string) (bool, string, string) {
|
flags ...string) (bool, string, string) {
|
||||||
|
|
||||||
cmd := fmt.Sprintf("gaiacli tx multisign %v %s %s %s", f.Flags(),
|
cmd := fmt.Sprintf("../../../build/gaiacli tx multisign %v %s %s %s", f.Flags(),
|
||||||
fileName, name, strings.Join(signaturesFiles, " "),
|
fileName, name, strings.Join(signaturesFiles, " "),
|
||||||
)
|
)
|
||||||
return executeWriteRetStdStreams(f.T, cmd)
|
return executeWriteRetStdStreams(f.T, cmd)
|
||||||
|
@ -333,7 +337,7 @@ func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string,
|
||||||
|
|
||||||
// TxStakingCreateValidator is gaiacli tx staking create-validator
|
// TxStakingCreateValidator is gaiacli tx staking create-validator
|
||||||
func (f *Fixtures) TxStakingCreateValidator(from, consPubKey string, amount sdk.Coin, flags ...string) (bool, string, string) {
|
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("../../../build/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(" --amount=%v --moniker=%v --commission-rate=%v", amount, from, "0.05")
|
||||||
cmd += fmt.Sprintf(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10")
|
cmd += fmt.Sprintf(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10")
|
||||||
cmd += fmt.Sprintf(" --min-self-delegation=%v", "1")
|
cmd += fmt.Sprintf(" --min-self-delegation=%v", "1")
|
||||||
|
@ -342,7 +346,7 @@ func (f *Fixtures) TxStakingCreateValidator(from, consPubKey string, amount sdk.
|
||||||
|
|
||||||
// TxStakingUnbond is gaiacli tx staking unbond
|
// TxStakingUnbond is gaiacli tx staking unbond
|
||||||
func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress, flags ...string) bool {
|
func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress, flags ...string) bool {
|
||||||
cmd := fmt.Sprintf("gaiacli tx staking unbond %s %v --from=%s %v", validator, shares, from, f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli tx staking unbond %s %v --from=%s %v", validator, shares, from, f.Flags())
|
||||||
return executeWrite(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
return executeWrite(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,20 +355,20 @@ func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress
|
||||||
|
|
||||||
// TxGovSubmitProposal is gaiacli tx gov submit-proposal
|
// TxGovSubmitProposal is gaiacli tx gov submit-proposal
|
||||||
func (f *Fixtures) TxGovSubmitProposal(from, typ, title, description string, deposit sdk.Coin, flags ...string) (bool, string, string) {
|
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("../../../build/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)
|
cmd += fmt.Sprintf(" --title=%s --description=%s --deposit=%s", title, description, deposit)
|
||||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxGovDeposit is gaiacli tx gov deposit
|
// TxGovDeposit is gaiacli tx gov deposit
|
||||||
func (f *Fixtures) TxGovDeposit(proposalID int, from string, amount sdk.Coin, flags ...string) (bool, string, string) {
|
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())
|
cmd := fmt.Sprintf("../../../build/gaiacli tx gov deposit %d %s --from=%s %v", proposalID, amount, from, f.Flags())
|
||||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxGovVote is gaiacli tx gov vote
|
// TxGovVote is gaiacli tx gov vote
|
||||||
func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string, flags ...string) (bool, string, string) {
|
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())
|
cmd := fmt.Sprintf("../../../build/gaiacli tx gov vote %d %s --from=%s %v", proposalID, option, from, f.Flags())
|
||||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +377,7 @@ func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string,
|
||||||
|
|
||||||
// QueryAccount is gaiacli query account
|
// QueryAccount is gaiacli query account
|
||||||
func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.BaseAccount {
|
func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.BaseAccount {
|
||||||
cmd := fmt.Sprintf("gaiacli query account %s %v", address, f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query account %s %v", address, f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var initRes map[string]json.RawMessage
|
var initRes map[string]json.RawMessage
|
||||||
err := json.Unmarshal([]byte(out), &initRes)
|
err := json.Unmarshal([]byte(out), &initRes)
|
||||||
|
@ -392,7 +396,7 @@ func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.Ba
|
||||||
|
|
||||||
// QueryTxs is gaiacli query txs
|
// QueryTxs is gaiacli query txs
|
||||||
func (f *Fixtures) QueryTxs(page, limit int, tags ...string) []sdk.TxResponse {
|
func (f *Fixtures) QueryTxs(page, limit int, tags ...string) []sdk.TxResponse {
|
||||||
cmd := fmt.Sprintf("gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, cmd, "")
|
out, _ := tests.ExecuteT(f.T, cmd, "")
|
||||||
var txs []sdk.TxResponse
|
var txs []sdk.TxResponse
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -403,7 +407,7 @@ func (f *Fixtures) QueryTxs(page, limit int, tags ...string) []sdk.TxResponse {
|
||||||
|
|
||||||
// QueryTxsInvalid query txs with wrong parameters and compare expected error
|
// QueryTxsInvalid query txs with wrong parameters and compare expected error
|
||||||
func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, tags ...string) {
|
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())
|
cmd := fmt.Sprintf("../../../build/gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
|
||||||
_, err := tests.ExecuteT(f.T, cmd, "")
|
_, err := tests.ExecuteT(f.T, cmd, "")
|
||||||
require.EqualError(f.T, expectedErr, err)
|
require.EqualError(f.T, expectedErr, err)
|
||||||
}
|
}
|
||||||
|
@ -413,7 +417,7 @@ func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, tags ...s
|
||||||
|
|
||||||
// QueryStakingValidator is gaiacli query staking validator
|
// QueryStakingValidator is gaiacli query staking validator
|
||||||
func (f *Fixtures) QueryStakingValidator(valAddr sdk.ValAddress, flags ...string) 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())
|
cmd := fmt.Sprintf("../../../build/gaiacli query staking validator %s %v", valAddr, f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var validator staking.Validator
|
var validator staking.Validator
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -424,7 +428,7 @@ func (f *Fixtures) QueryStakingValidator(valAddr sdk.ValAddress, flags ...string
|
||||||
|
|
||||||
// QueryStakingUnbondingDelegationsFrom is gaiacli query staking unbonding-delegations-from
|
// QueryStakingUnbondingDelegationsFrom is gaiacli query staking unbonding-delegations-from
|
||||||
func (f *Fixtures) QueryStakingUnbondingDelegationsFrom(valAddr sdk.ValAddress, flags ...string) []staking.UnbondingDelegation {
|
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())
|
cmd := fmt.Sprintf("../../../build/gaiacli query staking unbonding-delegations-from %s %v", valAddr, f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var ubds []staking.UnbondingDelegation
|
var ubds []staking.UnbondingDelegation
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -435,7 +439,7 @@ func (f *Fixtures) QueryStakingUnbondingDelegationsFrom(valAddr sdk.ValAddress,
|
||||||
|
|
||||||
// QueryStakingDelegationsTo is gaiacli query staking delegations-to
|
// QueryStakingDelegationsTo is gaiacli query staking delegations-to
|
||||||
func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...string) []staking.Delegation {
|
func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...string) []staking.Delegation {
|
||||||
cmd := fmt.Sprintf("gaiacli query staking delegations-to %s %v", valAddr, f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query staking delegations-to %s %v", valAddr, f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var delegations []staking.Delegation
|
var delegations []staking.Delegation
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -446,7 +450,7 @@ func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...st
|
||||||
|
|
||||||
// QueryStakingPool is gaiacli query staking pool
|
// QueryStakingPool is gaiacli query staking pool
|
||||||
func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool {
|
func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool {
|
||||||
cmd := fmt.Sprintf("gaiacli query staking pool %v", f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query staking pool %v", f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var pool staking.Pool
|
var pool staking.Pool
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -457,7 +461,7 @@ func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool {
|
||||||
|
|
||||||
// QueryStakingParameters is gaiacli query staking parameters
|
// QueryStakingParameters is gaiacli query staking parameters
|
||||||
func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params {
|
func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params {
|
||||||
cmd := fmt.Sprintf("gaiacli query staking params %v", f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query staking params %v", f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var params staking.Params
|
var params staking.Params
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -471,7 +475,7 @@ func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params {
|
||||||
|
|
||||||
// QueryGovParamDeposit is gaiacli query gov param deposit
|
// QueryGovParamDeposit is gaiacli query gov param deposit
|
||||||
func (f *Fixtures) QueryGovParamDeposit() gov.DepositParams {
|
func (f *Fixtures) QueryGovParamDeposit() gov.DepositParams {
|
||||||
cmd := fmt.Sprintf("gaiacli query gov param deposit %s", f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query gov param deposit %s", f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, cmd, "")
|
out, _ := tests.ExecuteT(f.T, cmd, "")
|
||||||
var depositParam gov.DepositParams
|
var depositParam gov.DepositParams
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -482,7 +486,7 @@ func (f *Fixtures) QueryGovParamDeposit() gov.DepositParams {
|
||||||
|
|
||||||
// QueryGovParamVoting is gaiacli query gov param voting
|
// QueryGovParamVoting is gaiacli query gov param voting
|
||||||
func (f *Fixtures) QueryGovParamVoting() gov.VotingParams {
|
func (f *Fixtures) QueryGovParamVoting() gov.VotingParams {
|
||||||
cmd := fmt.Sprintf("gaiacli query gov param voting %s", f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query gov param voting %s", f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, cmd, "")
|
out, _ := tests.ExecuteT(f.T, cmd, "")
|
||||||
var votingParam gov.VotingParams
|
var votingParam gov.VotingParams
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -493,7 +497,7 @@ func (f *Fixtures) QueryGovParamVoting() gov.VotingParams {
|
||||||
|
|
||||||
// QueryGovParamTallying is gaiacli query gov param tallying
|
// QueryGovParamTallying is gaiacli query gov param tallying
|
||||||
func (f *Fixtures) QueryGovParamTallying() gov.TallyParams {
|
func (f *Fixtures) QueryGovParamTallying() gov.TallyParams {
|
||||||
cmd := fmt.Sprintf("gaiacli query gov param tallying %s", f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query gov param tallying %s", f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, cmd, "")
|
out, _ := tests.ExecuteT(f.T, cmd, "")
|
||||||
var tallyingParam gov.TallyParams
|
var tallyingParam gov.TallyParams
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -504,7 +508,7 @@ func (f *Fixtures) QueryGovParamTallying() gov.TallyParams {
|
||||||
|
|
||||||
// QueryGovProposals is gaiacli query gov proposals
|
// QueryGovProposals is gaiacli query gov proposals
|
||||||
func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals {
|
func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals {
|
||||||
cmd := fmt.Sprintf("gaiacli query gov proposals %v", f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query gov proposals %v", f.Flags())
|
||||||
stdout, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
stdout, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
if strings.Contains(stderr, "No matching proposals found") {
|
if strings.Contains(stderr, "No matching proposals found") {
|
||||||
return gov.Proposals{}
|
return gov.Proposals{}
|
||||||
|
@ -519,7 +523,7 @@ func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals {
|
||||||
|
|
||||||
// QueryGovProposal is gaiacli query gov proposal
|
// QueryGovProposal is gaiacli query gov proposal
|
||||||
func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposal {
|
func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposal {
|
||||||
cmd := fmt.Sprintf("gaiacli query gov proposal %d %v", proposalID, f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query gov proposal %d %v", proposalID, f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var proposal gov.Proposal
|
var proposal gov.Proposal
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -530,7 +534,7 @@ func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposa
|
||||||
|
|
||||||
// QueryGovVote is gaiacli query gov vote
|
// QueryGovVote is gaiacli query gov vote
|
||||||
func (f *Fixtures) QueryGovVote(proposalID int, voter sdk.AccAddress, flags ...string) 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())
|
cmd := fmt.Sprintf("../../../build/gaiacli query gov vote %d %s %v", proposalID, voter, f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var vote gov.Vote
|
var vote gov.Vote
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -541,7 +545,7 @@ func (f *Fixtures) QueryGovVote(proposalID int, voter sdk.AccAddress, flags ...s
|
||||||
|
|
||||||
// QueryGovVotes is gaiacli query gov votes
|
// QueryGovVotes is gaiacli query gov votes
|
||||||
func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote {
|
func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote {
|
||||||
cmd := fmt.Sprintf("gaiacli query gov votes %d %v", proposalID, f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query gov votes %d %v", proposalID, f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var votes []gov.Vote
|
var votes []gov.Vote
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -552,7 +556,7 @@ func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote {
|
||||||
|
|
||||||
// QueryGovDeposit is gaiacli query gov deposit
|
// QueryGovDeposit is gaiacli query gov deposit
|
||||||
func (f *Fixtures) QueryGovDeposit(proposalID int, depositor sdk.AccAddress, flags ...string) 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())
|
cmd := fmt.Sprintf("../../../build/gaiacli query gov deposit %d %s %v", proposalID, depositor, f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var deposit gov.Deposit
|
var deposit gov.Deposit
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -563,7 +567,7 @@ func (f *Fixtures) QueryGovDeposit(proposalID int, depositor sdk.AccAddress, fla
|
||||||
|
|
||||||
// QueryGovDeposits is gaiacli query gov deposits
|
// QueryGovDeposits is gaiacli query gov deposits
|
||||||
func (f *Fixtures) QueryGovDeposits(propsalID int, flags ...string) []gov.Deposit {
|
func (f *Fixtures) QueryGovDeposits(propsalID int, flags ...string) []gov.Deposit {
|
||||||
cmd := fmt.Sprintf("gaiacli query gov deposits %d %v", propsalID, f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query gov deposits %d %v", propsalID, f.Flags())
|
||||||
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
|
||||||
var deposits []gov.Deposit
|
var deposits []gov.Deposit
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -577,7 +581,7 @@ func (f *Fixtures) QueryGovDeposits(propsalID int, flags ...string) []gov.Deposi
|
||||||
|
|
||||||
// QuerySigningInfo returns the signing info for a validator
|
// QuerySigningInfo returns the signing info for a validator
|
||||||
func (f *Fixtures) QuerySigningInfo(val string) slashing.ValidatorSigningInfo {
|
func (f *Fixtures) QuerySigningInfo(val string) slashing.ValidatorSigningInfo {
|
||||||
cmd := fmt.Sprintf("gaiacli query slashing signing-info %s %s", val, f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query slashing signing-info %s %s", val, f.Flags())
|
||||||
res, errStr := tests.ExecuteT(f.T, cmd, "")
|
res, errStr := tests.ExecuteT(f.T, cmd, "")
|
||||||
require.Empty(f.T, errStr)
|
require.Empty(f.T, errStr)
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
@ -589,7 +593,7 @@ func (f *Fixtures) QuerySigningInfo(val string) slashing.ValidatorSigningInfo {
|
||||||
|
|
||||||
// QuerySlashingParams is gaiacli query slashing params
|
// QuerySlashingParams is gaiacli query slashing params
|
||||||
func (f *Fixtures) QuerySlashingParams() slashing.Params {
|
func (f *Fixtures) QuerySlashingParams() slashing.Params {
|
||||||
cmd := fmt.Sprintf("gaiacli query slashing params %s", f.Flags())
|
cmd := fmt.Sprintf("../../../build/gaiacli query slashing params %s", f.Flags())
|
||||||
res, errStr := tests.ExecuteT(f.T, cmd, "")
|
res, errStr := tests.ExecuteT(f.T, cmd, "")
|
||||||
require.Empty(f.T, errStr)
|
require.Empty(f.T, errStr)
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
|
|
@ -6,11 +6,13 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
|
|
||||||
"github.com/rakyll/statik/fs"
|
"github.com/rakyll/statik/fs"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
amino "github.com/tendermint/go-amino"
|
"github.com/tendermint/go-amino"
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
@ -28,6 +30,7 @@ import (
|
||||||
dist "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
|
dist "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
|
||||||
gv "github.com/cosmos/cosmos-sdk/x/gov"
|
gv "github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
||||||
|
mintrest "github.com/cosmos/cosmos-sdk/x/mint/client/rest"
|
||||||
sl "github.com/cosmos/cosmos-sdk/x/slashing"
|
sl "github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
|
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
|
||||||
st "github.com/cosmos/cosmos-sdk/x/staking"
|
st "github.com/cosmos/cosmos-sdk/x/staking"
|
||||||
|
@ -35,11 +38,13 @@ import (
|
||||||
|
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||||
|
crisisclient "github.com/cosmos/cosmos-sdk/x/crisis/client"
|
||||||
distcmd "github.com/cosmos/cosmos-sdk/x/distribution"
|
distcmd "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||||
distClient "github.com/cosmos/cosmos-sdk/x/distribution/client"
|
distClient "github.com/cosmos/cosmos-sdk/x/distribution/client"
|
||||||
govClient "github.com/cosmos/cosmos-sdk/x/gov/client"
|
govClient "github.com/cosmos/cosmos-sdk/x/gov/client"
|
||||||
slashingClient "github.com/cosmos/cosmos-sdk/x/slashing/client"
|
mintclient "github.com/cosmos/cosmos-sdk/x/mint/client"
|
||||||
stakingClient "github.com/cosmos/cosmos-sdk/x/staking/client"
|
slashingclient "github.com/cosmos/cosmos-sdk/x/slashing/client"
|
||||||
|
stakingclient "github.com/cosmos/cosmos-sdk/x/staking/client"
|
||||||
|
|
||||||
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
|
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
|
||||||
)
|
)
|
||||||
|
@ -67,8 +72,10 @@ func main() {
|
||||||
mc := []sdk.ModuleClients{
|
mc := []sdk.ModuleClients{
|
||||||
govClient.NewModuleClient(gv.StoreKey, cdc),
|
govClient.NewModuleClient(gv.StoreKey, cdc),
|
||||||
distClient.NewModuleClient(distcmd.StoreKey, cdc),
|
distClient.NewModuleClient(distcmd.StoreKey, cdc),
|
||||||
stakingClient.NewModuleClient(st.StoreKey, cdc),
|
stakingclient.NewModuleClient(st.StoreKey, cdc),
|
||||||
slashingClient.NewModuleClient(sl.StoreKey, cdc),
|
mintclient.NewModuleClient(mint.StoreKey, cdc),
|
||||||
|
slashingclient.NewModuleClient(sl.StoreKey, cdc),
|
||||||
|
crisisclient.NewModuleClient(sl.StoreKey, cdc),
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCmd := &cobra.Command{
|
rootCmd := &cobra.Command{
|
||||||
|
@ -124,7 +131,10 @@ func queryCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, m := range mc {
|
for _, m := range mc {
|
||||||
queryCmd.AddCommand(m.GetQueryCmd())
|
mQueryCmd := m.GetQueryCmd()
|
||||||
|
if mQueryCmd != nil {
|
||||||
|
queryCmd.AddCommand(mQueryCmd)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return queryCmd
|
return queryCmd
|
||||||
|
@ -166,6 +176,7 @@ func registerRoutes(rs *lcd.RestServer) {
|
||||||
staking.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)
|
slashing.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
gov.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
gov.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
|
mintrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerSwaggerUI(rs *lcd.RestServer) {
|
func registerSwaggerUI(rs *lcd.RestServer) {
|
||||||
|
|
|
@ -22,6 +22,11 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// gaiad custom flags
|
||||||
|
const flagAssertInvariantsBlockly = "assert-invariants-blockly"
|
||||||
|
|
||||||
|
var assertInvariantsBlockly bool
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
|
||||||
|
@ -50,6 +55,8 @@ func main() {
|
||||||
|
|
||||||
// prepare and add flags
|
// prepare and add flags
|
||||||
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
|
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
|
||||||
|
rootCmd.PersistentFlags().BoolVar(&assertInvariantsBlockly, flagAssertInvariantsBlockly,
|
||||||
|
false, "Assert registered invariants on a blockly basis")
|
||||||
err := executor.Execute()
|
err := executor.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// handle with #870
|
// handle with #870
|
||||||
|
@ -59,7 +66,7 @@ func main() {
|
||||||
|
|
||||||
func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application {
|
func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application {
|
||||||
return app.NewGaiaApp(
|
return app.NewGaiaApp(
|
||||||
logger, db, traceStore, true,
|
logger, db, traceStore, true, assertInvariantsBlockly,
|
||||||
baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))),
|
baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))),
|
||||||
baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)),
|
baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)),
|
||||||
)
|
)
|
||||||
|
@ -68,14 +75,15 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application
|
||||||
func exportAppStateAndTMValidators(
|
func exportAppStateAndTMValidators(
|
||||||
logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string,
|
logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string,
|
||||||
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||||
|
|
||||||
if height != -1 {
|
if height != -1 {
|
||||||
gApp := app.NewGaiaApp(logger, db, traceStore, false)
|
gApp := app.NewGaiaApp(logger, db, traceStore, false, false)
|
||||||
err := gApp.LoadHeight(height)
|
err := gApp.LoadHeight(height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return gApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
return gApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
||||||
}
|
}
|
||||||
gApp := app.NewGaiaApp(logger, db, traceStore, true)
|
gApp := app.NewGaiaApp(logger, db, traceStore, true, false)
|
||||||
return gApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
return gApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ func run(rootDir string) {
|
||||||
// Application
|
// Application
|
||||||
fmt.Println("Creating application")
|
fmt.Println("Creating application")
|
||||||
myapp := app.NewGaiaApp(
|
myapp := app.NewGaiaApp(
|
||||||
ctx.Logger, appDB, traceStoreWriter, true,
|
ctx.Logger, appDB, traceStoreWriter, true, true,
|
||||||
baseapp.SetPruning(store.PruneEverything), // nothing
|
baseapp.SetPruning(store.PruneEverything), // nothing
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@ func TestAddGenesisAccount(t *testing.T) {
|
||||||
args{
|
args{
|
||||||
app.GenesisState{},
|
app.GenesisState{},
|
||||||
addr1,
|
addr1,
|
||||||
sdk.Coins{},
|
sdk.NewCoins(),
|
||||||
sdk.Coins{},
|
sdk.NewCoins(),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
|
@ -44,8 +44,8 @@ func TestAddGenesisAccount(t *testing.T) {
|
||||||
args{
|
args{
|
||||||
app.GenesisState{Accounts: []app.GenesisAccount{{Address: addr1}}},
|
app.GenesisState{Accounts: []app.GenesisAccount{{Address: addr1}}},
|
||||||
addr1,
|
addr1,
|
||||||
sdk.Coins{},
|
sdk.NewCoins(),
|
||||||
sdk.Coins{},
|
sdk.NewCoins(),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
|
@ -56,8 +56,8 @@ func TestAddGenesisAccount(t *testing.T) {
|
||||||
args{
|
args{
|
||||||
app.GenesisState{},
|
app.GenesisState{},
|
||||||
addr1,
|
addr1,
|
||||||
sdk.Coins{sdk.NewInt64Coin("stake", 50)},
|
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
|
||||||
sdk.Coins{sdk.NewInt64Coin("stake", 100)},
|
sdk.NewCoins(sdk.NewInt64Coin("stake", 100)),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
},
|
},
|
||||||
|
@ -68,8 +68,8 @@ func TestAddGenesisAccount(t *testing.T) {
|
||||||
args{
|
args{
|
||||||
app.GenesisState{},
|
app.GenesisState{},
|
||||||
addr1,
|
addr1,
|
||||||
sdk.Coins{sdk.NewInt64Coin("stake", 50)},
|
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
|
||||||
sdk.Coins{sdk.NewInt64Coin("stake", 50)},
|
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
|
||||||
1654668078,
|
1654668078,
|
||||||
1554668078,
|
1554668078,
|
||||||
},
|
},
|
||||||
|
|
|
@ -47,6 +47,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "gentx",
|
Use: "gentx",
|
||||||
Short: "Generate a genesis tx carrying a self delegation",
|
Short: "Generate a genesis tx carrying a self delegation",
|
||||||
|
Args: cobra.NoArgs,
|
||||||
Long: fmt.Sprintf(`This command is an alias of the 'gaiad tx create-validator' command'.
|
Long: fmt.Sprintf(`This command is an alias of the 'gaiad tx create-validator' command'.
|
||||||
|
|
||||||
It creates a genesis piece carrying a self delegation with the
|
It creates a genesis piece carrying a self delegation with the
|
||||||
|
@ -88,6 +89,10 @@ following delegation and commission default parameters:
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = app.GaiaValidateGenesisState(genesisState); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome))
|
kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -107,8 +112,12 @@ following delegation and commission default parameters:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
website := viper.GetString(cli.FlagWebsite)
|
||||||
|
details := viper.GetString(cli.FlagDetails)
|
||||||
|
identity := viper.GetString(cli.FlagIdentity)
|
||||||
|
|
||||||
// Set flags for creating gentx
|
// Set flags for creating gentx
|
||||||
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey)
|
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey, website, details, identity)
|
||||||
|
|
||||||
// Fetch the amount of coins staked
|
// Fetch the amount of coins staked
|
||||||
amount := viper.GetString(cli.FlagAmount)
|
amount := viper.GetString(cli.FlagAmount)
|
||||||
|
@ -122,9 +131,17 @@ following delegation and commission default parameters:
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run gaiad tx create-validator
|
|
||||||
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
|
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
|
||||||
|
// XXX: Set the generate-only flag here after the CLI context has
|
||||||
|
// been created. This allows the from name/key to be correctly populated.
|
||||||
|
//
|
||||||
|
// TODO: Consider removing the manual setting of generate-only in
|
||||||
|
// favor of a 'gentx' flag in the create-validator command.
|
||||||
|
viper.Set(client.FlagGenerateOnly, true)
|
||||||
|
|
||||||
|
// create a 'create-validator' message
|
||||||
txBldr, msg, err := cli.BuildCreateValidatorMsg(cliCtx, txBldr)
|
txBldr, msg, err := cli.BuildCreateValidatorMsg(cliCtx, txBldr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -188,6 +205,9 @@ following delegation and commission default parameters:
|
||||||
"write the genesis transaction JSON document to the given file instead of the default location")
|
"write the genesis transaction JSON document to the given file instead of the default location")
|
||||||
cmd.Flags().String(cli.FlagIP, ip, "The node's public IP")
|
cmd.Flags().String(cli.FlagIP, ip, "The node's public IP")
|
||||||
cmd.Flags().String(cli.FlagNodeID, "", "The node's NodeID")
|
cmd.Flags().String(cli.FlagNodeID, "", "The node's NodeID")
|
||||||
|
cmd.Flags().String(cli.FlagWebsite, "", "The validator's (optional) website")
|
||||||
|
cmd.Flags().String(cli.FlagDetails, "", "The validator's (optional) details")
|
||||||
|
cmd.Flags().String(cli.FlagIdentity, "", "The (optional) identity signature (ex. UPort or Keybase)")
|
||||||
cmd.Flags().AddFlagSet(cli.FsCommissionCreate)
|
cmd.Flags().AddFlagSet(cli.FsCommissionCreate)
|
||||||
cmd.Flags().AddFlagSet(cli.FsMinSelfDelegation)
|
cmd.Flags().AddFlagSet(cli.FsMinSelfDelegation)
|
||||||
cmd.Flags().AddFlagSet(cli.FsAmount)
|
cmd.Flags().AddFlagSet(cli.FsAmount)
|
||||||
|
@ -224,16 +244,20 @@ func accountInGenesis(genesisState app.GenesisState, key sdk.AccAddress, coins s
|
||||||
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,
|
func prepareFlagsForTxCreateValidator(
|
||||||
valPubKey crypto.PubKey) {
|
config *cfg.Config, nodeID, ip, chainID string, valPubKey crypto.PubKey, website, details, identity string,
|
||||||
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome)) // --home
|
) {
|
||||||
|
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome))
|
||||||
viper.Set(client.FlagChainID, chainID)
|
viper.Set(client.FlagChainID, chainID)
|
||||||
viper.Set(client.FlagFrom, viper.GetString(client.FlagName)) // --from
|
viper.Set(client.FlagFrom, viper.GetString(client.FlagName))
|
||||||
viper.Set(cli.FlagNodeID, nodeID) // --node-id
|
viper.Set(cli.FlagNodeID, nodeID)
|
||||||
viper.Set(cli.FlagIP, ip) // --ip
|
viper.Set(cli.FlagIP, ip)
|
||||||
viper.Set(cli.FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey)) // --pubkey
|
viper.Set(cli.FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey))
|
||||||
viper.Set(client.FlagGenerateOnly, true) // --genesis-format
|
viper.Set(cli.FlagMoniker, config.Moniker)
|
||||||
viper.Set(cli.FlagMoniker, config.Moniker) // --moniker
|
viper.Set(cli.FlagWebsite, website)
|
||||||
|
viper.Set(cli.FlagDetails, details)
|
||||||
|
viper.Set(cli.FlagIdentity, identity)
|
||||||
|
|
||||||
if config.Moniker == "" {
|
if config.Moniker == "" {
|
||||||
viper.Set(cli.FlagMoniker, viper.GetString(client.FlagName))
|
viper.Set(cli.FlagMoniker, viper.GetString(client.FlagName))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
package init
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||||
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_prepareFlagsForTxCreateValidator(t *testing.T) {
|
||||||
|
defer server.SetupViper(t)()
|
||||||
|
defer setupClientHome(t)()
|
||||||
|
config, err := tcmd.ParseConfig()
|
||||||
|
require.Nil(t, err)
|
||||||
|
logger := log.NewNopLogger()
|
||||||
|
ctx := server.NewContext(config, logger)
|
||||||
|
|
||||||
|
valPubKey, _ := sdk.GetConsPubKeyBech32("cosmosvalconspub1zcjduepq7jsrkl9fgqk0wj3ahmfr8pgxj6vakj2wzn656s8pehh0zhv2w5as5gd80a")
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
config *cfg.Config
|
||||||
|
nodeID string
|
||||||
|
ip string
|
||||||
|
chainID string
|
||||||
|
valPubKey crypto.PubKey
|
||||||
|
website string
|
||||||
|
details string
|
||||||
|
identity string
|
||||||
|
}
|
||||||
|
|
||||||
|
type extraParams struct {
|
||||||
|
amount string
|
||||||
|
commissionRate string
|
||||||
|
commissionMaxRate string
|
||||||
|
commissionMaxChangeRate string
|
||||||
|
minSelfDelegation string
|
||||||
|
}
|
||||||
|
|
||||||
|
type testcase struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}
|
||||||
|
|
||||||
|
runTest := func(t *testing.T, tt testcase, params extraParams) {
|
||||||
|
prepareFlagsForTxCreateValidator(tt.args.config, tt.args.nodeID, tt.args.ip, tt.args.chainID, tt.args.valPubKey, tt.args.website, tt.args.details, tt.args.identity)
|
||||||
|
require.Equal(t, tt.args.website, viper.GetString(cli.FlagWebsite))
|
||||||
|
require.Equal(t, tt.args.details, viper.GetString(cli.FlagDetails))
|
||||||
|
require.Equal(t, tt.args.identity, viper.GetString(cli.FlagIdentity))
|
||||||
|
require.Equal(t, params.amount, viper.GetString(cli.FlagAmount))
|
||||||
|
require.Equal(t, params.commissionRate, viper.GetString(cli.FlagCommissionRate))
|
||||||
|
require.Equal(t, params.commissionMaxRate, viper.GetString(cli.FlagCommissionMaxRate))
|
||||||
|
require.Equal(t, params.commissionMaxChangeRate, viper.GetString(cli.FlagCommissionMaxChangeRate))
|
||||||
|
require.Equal(t, params.minSelfDelegation, viper.GetString(cli.FlagMinSelfDelegation))
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []testcase{
|
||||||
|
{"No parameters", args{ctx.Config, "X", "0.0.0.0", "chainId", valPubKey, "", "", ""}},
|
||||||
|
{"Optional parameters fed", args{ctx.Config, "X", "0.0.0.0", "chainId", valPubKey, "cosmos.network", "details", "identity"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultParams := extraParams{defaultAmount, defaultCommissionRate, defaultCommissionMaxRate, defaultCommissionMaxChangeRate, defaultMinSelfDelegation}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Run(tt.name, func(t *testing.T) { runTest(t, tt, defaultParams) })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override default params
|
||||||
|
params := extraParams{"5stake", "1.0", "1.0", "1.0", "1.0"}
|
||||||
|
viper.Set(cli.FlagAmount, params.amount)
|
||||||
|
viper.Set(cli.FlagCommissionRate, params.commissionRate)
|
||||||
|
viper.Set(cli.FlagCommissionMaxRate, params.commissionMaxRate)
|
||||||
|
viper.Set(cli.FlagCommissionMaxChangeRate, params.commissionMaxChangeRate)
|
||||||
|
viper.Set(cli.FlagMinSelfDelegation, params.minSelfDelegation)
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) { runTest(t, tt, params) })
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DONTCOVER
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
|
func main() {
|
||||||
|
f, err := os.Open(os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
h := sha256.New()
|
||||||
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%x", h.Sum(nil))
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
# sdkch
|
||||||
|
Simple tool to maintain modular changelogs
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sdkch -help
|
||||||
|
usage: sdkch [-d directory] [-prune] command
|
||||||
|
|
||||||
|
Maintain unreleased changelog entries in a modular fashion.
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
add section stanza [message] Add an entry file.
|
||||||
|
If message is empty, start the editor to edit
|
||||||
|
the message.
|
||||||
|
generate [version] Generate a changelog in Markdown format and print
|
||||||
|
it to STDOUT. version defaults to UNRELEASED.
|
||||||
|
|
||||||
|
Sections Stanzas
|
||||||
|
--- ---
|
||||||
|
breaking gaia
|
||||||
|
features gaiacli
|
||||||
|
improvements gaiarest
|
||||||
|
bugfixes sdk
|
||||||
|
tendermint
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
-d string
|
||||||
|
entry files directory (default "/home/alessio/work/tendermint/src/github.com/cosmos/cosmos-sdk/.pending")
|
||||||
|
-prune
|
||||||
|
prune old entries after changelog generation
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add a new entry
|
||||||
|
|
||||||
|
You can either drop a text file in the appropriate directory or use the `add` command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sdkch add features gaiacli '#3452 New cool gaiacli command'
|
||||||
|
```
|
||||||
|
|
||||||
|
If no message is provided, a new entry file is opened in an editor is started
|
||||||
|
|
||||||
|
## Generate the full changelog
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sdkch generate v0.30.0
|
||||||
|
```
|
||||||
|
|
||||||
|
The `-prune` flag would remove the old entry files after the changelog is generated.
|
|
@ -0,0 +1,378 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
entriesDirName = ".pending"
|
||||||
|
ghLinkPattern = `#([0-9]+)`
|
||||||
|
ghLinkExpanded = `[\#$1](https://github.com/cosmos/cosmos-sdk/issues/$1)`
|
||||||
|
maxEntryFilenameLength = 20
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
progName string
|
||||||
|
verboseLog *log.Logger
|
||||||
|
|
||||||
|
entriesDir string
|
||||||
|
verboseLogging bool
|
||||||
|
|
||||||
|
// sections name-title map
|
||||||
|
sections = map[string]string{
|
||||||
|
"breaking": "Breaking Changes",
|
||||||
|
"features": "New features",
|
||||||
|
"improvements": "Improvements",
|
||||||
|
"bugfixes": "Bugfixes",
|
||||||
|
}
|
||||||
|
// stanzas name-title map
|
||||||
|
stanzas = map[string]string{
|
||||||
|
"gaia": "Gaia",
|
||||||
|
"gaiacli": "Gaia CLI",
|
||||||
|
"gaiarest": "Gaia REST API",
|
||||||
|
"sdk": "SDK",
|
||||||
|
"tendermint": "Tendermint",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
progName = filepath.Base(os.Args[0])
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.StringVar(&entriesDir, "d", filepath.Join(cwd, entriesDirName), "entry files directory")
|
||||||
|
flag.BoolVar(&verboseLogging, "v", false, "enable verbose logging")
|
||||||
|
flag.Usage = printUsage
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
logPrefix := fmt.Sprintf("%s: ", filepath.Base(progName))
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetPrefix(logPrefix)
|
||||||
|
flag.Parse()
|
||||||
|
verboseLog = log.New(ioutil.Discard, "", 0)
|
||||||
|
if verboseLogging {
|
||||||
|
verboseLog.SetOutput(os.Stderr)
|
||||||
|
verboseLog.SetPrefix(logPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
if flag.NArg() < 1 {
|
||||||
|
errInsufficientArgs()
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := flag.Arg(0)
|
||||||
|
switch cmd {
|
||||||
|
|
||||||
|
case "add":
|
||||||
|
if flag.NArg() < 3 {
|
||||||
|
errInsufficientArgs()
|
||||||
|
}
|
||||||
|
if flag.NArg() > 4 {
|
||||||
|
errTooManyArgs()
|
||||||
|
}
|
||||||
|
sectionDir, stanzaDir := flag.Arg(1), flag.Arg(2)
|
||||||
|
validateSectionStanzaDirs(sectionDir, stanzaDir)
|
||||||
|
if flag.NArg() == 4 {
|
||||||
|
addSinglelineEntryFile(sectionDir, stanzaDir, strings.TrimSpace(flag.Arg(3)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addEntryFile(sectionDir, stanzaDir)
|
||||||
|
|
||||||
|
case "generate":
|
||||||
|
version := "UNRELEASED"
|
||||||
|
if flag.NArg() > 1 {
|
||||||
|
version = strings.Join(flag.Args()[1:], " ")
|
||||||
|
}
|
||||||
|
generateChangelog(version)
|
||||||
|
|
||||||
|
case "prune":
|
||||||
|
pruneEmptyDirectories()
|
||||||
|
|
||||||
|
default:
|
||||||
|
unknownCommand(cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addSinglelineEntryFile(sectionDir, stanzaDir, message string) {
|
||||||
|
filename := filepath.Join(
|
||||||
|
filepath.Join(entriesDir, sectionDir, stanzaDir),
|
||||||
|
generateFileName(message),
|
||||||
|
)
|
||||||
|
|
||||||
|
writeEntryFile(filename, []byte(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
func addEntryFile(sectionDir, stanzaDir string) {
|
||||||
|
bs := readUserInput()
|
||||||
|
firstLine := strings.TrimSpace(strings.Split(string(bs), "\n")[0])
|
||||||
|
filename := filepath.Join(
|
||||||
|
filepath.Join(entriesDir, sectionDir, stanzaDir),
|
||||||
|
generateFileName(firstLine),
|
||||||
|
)
|
||||||
|
|
||||||
|
writeEntryFile(filename, bs)
|
||||||
|
}
|
||||||
|
|
||||||
|
var filenameInvalidChars = regexp.MustCompile(`[^a-zA-Z0-9-_]`)
|
||||||
|
|
||||||
|
func generateFileName(line string) string {
|
||||||
|
var chunks []string
|
||||||
|
subsWithInvalidCharsRemoved := strings.Split(filenameInvalidChars.ReplaceAllString(line, " "), " ")
|
||||||
|
for _, sub := range subsWithInvalidCharsRemoved {
|
||||||
|
sub = strings.TrimSpace(sub)
|
||||||
|
if len(sub) != 0 {
|
||||||
|
chunks = append(chunks, sub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := strings.Join(chunks, "-")
|
||||||
|
return ret[:int(math.Min(float64(len(ret)), float64(maxEntryFilenameLength)))]
|
||||||
|
}
|
||||||
|
|
||||||
|
func directoryContents(dirPath string) []os.FileInfo {
|
||||||
|
contents, err := ioutil.ReadDir(dirPath)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
log.Fatalf("couldn't read directory %s: %v", dirPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(contents) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out hidden files
|
||||||
|
newContents := contents[:0]
|
||||||
|
for _, f := range contents {
|
||||||
|
if f.Name()[0] != '.' { // skip hidden files
|
||||||
|
newContents = append(newContents, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := len(newContents); i < len(contents); i++ {
|
||||||
|
contents[i] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return newContents
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateChangelog(version string) {
|
||||||
|
fmt.Printf("# %s\n\n", version)
|
||||||
|
for sectionDir, sectionTitle := range sections {
|
||||||
|
sectionTitlePrinted := false
|
||||||
|
for stanzaDir, stanzaTitle := range stanzas {
|
||||||
|
path := filepath.Join(entriesDir, sectionDir, stanzaDir)
|
||||||
|
files := directoryContents(path)
|
||||||
|
if len(files) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sectionTitlePrinted {
|
||||||
|
fmt.Printf("## %s\n\n", sectionTitle)
|
||||||
|
sectionTitlePrinted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("### %s\n\n", stanzaTitle)
|
||||||
|
for _, f := range files {
|
||||||
|
verboseLog.Println("processing", f.Name())
|
||||||
|
filename := filepath.Join(path, f.Name())
|
||||||
|
if err := indentAndPrintFile(filename); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pruneEmptyDirectories() {
|
||||||
|
for sectionDir, _ := range sections {
|
||||||
|
for stanzaDir, _ := range stanzas {
|
||||||
|
mustPruneDirIfEmpty(filepath.Join(entriesDir, sectionDir, stanzaDir))
|
||||||
|
}
|
||||||
|
mustPruneDirIfEmpty(filepath.Join(entriesDir, sectionDir))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
|
func indentAndPrintFile(filename string) error {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
firstLine := true
|
||||||
|
ghLinkRe := regexp.MustCompile(ghLinkPattern)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.TrimSpace(scanner.Text())
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
linkified := ghLinkRe.ReplaceAllString(line, ghLinkExpanded)
|
||||||
|
if firstLine {
|
||||||
|
fmt.Printf("* %s\n", linkified)
|
||||||
|
firstLine = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(" %s\n", linkified)
|
||||||
|
}
|
||||||
|
|
||||||
|
return scanner.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
|
func writeEntryFile(filename string, bs []byte) {
|
||||||
|
if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
outFile, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
|
||||||
|
if _, err := outFile.Write(bs); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Unreleased changelog entry written to: %s\n", filename)
|
||||||
|
log.Println("To modify this entry please edit or delete the above file directly.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateSectionStanzaDirs(sectionDir, stanzaDir string) {
|
||||||
|
if _, ok := sections[sectionDir]; !ok {
|
||||||
|
log.Fatalf("invalid section -- %s", sectionDir)
|
||||||
|
}
|
||||||
|
if _, ok := stanzas[stanzaDir]; !ok {
|
||||||
|
log.Fatalf("invalid stanza -- %s", stanzaDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
|
func readUserInput() []byte {
|
||||||
|
tempfilename, err := launchUserEditor()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("couldn't open an editor: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(tempfilename)
|
||||||
|
bs, err := ioutil.ReadFile(tempfilename)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
return bs
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
|
func launchUserEditor() (string, error) {
|
||||||
|
editor, err := exec.LookPath("editor")
|
||||||
|
if err != nil {
|
||||||
|
editor = ""
|
||||||
|
}
|
||||||
|
if editor == "" {
|
||||||
|
editor = os.Getenv("VISUAL")
|
||||||
|
}
|
||||||
|
if editor == "" {
|
||||||
|
editor = os.Getenv("EDITOR")
|
||||||
|
}
|
||||||
|
if editor == "" {
|
||||||
|
return "", errors.New("no editor set, make sure that either " +
|
||||||
|
"VISUAL or EDITOR variables is set and pointing to a correct editor")
|
||||||
|
}
|
||||||
|
|
||||||
|
tempfile, err := ioutil.TempFile("", "sdkch_*")
|
||||||
|
tempfilename := tempfile.Name()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
tempfile.Close()
|
||||||
|
|
||||||
|
cmd := exec.Command(editor, tempfilename)
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
os.Remove(tempfilename)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo, err := os.Stat(tempfilename)
|
||||||
|
if err != nil {
|
||||||
|
os.Remove(tempfilename)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if fileInfo.Size() == 0 {
|
||||||
|
log.Fatal("aborting due to empty message")
|
||||||
|
}
|
||||||
|
|
||||||
|
return tempfilename, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustPruneDirIfEmpty(path string) {
|
||||||
|
if contents := directoryContents(path); len(contents) == 0 {
|
||||||
|
if err := os.Remove(path); err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println(path, "removed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printUsage() {
|
||||||
|
usageText := fmt.Sprintf(`usage: %s [-d directory] [-v] command
|
||||||
|
|
||||||
|
Maintain unreleased changelog entries in a modular fashion.
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
add [section] [stanza] [message] Add an entry file. If message is empty, start
|
||||||
|
the editor to edit the message.
|
||||||
|
generate [version] Generate a changelog in Markdown format and print
|
||||||
|
it to STDOUT. version defaults to UNRELEASED.
|
||||||
|
prune Delete empty sub-directories recursively.
|
||||||
|
|
||||||
|
Sections Stanzas
|
||||||
|
--- ---
|
||||||
|
breaking gaia
|
||||||
|
features gaiacli
|
||||||
|
improvements gaiarest
|
||||||
|
bugfixes sdk
|
||||||
|
tendermint
|
||||||
|
`, progName)
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\nFlags:\n", usageText)
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
func errInsufficientArgs() {
|
||||||
|
log.Println("insufficient arguments")
|
||||||
|
printUsage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func errTooManyArgs() {
|
||||||
|
log.Println("too many arguments")
|
||||||
|
printUsage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unknownCommand(cmd string) {
|
||||||
|
log.Fatalf("unknown command -- '%s'\nTry '%s -help' for more information.", cmd, progName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONTCOVER
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def init_default_argument_parser(prog_desc, default_chain_id, default_start_time):
|
||||||
|
parser = argparse.ArgumentParser(description=prog_desc)
|
||||||
|
parser.add_argument(
|
||||||
|
'exported_genesis',
|
||||||
|
help='exported genesis.json file',
|
||||||
|
type=argparse.FileType('r'), default=sys.stdin,
|
||||||
|
)
|
||||||
|
parser.add_argument('--chain-id', type=str, default=default_chain_id)
|
||||||
|
parser.add_argument('--start-time', type=str, default=default_start_time)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main(argument_parser, process_genesis_func):
|
||||||
|
args = argument_parser.parse_args()
|
||||||
|
if args.chain_id.strip() == '':
|
||||||
|
sys.exit('chain-id required')
|
||||||
|
|
||||||
|
genesis = json.loads(args.exported_genesis.read())
|
||||||
|
|
||||||
|
print(json.dumps(process_genesis_func(
|
||||||
|
genesis=genesis, parsed_args=args,), indent=True))
|
|
@ -0,0 +1,45 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import lib
|
||||||
|
|
||||||
|
|
||||||
|
def process_raw_genesis(genesis, parsed_args):
|
||||||
|
# update genesis with breaking changes
|
||||||
|
genesis['consensus_params']['block'] = genesis['consensus_params']['block_size']
|
||||||
|
del genesis['consensus_params']['block_size']
|
||||||
|
|
||||||
|
genesis['app_state']['crisis'] = {
|
||||||
|
'constant_fee': {
|
||||||
|
'amount': '1333000000', # ~$5,000 worth of uatoms
|
||||||
|
'denom': 'uatom',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# default tm value
|
||||||
|
genesis['consensus_params']['block']['time_iota_ms'] = '1000'
|
||||||
|
|
||||||
|
# proposal #1 updates
|
||||||
|
genesis['app_state']['mint']['params']['blocks_per_year'] = '4855015'
|
||||||
|
|
||||||
|
# proposal #2 updates
|
||||||
|
genesis['consensus_params']['block']['max_gas'] = '2000000'
|
||||||
|
genesis['consensus_params']['block']['max_bytes'] = '200000'
|
||||||
|
|
||||||
|
# enable transfers
|
||||||
|
genesis['app_state']['bank']['send_enabled'] = True
|
||||||
|
genesis['app_state']['distr']['withdraw_addr_enabled'] = True
|
||||||
|
|
||||||
|
# Set new chain ID and genesis start time
|
||||||
|
genesis['chain_id'] = parsed_args.chain_id.strip()
|
||||||
|
genesis['genesis_time'] = parsed_args.start_time
|
||||||
|
|
||||||
|
return genesis
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = lib.init_default_argument_parser(
|
||||||
|
prog_desc='Convert genesis.json from v0.33.x to v0.34.0',
|
||||||
|
default_chain_id='cosmoshub-n',
|
||||||
|
default_start_time='2019-02-11T12:00:00Z',
|
||||||
|
)
|
||||||
|
lib.main(parser, process_raw_genesis)
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
installer="$(mktemp)"
|
||||||
|
trap "rm -f ${installer}" EXIT
|
||||||
|
|
||||||
|
GOBIN="${1}"
|
||||||
|
VERSION="${2}"
|
||||||
|
HASHSUM="${3}"
|
||||||
|
CURL="$(which curl)"
|
||||||
|
GOSUM="$(which gosum)"
|
||||||
|
|
||||||
|
echo "Downloading golangci-lint ${VERSION} installer ..." >&2
|
||||||
|
"${CURL}" -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/${VERSION}/install.sh" > "${installer}"
|
||||||
|
|
||||||
|
echo "Checking hashsum ..." >&2
|
||||||
|
[ "${HASHSUM}" = "$(${GOSUM} ${installer})" ]
|
||||||
|
chmod +x "${installer}"
|
||||||
|
|
||||||
|
echo "Launching installer ..." >&2
|
||||||
|
exec "${installer}" -d -b "${GOBIN}" "${VERSION}"
|
|
@ -0,0 +1,344 @@
|
||||||
|
package keys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/crypto/keys/hd"
|
||||||
|
"github.com/cosmos/cosmos-sdk/tests"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
kb := New("keybasename", dir)
|
||||||
|
lazykb, ok := kb.(lazyKeybase)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, lazykb.name, "keybasename")
|
||||||
|
require.Equal(t, lazykb.dir, dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLazyKeyManagement(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
kb := New("keybasename", dir)
|
||||||
|
|
||||||
|
algo := Secp256k1
|
||||||
|
n1, n2, n3 := "personal", "business", "other"
|
||||||
|
p1, p2 := "1234", "really-secure!@#$"
|
||||||
|
|
||||||
|
// Check empty state
|
||||||
|
l, err := kb.List()
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Empty(t, l)
|
||||||
|
|
||||||
|
_, _, err = kb.CreateMnemonic(n1, English, p1, Ed25519)
|
||||||
|
require.Error(t, err, "ed25519 keys are currently not supported by keybase")
|
||||||
|
|
||||||
|
// create some keys
|
||||||
|
_, err = kb.Get(n1)
|
||||||
|
require.Error(t, err)
|
||||||
|
i, _, err := kb.CreateMnemonic(n1, English, p1, algo)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, n1, i.GetName())
|
||||||
|
_, _, err = kb.CreateMnemonic(n2, English, p2, algo)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// we can get these keys
|
||||||
|
i2, err := kb.Get(n2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = kb.Get(n3)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
_, err = kb.GetByAddress(accAddr(i2))
|
||||||
|
require.NoError(t, err)
|
||||||
|
addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t")
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = kb.GetByAddress(addr)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
|
||||||
|
// list shows them in order
|
||||||
|
keyS, err := kb.List()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(keyS))
|
||||||
|
// note these are in alphabetical order
|
||||||
|
require.Equal(t, n2, keyS[0].GetName())
|
||||||
|
require.Equal(t, n1, keyS[1].GetName())
|
||||||
|
require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey())
|
||||||
|
|
||||||
|
// deleting a key removes it
|
||||||
|
err = kb.Delete("bad name", "foo", false)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
err = kb.Delete(n1, p1, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
keyS, err = kb.List()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(keyS))
|
||||||
|
_, err = kb.Get(n1)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
// create an offline key
|
||||||
|
o1 := "offline"
|
||||||
|
priv1 := ed25519.GenPrivKey()
|
||||||
|
pub1 := priv1.PubKey()
|
||||||
|
i, err = kb.CreateOffline(o1, pub1)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, pub1, i.GetPubKey())
|
||||||
|
require.Equal(t, o1, i.GetName())
|
||||||
|
keyS, err = kb.List()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(keyS))
|
||||||
|
|
||||||
|
// delete the offline key
|
||||||
|
err = kb.Delete(o1, "", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
keyS, err = kb.List()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(keyS))
|
||||||
|
|
||||||
|
// addr cache gets nuked - and test skip flag
|
||||||
|
err = kb.Delete(n2, "", true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLazySignVerify(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
kb := New("keybasename", dir)
|
||||||
|
algo := Secp256k1
|
||||||
|
|
||||||
|
n1, n2, n3 := "some dude", "a dudette", "dude-ish"
|
||||||
|
p1, p2, p3 := "1234", "foobar", "foobar"
|
||||||
|
|
||||||
|
// create two users and get their info
|
||||||
|
i1, _, err := kb.CreateMnemonic(n1, English, p1, algo)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
i2, _, err := kb.CreateMnemonic(n2, English, p2, algo)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
// Import a public key
|
||||||
|
armor, err := kb.ExportPubKey(n2)
|
||||||
|
require.Nil(t, err)
|
||||||
|
kb.ImportPubKey(n3, armor)
|
||||||
|
i3, err := kb.Get(n3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, i3.GetName(), n3)
|
||||||
|
|
||||||
|
// let's try to sign some messages
|
||||||
|
d1 := []byte("my first message")
|
||||||
|
d2 := []byte("some other important info!")
|
||||||
|
d3 := []byte("feels like I forgot something...")
|
||||||
|
|
||||||
|
// try signing both data with both ..
|
||||||
|
s11, pub1, err := kb.Sign(n1, p1, d1)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, i1.GetPubKey(), pub1)
|
||||||
|
|
||||||
|
s12, pub1, err := kb.Sign(n1, p1, d2)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, i1.GetPubKey(), pub1)
|
||||||
|
|
||||||
|
s21, pub2, err := kb.Sign(n2, p2, d1)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, i2.GetPubKey(), pub2)
|
||||||
|
|
||||||
|
s22, pub2, err := kb.Sign(n2, p2, d2)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, i2.GetPubKey(), pub2)
|
||||||
|
|
||||||
|
// let's try to validate and make sure it only works when everything is proper
|
||||||
|
cases := []struct {
|
||||||
|
key crypto.PubKey
|
||||||
|
data []byte
|
||||||
|
sig []byte
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
// proper matches
|
||||||
|
{i1.GetPubKey(), d1, s11, true},
|
||||||
|
// change data, pubkey, or signature leads to fail
|
||||||
|
{i1.GetPubKey(), d2, s11, false},
|
||||||
|
{i2.GetPubKey(), d1, s11, false},
|
||||||
|
{i1.GetPubKey(), d1, s21, false},
|
||||||
|
// make sure other successes
|
||||||
|
{i1.GetPubKey(), d2, s12, true},
|
||||||
|
{i2.GetPubKey(), d1, s21, true},
|
||||||
|
{i2.GetPubKey(), d2, s22, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
valid := tc.key.VerifyBytes(tc.data, tc.sig)
|
||||||
|
require.Equal(t, tc.valid, valid, "%d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now try to sign data with a secret-less key
|
||||||
|
_, _, err = kb.Sign(n3, p3, d3)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLazyExportImport(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
kb := New("keybasename", dir)
|
||||||
|
|
||||||
|
info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, info.GetName(), "john")
|
||||||
|
|
||||||
|
john, err := kb.Get("john")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, info.GetName(), "john")
|
||||||
|
johnAddr := info.GetPubKey().Address()
|
||||||
|
|
||||||
|
armor, err := kb.Export("john")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = kb.Import("john2", armor)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
john2, err := kb.Get("john2")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, john.GetPubKey().Address(), johnAddr)
|
||||||
|
require.Equal(t, john.GetName(), "john")
|
||||||
|
require.Equal(t, john, john2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLazyExportImportPubKey(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
kb := New("keybasename", dir)
|
||||||
|
|
||||||
|
// CreateMnemonic a private-public key pair and ensure consistency
|
||||||
|
notPasswd := "n9y25ah7"
|
||||||
|
info, _, err := kb.CreateMnemonic("john", English, notPasswd, Secp256k1)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.NotEqual(t, info, "")
|
||||||
|
require.Equal(t, info.GetName(), "john")
|
||||||
|
addr := info.GetPubKey().Address()
|
||||||
|
john, err := kb.Get("john")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, john.GetName(), "john")
|
||||||
|
require.Equal(t, john.GetPubKey().Address(), addr)
|
||||||
|
|
||||||
|
// Export the public key only
|
||||||
|
armor, err := kb.ExportPubKey("john")
|
||||||
|
require.NoError(t, err)
|
||||||
|
// Import it under a different name
|
||||||
|
err = kb.ImportPubKey("john-pubkey-only", armor)
|
||||||
|
require.NoError(t, err)
|
||||||
|
// Ensure consistency
|
||||||
|
john2, err := kb.Get("john-pubkey-only")
|
||||||
|
require.NoError(t, err)
|
||||||
|
// Compare the public keys
|
||||||
|
require.True(t, john.GetPubKey().Equals(john2.GetPubKey()))
|
||||||
|
// Ensure the original key hasn't changed
|
||||||
|
john, err = kb.Get("john")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, john.GetPubKey().Address(), addr)
|
||||||
|
require.Equal(t, john.GetName(), "john")
|
||||||
|
|
||||||
|
// Ensure keys cannot be overwritten
|
||||||
|
err = kb.ImportPubKey("john-pubkey-only", armor)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLazyExportPrivateKeyObject(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
kb := New("keybasename", dir)
|
||||||
|
|
||||||
|
info, _, err := kb.CreateMnemonic("john", English, "secretcpw", Secp256k1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, info.GetName(), "john")
|
||||||
|
|
||||||
|
// export private key object
|
||||||
|
_, err = kb.ExportPrivateKeyObject("john", "invalid")
|
||||||
|
require.NotNil(t, err, "%+v", err)
|
||||||
|
exported, err := kb.ExportPrivateKeyObject("john", "secretcpw")
|
||||||
|
require.Nil(t, err, "%+v", err)
|
||||||
|
require.True(t, exported.PubKey().Equals(info.GetPubKey()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLazyAdvancedKeyManagement(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
kb := New("keybasename", dir)
|
||||||
|
|
||||||
|
algo := Secp256k1
|
||||||
|
n1, n2 := "old-name", "new name"
|
||||||
|
p1, p2 := "1234", "foobar"
|
||||||
|
|
||||||
|
// make sure key works with initial password
|
||||||
|
_, _, err := kb.CreateMnemonic(n1, English, p1, algo)
|
||||||
|
require.Nil(t, err, "%+v", err)
|
||||||
|
assertPassword(t, kb, n1, p1, p2)
|
||||||
|
|
||||||
|
// update password requires the existing password
|
||||||
|
getNewpass := func() (string, error) { return p2, nil }
|
||||||
|
err = kb.Update(n1, "jkkgkg", getNewpass)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
assertPassword(t, kb, n1, p1, p2)
|
||||||
|
|
||||||
|
// then it changes the password when correct
|
||||||
|
err = kb.Update(n1, p1, getNewpass)
|
||||||
|
require.NoError(t, err)
|
||||||
|
// p2 is now the proper one!
|
||||||
|
assertPassword(t, kb, n1, p2, p1)
|
||||||
|
|
||||||
|
// exporting requires the proper name and passphrase
|
||||||
|
_, err = kb.Export(n1 + ".notreal")
|
||||||
|
require.NotNil(t, err)
|
||||||
|
_, err = kb.Export(" " + n1)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
_, err = kb.Export(n1 + " ")
|
||||||
|
require.NotNil(t, err)
|
||||||
|
_, err = kb.Export("")
|
||||||
|
require.NotNil(t, err)
|
||||||
|
exported, err := kb.Export(n1)
|
||||||
|
require.Nil(t, err, "%+v", err)
|
||||||
|
|
||||||
|
// import succeeds
|
||||||
|
err = kb.Import(n2, exported)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// second import fails
|
||||||
|
err = kb.Import(n2, exported)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSeedPhrase verifies restoring from a seed phrase
|
||||||
|
func TestLazySeedPhrase(t *testing.T) {
|
||||||
|
dir, cleanup := tests.NewTestCaseDir(t)
|
||||||
|
defer cleanup()
|
||||||
|
kb := New("keybasename", dir)
|
||||||
|
|
||||||
|
algo := Secp256k1
|
||||||
|
n1, n2 := "lost-key", "found-again"
|
||||||
|
p1, p2 := "1234", "foobar"
|
||||||
|
|
||||||
|
// make sure key works with initial password
|
||||||
|
info, mnemonic, err := kb.CreateMnemonic(n1, English, p1, algo)
|
||||||
|
require.Nil(t, err, "%+v", err)
|
||||||
|
require.Equal(t, n1, info.GetName())
|
||||||
|
assert.NotEmpty(t, mnemonic)
|
||||||
|
|
||||||
|
// now, let us delete this key
|
||||||
|
err = kb.Delete(n1, p1, false)
|
||||||
|
require.Nil(t, err, "%+v", err)
|
||||||
|
_, err = kb.Get(n1)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
|
||||||
|
// let us re-create it from the mnemonic-phrase
|
||||||
|
params := *hd.NewFundraiserParams(0, 0)
|
||||||
|
newInfo, err := kb.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, n2, newInfo.GetName())
|
||||||
|
require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address())
|
||||||
|
require.Equal(t, info.GetPubKey(), newInfo.GetPubKey())
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package mintkey_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
|
"github.com/cosmos/cosmos-sdk/crypto/keys/mintkey"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
cryptoAmino "github.com/tendermint/tendermint/crypto/encoding/amino"
|
||||||
|
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestArmorUnarmorPrivKey(t *testing.T) {
|
||||||
|
priv := secp256k1.GenPrivKey()
|
||||||
|
armor := mintkey.EncryptArmorPrivKey(priv, "passphrase")
|
||||||
|
_, err := mintkey.UnarmorDecryptPrivKey(armor, "wrongpassphrase")
|
||||||
|
require.Error(t, err)
|
||||||
|
decrypted, err := mintkey.UnarmorDecryptPrivKey(armor, "passphrase")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, priv.Equals(decrypted))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArmorUnarmorPubKey(t *testing.T) {
|
||||||
|
// Select the encryption and storage for your cryptostore
|
||||||
|
cstore := keys.NewInMemory()
|
||||||
|
|
||||||
|
// Add keys and see they return in alphabetical order
|
||||||
|
info, _, err := cstore.CreateMnemonic("Bob", keys.English, "passphrase", keys.Secp256k1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
armor := mintkey.ArmorPubKeyBytes(info.GetPubKey().Bytes())
|
||||||
|
pubBytes, err := mintkey.UnarmorPubKeyBytes(armor)
|
||||||
|
require.NoError(t, err)
|
||||||
|
pub, err := cryptoAmino.PubKeyFromBytes(pubBytes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, pub.Equals(info.GetPubKey()))
|
||||||
|
}
|
|
@ -34,21 +34,22 @@ module.exports = {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Gaia",
|
title: "Cosmos Hub",
|
||||||
collapsable: true,
|
collapsable: true,
|
||||||
children: [
|
children: [
|
||||||
"/gaia/what-is-gaia",
|
"/cosmos-hub/what-is-gaia",
|
||||||
"/gaia/installation",
|
"/cosmos-hub/installation",
|
||||||
"/gaia/join-mainnet",
|
"/cosmos-hub/join-mainnet",
|
||||||
"/gaia/validators/validator-setup",
|
"/cosmos-hub/validators/validator-setup",
|
||||||
"/gaia/validators/overview",
|
"/cosmos-hub/validators/overview",
|
||||||
"/gaia/validators/security",
|
"/cosmos-hub/validators/security",
|
||||||
"/gaia/validators/validator-faq",
|
"/cosmos-hub/validators/validator-faq",
|
||||||
"/gaia/delegator-guide-cli",
|
"/cosmos-hub/delegator-guide-cli",
|
||||||
"/gaia/ledger",
|
"/cosmos-hub/genesis",
|
||||||
"/gaia/gaiacli",
|
"/cosmos-hub/ledger",
|
||||||
"/gaia/join-testnet",
|
"/cosmos-hub/gaiacli",
|
||||||
"/gaia/deploy-testnet"
|
"/cosmos-hub/join-testnet",
|
||||||
|
"/cosmos-hub/deploy-testnet"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -95,7 +95,7 @@ then navigate to localhost:8080 in your browser.
|
||||||
|
|
||||||
## Build RPC Docs
|
## Build RPC Docs
|
||||||
|
|
||||||
First, run `make get_tools` from the root of repo, to install the swagger-ui tool.
|
First, run `make tools` from the root of repo, to install the swagger-ui tool.
|
||||||
|
|
||||||
Then, edit the `swagger.yaml` manually; it is found [here](https://github.com/cosmos/cosmos-sdk/blob/develop/client/lcd/swagger-ui/swagger.yaml)
|
Then, edit the `swagger.yaml` manually; it is found [here](https://github.com/cosmos/cosmos-sdk/blob/develop/client/lcd/swagger-ui/swagger.yaml)
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ When a validator wishes to withdraw their transaction fees it must send
|
||||||
triggered each with any change in individual delegations, such as an unbond,
|
triggered each with any change in individual delegations, such as an unbond,
|
||||||
redelegation, or delegation of additional tokens to a specific validator. This
|
redelegation, or delegation of additional tokens to a specific validator. This
|
||||||
transaction withdraws the validators commission rewards, as well as any rewards
|
transaction withdraws the validators commission rewards, as well as any rewards
|
||||||
earning on their self-delegation.
|
earning on their self-delegation.
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type TxWithdrawValidator struct {
|
type TxWithdrawValidator struct {
|
||||||
|
|
|
@ -153,11 +153,11 @@ Along with the message, the Handler takes environmental information (a `Context`
|
||||||
All information necessary for processing a message should be available in the context.
|
All information necessary for processing a message should be available in the context.
|
||||||
|
|
||||||
Where is the KVStore in all of this? Access to the KVStore in a message handler is restricted by the Context via object-capability keys.
|
Where is the KVStore in all of this? Access to the KVStore in a message handler is restricted by the Context via object-capability keys.
|
||||||
Only handlers which were given explict access to a store's key will be able to access that store during message processsing.
|
Only handlers which were given explicit access to a store's key will be able to access that store during message processsing.
|
||||||
|
|
||||||
### Context
|
### Context
|
||||||
|
|
||||||
The SDK uses a `Context` to propogate common information across functions.
|
The SDK uses a `Context` to propagate common information across functions.
|
||||||
Most importantly, the `Context` restricts access to KVStores based on object-capability keys.
|
Most importantly, the `Context` restricts access to KVStores based on object-capability keys.
|
||||||
Only handlers which have been given explicit access to a key will be able to access the corresponding store.
|
Only handlers which have been given explicit access to a key will be able to access the corresponding store.
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ func newFooHandler(key sdk.StoreKey) sdk.Handler {
|
||||||
`Context` is modeled after the Golang
|
`Context` is modeled after the Golang
|
||||||
[context.Context](https://golang.org/pkg/context/), which has
|
[context.Context](https://golang.org/pkg/context/), which has
|
||||||
become ubiquitous in networking middleware and routing applications as a means
|
become ubiquitous in networking middleware and routing applications as a means
|
||||||
to easily propogate request context through handler functions.
|
to easily propagate request context through handler functions.
|
||||||
Many methods on SDK objects receive a context as the first argument.
|
Many methods on SDK objects receive a context as the first argument.
|
||||||
|
|
||||||
The Context also contains the
|
The Context also contains the
|
||||||
|
|
|
@ -19,18 +19,4 @@ gaiacli rest-server --chain-id=test \
|
||||||
--trust-node=false
|
--trust-node=false
|
||||||
```
|
```
|
||||||
|
|
||||||
The server listens on HTTP by default. You can enable the secure layer by adding the `--tls` flag.
|
|
||||||
By default a self-signed certificate will be generated and its fingerprint printed out. You can
|
|
||||||
configure the server to use a SSL certificate by passing the certificate and key files via the
|
|
||||||
`--ssl-certfile` and `--ssl-keyfile` flags:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
gaiacli rest-server --chain-id=test \
|
|
||||||
--laddr=tcp://localhost:1317 \
|
|
||||||
--node tcp://localhost:26657 \
|
|
||||||
--trust-node=false \
|
|
||||||
--tls \
|
|
||||||
--ssl-certfile=mycert.pem --ssl-keyfile=mykey.key
|
|
||||||
```
|
|
||||||
|
|
||||||
For more information about the Gaia-Lite RPC, see the [swagger documentation](https://cosmos.network/rpc/)
|
For more information about the Gaia-Lite RPC, see the [swagger documentation](https://cosmos.network/rpc/)
|
||||||
|
|
|
@ -121,3 +121,69 @@ mechanism for instance.
|
||||||
In order to generate an unsigned transaction (example with
|
In order to generate an unsigned transaction (example with
|
||||||
[coin transfer](https://cosmos.network/rpc/#/ICS20/post_bank_accounts__address__transfers)),
|
[coin transfer](https://cosmos.network/rpc/#/ICS20/post_bank_accounts__address__transfers)),
|
||||||
you need to use the field `generate_only` in the body of `base_req`.
|
you need to use the field `generate_only` in the body of `base_req`.
|
||||||
|
|
||||||
|
## Cosmos SDK Transaction Signing
|
||||||
|
|
||||||
|
Cosmos SDK transaction signing is a fairly simple process.
|
||||||
|
|
||||||
|
Every Cosmos SDK transaction has a canonical JSON representation. The `gaiacli`
|
||||||
|
and Stargate REST interfaces provide canonical JSON representations of transactions
|
||||||
|
and their "broadcast" functions will provide compact Amino (a protobuf-like wire format)
|
||||||
|
encoding translations.
|
||||||
|
|
||||||
|
Things to know when signing messages:
|
||||||
|
|
||||||
|
The format is as follows
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"account_number": XXX,
|
||||||
|
"chain_id": XXX,
|
||||||
|
"fee": XXX,
|
||||||
|
"sequence": XXX,
|
||||||
|
"memo": XXX,
|
||||||
|
"msgs": XXX
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The signer must supply `"chain_id"`, `"account number"` and `"sequence number"`.
|
||||||
|
|
||||||
|
The `"fee"`, `"msgs"` and `"memo"` fields will be supplied by the transaction
|
||||||
|
composer interface.
|
||||||
|
|
||||||
|
The `"account_number"` and `"sequence"` fields can be queried directly from the
|
||||||
|
blockchain or cached locally. Getting these numbers wrong, along with the chainID,
|
||||||
|
is a common cause of invalid signature error. You can load the mempool of a full
|
||||||
|
node or validator with a sequence of uncommitted transactions with incrementing
|
||||||
|
sequence numbers and it will mostly do the correct thing.
|
||||||
|
|
||||||
|
Before signing, all keys are lexicographically sorted and all white space is
|
||||||
|
removed from the JSON output.
|
||||||
|
|
||||||
|
The signature encoding is the 64-byte concatenation of ECDSArands (i.e. `r || s`),
|
||||||
|
where `s` is lexicographically less than its inverse in order to prevent malleability.
|
||||||
|
This is like Ethereum, but without the extra byte for PubKey recovery, since
|
||||||
|
Tendermint assumes the PubKey is always provided anyway.
|
||||||
|
|
||||||
|
Signatures and public key examples in a signed transaction:
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"type": "auth/StdTx",
|
||||||
|
"value": {
|
||||||
|
"msg": [...],
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"pub_key": {
|
||||||
|
"type": "tendermint/PubKeySecp256k1",
|
||||||
|
"value": XXX
|
||||||
|
},
|
||||||
|
"signature": XXX
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Once signatures are properly generated, insert the JSON into into the generated
|
||||||
|
transaction and then use the broadcast endpoint.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Gaia Documentation
|
# Cosmos Hub Documentation
|
||||||
|
|
||||||
Welcome to the `Gaia` docs. `Gaia` is the current name of the Cosmos SDK application for the Cosmos Hub.
|
Welcome to the documentation of the **Cosmos Hub application: `gaia`**.
|
||||||
|
|
||||||
## Join the Cosmos Hub Mainnet
|
## Join the Cosmos Hub Mainnet
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@ Welcome to the `Gaia` docs. `Gaia` is the current name of the Cosmos SDK applica
|
||||||
|
|
||||||
- [Join the testnet](./join-testnet.md)
|
- [Join the testnet](./join-testnet.md)
|
||||||
|
|
||||||
## Setup your own `gaia` testnet
|
## Setup Your Own `gaia` Testnet
|
||||||
|
|
||||||
- [Setup your own `gaia` testnet](./deploy-testnet.md)
|
- [Setup your own `gaia` testnet](./deploy-testnet.md)
|
||||||
|
|
||||||
## Additional resources
|
## Additional Resources
|
||||||
|
|
||||||
- [Intro to validators](./validators/overview.md)
|
- [Intro to validators](./validators/overview.md)
|
||||||
- [Validator FAQ](./validators/validator-faq.md)
|
- [Validator FAQ](./validators/validator-faq.md)
|
|
@ -27,22 +27,22 @@ of any kind.
|
||||||
|
|
||||||
Please exercise extreme caution!
|
Please exercise extreme caution!
|
||||||
|
|
||||||
## Table of contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Installing `gaiacli`](#installing-gaiacli)
|
- [Installing `gaiacli`](#installing-gaiacli)
|
||||||
- [Cosmos Accounts](#cosmos-accounts)
|
- [Cosmos Accounts](#cosmos-accounts)
|
||||||
+ [Restoring an account from the fundrasier](#restoring-an-account-from-the-fundraiser)
|
+ [Restoring an Account from the Fundraiser](#restoring-an-account-from-the-fundraiser)
|
||||||
+ [Creating an account](#creating-an-account)
|
+ [Creating an Account](#creating-an-account)
|
||||||
- [Accessing the Cosmos Hub network](#accessing-the-cosmos-hub-network)
|
- [Accessing the Cosmos Hub Network](#accessing-the-cosmos-hub-network)
|
||||||
+ [Running your own full-node](#running-your-own-full-node)
|
+ [Running Your Own Full-Node](#running-your-own-full-node)
|
||||||
+ [Connecting to a remote full-node](#connecting-to-a-remote-full-node)
|
+ [Connecting to a Remote Full-Node](#connecting-to-a-remote-full-node)
|
||||||
- [Setting up `gaiacli`](#setting-up-gaiacli)
|
- [Setting Up `gaiacli`](#setting-up-gaiacli)
|
||||||
- [Querying the state](#querying-the-state)
|
- [Querying the State](#querying-the-state)
|
||||||
- [Sending Transactions](#sending-transactions)
|
- [Sending Transactions](#sending-transactions)
|
||||||
+ [A note on gas and fees](#a-note-on-gas-and-fees)
|
+ [A Note on Gas and Fees](#a-note-on-gas-and-fees)
|
||||||
+ [Bonding Atoms and Withdrawing rewards](#bonding-atoms-and-withdrawing-rewards)
|
+ [Bonding Atoms and Withdrawing Rewards](#bonding-atoms-and-withdrawing-rewards)
|
||||||
+ [Participating in Governance](#participating-in-governance)
|
+ [Participating in Governance](#participating-in-governance)
|
||||||
+ [Signing transactions from an offline computer](#signing-transactions-from-an-offline-computer)
|
+ [Signing Transactions from an Offline Computer](#signing-transactions-from-an-offline-computer)
|
||||||
|
|
||||||
## Installing `gaiacli`
|
## Installing `gaiacli`
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ The funds stored in an account are controlled by the private key. This private k
|
||||||
|
|
||||||
The address is a public string with a human-readable prefix (e.g. `cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg`) that identifies your account. When someone wants to send you funds, they send it to your address. It is computationally infeasible to find the private key associated with a given address.
|
The address is a public string with a human-readable prefix (e.g. `cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg`) that identifies your account. When someone wants to send you funds, they send it to your address. It is computationally infeasible to find the private key associated with a given address.
|
||||||
|
|
||||||
### Restoring an account from the fundraiser
|
### Restoring an Account from the Fundraiser
|
||||||
|
|
||||||
::: tip
|
::: tip
|
||||||
*NOTE: This section only concerns fundraiser participants*
|
*NOTE: This section only concerns fundraiser participants*
|
||||||
|
@ -117,7 +117,7 @@ The address is a public string with a human-readable prefix (e.g. `cosmos10snjt8
|
||||||
|
|
||||||
If you participated in the fundraiser, you should be in possession of a 12-words mnemonic. Newly generated mnemonics use 24 words, but 12-word mnemonics are also compatible with all the Cosmos tools.
|
If you participated in the fundraiser, you should be in possession of a 12-words mnemonic. Newly generated mnemonics use 24 words, but 12-word mnemonics are also compatible with all the Cosmos tools.
|
||||||
|
|
||||||
#### On a ledger device
|
#### On a Ledger Device
|
||||||
|
|
||||||
At the core of a ledger device, there is a mnemonic used to generate accounts on multiple blockchains (including the Cosmos Hub). Usually, you will create a new mnemonic when you initialize your ledger device. However, it is possible to tell the ledger device to use a mnemonic provided by the user instead. Let us go ahead and see how you can input the mnemonic you obtained during the fundraiser as the seed of your ledger device.
|
At the core of a ledger device, there is a mnemonic used to generate accounts on multiple blockchains (including the Cosmos Hub). Usually, you will create a new mnemonic when you initialize your ledger device. However, it is possible to tell the ledger device to use a mnemonic provided by the user instead. Let us go ahead and see how you can input the mnemonic you obtained during the fundraiser as the seed of your ledger device.
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ Your ledger is now correctly set up with your fundraiser mnemonic! Do not lose t
|
||||||
|
|
||||||
Next, click [here](#using-a-ledger-device) to learn how to generate an account.
|
Next, click [here](#using-a-ledger-device) to learn how to generate an account.
|
||||||
|
|
||||||
#### On a computer
|
#### On a Computer
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
**NOTE: It is more secure to perform this action on an offline computer**
|
**NOTE: It is more secure to perform this action on an offline computer**
|
||||||
|
@ -155,11 +155,11 @@ You will be prompted to input a passphrase that is used to encrypt the private k
|
||||||
- `<yourKeyName>` is the name of the account. It is a reference to the account number used to derive the key pair from the mnemonic. You will use this name to identify your account when you want to send a transaction.
|
- `<yourKeyName>` is the name of the account. It is a reference to the account number used to derive the key pair from the mnemonic. You will use this name to identify your account when you want to send a transaction.
|
||||||
- You can add the optional `--account` flag to specify the path (`0`, `1`, `2`, ...) you want to use to generate your account. By default, account `0` is generated.
|
- You can add the optional `--account` flag to specify the path (`0`, `1`, `2`, ...) you want to use to generate your account. By default, account `0` is generated.
|
||||||
|
|
||||||
### Creating an account
|
### Creating an Account
|
||||||
|
|
||||||
To create an account, you just need to have `gaiacli` installed. Before creating it, you need to know where you intend to store and interract with your private keys. The best options are to store them in an offline dedicated computer or a ledger device. Storing them on your regular online computer involves more risk, since anyone who infiltrates your computer through the internet could exfiltrate your private keys and steal your funds.
|
To create an account, you just need to have `gaiacli` installed. Before creating it, you need to know where you intend to store and interact with your private keys. The best options are to store them in an offline dedicated computer or a ledger device. Storing them on your regular online computer involves more risk, since anyone who infiltrates your computer through the internet could exfiltrate your private keys and steal your funds.
|
||||||
|
|
||||||
#### Using a ledger device
|
#### Using a Ledger Device
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
**Only use Ledger devices that you bought factory new or trust fully**
|
**Only use Ledger devices that you bought factory new or trust fully**
|
||||||
|
@ -185,7 +185,7 @@ gaiacli keys add <yourAccountName> --ledger
|
||||||
- `<yourKeyName>` is the name of the account. It is a reference to the account number used to derive the key pair from the mnemonic. You will use this name to identify your account when you want to send a transaction.
|
- `<yourKeyName>` is the name of the account. It is a reference to the account number used to derive the key pair from the mnemonic. You will use this name to identify your account when you want to send a transaction.
|
||||||
- You can add the optional `--account` flag to specify the path (`0`, `1`, `2`, ...) you want to use to generate your account. By default, account `0` is generated.
|
- You can add the optional `--account` flag to specify the path (`0`, `1`, `2`, ...) you want to use to generate your account. By default, account `0` is generated.
|
||||||
|
|
||||||
#### Using a computer
|
#### Using a Computer
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
**NOTE: It is more secure to perform this action on an offline computer**
|
**NOTE: It is more secure to perform this action on an offline computer**
|
||||||
|
@ -225,7 +225,7 @@ gaiacli keys add <yourKeyName> --recover --account 1
|
||||||
This command will prompt you to input a passphrase as well as your mnemonic. Change the account number to generate a different account.
|
This command will prompt you to input a passphrase as well as your mnemonic. Change the account number to generate a different account.
|
||||||
|
|
||||||
|
|
||||||
## Accessing the Cosmos Hub network
|
## Accessing the Cosmos Hub Network
|
||||||
|
|
||||||
In order to query the state and send transactions, you need a way to access the network. To do so, you can either run your own full-node, or connect to someone else's.
|
In order to query the state and send transactions, you need a way to access the network. To do so, you can either run your own full-node, or connect to someone else's.
|
||||||
|
|
||||||
|
@ -233,19 +233,19 @@ In order to query the state and send transactions, you need a way to access the
|
||||||
**NOTE: Do not share your mnemonic (12 or 24 words) with anyone. The only person who should ever need to know it is you. This is especially important if you are ever approached via email or direct message by someone requesting that you share your mnemonic for any kind of blockchain services or support. No one from Cosmos, the Tendermint team or the Interchain Foundation will ever send an email that asks for you to share any kind of account credentials or your mnemonic."**.
|
**NOTE: Do not share your mnemonic (12 or 24 words) with anyone. The only person who should ever need to know it is you. This is especially important if you are ever approached via email or direct message by someone requesting that you share your mnemonic for any kind of blockchain services or support. No one from Cosmos, the Tendermint team or the Interchain Foundation will ever send an email that asks for you to share any kind of account credentials or your mnemonic."**.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Running your own full-node
|
### Running Your Own Full-Node
|
||||||
|
|
||||||
This is the most secure option, but comes with relatively high resource requirements. In order to run your own full-node, you need good bandwidth and at least 1TB of disk space.
|
This is the most secure option, but comes with relatively high resource requirements. In order to run your own full-node, you need good bandwidth and at least 1TB of disk space.
|
||||||
|
|
||||||
You will find the tutorial on how to install `gaiad` [here](https://cosmos.network/docs/gaia/installation.html), and the guide to run a full-node [here](https://cosmos.network/docs/gaia/join-mainnet.html).
|
You will find the tutorial on how to install `gaiad` [here](https://cosmos.network/docs/gaia/installation.html), and the guide to run a full-node [here](https://cosmos.network/docs/gaia/join-mainnet.html).
|
||||||
|
|
||||||
### Connecting to a remote full-node
|
### Connecting to a Remote Full-Node
|
||||||
|
|
||||||
If you do not want or cannot run your own node, you can connect to someone else's full-node. You should pick an operator you trust, because a malicious operator could return incorrect query results or censor your transactions. However, they will never be able to steal your funds, as your private keys are stored locally on your computer or ledger device. Possible options of full-node operators include validators, wallet providers or exchanges.
|
If you do not want or cannot run your own node, you can connect to someone else's full-node. You should pick an operator you trust, because a malicious operator could return incorrect query results or censor your transactions. However, they will never be able to steal your funds, as your private keys are stored locally on your computer or ledger device. Possible options of full-node operators include validators, wallet providers or exchanges.
|
||||||
|
|
||||||
In order to connect to the full-node, you will need an address of the following form: `https://77.87.106.33:26657` (*Note: This is a placeholder*). This address has to be communicated by the full-node operator you choose to trust. You will use this address in the [following section](#setting-up-gaiacli).
|
In order to connect to the full-node, you will need an address of the following form: `https://77.87.106.33:26657` (*Note: This is a placeholder*). This address has to be communicated by the full-node operator you choose to trust. You will use this address in the [following section](#setting-up-gaiacli).
|
||||||
|
|
||||||
## Setting up `gaiacli`
|
## Setting Up `gaiacli`
|
||||||
|
|
||||||
::: tip
|
::: tip
|
||||||
**Before setting up `gaiacli`, make sure you have set up a way to [access the Cosmos Hub network](#accessing-the-cosmos-hub-network)**
|
**Before setting up `gaiacli`, make sure you have set up a way to [access the Cosmos Hub network](#accessing-the-cosmos-hub-network)**
|
||||||
|
@ -289,7 +289,7 @@ Finally, let us set the `chain-id` of the blockchain we want to interact with:
|
||||||
gaiacli config chain-id cosmoshub-1
|
gaiacli config chain-id cosmoshub-1
|
||||||
```
|
```
|
||||||
|
|
||||||
## Querying the state
|
## Querying the State
|
||||||
|
|
||||||
::: tip
|
::: tip
|
||||||
**Before you can bond atoms and withdraw rewards, you need to [set up `gaiacli`](#setting-up-gaiacli)**
|
**Before you can bond atoms and withdraw rewards, you need to [set up `gaiacli`](#setting-up-gaiacli)**
|
||||||
|
@ -337,10 +337,10 @@ For each command, you can use the `-h` or `--help` flag to get more information.
|
||||||
## Sending Transactions
|
## Sending Transactions
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
On Cosmos Hub mainnet, the accepted denom is `uatom` (micro-Atom), where `1atom = 1,000,000uatom`
|
On Cosmos Hub mainnet, the accepted denom is `uatom`, where `1atom = 1,000,000uatom`
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### A note on gas and fees
|
### A Note on Gas and Fees
|
||||||
|
|
||||||
Transactions on the Cosmos Hub network need to include a transaction fee in order to be processed. This fee pays for the gas required to run the transaction. The formula is the following:
|
Transactions on the Cosmos Hub network need to include a transaction fee in order to be processed. This fee pays for the gas required to run the transaction. The formula is the following:
|
||||||
|
|
||||||
|
@ -358,14 +358,14 @@ The transaction `fees` are the product of `gas` and `gasPrice`. As a user, you h
|
||||||
For mainnet, the recommended `gas-prices` is `0.025uatom`.
|
For mainnet, the recommended `gas-prices` is `0.025uatom`.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Bonding Atoms and Withdrawing rewards
|
### Bonding Atoms and Withdrawing Rewards
|
||||||
|
|
||||||
::: tip
|
::: tip
|
||||||
**Before you can bond atoms and withdraw rewards, you need to [set up `gaiacli`](#setting-up-gaiacli) and [create an account](#creating-an-account)**
|
**Before you can bond atoms and withdraw rewards, you need to [set up `gaiacli`](#setting-up-gaiacli) and [create an account](#creating-an-account)**
|
||||||
:::
|
:::
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
**Before bonding Atoms, please read the [delegator faq](https://cosmos.network/resources/delegators) to understand the risk and responsabilities involved with delegating**
|
**Before bonding Atoms, please read the [delegator faq](https://cosmos.network/resources/delegators) to understand the risk and responsibilities involved with delegating**
|
||||||
:::
|
:::
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
|
@ -379,6 +379,14 @@ For mainnet, the recommended `gas-prices` is `0.025uatom`.
|
||||||
gaiacli tx staking delegate <validatorAddress> <amountToBond> --from <delegatorKeyName> --gas auto --gas-adjustment 1.5 --gas-prices <gasPrice>
|
gaiacli tx staking delegate <validatorAddress> <amountToBond> --from <delegatorKeyName> --gas auto --gas-adjustment 1.5 --gas-prices <gasPrice>
|
||||||
|
|
||||||
|
|
||||||
|
// Redelegate a certain amount of Atoms from a validator to another
|
||||||
|
// Can only be used if already bonded to a validator
|
||||||
|
// Redelegation takes effect immediately, there is no waiting period to redelegate
|
||||||
|
// After a redelegation, no other redelegation can be made from the account for the next 3 weeks
|
||||||
|
// ex value for flags: <stcValidatorAddress>=cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, <amountToRedelegate>=100000000uatom, <gasPrice>=0.025uatom
|
||||||
|
|
||||||
|
gaiacli tx staking redelegate <srcValidatorAddress> <destValidatorAddress> <amountToRedelegate> --from <delegatorKeyName> --gas auto --gas-adjustment 1.5 --gas-prices <gasPrice>
|
||||||
|
|
||||||
// Withdraw all rewards
|
// Withdraw all rewards
|
||||||
// ex value for flag: <gasPrice>=0.025uatom
|
// ex value for flag: <gasPrice>=0.025uatom
|
||||||
|
|
||||||
|
@ -413,9 +421,9 @@ gaiacli query tx <txHash>
|
||||||
|
|
||||||
Double check with a block explorer if you interact with the network through a trusted full-node.
|
Double check with a block explorer if you interact with the network through a trusted full-node.
|
||||||
|
|
||||||
## Participating in governance
|
## Participating in Governance
|
||||||
|
|
||||||
#### Primer on governance
|
#### Primer on Governance
|
||||||
|
|
||||||
The Cosmos Hub has a built-in governance system that lets bonded Atom holders vote on proposals. There are three types of proposal:
|
The Cosmos Hub has a built-in governance system that lets bonded Atom holders vote on proposals. There are three types of proposal:
|
||||||
|
|
||||||
|
@ -429,7 +437,7 @@ Once the `deposit` reaches `minDeposit`, the proposal enters the `voting_period`
|
||||||
|
|
||||||
At the end of the voting period, the proposal is accepted if there are more than 50% `Yes` votes (excluding `Abstain ` votes) and less than 33.33% of `NoWithVeto` votes (excluding `Abstain` votes).
|
At the end of the voting period, the proposal is accepted if there are more than 50% `Yes` votes (excluding `Abstain ` votes) and less than 33.33% of `NoWithVeto` votes (excluding `Abstain` votes).
|
||||||
|
|
||||||
#### In practice
|
#### In Practice
|
||||||
|
|
||||||
::: tip
|
::: tip
|
||||||
**Before you can bond atoms and withdraw rewards, you need to [bond Atoms](#bonding-atoms-and-withdrawing-rewards)**
|
**Before you can bond atoms and withdraw rewards, you need to [bond Atoms](#bonding-atoms-and-withdrawing-rewards)**
|
||||||
|
@ -459,7 +467,7 @@ gaiacli tx gov deposit <proposalID> <deposit> --gas auto --gas-adjustment 1.5 --
|
||||||
gaiacli tx gov vote <proposalID> <option> --gas auto --gas-adjustment 1.5 --gas-prices <gasPrice> --from <delegatorKeyName>
|
gaiacli tx gov vote <proposalID> <option> --gas auto --gas-adjustment 1.5 --gas-prices <gasPrice> --from <delegatorKeyName>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Signing transactions from an offline computer
|
### Signing Transactions From an Offline Computer
|
||||||
|
|
||||||
If you do not have a ledger device and want to interact with your private key on an offline computer, you can use the following procedure. First, generate an unsigned transaction on an **online computer** with the following command (example with a bonding transaction):
|
If you do not have a ledger device and want to interact with your private key on an offline computer, you can use the following procedure. First, generate an unsigned transaction on an **online computer** with the following command (example with a bonding transaction):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Deploy your own testnet
|
# Deploy Your Own Testnet
|
||||||
|
|
||||||
This document describes 3 ways to setup a network of `gaiad` nodes, each serving a different usecase:
|
This document describes 3 ways to setup a network of `gaiad` nodes, each serving a different usecase:
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ In case you need to use or deploy gaia as a container you could skip the `build`
|
||||||
|
|
||||||
The same images can be used to build your own docker-compose stack.
|
The same images can be used to build your own docker-compose stack.
|
||||||
|
|
||||||
## Single-node, local, manual testnet
|
## Single-node, Local, Manual Testnet
|
||||||
|
|
||||||
This guide helps you create a single validator node that runs a network locally for testing and other development related uses.
|
This guide helps you create a single validator node that runs a network locally for testing and other development related uses.
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ This guide helps you create a single validator node that runs a network locally
|
||||||
- [Install gaia](./installation.md)
|
- [Install gaia](./installation.md)
|
||||||
- [Install `jq`](https://stedolan.github.io/jq/download/) (optional)
|
- [Install `jq`](https://stedolan.github.io/jq/download/) (optional)
|
||||||
|
|
||||||
### Create genesis file and start the network
|
### Create Genesis File and Start the Network
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# You can run all of these commands from your home directory
|
# You can run all of these commands from your home directory
|
||||||
|
@ -58,7 +58,7 @@ gaiad start
|
||||||
|
|
||||||
This setup puts all the data for `gaiad` in `~/.gaiad`. You can examine the genesis file you created at `~/.gaiad/config/genesis.json`. With this configuration `gaiacli` is also ready to use and has an account with tokens (both staking and custom).
|
This setup puts all the data for `gaiad` in `~/.gaiad`. You can examine the genesis file you created at `~/.gaiad/config/genesis.json`. With this configuration `gaiacli` is also ready to use and has an account with tokens (both staking and custom).
|
||||||
|
|
||||||
## Multi-node, local, automated testnet
|
## Multi-node, Local, Automated Testnet
|
||||||
|
|
||||||
From the [networks/local directory](https://github.com/cosmos/cosmos-sdk/tree/develop/networks/local):
|
From the [networks/local directory](https://github.com/cosmos/cosmos-sdk/tree/develop/networks/local):
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ make build-linux
|
||||||
make build-docker-gaiadnode
|
make build-docker-gaiadnode
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run your testnet
|
### Run Your Testnet
|
||||||
|
|
||||||
To start a 4 node testnet run:
|
To start a 4 node testnet run:
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ funds!
|
||||||
**Note**: Each node's seed is located at `./build/nodeN/gaiacli/key_seed.json` and can be restored to the CLI using the `gaiacli keys add --restore` command
|
**Note**: Each node's seed is located at `./build/nodeN/gaiacli/key_seed.json` and can be restored to the CLI using the `gaiacli keys add --restore` command
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Special binaries
|
### Special Binaries
|
||||||
|
|
||||||
If you have multiple binaries with different names, you can specify which one to run with the BINARY environment variable. The path of the binary is relative to the attached volume. For example:
|
If you have multiple binaries with different names, you can specify which one to run with the BINARY environment variable. The path of the binary is relative to the attached volume. For example:
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ If you have multiple binaries with different names, you can specify which one to
|
||||||
BINARY=gaiafoo make localnet-start
|
BINARY=gaiafoo make localnet-start
|
||||||
```
|
```
|
||||||
|
|
||||||
## Multi-node, remote, automated testnet
|
## Multi-Node, Remote, Automated Testnet
|
||||||
|
|
||||||
The following should be run from the [networks directory](https://github.com/cosmos/cosmos-sdk/tree/develop/networks).
|
The following should be run from the [networks directory](https://github.com/cosmos/cosmos-sdk/tree/develop/networks).
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ export SSH_PUBLIC_FILE="$HOME/.ssh/id_rsa.pub"
|
||||||
|
|
||||||
These will be used by both `terraform` and `ansible`.
|
These will be used by both `terraform` and `ansible`.
|
||||||
|
|
||||||
### Create a remote network
|
### Create a Remote Network
|
||||||
|
|
||||||
```
|
```
|
||||||
SERVERS=1 REGION_LIMIT=1 make validators-start
|
SERVERS=1 REGION_LIMIT=1 make validators-start
|
||||||
|
@ -228,13 +228,13 @@ The testnet name is what's going to be used in --chain-id, while the cluster nam
|
||||||
./new-testnet.sh "$TESTNET_NAME" "$CLUSTER_NAME" 1 1
|
./new-testnet.sh "$TESTNET_NAME" "$CLUSTER_NAME" 1 1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Quickly see the /status endpoint
|
### Quickly see the /status Endpoint
|
||||||
|
|
||||||
```
|
```
|
||||||
make validators-status
|
make validators-status
|
||||||
```
|
```
|
||||||
|
|
||||||
### Delete servers
|
### Delete Servers
|
||||||
|
|
||||||
```
|
```
|
||||||
make validators-stop
|
make validators-stop
|
|
@ -1,4 +1,4 @@
|
||||||
# Gaia client
|
# Gaia Client
|
||||||
|
|
||||||
## Gaia CLI
|
## Gaia CLI
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ Note that this is the Tendermint signing key, _not_ the operator key you will us
|
||||||
We strongly recommend _NOT_ using the same passphrase for multiple keys. The Tendermint team and the Interchain Foundation will not be responsible for the loss of funds.
|
We strongly recommend _NOT_ using the same passphrase for multiple keys. The Tendermint team and the Interchain Foundation will not be responsible for the loss of funds.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Generate multisig public keys
|
#### Generate Multisig Public Keys
|
||||||
|
|
||||||
You can generate and print a multisig public key by typing:
|
You can generate and print a multisig public key by typing:
|
||||||
|
|
||||||
|
@ -128,6 +128,19 @@ gaiacli keys show --multisig-threshold K name1 name2 name3 [...]
|
||||||
For more information regarding how to generate, sign and broadcast transactions with a
|
For more information regarding how to generate, sign and broadcast transactions with a
|
||||||
multi signature account see [Multisig Transactions](#multisig-transactions).
|
multi signature account see [Multisig Transactions](#multisig-transactions).
|
||||||
|
|
||||||
|
### Tx Broadcasting
|
||||||
|
|
||||||
|
When broadcasting transactions, `gaiacli` accepts a `--broadcast-mode` flag. This
|
||||||
|
flag can have a value of `sync` (default), `async`, or `block`, where `sync` makes
|
||||||
|
the client return a CheckTx response, `async` makes the client return immediately,
|
||||||
|
and `block` makes the client wait for the tx to be committed (or timing out).
|
||||||
|
|
||||||
|
It is important to note that the `block` mode should **not** be used in most
|
||||||
|
circumstances. This is because broadcasting can timeout but the tx may still be
|
||||||
|
included in a block. This can result in many undesirable situations. Therefor, it
|
||||||
|
is best to use `sync` or `async` and query by tx hash to determine when the tx
|
||||||
|
is included in a block.
|
||||||
|
|
||||||
### Fees & Gas
|
### Fees & Gas
|
||||||
|
|
||||||
Each transaction may either supply fees or gas prices, but not both.
|
Each transaction may either supply fees or gas prices, but not both.
|
||||||
|
@ -156,7 +169,7 @@ gaiacli tx send ... --gas-prices=0.025uatom
|
||||||
|
|
||||||
The best way to get tokens is from the [Cosmos Testnet Faucet](https://faucetcosmos.network). If the faucet is not working for you, try asking [#cosmos-validators](https://riot.im/app/#/room/#cosmos-validators:matrix.org). The faucet needs the `cosmos` from the account you wish to use for staking.
|
The best way to get tokens is from the [Cosmos Testnet Faucet](https://faucetcosmos.network). If the faucet is not working for you, try asking [#cosmos-validators](https://riot.im/app/#/room/#cosmos-validators:matrix.org). The faucet needs the `cosmos` from the account you wish to use for staking.
|
||||||
|
|
||||||
#### Query Account balance
|
#### Query Account Balance
|
||||||
|
|
||||||
After receiving tokens to your address, you can view your account's balance by typing:
|
After receiving tokens to your address, you can view your account's balance by typing:
|
||||||
|
|
||||||
|
@ -243,7 +256,7 @@ gaiacli tx broadcast --node=<node> signedSendTx.json
|
||||||
|
|
||||||
### Query Transactions
|
### Query Transactions
|
||||||
|
|
||||||
#### Matching a set of tags
|
#### Matching a Set of Tags
|
||||||
|
|
||||||
You can use the transaction search command to query for transactions that match a specific set of `tags`, which are added on every transaction.
|
You can use the transaction search command to query for transactions that match a specific set of `tags`, which are added on every transaction.
|
||||||
|
|
||||||
|
@ -280,7 +293,7 @@ You can find a list of available `tags` on each of the SDK modules:
|
||||||
- [Bank tags](https://github.com/cosmos/cosmos-sdk/blob/d1e76221d8e28824bb4791cb4ad8662d2ae9051e/x/bank/keeper.go#L193-L206)
|
- [Bank tags](https://github.com/cosmos/cosmos-sdk/blob/d1e76221d8e28824bb4791cb4ad8662d2ae9051e/x/bank/keeper.go#L193-L206)
|
||||||
:::
|
:::
|
||||||
|
|
||||||
#### Matching a transaction's hash
|
#### Matching a Transaction's Hash
|
||||||
|
|
||||||
You can also query a single transaction by its hash using the following command:
|
You can also query a single transaction by its hash using the following command:
|
||||||
|
|
||||||
|
@ -314,6 +327,26 @@ You can get the current slashing parameters via:
|
||||||
gaiacli query slashing params
|
gaiacli query slashing params
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Minting
|
||||||
|
|
||||||
|
You can query for the minting/inflation parameters via:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gaiacli query minting params
|
||||||
|
```
|
||||||
|
|
||||||
|
To query for the current inflation value:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gaiacli query minting inflation
|
||||||
|
```
|
||||||
|
|
||||||
|
To query for the current annual provisions value:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gaiacli query minting annual-provisions
|
||||||
|
```
|
||||||
|
|
||||||
### Staking
|
### Staking
|
||||||
|
|
||||||
#### Set up a Validator
|
#### Set up a Validator
|
||||||
|
@ -374,16 +407,15 @@ Or if you want to check all your current delegations with disctinct validators:
|
||||||
gaiacli query staking delegations <delegator_addr>
|
gaiacli query staking delegations <delegator_addr>
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also get previous delegation(s) status by adding the `--height` flag.
|
|
||||||
|
|
||||||
#### Unbond Tokens
|
#### Unbond Tokens
|
||||||
|
|
||||||
If for any reason the validator misbehaves, or you just want to unbond a certain amount of tokens, use this following command. You can unbond a specific `shares-amount` (eg:`12.1`\) or a `shares-fraction` (eg:`0.25`) with the corresponding flags.
|
If for any reason the validator misbehaves, or you just want to unbond a certain
|
||||||
|
amount of tokens, use this following command.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gaiacli tx staking unbond \
|
gaiacli tx staking unbond \
|
||||||
--validator=<account_cosmosval> \
|
<validator_addr> \
|
||||||
--shares-fraction=0.5 \
|
10atom \
|
||||||
--from=<key_name> \
|
--from=<key_name> \
|
||||||
--chain-id=<chain_id>
|
--chain-id=<chain_id>
|
||||||
```
|
```
|
||||||
|
@ -410,17 +442,15 @@ Additionally, as you can get all the unbonding-delegations from a particular val
|
||||||
gaiacli query staking unbonding-delegations-from <account_cosmosval>
|
gaiacli query staking unbonding-delegations-from <account_cosmosval>
|
||||||
```
|
```
|
||||||
|
|
||||||
To get previous unbonding-delegation(s) status on past blocks, try adding the `--height` flag.
|
|
||||||
|
|
||||||
#### Redelegate Tokens
|
#### Redelegate Tokens
|
||||||
|
|
||||||
A redelegation is a type delegation that allows you to bond illiquid tokens from one validator to another:
|
A redelegation is a type delegation that allows you to bond illiquid tokens from one validator to another:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gaiacli tx staking redelegate \
|
gaiacli tx staking redelegate \
|
||||||
--addr-validator-source=<account_cosmosval> \
|
<src-validator-operator-addr> \
|
||||||
--addr-validator-dest=<account_cosmosval> \
|
<dst-validator-operator-addr> \
|
||||||
--shares-fraction=50 \
|
10atom \
|
||||||
--from=<key_name> \
|
--from=<key_name> \
|
||||||
--chain-id=<chain_id>
|
--chain-id=<chain_id>
|
||||||
```
|
```
|
||||||
|
@ -437,7 +467,7 @@ Once you begin an redelegation, you can see it's information by using the follow
|
||||||
gaiacli query staking redelegation <delegator_addr> <src_val_addr> <dst_val_addr>
|
gaiacli query staking redelegation <delegator_addr> <src_val_addr> <dst_val_addr>
|
||||||
```
|
```
|
||||||
|
|
||||||
Or if you want to check all your current unbonding-delegations with disctinct validators:
|
Or if you want to check all your current unbonding-delegations with distinct validators:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gaiacli query staking redelegations <account_cosmos>
|
gaiacli query staking redelegations <account_cosmos>
|
||||||
|
@ -449,8 +479,6 @@ Additionally, as you can get all the outgoing redelegations from a particular va
|
||||||
gaiacli query staking redelegations-from <account_cosmosval>
|
gaiacli query staking redelegations-from <account_cosmosval>
|
||||||
```
|
```
|
||||||
|
|
||||||
To get previous redelegation(s) status on past blocks, try adding the `--height` flag.
|
|
||||||
|
|
||||||
#### Query Parameters
|
#### Query Parameters
|
||||||
|
|
||||||
Parameters define high level settings for staking. You can get the current values by using:
|
Parameters define high level settings for staking. You can get the current values by using:
|
||||||
|
@ -505,7 +533,7 @@ Some considerations about the voting process:
|
||||||
|
|
||||||
For more information about the governance process and how it works, please check out the Governance module [specification](./../spec/governance).
|
For more information about the governance process and how it works, please check out the Governance module [specification](./../spec/governance).
|
||||||
|
|
||||||
#### Create a Governance proposal
|
#### Create a Governance Proposal
|
||||||
|
|
||||||
In order to create a governance proposal, you must submit an initial deposit along with the proposal details:
|
In order to create a governance proposal, you must submit an initial deposit along with the proposal details:
|
||||||
|
|
||||||
|
@ -523,7 +551,7 @@ gaiacli tx gov submit-proposal \
|
||||||
--chain-id=<chain_id>
|
--chain-id=<chain_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Query proposals
|
##### Query Proposals
|
||||||
|
|
||||||
Once created, you can now query information of the proposal:
|
Once created, you can now query information of the proposal:
|
||||||
|
|
||||||
|
@ -545,7 +573,7 @@ To query for the proposer of a given governance proposal:
|
||||||
gaiacli query gov proposer <proposal_id>
|
gaiacli query gov proposer <proposal_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Increase deposit
|
#### Increase Deposit
|
||||||
|
|
||||||
In order for a proposal to be broadcasted to the network, the amount deposited must be above a `minDeposit` value (initial value: `512000000uatom`). If the proposal you previously created didn't meet this requirement, you can still increase the total amount deposited to activate it. Once the minimum deposit is reached, the proposal enters voting period:
|
In order for a proposal to be broadcasted to the network, the amount deposited must be above a `minDeposit` value (initial value: `512000000uatom`). If the proposal you previously created didn't meet this requirement, you can still increase the total amount deposited to activate it. Once the minimum deposit is reached, the proposal enters voting period:
|
||||||
|
|
||||||
|
@ -557,7 +585,7 @@ gaiacli tx gov deposit <proposal_id> "10000000uatom" \
|
||||||
|
|
||||||
> _NOTE_: Proposals that don't meet this requirement will be deleted after `MaxDepositPeriod` is reached.
|
> _NOTE_: Proposals that don't meet this requirement will be deleted after `MaxDepositPeriod` is reached.
|
||||||
|
|
||||||
##### Query deposits
|
##### Query Deposits
|
||||||
|
|
||||||
Once a new proposal is created, you can query all the deposits submitted to it:
|
Once a new proposal is created, you can query all the deposits submitted to it:
|
||||||
|
|
||||||
|
@ -571,7 +599,7 @@ You can also query a deposit submitted by a specific address:
|
||||||
gaiacli query gov deposit <proposal_id> <depositor_address>
|
gaiacli query gov deposit <proposal_id> <depositor_address>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Vote on a proposal
|
#### Vote on a Proposal
|
||||||
|
|
||||||
After a proposal's deposit reaches the `MinDeposit` value, the voting period opens. Bonded `Atom` holders can then cast vote on it:
|
After a proposal's deposit reaches the `MinDeposit` value, the voting period opens. Bonded `Atom` holders can then cast vote on it:
|
||||||
|
|
||||||
|
@ -581,7 +609,7 @@ gaiacli tx gov vote <proposal_id> <Yes/No/NoWithVeto/Abstain> \
|
||||||
--chain-id=<chain_id>
|
--chain-id=<chain_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Query votes
|
##### Query Votes
|
||||||
|
|
||||||
Check the vote with the option you just submitted:
|
Check the vote with the option you just submitted:
|
||||||
|
|
||||||
|
@ -603,7 +631,7 @@ To check the current tally of a given proposal you can use the `tally` command:
|
||||||
gaiacli query gov tally <proposal_id>
|
gaiacli query gov tally <proposal_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Query governance parameters
|
#### Query Governance Parameters
|
||||||
|
|
||||||
To check the current governance parameters run:
|
To check the current governance parameters run:
|
||||||
|
|
||||||
|
@ -621,7 +649,7 @@ gaiacli query gov param deposit
|
||||||
|
|
||||||
### Fee Distribution
|
### Fee Distribution
|
||||||
|
|
||||||
#### Query distribution parameters
|
#### Query Distribution Parameters
|
||||||
|
|
||||||
To check the current distribution parameters, run:
|
To check the current distribution parameters, run:
|
||||||
|
|
||||||
|
@ -629,6 +657,14 @@ To check the current distribution parameters, run:
|
||||||
gaiacli query distr params
|
gaiacli query distr params
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Query distribution Community Pool
|
||||||
|
|
||||||
|
To query all coins in the community pool which is under Governance control:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gaiacli query distr community-pool
|
||||||
|
```
|
||||||
|
|
||||||
#### Query outstanding rewards
|
#### Query outstanding rewards
|
||||||
|
|
||||||
To check the current outstanding (un-withdrawn) rewards, run:
|
To check the current outstanding (un-withdrawn) rewards, run:
|
||||||
|
@ -637,7 +673,7 @@ To check the current outstanding (un-withdrawn) rewards, run:
|
||||||
gaiacli query distr outstanding-rewards
|
gaiacli query distr outstanding-rewards
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Query validator commission
|
#### Query Validator Commission
|
||||||
|
|
||||||
To check the current outstanding commission for a validator, run:
|
To check the current outstanding commission for a validator, run:
|
||||||
|
|
||||||
|
@ -645,7 +681,7 @@ To check the current outstanding commission for a validator, run:
|
||||||
gaiacli query distr commission <validator_address>
|
gaiacli query distr commission <validator_address>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Query validator slashes
|
#### Query Validator Slashes
|
||||||
|
|
||||||
To check historical slashes for a validator, run:
|
To check historical slashes for a validator, run:
|
||||||
|
|
||||||
|
@ -653,7 +689,7 @@ To check historical slashes for a validator, run:
|
||||||
gaiacli query distr slashes <validator_address> <start_height> <end_height>
|
gaiacli query distr slashes <validator_address> <start_height> <end_height>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Query delegator rewards
|
#### Query Delegator Rewards
|
||||||
|
|
||||||
To check current rewards for a delegation (were they to be withdrawn), run:
|
To check current rewards for a delegation (were they to be withdrawn), run:
|
||||||
|
|
||||||
|
@ -661,7 +697,7 @@ To check current rewards for a delegation (were they to be withdrawn), run:
|
||||||
gaiacli query distr rewards <delegator_address> <validator_address>
|
gaiacli query distr rewards <delegator_address> <validator_address>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Query all delegator rewards
|
#### Query All Delegator Rewards
|
||||||
|
|
||||||
To check all current rewards for a delegation (were they to be withdrawn), run:
|
To check all current rewards for a delegation (were they to be withdrawn), run:
|
||||||
|
|
||||||
|
@ -669,7 +705,7 @@ To check all current rewards for a delegation (were they to be withdrawn), run:
|
||||||
gaiacli query distr rewards <delegator_address>
|
gaiacli query distr rewards <delegator_address>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Multisig transactions
|
### Multisig Transactions
|
||||||
|
|
||||||
Multisig transactions require signatures of multiple private keys. Thus, generating and signing
|
Multisig transactions require signatures of multiple private keys. Thus, generating and signing
|
||||||
a transaction from a multisig account involve cooperation among the parties involved. A multisig
|
a transaction from a multisig account involve cooperation among the parties involved. A multisig
|
||||||
|
@ -761,7 +797,7 @@ The transaction can now be sent to the node:
|
||||||
gaiacli tx broadcast signedTx.json
|
gaiacli tx broadcast signedTx.json
|
||||||
```
|
```
|
||||||
|
|
||||||
## Shells completion scripts
|
## Shells Completion Scripts
|
||||||
|
|
||||||
Completion scripts for popular UNIX shell interpreters such as `Bash` and `Zsh`
|
Completion scripts for popular UNIX shell interpreters such as `Bash` and `Zsh`
|
||||||
can be generated through the `completion` command, which is available for both
|
can be generated through the `completion` command, which is available for both
|
|
@ -0,0 +1,332 @@
|
||||||
|
# Genesis File
|
||||||
|
|
||||||
|
This document explains how the genesis file of the Cosmmos Hub mainnet is structured. It also explains how you can build a genesis file for your own `gaia` testnet.
|
||||||
|
|
||||||
|
Note that you can generate a default genesis file for your own testnet by running the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gaiad init <moniker> --chain-id <chain-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
The genesis file is stored in `~/.gaiad/config/genesis.toml`.
|
||||||
|
|
||||||
|
## What is a Genesis File
|
||||||
|
|
||||||
|
A genesis file is a JSON file which defines the initial state of your blockchain. It can be seen as height `0` of your blockchain. The first block, at height `1`, will reference the genesis file as its parent.
|
||||||
|
|
||||||
|
The state defined in the genesis file contains all the necessary information, like initial token allocation, genesis time, default parameters, and more. Let us break down these information.
|
||||||
|
|
||||||
|
## Genesis Time and Chain_id
|
||||||
|
|
||||||
|
The `genesis_time` is defined at the top of the genesis file. It is a `UTC` timestamps which specifies when the blockchain is due to start. At this time, genesis validators are supposed to come online and start participating in the consensus process. The blockchain starts when more than 2/3rd of the genesis validators (weighted by voting power) are online.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"genesis_time": "2019-03-13T17:00:00.000000000Z",
|
||||||
|
```
|
||||||
|
|
||||||
|
The `chain_id` is a unique identifier for your chain. It helps differentiate between different chains using the same version of the software.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"chain_id": "cosmoshub-1",
|
||||||
|
```
|
||||||
|
|
||||||
|
## Consensus Parameters
|
||||||
|
|
||||||
|
Next, the genesis file defines consensus parameters. Consensus parameters regroup all the parameters that are related to the consensus layer, which is `Tendermint` in the case of `gaia`. Let us look at these parameters:
|
||||||
|
|
||||||
|
- `block`
|
||||||
|
+ `max_bytes`: Maximum number of bytes per block.
|
||||||
|
+ `max_gas`: Gas limit per block. Each transaction included in the block will consume some gas. The total gas used by transactions included in a block cannot exceed this limit.
|
||||||
|
- `evidence`
|
||||||
|
+ `max_age`: An evidence is a proof that a validator signed two different blocks at the same height (and round). This is an explicitely malicious behaviour that is punished at the state-machine level. The `max_age` defines the maximum number of **blocks** after which an evidence is not valid anymore.
|
||||||
|
- `validator`
|
||||||
|
+ `pub_key_types`: The types of pubkey (`ed25519`, `secp256k1`, ...) that are accepted for validators. Currently only `ed25519` is accepted.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"consensus_params": {
|
||||||
|
"block_size": {
|
||||||
|
"max_bytes": "150000",
|
||||||
|
"max_gas": "1500000"
|
||||||
|
},
|
||||||
|
"evidence": {
|
||||||
|
"max_age": "1000000"
|
||||||
|
},
|
||||||
|
"validator": {
|
||||||
|
"pub_key_types": [
|
||||||
|
"ed25519"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
## Application State
|
||||||
|
|
||||||
|
The application state defines the initial state of the state-machine.
|
||||||
|
|
||||||
|
### Genesis Accounts
|
||||||
|
|
||||||
|
In this section, initial allocation of tokens is defined. It is possible to add accounts manually by directly editing the genesis file, but it is also possible to use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Example: gaiad add-genesis-account cosmos1qs8tnw2t8l6amtzvdemnnsq9dzk0ag0z37gh3h 10000000uatom
|
||||||
|
|
||||||
|
gaiad add-genesis-account <account-address> <amount><denom>
|
||||||
|
```
|
||||||
|
|
||||||
|
This command creates an item in the `accounts` list, under the `app_state` section.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"address": "cosmos1qs8tnw2t8l6amtzvdemnnsq9dzk0ag0z37gh3h",
|
||||||
|
"coins": [
|
||||||
|
{
|
||||||
|
"denom": "uatom",
|
||||||
|
"amount": "10000000"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sequence_number": "0",
|
||||||
|
"account_number": "0",
|
||||||
|
"original_vesting": [
|
||||||
|
{
|
||||||
|
"denom": "uatom",
|
||||||
|
"amount": "26306000000"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"delegated_free": null,
|
||||||
|
"delegated_vesting": null,
|
||||||
|
"start_time": "0",
|
||||||
|
"end_time": "10000"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Let us break down the parameters:
|
||||||
|
|
||||||
|
- `sequence_number`: This number is used to count the number of transactions sent by this account. It is incremented each time a transaction is included in a block, and used to prevent replay attacks. Initial value is `0`.
|
||||||
|
- `account_number`: Unique identifier for the account. It is generated the first time a transaction including this account is included in a block.
|
||||||
|
- `original_vesting`: Vesting is natively supported by `gaia`. You can define an amount of token owned by the account that needs to be vested for a period of time before they can be transferred. Vested tokens can be delegated. Default value is `null`.
|
||||||
|
- `delegated_free`: Amount of delegated tokens that can be transferred after they've been vested. Most of the time, will be `null` in genesis.
|
||||||
|
- `delegated_vesting`: Amount of delegated tokens that are still vesting. Most of the time, will be `null` in genesis.
|
||||||
|
- `start_time`: Block at which the vesting period starts. `0` most of the time in genesis.
|
||||||
|
- `end_time`: Block at which the vesting period ends. `0` if no vesting for this account.
|
||||||
|
|
||||||
|
### Bank
|
||||||
|
|
||||||
|
The `bank` module handles tokens. The only parameter that needs to be defined in this section is wether `transfers` are enabled at genesis or not.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"bank": {
|
||||||
|
"send_enabled": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Staking
|
||||||
|
|
||||||
|
The `staking` module handles the bulk of the Proof-of-Stake logic of the state-machine. This section should look like the following:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"staking": {
|
||||||
|
"pool": {
|
||||||
|
"not_bonded_tokens": "10000000",
|
||||||
|
"bonded_tokens": "0"
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"unbonding_time": "1814400000000000",
|
||||||
|
"max_validators": 100,
|
||||||
|
"max_entries": 7,
|
||||||
|
"bond_denom": "uatom"
|
||||||
|
},
|
||||||
|
"last_total_power": "0",
|
||||||
|
"last_validator_powers": null,
|
||||||
|
"validators": null,
|
||||||
|
"bonds": null,
|
||||||
|
"unbonding_delegations": null,
|
||||||
|
"redelegations": null,
|
||||||
|
"exported": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Let us break down the parameters:
|
||||||
|
|
||||||
|
- `pool`
|
||||||
|
+ `not_bonded_tokens`: Defines the amount of tokens not bonded (i.e. delegated) in genesis. Generally, it equals the total supply of the staking token (`uatom` in this example).
|
||||||
|
+ `bonded_tokens`: Amount of bonded tokens in genesis. Generally `0`.
|
||||||
|
- `params`
|
||||||
|
+ `unbonding_time`: Time in **nanosecond** it takes for tokens to complete unbonding.
|
||||||
|
+ `max_validators`: Maximum number of active validators.
|
||||||
|
+ `max_entries`: Maximum unbonding delegations and redelegations between a particular pair of delegator / validator.
|
||||||
|
+ `bond_denom`: Denomination of the staking token.
|
||||||
|
- `last_total_power`: Total amount of voting power. Generally `0` in genesis (except if genesis was generated using a previous state).
|
||||||
|
- `last_validator_powers`: Power of each validator in last known state. Generally `null` in genesis (except if genesis was generated using a previous state).
|
||||||
|
- `validators`: List of last knoww validators. Generally `null` in genesis (except if genesis was generated using a previous state).
|
||||||
|
- `bonds`: List of last known delegation. Generally `null` in genesis (except if genesis was generated using a previous state).
|
||||||
|
- `unbonding_delegations`: List of last known unbonding delegations. Generally `null` in genesis (except if genesis was generated using a previous state).
|
||||||
|
- `redelegations`: List of last known redelegations. Generally `null` in genesis (except if genesis was generated using a previous state).
|
||||||
|
- `exported`: Wether this genesis was generated using the export of a previous state.
|
||||||
|
|
||||||
|
### Mint
|
||||||
|
|
||||||
|
The `mint` module governs the logic of inflating the supply of token. The `mint` section in the genesis file looks like the follwing:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"mint": {
|
||||||
|
"minter": {
|
||||||
|
"inflation": "0.070000000000000000",
|
||||||
|
"annual_provisions": "0.000000000000000000"
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"mint_denom": "uatom",
|
||||||
|
"inflation_rate_change": "0.130000000000000000",
|
||||||
|
"inflation_max": "0.200000000000000000",
|
||||||
|
"inflation_min": "0.070000000000000000",
|
||||||
|
"goal_bonded": "0.670000000000000000",
|
||||||
|
"blocks_per_year": "6311520"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Let us break down the parameters:
|
||||||
|
|
||||||
|
- `minter`
|
||||||
|
+ `inflation`: Initial yearly percentage of increase in the total supply of staking token, compounded weekly. A `0.070000000000000000` value means the target is `7%` yearly inflation, compounded weekly.
|
||||||
|
+ `annual_provisions`: Calculated each block. Initialize at `0.000000000000000000`.
|
||||||
|
- `params`
|
||||||
|
+ `mint_denom`: Denom of the staking token that is inflated.
|
||||||
|
+ `inflation_rate_change`: Max yearly change in inflation.
|
||||||
|
+ `inflation_max`: Maximum level of inflation.
|
||||||
|
+ `inflation_min`: Minimum level of inflation.
|
||||||
|
+ `goal_bonded`: Percentage of the total supply that is targeted to be bonded. If the percentage of bonded staking tokens is below this target, the inflation increases (following `inflation_rate_change`) until it reaches `inflation_max`. If the percentage of bonded staking tokens is above this target, the inflation decreases (following `inflation_rate_change`) until it reaches `inflation_min`.
|
||||||
|
+ `blocks_per_year`: Estimation of the amount of blocks per year. Used to compute the block reward coming from inflated staking token (called block provisions).
|
||||||
|
|
||||||
|
### Distribution
|
||||||
|
|
||||||
|
The `distr` module handles the logic of distribution block provisions and fees to validators and delegators. The `distr` section in the genesis file looks like the follwing:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"distr": {
|
||||||
|
"fee_pool": {
|
||||||
|
"community_pool": null
|
||||||
|
},
|
||||||
|
"community_tax": "0.020000000000000000",
|
||||||
|
"base_proposer_reward": "0.010000000000000000",
|
||||||
|
"bonus_proposer_reward": "0.040000000000000000",
|
||||||
|
"withdraw_addr_enabled": false,
|
||||||
|
"delegator_withdraw_infos": null,
|
||||||
|
"previous_proposer": "",
|
||||||
|
"outstanding_rewards": null,
|
||||||
|
"validator_accumulated_commissions": null,
|
||||||
|
"validator_historical_rewards": null,
|
||||||
|
"validator_current_rewards": null,
|
||||||
|
"delegator_starting_infos": null,
|
||||||
|
"validator_slash_events": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Let us break down the parameters:
|
||||||
|
|
||||||
|
- `fee_pool`
|
||||||
|
+ `community_pool`: The community pool is a pool of tokens that can be used to pay for bounties. It is allocated via governance proposals. Generally `null` in genesis.
|
||||||
|
- `community_tax`: The tax percentage on fees and block rewards that goes to the community pool.
|
||||||
|
- `base_proposer_reward`: Base bonus on transaction fees collected in a valid block that goes to the proposer of block. If value is `0.010000000000000000`, 1% of the fees go to the proposer.
|
||||||
|
- `bonus_proposer_reward`: Max bonus on transaction fees collected in a valid block that goes to the proposer of block. The bonus depends on the number of `precommits` the proposer includes. If the proposer includes 2/3rd `precommits` weighted by voting power (minimum for the block to be valid), they get a bonus of `base_proposer_reward`. This bonus increases linearly up to `bonus_proposer_reward` if the proposer includes 100% of `precommits`.
|
||||||
|
- `withdraw_addr_enabled`: If `true`, delegators can set a different address to withdraw their rewards. Set to `false` if you want to disable transfers at genesis, as it can be used as a way to get around the restriction.
|
||||||
|
- `delegator_withdraw_infos`: List of delegators withdraw address. Generally `null` if genesis was not exported from previous state.
|
||||||
|
- `previous_proposer`: Proposer of the previous block. Set to `""` if genesis was not exported from previous state.
|
||||||
|
- `outstanding_rewards`: Outstanding (un-withdrawn) rewards. Set to `null` if genesis was not exported from previous state.
|
||||||
|
- `validator_accumulated_commission`: Outstanding (un-withdrawn) commission of validators. Set to `null` if genesis was not exported from previous state.
|
||||||
|
- `validator_historical_rewards`: Set of information related to the historical rewards of validators and used by the `distr` module for various computation. Set to `null` if genesis was not exported from previous state.
|
||||||
|
- `validators_current_rewards`: Set of information related to the current rewards of validators and used by the `distr` module for various computation. Set to `null` if genesis was not exported from previous state.
|
||||||
|
- `delegator_starting_infos`: Tracks the previous validator period, the delegation's amount of staking token, and the creation height (to check later on if any slashes have occurred). Set to `null` if genesis was not exported from previous state.
|
||||||
|
- `validator_slash_events`: Set of information related to the past slashing of validators. Set to `null` if genesis was not exported from previous state.
|
||||||
|
|
||||||
|
### Governance
|
||||||
|
|
||||||
|
The `gov` module handles all governance-related transactions. The initial state of the `gov` section looks like the following:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"gov": {
|
||||||
|
"starting_proposal_id": "1",
|
||||||
|
"deposits": null,
|
||||||
|
"votes": null,
|
||||||
|
"proposals": null,
|
||||||
|
"deposit_params": {
|
||||||
|
"min_deposit": [
|
||||||
|
{
|
||||||
|
"denom": "uatom",
|
||||||
|
"amount": "512000000"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"max_deposit_period": "1209600000000000"
|
||||||
|
},
|
||||||
|
"voting_params": {
|
||||||
|
"voting_period": "1209600000000000"
|
||||||
|
},
|
||||||
|
"tally_params": {
|
||||||
|
"quorum": "0.4",
|
||||||
|
"threshold": "0.5",
|
||||||
|
"veto": "0.334",
|
||||||
|
"governance_penalty": "0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Let us break down the parameters:
|
||||||
|
|
||||||
|
- `starting_proposal_id`: This parameter defines the ID of the first proposal. Each proposal is identified by a unique ID.
|
||||||
|
- `deposits`: List of deposits for each proposal ID. Set to `null` if genesis was not exported from previous state.
|
||||||
|
- `votes`: List of votes for each proposal ID. Set to `null` if genesis was not exported from previous state.
|
||||||
|
- `proposals`: List of proposals for each proposal ID: Set to `null` if genesis was not exported from previous state.
|
||||||
|
- `deposit_params`
|
||||||
|
+ `min_deposit`: The minimum deposit required for the proposal to enter `Voting Period`. If multiple denoms are provided, the `OR` operator applies.
|
||||||
|
+ `max_deposit_period`: The maximum period (in **nanoseconds**) after which it is not possible to deposit on the proposal anymore.
|
||||||
|
- `voting_params`
|
||||||
|
+ `voting_period`: Length of the voting period in **nanoseconds**.
|
||||||
|
- `tally_params`
|
||||||
|
+ `quorum`: Minimum percentage of bonded staking tokens that needs to vote for the result to be valid.
|
||||||
|
+ `threshold`: Minimum percentage of votes that need to be `YES` for the result to be valid.
|
||||||
|
+ `veto`: Maximum percentage `NO_WITH_VETO` votes for the result to be valid.
|
||||||
|
+ `governance_penalty`: Penalty for validators that do not vote on a given proposal.
|
||||||
|
|
||||||
|
### Slashing
|
||||||
|
|
||||||
|
The `slashing` module handles the logic to slash delegators if their validator misbehave. The `slashing` section in genesis looks as follows:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"slashing": {
|
||||||
|
"params": {
|
||||||
|
"max_evidence_age": "1814400000000000",
|
||||||
|
"signed_blocks_window": "10000",
|
||||||
|
"min_signed_per_window": "0.050000000000000000",
|
||||||
|
"downtime_jail_duration": "600000000000",
|
||||||
|
"slash_fraction_double_sign": "0.050000000000000000",
|
||||||
|
"slash_fraction_downtime": "0.000100000000000000"
|
||||||
|
},
|
||||||
|
"signing_infos": {},
|
||||||
|
"missed_blocks": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Let us break down the parameters:
|
||||||
|
|
||||||
|
- `params`
|
||||||
|
+ `max_evidence_age`: Maximum age of the evidence in **nanoseconds**.
|
||||||
|
+ `signed_blocks_window`: Moving window of blocks to figure out offline validators.
|
||||||
|
+ `min_signed_per_window`: Minimum percentage of `precommits`that must be present in the `block window` for the validator to be considered online.
|
||||||
|
+ `downtime_jail_duration`: Duration in **nanoseconds** for which a validator is jailed after they get slashed for downtime.
|
||||||
|
+ `slash_fraction_double_sign`: Percentage of delegators bonded stake slashed when their validator double signs.
|
||||||
|
+ `slash_fraction_downtime`: Percentage of delegators bonded stake slashed when their validator is down.
|
||||||
|
- `signing_infos`: Various infos per validator needed by the `slashing` module. Set to `{}` if genesis was not exported from previous state.
|
||||||
|
- `missed_blocks`: Various infos related to missed blocks needed by the `slashing` module. Set to `{}` if genesis was not exported from previous state.
|
||||||
|
|
||||||
|
### Genesis Transactions
|
||||||
|
|
||||||
|
By default, the genesis file do not contain any `gentxs`. A `gentx` is a transaction that bonds staking token present in the genesis file under `accounts` to a validator, essentially creating a validator at genesis. The chain will start as soon as more than 2/3rds of the validators (weighted by voting power) that are the recipient of a valid `gentx` come online after `genesis_time`.
|
||||||
|
|
||||||
|
A `gentx` can be added manually to the genesis file, or via the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gaiad collect-gentxs
|
||||||
|
```
|
||||||
|
|
||||||
|
This command will add all the `gentxs` stored in `~/.gaiad/config/gentx` to the genesis file. In order to create a genesis transaction, click [here](./validators/validator-setup.md#participate-in-genesis-as-a-validator).
|
|
@ -15,7 +15,7 @@ source ~/.bash_profile
|
||||||
```
|
```
|
||||||
|
|
||||||
::: tip
|
::: tip
|
||||||
**Go 1.11.5+** is required for the Cosmos SDK.
|
**Go 1.12.1+** is required for the Cosmos SDK.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Install the binaries
|
### Install the binaries
|
||||||
|
@ -25,7 +25,7 @@ If necessary, make sure you `git checkout` the correct
|
||||||
[released version](https://github.com/cosmos/cosmos-sdk/releases).
|
[released version](https://github.com/cosmos/cosmos-sdk/releases).
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
For the mainnet, make sure your version if greather than `v0.33.0`
|
For the mainnet, make sure your version if greater than `v0.33.0`
|
||||||
:::
|
:::
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -66,7 +66,7 @@ Build tags indicate special features that have been enabled in the binary.
|
||||||
|
|
||||||
### Install binary distribution via snap (Linux only)
|
### Install binary distribution via snap (Linux only)
|
||||||
|
|
||||||
**Do not use snap at this time to install the binaries for production until we have a reproduceable binary system.**
|
**Do not use snap at this time to install the binaries for production until we have a reproducible binary system.**
|
||||||
|
|
||||||
|
|
||||||
### Next
|
### Next
|
|
@ -56,7 +56,7 @@ Fetch the testnet's `genesis.json` file into `gaiad`'s config directory.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mkdir -p $HOME/.gaiad/config
|
mkdir -p $HOME/.gaiad/config
|
||||||
curl https://raw.githubusercontent.com/cosmos/launch/master/latest/genesis.json > $HOME/.gaiad/config/genesis.json
|
curl https://raw.githubusercontent.com/cosmos/launch/master/genesis.json > $HOME/.gaiad/config/genesis.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Note we use the `latest` directory in the [launch repo](https://github.com/cosmos/launch) which contains details for the mainnet like the latest version and the genesis file.
|
Note we use the `latest` directory in the [launch repo](https://github.com/cosmos/launch) which contains details for the mainnet like the latest version and the genesis file.
|
||||||
|
@ -81,7 +81,7 @@ You can also ask for peers on the [Validators Riot Room](https://riot.im/app/#/r
|
||||||
|
|
||||||
For more information on seeds and peers, you can [read this](https://github.com/tendermint/tendermint/blob/develop/docs/tendermint-core/using-tendermint.md#peers).
|
For more information on seeds and peers, you can [read this](https://github.com/tendermint/tendermint/blob/develop/docs/tendermint-core/using-tendermint.md#peers).
|
||||||
|
|
||||||
## A note on gas and fees
|
## A Note on Gas and Fees
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
On Cosmos Hub mainnet, the accepted denom is `uatom`, where `1atom = 1.000.000uatom`
|
On Cosmos Hub mainnet, the accepted denom is `uatom`, where `1atom = 1.000.000uatom`
|
||||||
|
@ -147,6 +147,36 @@ If you plan to start a new network from the exported state, export with the `--f
|
||||||
gaiad export --height [height] --for-zero-height > [filename].json
|
gaiad export --height [height] --for-zero-height > [filename].json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Verify Mainnet
|
||||||
|
|
||||||
|
Help to prevent a catastrophe by running invariants on each block on your full
|
||||||
|
node. In essence, by running invariants you ensure that the state of mainnet is
|
||||||
|
the correct expected state. One vital invariant check is that no atoms are
|
||||||
|
being created or destroyed outside of expected protocol, however there are many
|
||||||
|
other invariant checks each unique to their respective module. Because invariant checks
|
||||||
|
are computationally expensive, they are not enabled by default. To run a node with
|
||||||
|
these checks start your node with the assert-invariants-blockly flag:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gaiad start --assert-invariants-blockly
|
||||||
|
```
|
||||||
|
|
||||||
|
If an invariant is broken on your node, your node will panic and prompt you to send
|
||||||
|
a transaction which will halt mainnet. For example the provided message may look like:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
invariant broken:
|
||||||
|
loose token invariance:
|
||||||
|
pool.NotBondedTokens: 100
|
||||||
|
sum of account tokens: 101
|
||||||
|
CRITICAL please submit the following transaction:
|
||||||
|
gaiacli tx crisis invariant-broken staking supply
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
When submitting a invariant-broken transaction, transaction fee tokens are not
|
||||||
|
deducted as the blockchain will halt (aka. this is a free transaction).
|
||||||
|
|
||||||
## Upgrade to Validator Node
|
## Upgrade to Validator Node
|
||||||
|
|
||||||
You now have an active full node. What's the next step? You can upgrade your full node to become a Cosmos Validator. The top 100 validators have the ability to propose new blocks to the Cosmos Hub. Continue onto [the Validator Setup](./validators/validator-setup.md).
|
You now have an active full node. What's the next step? You can upgrade your full node to become a Cosmos Validator. The top 100 validators have the ability to propose new blocks to the Cosmos Hub. Continue onto [the Validator Setup](./validators/validator-setup.md).
|
|
@ -10,7 +10,7 @@ of the Cosmos-SDK to use and details about the genesis file.
|
||||||
**You need to [install gaia](./installation.md) before you go further**
|
**You need to [install gaia](./installation.md) before you go further**
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Starting a new Node
|
## Starting a New Node
|
||||||
|
|
||||||
> NOTE: If you ran a full node on a previous testnet, please skip to [Upgrading From Previous Testnet](#upgrading-from-previous-testnet).
|
> NOTE: If you ran a full node on a previous testnet, please skip to [Upgrading From Previous Testnet](#upgrading-from-previous-testnet).
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ To start a new node, the mainnet instructions apply:
|
||||||
|
|
||||||
The only difference is the SDK version and genesis file. See the [testnet repo](https://github.com/cosmos/testnets) for information on testnets, including the correct version of the Cosmos-SDK to use and details about the genesis file.
|
The only difference is the SDK version and genesis file. See the [testnet repo](https://github.com/cosmos/testnets) for information on testnets, including the correct version of the Cosmos-SDK to use and details about the genesis file.
|
||||||
|
|
||||||
## Upgrading your Node
|
## Upgrading Your Node
|
||||||
|
|
||||||
These instructions are for full nodes that have ran on previous versions of and would like to upgrade to the latest testnet.
|
These instructions are for full nodes that have ran on previous versions of and would like to upgrade to the latest testnet.
|
||||||
|
|
||||||
|
@ -59,4 +59,4 @@ make update_tools install
|
||||||
Note we use `master` here since it contains the latest stable release.
|
Note we use `master` here since it contains the latest stable release.
|
||||||
See the [testnet repo](https://github.com/cosmos/testnets) for details on which version is needed for which testnet, and the [SDK release page](https://github.com/cosmos/cosmos-sdk/releases) for details on each release.
|
See the [testnet repo](https://github.com/cosmos/testnets) for details on which version is needed for which testnet, and the [SDK release page](https://github.com/cosmos/cosmos-sdk/releases) for details on each release.
|
||||||
|
|
||||||
Your full node has been cleanly upgraded!
|
Your full node has been cleanly upgraded!
|
|
@ -1,6 +1,6 @@
|
||||||
# Ledger Nano Support
|
# Ledger Nano Support
|
||||||
|
|
||||||
## A note on HD wallet
|
## A Note on HD Wallet
|
||||||
|
|
||||||
HD Wallets, originally specified in Bitcoin's [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki), are a special kind of wallet that let users derive any number of accounts from a single seed. To understand what that means, let us first define some terminology:
|
HD Wallets, originally specified in Bitcoin's [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki), are a special kind of wallet that let users derive any number of accounts from a single seed. To understand what that means, let us first define some terminology:
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ The process of derivating accounts from the seed is deterministic. This means th
|
||||||
|
|
||||||
The funds stored in an account are controlled by the private key. This private key is generated using a one-way function from the mnemonic. If you lose the private key, you can retrieve it using the mnemonic. However, if you lose the mnemonic, you will lose access to all the derived private keys. Likewise, if someone gains access to your mnemonic, they gain access to all the associated accounts.
|
The funds stored in an account are controlled by the private key. This private key is generated using a one-way function from the mnemonic. If you lose the private key, you can retrieve it using the mnemonic. However, if you lose the mnemonic, you will lose access to all the derived private keys. Likewise, if someone gains access to your mnemonic, they gain access to all the associated accounts.
|
||||||
|
|
||||||
## Ledger Support for account keys
|
## Ledger Support for Account Keys
|
||||||
|
|
||||||
At the core of a Ledger device, there is a mnemonic that is used to generate private keys. When you initialize you Ledger, a mnemonic is generated.
|
At the core of a Ledger device, there is a mnemonic that is used to generate private keys. When you initialize you Ledger, a mnemonic is generated.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Each validator candidate is encouraged to run its operations independently, as diverse setups increase the resilience of the network. Validator candidates should commence their setup phase now in order to be on time for launch.
|
Each validator candidate is encouraged to run its operations independently, as diverse setups increase the resilience of the network. Validator candidates should commence their setup phase now in order to be on time for launch.
|
||||||
|
|
||||||
## Key management - HSM
|
## Key Management - HSM
|
||||||
|
|
||||||
It is mission critical that an attacker cannot steal a validator's key. If this is possible, it puts the entire stake delegated to the compromised validator at risk. Hardware security modules are an important strategy for mitigating this risk.
|
It is mission critical that an attacker cannot steal a validator's key. If this is possible, it puts the entire stake delegated to the compromised validator at risk. Hardware security modules are an important strategy for mitigating this risk.
|
||||||
|
|
||||||
|
@ -37,7 +37,9 @@ pex = false
|
||||||
Sentry Nodes should edit their config.toml:
|
Sentry Nodes should edit their config.toml:
|
||||||
```bash
|
```bash
|
||||||
# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
|
# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
|
||||||
private_peer_ids = "ipaddress of validator nodes"
|
# Example ID: 3e16af0cead27979e1fc3dac57d03df3c7a77acc@3.87.179.235:26656
|
||||||
|
|
||||||
|
private_peer_ids = "node_ids_of_private_peers"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
|
@ -16,7 +16,7 @@ The Cosmos Hub is a public Proof-Of-Stake (PoS) blockchain, meaning that the wei
|
||||||
|
|
||||||
Any user in the system can declare their intention to become a validator by sending a `create-validator` transaction. From there, they become validator candidates.
|
Any user in the system can declare their intention to become a validator by sending a `create-validator` transaction. From there, they become validator candidates.
|
||||||
|
|
||||||
The weight (i.e. voting power) of a validator determines wether or not they are an active validator. Initially, only the top 100 validators with the most voting power will be active validators.
|
The weight (i.e. voting power) of a validator determines whether or not they are an active validator. Initially, only the top 100 validators with the most voting power will be active validators.
|
||||||
|
|
||||||
### What is a full-node?
|
### What is a full-node?
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ After a validator is created with a `create-validator` transaction, they can be
|
||||||
- `unbonded`: Validator is not in the active set, and therefore not signing blocs. Validator cannot be slashed, and does not earn any reward. It is still possible to delegate Atoms to this validator. Un-delegating from an `unbonded` validator is immediate.
|
- `unbonded`: Validator is not in the active set, and therefore not signing blocs. Validator cannot be slashed, and does not earn any reward. It is still possible to delegate Atoms to this validator. Un-delegating from an `unbonded` validator is immediate.
|
||||||
|
|
||||||
|
|
||||||
### What is 'self-delegation'? How can I increase my 'self-delegatino'?
|
### What is 'self-delegation'? How can I increase my 'self-delegation'?
|
||||||
|
|
||||||
Self-delegation is delegation from a validator to themselves. This amount can be increases by sending a `delegate` transaction from your validator's `application` application key.
|
Self-delegation is delegation from a validator to themselves. This amount can be increases by sending a `delegate` transaction from your validator's `application` application key.
|
||||||
|
|
||||||
|
@ -113,13 +113,13 @@ Delegators are free to choose validators according to their own subjective crite
|
||||||
|
|
||||||
Apart from these criteria, there will be a possibility for validators to signal a website address to complete their resume. Validators will need to build reputation one way or another to attract delegators. For example, it would be a good practice for validators to have their setup audited by third parties. Note though, that the Tendermint team will not approve or conduct any audit themselves. For more on due diligence, see [this blog post](https://medium.com/@interchain_io/3d0faf10ce6f)
|
Apart from these criteria, there will be a possibility for validators to signal a website address to complete their resume. Validators will need to build reputation one way or another to attract delegators. For example, it would be a good practice for validators to have their setup audited by third parties. Note though, that the Tendermint team will not approve or conduct any audit themselves. For more on due diligence, see [this blog post](https://medium.com/@interchain_io/3d0faf10ce6f)
|
||||||
|
|
||||||
## Responsibilites
|
## Responsibilities
|
||||||
|
|
||||||
### Do validators need to be publicly identified?
|
### Do validators need to be publicly identified?
|
||||||
|
|
||||||
No, they do not. Each delegator will value validators based on their own criteria. Validators will be able to register a website address when they nominate themselves so that they can advertise their operation as they see fit. Some delegators may prefer a website that clearly displays the team operating the validator and their resume, while others might prefer anonymous validators with positive track records.
|
No, they do not. Each delegator will value validators based on their own criteria. Validators will be able to register a website address when they nominate themselves so that they can advertise their operation as they see fit. Some delegators may prefer a website that clearly displays the team operating the validator and their resume, while others might prefer anonymous validators with positive track records.
|
||||||
|
|
||||||
### What are the responsiblities of a validator?
|
### What are the responsibilities of a validator?
|
||||||
|
|
||||||
Validators have two main responsibilities:
|
Validators have two main responsibilities:
|
||||||
|
|
|
@ -55,7 +55,7 @@ When specifying commission parameters, the `commission-max-change-rate` is used
|
||||||
|
|
||||||
You can confirm that you are in the validator set by using a third party explorer.
|
You can confirm that you are in the validator set by using a third party explorer.
|
||||||
|
|
||||||
## Participate in genesis as a validator
|
## Participate in Genesis as a Validator
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
The genesis ceremony for the Cosmos Hub mainnet is closed. Please skip to the next section.
|
The genesis ceremony for the Cosmos Hub mainnet is closed. Please skip to the next section.
|
||||||
|
@ -98,7 +98,9 @@ You can then submit your `gentx` on the [launch repository](https://github.com/c
|
||||||
|
|
||||||
## Edit Validator Description
|
## Edit Validator Description
|
||||||
|
|
||||||
You can edit your validator's public description. This info is to identify your validator, and will be relied on by delegators to decide which validators to stake to. Make sure to provide input for every flag below, otherwise the field will default to empty (`--moniker` defaults to the machine name).
|
You can edit your validator's public description. This info is to identify your validator, and will be relied on by delegators to decide which validators to stake to. Make sure to provide input for every flag below. If a flag is not included in the command the field will default to empty (`--moniker` defaults to the machine name) if the field has never been set or remain the same if it has been set in the past.
|
||||||
|
|
||||||
|
The <key_name> specifies which validator you are editing. If you choose to not include certain flags, remember that the --from flag must be included to identify the validator to update.
|
||||||
|
|
||||||
The `--identity` can be used as to verify identity with systems like Keybase or UPort. When using with Keybase `--identity` should be populated with a 16-digit string that is generated with a [keybase.io](https://keybase.io) account. It's a cryptographically secure method of verifying your identity across multiple online networks. The Keybase API allows us to retrieve your Keybase avatar. This is how you can add a logo to your validator profile.
|
The `--identity` can be used as to verify identity with systems like Keybase or UPort. When using with Keybase `--identity` should be populated with a 16-digit string that is generated with a [keybase.io](https://keybase.io) account. It's a cryptographically secure method of verifying your identity across multiple online networks. The Keybase API allows us to retrieve your Keybase avatar. This is how you can add a logo to your validator profile.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
`gaia` is the name of the Cosmos SDK application for the Cosmos Hub. It comes with 2 main entrypoints:
|
`gaia` is the name of the Cosmos SDK application for the Cosmos Hub. It comes with 2 main entrypoints:
|
||||||
|
|
||||||
- `gaiad`: The Gaia Daemon, runs a full-node of the `gaia` application.
|
- `gaiad`: The Gaia Daemon, runs a full-node of the `gaia` application.
|
||||||
- `gaiacli`: The Gaia command-line interface, which enables interraction with a Gaia full-node.
|
- `gaiacli`: The Gaia command-line interface, which enables interaction with a Gaia full-node.
|
||||||
|
|
||||||
`gaia` is built on the Cosmos SDK using the following modules:
|
`gaia` is built on the Cosmos SDK using the following modules:
|
||||||
|
|
|
@ -8,6 +8,6 @@ It is based on two major principles:
|
||||||
|
|
||||||
- **Composability:** Anyone can create a module for the Cosmos-SDK, and integrating the already-built modules is as simple as importing them into your blockchain application.
|
- **Composability:** Anyone can create a module for the Cosmos-SDK, and integrating the already-built modules is as simple as importing them into your blockchain application.
|
||||||
|
|
||||||
- **Capabilities:** The SDK is inspired by capabilities-based security, and informed by years of wrestling with blockchain state-machines. Most developers will need to access other 3rd party modules when building their own modules. Given that the Cosmos-SDK is an open framework, some of the modules may be malicious, which means there is a need for security principles to reason about inter-module interactions. These principles are based on object-cababilities. In practice, this means that instead of having each module keep an access control list for other modules, each module implements special objects called keepers that can be passed to other modules to grant a pre-defined set of capabilities. For example, if an instance of module A's keepers is passed to module B, the latter will be able to call a restricted set of module A's functions. The capabilities of each keeper are defined by the module's developer, and it's the developer's job to understand and audit the safety of foreign code from 3rd party modules based on the capabilities they are passing into each third party module. For a deeper look at capabilities, jump to [this section](./ocap.md).
|
- **Capabilities:** The SDK is inspired by capabilities-based security, and informed by years of wrestling with blockchain state-machines. Most developers will need to access other 3rd party modules when building their own modules. Given that the Cosmos-SDK is an open framework, some of the modules may be malicious, which means there is a need for security principles to reason about inter-module interactions. These principles are based on object-capabilities. In practice, this means that instead of having each module keep an access control list for other modules, each module implements special objects called keepers that can be passed to other modules to grant a pre-defined set of capabilities. For example, if an instance of module A's keepers is passed to module B, the latter will be able to call a restricted set of module A's functions. The capabilities of each keeper are defined by the module's developer, and it's the developer's job to understand and audit the safety of foreign code from 3rd party modules based on the capabilities they are passing into each third party module. For a deeper look at capabilities, jump to [this section](./ocap.md).
|
||||||
|
|
||||||
### Next, learn more about the [SDK Application Architecture](./sdk-app-architecture.md)
|
### Next, learn more about the [SDK Application Architecture](./sdk-app-architecture.md)
|
||||||
|
|
|
@ -32,7 +32,7 @@ The Cosmos SDK gives you maximum flexibility to define the state of your applica
|
||||||
|
|
||||||
## Tendermint
|
## Tendermint
|
||||||
|
|
||||||
As a developer, you just have to define the state machine using the Cosmos-SDK, and [*Tendermint*](https://tendermint.com/docs/introduction/introduction.html) will handle replication over the network for you.
|
As a developer, you just have to define the state machine using the Cosmos-SDK, and [*Tendermint*](https://tendermint.com/docs/introduction/what-is-tendermint.html) will handle replication over the network for you.
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -52,7 +52,7 @@ Blockchain node | | Consensus | |
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Tendermint is an application-agnostic engine that is responsible for handling the *networking* and *consensus* layers of your blockchain. In practice, this means that Tendermint is reponsible for propagating and ordering transaction bytes. Tendermint Core relies on an eponymous Byzantine-Fault-Tolerant (BFT) algorithm to reach consensus on the order of transactions. For more on Tendermint, click [here](https://tendermint.com/docs/introduction/introduction.html).
|
Tendermint is an application-agnostic engine that is responsible for handling the *networking* and *consensus* layers of your blockchain. In practice, this means that Tendermint is responsible for propagating and ordering transaction bytes. Tendermint Core relies on an eponymous Byzantine-Fault-Tolerant (BFT) algorithm to reach consensus on the order of transactions. For more on Tendermint, click [here](https://tendermint.com/docs/introduction/what-is-tendermint.html).
|
||||||
|
|
||||||
Tendermint consensus algorithm works with a set of special nodes called *Validators*. Validators are responsible for adding blocks of transactions to the blockchain. At any given block, there is a validator set V. A validator in V is chosen by the algorithm to be the proposer of the next block. This block is considered valid if more than two thirds of V signed a *[prevote](https://tendermint.com/docs/spec/consensus/consensus.html#prevote-step-height-h-round-r)* and a *[precommit](https://tendermint.com/docs/spec/consensus/consensus.html#precommit-step-height-h-round-r)* on it, and if all the transactions that it contains are valid. The validator set can be changed by rules written in the state-machine. For a deeper look at the algorithm, click [here](https://tendermint.com/docs/introduction/what-is-tendermint.html#consensus-overview).
|
Tendermint consensus algorithm works with a set of special nodes called *Validators*. Validators are responsible for adding blocks of transactions to the blockchain. At any given block, there is a validator set V. A validator in V is chosen by the algorithm to be the proposer of the next block. This block is considered valid if more than two thirds of V signed a *[prevote](https://tendermint.com/docs/spec/consensus/consensus.html#prevote-step-height-h-round-r)* and a *[precommit](https://tendermint.com/docs/spec/consensus/consensus.html#precommit-step-height-h-round-r)* on it, and if all the transactions that it contains are valid. The validator set can be changed by rules written in the state-machine. For a deeper look at the algorithm, click [here](https://tendermint.com/docs/introduction/what-is-tendermint.html#consensus-overview).
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ Tendermint passes transactions from the network to the application through an in
|
||||||
+---------------------+
|
+---------------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that Tendermint only handles transaction bytes. It has no knowledge of what these bytes realy mean. All Tendermint does is to order them deterministically. It is the job of the application to give meaning to these bytes. Tendermint passes the bytes to the application via the ABCI, and expects a return code to inform it if the message was succesful or not.
|
Note that Tendermint only handles transaction bytes. It has no knowledge of what these bytes really mean. All Tendermint does is to order them deterministically. It is the job of the application to give meaning to these bytes. Tendermint passes the bytes to the application via the ABCI, and expects a return code to inform it if the message was successful or not.
|
||||||
|
|
||||||
Here are the most important messages of the ABCI:
|
Here are the most important messages of the ABCI:
|
||||||
|
|
||||||
|
|
|
@ -74,9 +74,9 @@ The power of the Cosmos SDK lies in its modularity. SDK applications are built b
|
||||||
v
|
v
|
||||||
```
|
```
|
||||||
|
|
||||||
Each module can be seen as a little state-machine. Developers need to define the subset of the state handled by the module, as well as custom message types that modify the state (*Note:* Messages are extracted from transactions in `baseapp`'s methods). In general, each module declares its own `KVStore` in the multistore to persist the subset of the state it defines. Most developers will need to access other 3rd party modules when building their own modules. Given that the Cosmos-SDK is an open framework, some of the modules may be malicious, which means there is a need for security principles to reason about inter-module interactions. These principles are based on [object-cababilities](./ocap.md). In practice, this means that instead of having each module keep an access control list for other modules, each module implements special objects called keepers that can be passed to other modules to grant a pre-defined set of capabilities.
|
Each module can be seen as a little state-machine. Developers need to define the subset of the state handled by the module, as well as custom message types that modify the state (*Note:* Messages are extracted from transactions in `baseapp`'s methods). In general, each module declares its own `KVStore` in the multistore to persist the subset of the state it defines. Most developers will need to access other 3rd party modules when building their own modules. Given that the Cosmos-SDK is an open framework, some of the modules may be malicious, which means there is a need for security principles to reason about inter-module interactions. These principles are based on [object-capabilities](./ocap.md). In practice, this means that instead of having each module keep an access control list for other modules, each module implements special objects called keepers that can be passed to other modules to grant a pre-defined set of capabilities.
|
||||||
|
|
||||||
SDK modules are defined in the `.x/` folder of the SDK. Some core modules include:
|
SDK modules are defined in the `x/` folder of the SDK. Some core modules include:
|
||||||
|
|
||||||
- `x/auth`: Used to manage accounts and signatures.
|
- `x/auth`: Used to manage accounts and signatures.
|
||||||
- `x/bank`: Used to enable tokens and token transfers.
|
- `x/bank`: Used to enable tokens and token transfers.
|
||||||
|
|
|
@ -15,7 +15,7 @@ signature verification, as well as costs proportional to the tx size. Operators
|
||||||
should set minimum gas prices when starting their nodes. They must set the unit
|
should set minimum gas prices when starting their nodes. They must set the unit
|
||||||
costs of gas in each token denomination they wish to support:
|
costs of gas in each token denomination they wish to support:
|
||||||
|
|
||||||
`gaiad start ... --minimum-gas-prices=0.00001steak;0.05photinos`
|
`gaiad start ... --minimum-gas-prices=0.00001stake;0.05photinos`
|
||||||
|
|
||||||
When adding transactions to mempool or gossipping transactions, validators check
|
When adding transactions to mempool or gossipping transactions, validators check
|
||||||
if the transaction's gas prices, which are determined by the provided fees, meet
|
if the transaction's gas prices, which are determined by the provided fees, meet
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Concepts
|
||||||
|
|
||||||
|
The intention of the circuit breaker is to have a contingency plan for a
|
||||||
|
running network which maintains network liveness. This can be achieved through
|
||||||
|
selectively "pausing" functionality of specific modules on a running network.
|
||||||
|
The circuit breaker is intended to be enabled through either:
|
||||||
|
|
||||||
|
- governance
|
||||||
|
- for emergencies a special subset of accounts selected by the state machine
|
||||||
|
- a transaction which proves the expected behaviour is broken
|
||||||
|
|
||||||
|
## Pause state
|
||||||
|
|
||||||
|
The basic pause state of any module simply disables all message routes to
|
||||||
|
that module. Beyond that, it may be a appropriate for different modules to
|
||||||
|
process begin-block/end-block in an altered "safe" way.
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue