Merge PR #4036: Release v0.34.0

This commit is contained in:
Jack Zampolin 2019-04-15 06:56:42 -07:00 committed by GitHub
commit 7cb34220af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
287 changed files with 10229 additions and 4227 deletions

View File

@ -3,7 +3,7 @@ version: 2
defaults: &linux_defaults
working_directory: /go/src/github.com/cosmos/cosmos-sdk
docker:
- image: circleci/golang:1.11.5
- image: circleci/golang:1.12.1
environment:
GOBIN: /tmp/workspace/bin
@ -17,7 +17,7 @@ macos_config: &macos_defaults
xcode: "10.1.0"
working_directory: /Users/distiller/project/src/github.com/cosmos/cosmos-sdk
environment:
GO_VERSION: "1.11.5"
GO_VERSION: "1.12.1"
set_macos_env: &macos_env
run:
@ -27,6 +27,7 @@ set_macos_env: &macos_env
echo 'export GOPATH=$HOME/project' >> $BASH_ENV
echo 'export GOBIN=$GOPATH/bin' >> $BASH_ENV
echo 'export PATH=$PATH:$HOME/go/bin:$GOBIN' >> $BASH_ENV
echo 'export GO111MODULE=on'
############
#
@ -35,7 +36,7 @@ set_macos_env: &macos_env
docs_update: &docs_deploy
working_directory: ~/repo
docker:
- image: tendermint/docs_deployment
- image: tendermintdev/jq_curl
environment:
AWS_REGION: us-east-1
@ -44,7 +45,6 @@ deps: &dependencies
name: dependencies
command: |
export PATH="$GOBIN:$PATH"
make vendor-deps
jobs:
setup_dependencies:
@ -53,6 +53,9 @@ jobs:
- run: mkdir -p /tmp/workspace/bin
- run: mkdir -p /tmp/workspace/profiles
- checkout
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: tools
command: |
@ -63,7 +66,12 @@ jobs:
name: binaries
command: |
export PATH="$GOBIN:$PATH"
make go-mod-cache
make install
- save_cache:
key: go-mod-v1-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
- persist_to_workspace:
root: /tmp/workspace
paths:
@ -78,17 +86,14 @@ jobs:
at: /tmp/workspace
- checkout
- *dependencies
- run:
name: Get metalinter
command: |
export PATH="$GOBIN:$PATH"
make devtools-clean
make devtools
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: Lint source
command: |
export PATH="$GOBIN:$PATH"
make test_lint
make ci-lint
integration_tests:
<<: *linux_defaults
@ -98,6 +103,9 @@ jobs:
at: /tmp/workspace
- checkout
- *dependencies
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: Test cli
command: |
@ -112,6 +120,9 @@ jobs:
at: /tmp/workspace
- checkout
- *dependencies
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: Test individual module simulations
command: |
@ -126,6 +137,9 @@ jobs:
at: /tmp/workspace
- checkout
- *dependencies
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: Test full Gaia simulation
command: |
@ -140,6 +154,9 @@ jobs:
at: /tmp/workspace
- checkout
- *dependencies
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: Test Gaia import/export simulation
command: |
@ -154,6 +171,9 @@ jobs:
at: /tmp/workspace
- checkout
- *dependencies
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: Test Gaia import/export simulation
command: |
@ -168,10 +188,14 @@ jobs:
at: /tmp/workspace
- checkout
- *dependencies
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: Test multi-seed Gaia simulation long
command: |
export PATH="$GOBIN:$PATH"
export GO111MODULE=on
scripts/multisim.sh 500 50 TestFullGaiaSimulation
test_sim_gaia_multi_seed:
@ -182,10 +206,14 @@ jobs:
at: /tmp/workspace
- checkout
- *dependencies
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: Test multi-seed Gaia simulation short
command: |
export PATH="$GOBIN:$PATH"
export GO111MODULE=on
scripts/multisim.sh 50 10 TestFullGaiaSimulation
test_cover:
@ -197,14 +225,18 @@ jobs:
- checkout
- *dependencies
- run: mkdir -p /tmp/logs
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
- run:
name: Run tests
command: |
export PATH="$GOBIN:$PATH"
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
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
- persist_to_workspace:
root: /tmp/workspace
@ -253,7 +285,7 @@ jobs:
GOPATH: /home/circleci/.go_workspace/
GOOS: linux
GOARCH: amd64
GO_VERSION: "1.11.5"
GO_VERSION: "1.12.1"
parallelism: 1
steps:
- checkout
@ -268,7 +300,6 @@ jobs:
popd
set -x
make tools
make vendor-deps
make build-linux
make localnet-start
./scripts/localnet-blocks-test.sh 40 5 10 localhost
@ -280,7 +311,22 @@ jobs:
- run:
name: Trigger website build
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_defaults
@ -300,7 +346,6 @@ jobs:
command: |
source $BASH_ENV
make tools
make vendor-deps
make install
- run:
name: Integration tests
@ -322,14 +367,19 @@ jobs:
- setup_remote_docker:
docker_layer_caching: true
- run: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
GAIAD_VERSION=''
if [ "${CIRCLE_BRANCH}" = "master" ]; then
GAIAD_VERSION="stable"
elif [ "${CIRCLE_BRANCH}" == "develop" ]; then
elif [ "${CIRCLE_BRANCH}" = "develop" ]; then
GAIAD_VERSION="develop"
fi
docker build -t tendermint/gaia:$GAIAD_VERSION .
docker login -u $DOCKER_USER -p $DOCKER_PASS
docker push tendermint/gaia:$GAIAD_VERSION
if [ -z "${GAIAD_VERSION}" ]; then
docker build .
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:
<<: *linux_defaults
@ -349,11 +399,6 @@ workflows:
test-suite:
jobs:
- docker_image:
filters:
branches:
only:
- master
- develop
requires:
- setup_dependencies
- docker_tagged:
@ -378,7 +423,12 @@ workflows:
only:
- master
- develop
- setup_dependencies
- setup_dependencies:
# filters here are needed to enable this job also for tags
filters:
tags:
only:
- /^v.*/
- lint:
requires:
- setup_dependencies

View File

@ -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.
- [ ] Wrote tests
- [ ] 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
______

5
.gitignore vendored
View File

@ -7,18 +7,17 @@
*.swn
.vscode
.idea
*.pyc
# Build
vendor
vendor-deps
.vendor-new
build
tools/bin/*
examples/build/*
docs/_build
docs/tutorial
dist
devtools-stamp
tools-stamp
# Data - ideally these don't exist
baseapp/data/*

17
.golangci.yml Normal file
View File

@ -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

View File

@ -1,5 +1,153 @@
# 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
### Improvements

View File

@ -100,21 +100,15 @@ Please don't make Pull Requests to `master`.
## 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
with `go get`, which means they should be kept up-to-date with their
dependencies so we can get away with telling people they can just `go get` our
software.
The master branch of every Cosmos repository should just build with `go get`,
which means they should be kept up-to-date with their dependencies so we can
get away with telling people they can just `go get` our software.
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
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.
build, in which case we can fall back on `go mod tidy -v`.
## Testing
@ -171,7 +165,7 @@ only pull requests targeted directly against master.
### Development Procedure:
- the latest state of development is on `develop`
- `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)
- 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`

View File

@ -5,7 +5,7 @@
FROM golang:alpine AS build-env
# 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
WORKDIR /go/src/github.com/cosmos/cosmos-sdk
@ -16,8 +16,6 @@ COPY . .
# Install minimum necessary dependencies, build Cosmos SDK, remove packages
RUN apk add --no-cache $PACKAGES && \
make tools && \
make vendor-deps && \
make build && \
make install
# Final image

725
Gopkg.lock generated
View File

@ -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

View File

@ -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
View File

@ -4,11 +4,10 @@ VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//')
COMMIT := $(shell git log -1 --format='%H')
CAT := $(if $(filter $(OS),Windows_NT),type,cat)
LEDGER_ENABLED ?= true
GOTOOLS = \
github.com/golang/dep/cmd/dep \
github.com/alecthomas/gometalinter \
github.com/rakyll/statik
GOBIN ?= $(GOPATH)/bin
GOSUM := $(shell which gosum)
export GO111MODULE = on
# process build tags
@ -46,9 +45,12 @@ build_tags := $(strip $(build_tags))
ldflags = -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
-X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \
-X github.com/cosmos/cosmos-sdk/version.VendorDirHash=$(shell $(CAT) vendor-deps) \
-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)
ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=cleveldb
endif
@ -57,7 +59,7 @@ ldflags := $(strip $(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.
include scripts/Makefile
@ -65,36 +67,36 @@ include scripts/Makefile
########################################
### CI
ci: devtools vendor-deps install test_cover test_lint test
ci: tools install test_cover lint test
########################################
### Build/Install
build:
build: go.sum
ifeq ($(OS),Windows_NT)
go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaia/cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaia/cmd/gaiacli
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaia/cmd/gaiad
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaia/cmd/gaiacli
else
go build $(BUILD_FLAGS) -o build/gaiad ./cmd/gaia/cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli
go build $(BUILD_FLAGS) -o build/gaiareplay ./cmd/gaia/cmd/gaiareplay
go build $(BUILD_FLAGS) -o build/gaiakeyutil ./cmd/gaia/cmd/gaiakeyutil
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiad ./cmd/gaia/cmd/gaiad
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiareplay ./cmd/gaia/cmd/gaiareplay
go build -mod=readonly $(BUILD_FLAGS) -o build/gaiakeyutil ./cmd/gaia/cmd/gaiakeyutil
endif
build-linux: vendor-deps
build-linux: go.sum
LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build
update_gaia_lite_docs:
@statik -src=client/lcd/swagger-ui -dest=client/lcd -f
install: vendor-deps check-ledger update_gaia_lite_docs
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiareplay
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiakeyutil
install: go.sum check-ledger update_gaia_lite_docs
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiareplay
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiakeyutil
install_debug:
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiadebug
install_debug: go.sum
go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiadebug
dist:
@bash publish/dist.sh
@ -103,38 +105,13 @@ dist:
########################################
### Tools & dependencies
check_tools:
@# https://stackoverflow.com/a/25668869
@echo "Found tools: $(foreach tool,$(notdir $(GOTOOLS)),\
$(if $(shell which $(tool)),$(tool),$(error "No $(tool) in PATH")))"
go-mod-cache: go.sum
@echo "--> Download go modules to local cache"
@go mod download
update_tools:
@echo "--> Updating tools to correct version"
$(MAKE) --always-make tools
update_dev_tools:
@echo "--> Downloading linters (this may take awhile)"
$(GOPATH)/src/github.com/alecthomas/gometalinter/scripts/install.sh -b $(GOBIN)
go get -u github.com/tendermint/lint/golint
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
go.sum: tools go.mod
@echo "--> Ensure dependencies have not been modified"
@go mod verify
draw_deps: tools
@# 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
clean:
rm -f devtools-stamp vendor-deps snapcraft-local.yaml
rm -rf snapcraft-local.yaml build/
distclean: clean
rm -rf vendor/
@ -160,34 +137,34 @@ godocs:
test: test_unit
test_cli:
@go test -p 4 `go list github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test` -tags=cli_test
test_cli: build
@go test -mod=readonly -p 4 `go list ./cmd/gaia/cli_test/...` -tags=cli_test
test_ledger:
# 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
@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:
@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:
@VERSION=$(VERSION) go test -race $(PACKAGES_NOSIMULATION)
@VERSION=$(VERSION) go test -mod=readonly -race $(PACKAGES_NOSIMULATION)
test_sim_gaia_nondeterminism:
@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:
@echo "Running custom genesis simulation..."
@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
test_sim_gaia_fast:
@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:
@echo "Running Gaia import/export simulation. This may take several minutes..."
@ -211,31 +188,31 @@ SIM_BLOCK_SIZE ?= 200
SIM_COMMIT ?= true
test_sim_gaia_benchmark:
@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
test_sim_gaia_profile:
@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
test_cover:
@export VERSION=$(VERSION); bash -x tests/test_cover.sh
test_lint:
gometalinter --config=tools/gometalinter.json ./...
!(gometalinter --exclude /usr/lib/go/src/ --exclude client/lcd/statik/statik.go --exclude 'vendor/*' --disable-all --enable='errcheck' --vendor ./... | grep -v "client/")
lint: tools ci-lint
ci-lint:
golangci-lint run
go vet -composites=false -tests=false ./...
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s
dep status >> /dev/null
!(grep -n branch Gopkg.toml)
go mod verify
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 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
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
# unless there is a reason not to.
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: build install install_debug dist clean distclean \
check_tools check_dev_tools get_vendor_deps draw_deps test test_cli test_unit \
test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
.PHONY: install install_debug dist clean distclean \
draw_deps test test_cli test_unit \
test_cover lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
build-linux build-docker-gaiadnode localnet-start localnet-stop \
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast \
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 \
devtools-clean
test_sim_gaia_multi_seed test_sim_gaia_import_export \
go-mod-cache

View File

@ -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

View File

@ -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
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

View File

@ -287,12 +287,25 @@ func (app *BaseApp) storeConsensusParams(consensusParams *abci.ConsensusParams)
mainStore.Set(mainConsensusParamsKey, consensusParamsBz)
}
// getMaximumBlockGas gets the maximum gas from the consensus params.
func (app *BaseApp) getMaximumBlockGas() (maxGas uint64) {
if app.consensusParams == nil || app.consensusParams.BlockSize == nil {
// getMaximumBlockGas gets the maximum gas from the consensus params. It panics
// if maximum block gas is less than negative one and returns zero if negative
// one.
func (app *BaseApp) getMaximumBlockGas() uint64 {
if app.consensusParams == nil || app.consensusParams.Block == nil {
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.
func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) {
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
// already be initialized in InitChain. Otherwise app.deliverState will be
// 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.
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 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
if !msgResult.IsOK() {
idxLog.Success = false
idxlogs = append(idxlogs, idxLog)
idxLogs = append(idxLogs, idxLog)
code = msgResult.Code
codespace = msgResult.Codespace
@ -673,10 +703,10 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
}
idxLog.Success = true
idxlogs = append(idxlogs, idxLog)
idxLogs = append(idxLogs, idxLog)
}
logJSON := codec.Cdc.MustMarshalJSON(idxlogs)
logJSON := codec.Cdc.MustMarshalJSON(idxLogs)
result = sdk.Result{
Code: code,
Codespace: codespace,
@ -689,7 +719,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
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.
func (app *BaseApp) getState(mode runTxMode) *state {
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.
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() {
// At this point, newCtx.MultiStore() is cache-wrapped, or something else
// replaced by the ante handler. We want the original multistore, not one

View File

@ -296,6 +296,7 @@ func TestInitChainer(t *testing.T) {
// stores are mounted and private members are set - sealing baseapp
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
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
@ -308,6 +309,7 @@ func TestInitChainer(t *testing.T) {
app.Commit()
res = app.Query(query)
require.Equal(t, int64(1), app.LastBlockHeight())
require.Equal(t, value, res.Value)
// reload app
@ -316,14 +318,17 @@ func TestInitChainer(t *testing.T) {
app.MountStores(capKey, capKey2)
err = app.LoadLatestVersion(capKey) // needed to make stores non-nil
require.Nil(t, err)
require.Equal(t, int64(1), app.LastBlockHeight())
// ensure we can still query after reloading
res = app.Query(query)
require.Equal(t, value, res.Value)
// 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()
res = app.Query(query)
require.Equal(t, value, res.Value)
}
@ -514,7 +519,6 @@ func TestCheckTx(t *testing.T) {
app := setupBaseApp(t, anteOpt, routerOpt)
nTxs := int64(5)
app.InitChain(abci.RequestInitChain{})
// Create same codec used in txDecoder
@ -536,7 +540,8 @@ func TestCheckTx(t *testing.T) {
require.Equal(t, nTxs, storedCounter)
// 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.Commit()
@ -567,16 +572,22 @@ func TestDeliverTx(t *testing.T) {
nBlocks := 3
txPerHeight := 5
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++ {
counter := int64(blockN*txPerHeight + i)
tx := newTxCounter(counter, counter)
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
require.NoError(t, err)
res := app.DeliverTx(txBytes)
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
}
app.EndBlock(abci.RequestEndBlock{})
app.Commit()
}
@ -610,48 +621,47 @@ func TestMultiMsgDeliverTx(t *testing.T) {
// run a multi-msg tx
// 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
txCounter := getIntFromStore(store, anteKey)
require.Equal(t, int64(1), txCounter)
store := app.deliverState.ctx.KVStore(capKey1)
// msg counter incremented three times
msgCounter := getIntFromStore(store, deliverKey)
require.Equal(t, int64(3), msgCounter)
}
// tx counter only incremented once
txCounter := getIntFromStore(store, anteKey)
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
{
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
txCounter := getIntFromStore(store, anteKey)
require.Equal(t, int64(2), txCounter)
store = app.deliverState.ctx.KVStore(capKey1)
// original counter increments by one
// 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)
}
// tx counter only incremented once
txCounter = getIntFromStore(store, anteKey)
require.Equal(t, int64(2), txCounter)
// original counter increments by one
// 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
@ -692,7 +702,8 @@ func TestSimulateTx(t *testing.T) {
nBlocks := 3
for blockN := 0; blockN < nBlocks; blockN++ {
count := int64(blockN + 1)
app.BeginBlock(abci.RequestBeginBlock{})
header := abci.Header{Height: count}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
tx := newTxCounter(count, count)
txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx)
@ -737,7 +748,9 @@ func TestRunInvalidTransaction(t *testing.T) {
}
app := setupBaseApp(t, anteOpt, routerOpt)
app.BeginBlock(abci.RequestBeginBlock{})
header := abci.Header{Height: 1}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
// Transaction with no messages
{
@ -847,7 +860,8 @@ func TestTxGasLimits(t *testing.T) {
app := setupBaseApp(t, anteOpt, routerOpt)
app.BeginBlock(abci.RequestBeginBlock{})
header := abci.Header{Height: 1}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
testCases := []struct {
tx *txTest
@ -932,7 +946,7 @@ func TestMaxBlockGasLimits(t *testing.T) {
app := setupBaseApp(t, anteOpt, routerOpt)
app.InitChain(abci.RequestInitChain{
ConsensusParams: &abci.ConsensusParams{
BlockSize: &abci.BlockSizeParams{
Block: &abci.BlockParams{
MaxGas: 100,
},
},
@ -962,7 +976,8 @@ func TestMaxBlockGasLimits(t *testing.T) {
tx := tc.tx
// 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
for j := 0; j < tc.numDelivers; j++ {
@ -1005,7 +1020,9 @@ func TestBaseAppAnteHandler(t *testing.T) {
app.InitChain(abci.RequestInitChain{})
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
//
@ -1105,14 +1122,16 @@ func TestGasConsumptionBadTx(t *testing.T) {
app := setupBaseApp(t, anteOpt, routerOpt)
app.InitChain(abci.RequestInitChain{
ConsensusParams: &abci.ConsensusParams{
BlockSize: &abci.BlockSizeParams{
Block: &abci.BlockParams{
MaxGas: 9,
},
},
})
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.setFailOnAnte(true)
@ -1174,7 +1193,9 @@ func TestQuery(t *testing.T) {
require.Equal(t, 0, len(res.Value))
// 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)
require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
res = app.Query(query)
@ -1216,3 +1237,19 @@ func TestP2PQuery(t *testing.T) {
res = app.Query(idQuery)
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() })
}

View File

@ -18,14 +18,11 @@ const (
flagGet = "get"
)
var configDefaults map[string]string
func init() {
configDefaults = map[string]string{
"chain-id": "",
"output": "text",
"node": "tcp://localhost:26657",
}
var configDefaults = map[string]string{
"chain-id": "",
"output": "text",
"node": "tcp://localhost:26657",
"broadcast-mode": "sync",
}
// 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")
}
// Load configuration
// load configuration
tree, err := loadConfigFile(cfgFile)
if err != nil {
return err
}
// Print the config and exit
// print the config and exit
if len(args) == 0 {
s, err := tree.ToTomlString()
if err != nil {
@ -73,45 +70,54 @@ func runConfigCmd(cmd *cobra.Command, args []string) error {
}
key := args[0]
// Get value action
// get config value for a given key
if getAction {
switch key {
case "trace", "trust-node", "indent":
fmt.Println(tree.GetDefault(key, false).(bool))
default:
if defaultValue, ok := configDefaults[key]; ok {
fmt.Println(tree.GetDefault(key, defaultValue).(string))
return nil
}
return errUnknownConfigKey(key)
}
return nil
}
// Set value action
if len(args) != 2 {
return fmt.Errorf("wrong number of arguments")
}
value := args[1]
// set config value for a given key
switch key {
case "chain-id", "output", "node":
case "chain-id", "output", "node", "broadcast-mode":
tree.Set(key, value)
case "trace", "trust-node", "indent":
boolVal, err := strconv.ParseBool(value)
if err != nil {
return err
}
tree.Set(key, boolVal)
default:
return errUnknownConfigKey(key)
}
// Save configuration to disk
// save configuration to disk
if err := saveConfigFile(cfgFile, tree); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "configuration saved to %s\n", cfgFile)
fmt.Fprintf(os.Stderr, "configuration saved to %s\n", cfgFile)
return nil
}
@ -144,7 +150,7 @@ func loadConfigFile(cfgFile string) (*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 {
return err
}

44
client/config_test.go Normal file
View File

@ -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) }
}

View File

@ -3,6 +3,7 @@ package context
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -11,29 +12,36 @@ import (
// an intermediate structure which is logged if the context has a logger
// defined.
func (ctx CLIContext) BroadcastTx(txBytes []byte) (res sdk.TxResponse, err error) {
if ctx.Async {
if res, err = ctx.BroadcastTxAsync(txBytes); err != nil {
return
}
return
switch ctx.BroadcastMode {
case client.BroadcastSync:
res, err = ctx.BroadcastTxSync(txBytes)
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
}
return
return res, err
}
// BroadcastTxAndAwaitCommit broadcasts transaction bytes to a Tendermint node
// and waits for a commit.
func (ctx CLIContext) BroadcastTxAndAwaitCommit(tx []byte) (sdk.TxResponse, error) {
// BroadcastTxCommit broadcasts transaction bytes to a Tendermint node and
// waits for a commit.
//
// 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()
if err != nil {
return sdk.TxResponse{}, err
}
res, err := node.BroadcastTxCommit(tx)
res, err := node.BroadcastTxCommit(txBytes)
if err != nil {
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), err
return sdk.NewResponseFormatBroadcastTxCommit(res), nil
}
// BroadcastTxSync broadcasts transaction bytes to a Tendermint node synchronously.
func (ctx CLIContext) BroadcastTxSync(tx []byte) (sdk.TxResponse, error) {
// BroadcastTxSync broadcasts transaction bytes to a Tendermint node
// synchronously (i.e. returns after CheckTx execution).
func (ctx CLIContext) BroadcastTxSync(txBytes []byte) (sdk.TxResponse, error) {
node, err := ctx.GetNode()
if err != nil {
return sdk.TxResponse{}, err
}
res, err := node.BroadcastTxSync(tx)
if err != nil {
return sdk.NewResponseFormatBroadcastTx(res), err
}
res, err := node.BroadcastTxSync(txBytes)
return sdk.NewResponseFormatBroadcastTx(res), err
}
// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node asynchronously.
func (ctx CLIContext) BroadcastTxAsync(tx []byte) (sdk.TxResponse, error) {
// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node
// asynchronously (i.e. returns immediately).
func (ctx CLIContext) BroadcastTxAsync(txBytes []byte) (sdk.TxResponse, error) {
node, err := ctx.GetNode()
if err != nil {
return sdk.TxResponse{}, err
}
res, err := node.BroadcastTxAsync(tx)
if err != nil {
return sdk.NewResponseFormatBroadcastTx(res), err
}
res, err := node.BroadcastTxAsync(txBytes)
return sdk.NewResponseFormatBroadcastTx(res), err
}

View File

@ -44,7 +44,7 @@ type CLIContext struct {
AccountStore string
TrustNode bool
UseLedger bool
Async bool
BroadcastMode string
PrintResponse bool
Verifier tmlite.Verifier
VerifierHome string
@ -67,7 +67,8 @@ func NewCLIContext() CLIContext {
}
from := viper.GetString(client.FlagFrom)
fromAddress, fromName, err := GetFromFields(from)
genOnly := viper.GetBool(client.FlagGenerateOnly)
fromAddress, fromName, err := GetFromFields(from, genOnly)
if err != nil {
fmt.Printf("failed to get from fields: %v", err)
os.Exit(1)
@ -89,11 +90,11 @@ func NewCLIContext() CLIContext {
Height: viper.GetInt64(client.FlagHeight),
TrustNode: viper.GetBool(client.FlagTrustNode),
UseLedger: viper.GetBool(client.FlagUseLedger),
Async: viper.GetBool(client.FlagAsync),
BroadcastMode: viper.GetString(client.FlagBroadcastMode),
PrintResponse: viper.GetBool(client.FlagPrintResponse),
Verifier: verifier,
Simulate: viper.GetBool(client.FlagDryRun),
GenerateOnly: viper.GetBool(client.FlagGenerateOnly),
GenerateOnly: genOnly,
FromAddress: fromAddress,
FromName: fromName,
Indent: viper.GetBool(client.FlagIndentResponse),
@ -247,6 +248,13 @@ func (ctx CLIContext) WithFromAddress(addr sdk.AccAddress) CLIContext {
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
// NOTE: pass in marshalled structs that have been unmarshaled
// because this function will panic on marshaling errors
@ -259,7 +267,7 @@ func (ctx CLIContext) PrintOutput(toPrint fmt.Stringer) (err error) {
case "json":
if ctx.Indent {
out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ")
out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ")
} else {
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
// an address or key name.
func GetFromFields(from string) (sdk.AccAddress, string, error) {
// an address or key name. If genOnly is true, only a valid Bech32 cosmos
// address is returned.
func GetFromFields(from string, genOnly bool) (sdk.AccAddress, string, error) {
if from == "" {
return nil, "", nil
}
if genOnly {
addr, err := sdk.AccAddressFromBech32(from)
if err != nil {
return nil, "", err
}
return addr, "", nil
}
keybase, err := keys.NewKeyBaseFromHomeFlag()
if err != nil {
return nil, "", err

View File

@ -18,11 +18,20 @@ const (
DefaultGasLimit = 200000
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"
FlagChainID = "chain-id"
FlagNode = "node"
FlagHeight = "height"
FlagGas = "gas"
FlagGasAdjustment = "gas-adjustment"
FlagTrustNode = "trust-node"
FlagFrom = "from"
@ -32,7 +41,7 @@ const (
FlagMemo = "memo"
FlagFees = "fees"
FlagGasPrices = "gas-prices"
FlagAsync = "async"
FlagBroadcastMode = "broadcast-mode"
FlagPrintResponse = "print-response"
FlagDryRun = "dry-run"
FlagGenerateOnly = "generate-only"
@ -40,10 +49,6 @@ const (
FlagListenAddr = "laddr"
FlagCORS = "cors"
FlagMaxOpenConnections = "max-open"
FlagTLS = "tls"
FlagSSLHosts = "ssl-hosts"
FlagSSLCertFile = "ssl-certfile"
FlagSSLKeyFile = "ssl-keyfile"
FlagOutputDocument = "output-document" // inspired by wget -O
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(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().Int64(FlagHeight, 0, "block height to query, omit to get most recent provable block")
viper.BindPFlag(FlagTrustNode, c.Flags().Lookup(FlagTrustNode))
viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger))
viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode))
@ -77,15 +81,15 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
for _, c := range cmds {
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().Uint64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
c.Flags().Uint64(FlagSequence, 0, "Sequence number to sign the tx")
c.Flags().Uint64P(FlagAccountNumber, "a", 0, "The account number of the signing account (offline mode only)")
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(FlagFees, "", "Fees to pay along with transaction; eg: 10stake,1atom")
c.Flags().String(FlagGasPrices, "", "Gas prices to determine the transaction fee (e.g. 0.00001stake)")
c.Flags().String(FlagFees, "", "Fees to pay along with transaction; eg: 10uatom")
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().Bool(FlagUseLedger, false, "Use a connected Ledger device")
c.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ")
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
c.Flags().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(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")
@ -111,10 +115,6 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
func RegisterRestServerFlags(cmd *cobra.Command) *cobra.Command {
cmd = GetCommands(cmd)[0]
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().Int(FlagMaxOpenConnections, 1000, "The number of maximum open connections")

View File

@ -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().Uint32(flagAccount, 0, "Account 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
}
@ -146,7 +147,7 @@ func runAddCmd(_ *cobra.Command, args []string) error {
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
}
@ -216,7 +217,7 @@ func runAddCmd(_ *cobra.Command, args []string) error {
}
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
}

View File

@ -1,17 +1,20 @@
package keys
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
)
func listKeysCmd() *cobra.Command {
return &cobra.Command{
cmd := &cobra.Command{
Use: "list",
Short: "List all keys",
Long: `Return a list of all public keys stored by this key manager
along with their associated name and address.`,
RunE: runListCmd,
}
cmd.Flags().Bool(client.FlagIndentResponse, false, "Add indent to JSON response")
return cmd
}
func runListCmd(cmd *cobra.Command, args []string) error {

View File

@ -3,6 +3,7 @@ package keys
import (
"errors"
"fmt"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto"
"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().Uint(flagMultiSigThreshold, 1, "K out of N required signatures")
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
}

View File

@ -11,6 +11,17 @@ type AddNewKey struct {
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
type RecoverKey struct {
Password string `json:"password"`
@ -19,13 +30,26 @@ type RecoverKey struct {
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
type UpdateKeyReq struct {
OldPassword string `json:"old_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
type DeleteKeyReq struct {
Password string `json:"password"`
}
// NewDeleteKeyReq constructs a new DeleteKeyReq structure.
func NewDeleteKeyReq(password string) DeleteKeyReq { return DeleteKeyReq{Password: password} }

View File

@ -118,8 +118,14 @@ func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) {
printKeyTextHeader()
printKeyOutput(ko)
case "json":
out, err := MarshalJSON(ko)
case OutputFormatJSON:
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 {
panic(err)
}
@ -142,11 +148,18 @@ func printInfos(infos []keys.Info) {
}
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 {
panic(err)
}
fmt.Println(string(out))
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -11,6 +11,8 @@ import (
"testing"
"time"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client"
@ -520,9 +522,18 @@ func TestBonding(t *testing.T) {
// test redelegation
rdTokens := sdk.TokensFromTendermintPower(30)
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)
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
acc = getAccount(t, port, addr)
@ -542,20 +553,6 @@ func TestBonding(t *testing.T) {
require.Len(t, txs, 1)
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])
require.Len(t, redelegation, 1)
require.Len(t, redelegation[0].Entries, 1)
@ -614,7 +611,9 @@ func TestSubmitProposal(t *testing.T) {
require.Equal(t, uint32(0), resultTx.Code)
var proposalID uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.Data, &proposalID)
bz, err := hex.DecodeString(resultTx.Data)
require.NoError(t, err)
cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
// verify balance
acc = getAccount(t, port, addr)
@ -649,7 +648,9 @@ func TestDeposit(t *testing.T) {
require.Equal(t, uint32(0), resultTx.Code)
var proposalID uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.Data, &proposalID)
bz, err := hex.DecodeString(resultTx.Data)
require.NoError(t, err)
cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
// verify balance
acc = getAccount(t, port, addr)
@ -680,7 +681,7 @@ func TestDeposit(t *testing.T) {
// query proposal
totalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(10))}
proposal = getProposal(t, port, proposalID)
require.True(t, proposal.GetTotalDeposit().IsEqual(totalCoins))
require.True(t, proposal.TotalDeposit.IsEqual(totalCoins))
// query deposit
deposit := getDeposit(t, port, proposalID, addr)
@ -706,7 +707,9 @@ func TestVote(t *testing.T) {
require.Equal(t, uint32(0), resultTx.Code)
var proposalID uint64
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.Data, &proposalID)
bz, err := hex.DecodeString(resultTx.Data)
require.NoError(t, err)
cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
// verify balance
acc = getAccount(t, port, addr)
@ -718,7 +721,7 @@ func TestVote(t *testing.T) {
// query proposal
proposal := getProposal(t, port, proposalID)
require.Equal(t, "Test", proposal.GetTitle())
require.Equal(t, gov.StatusVotingPeriod, proposal.GetStatus())
require.Equal(t, gov.StatusVotingPeriod, proposal.Status)
// vote
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, time.Unix(0, 0).UTC(), signingInfo.JailedUntil)
require.Equal(t, true, signingInfo.MissedBlocksCounter == 0)
signingInfoList := getSigningInfoList(t, port)
require.NotZero(t, len(signingInfoList))
}
func TestProposalsQuery(t *testing.T) {
@ -805,18 +810,24 @@ func TestProposalsQuery(t *testing.T) {
// Addr1 proposes (and deposits) proposals #1 and #2
resultTx := doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit, fees)
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)
resultTx = doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], halfMinDeposit, fees)
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)
// Addr2 proposes (and deposits) proposals #3
resultTx = doSubmitProposal(t, port, seeds[1], names[1], passwords[1], addrs[1], halfMinDeposit, fees)
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)
// Addr2 deposits on proposals #2 & #3
@ -855,13 +866,13 @@ func TestProposalsQuery(t *testing.T) {
// Only proposals #1 should be in Deposit Period
proposals := getProposalsFilterStatus(t, port, gov.StatusDepositPeriod)
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
proposals = getProposalsFilterStatus(t, port, gov.StatusVotingPeriod)
require.Len(t, proposals, 2)
require.Equal(t, proposalID2, proposals[0].GetProposalID())
require.Equal(t, proposalID3, proposals[1].GetProposalID())
require.Equal(t, proposalID2, proposals[0].ProposalID)
require.Equal(t, proposalID3, proposals[1].ProposalID)
// Addr1 votes on proposals #2 & #3
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
proposals = getProposalsAll(t, port)
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
require.Equal(t, proposalID2, (proposals[1]).GetProposalID())
require.Equal(t, proposalID3, (proposals[2]).GetProposalID())
require.Equal(t, proposalID1, (proposals[0]).ProposalID)
require.Equal(t, proposalID2, (proposals[1]).ProposalID)
require.Equal(t, proposalID3, (proposals[2]).ProposalID)
// Test query deposited by addr1
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
proposals = getProposalsFilterDepositor(t, port, addrs[1])
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query voted by addr1
proposals = getProposalsFilterVoter(t, port, addrs[0])
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
require.Equal(t, proposalID2, (proposals[0]).ProposalID)
require.Equal(t, proposalID3, (proposals[1]).ProposalID)
// Test query voted by addr2
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
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
votes := getVotes(t, port, proposalID2)
@ -1008,3 +1019,29 @@ func TestDistributionFlow(t *testing.T) {
resultTx = doWithdrawDelegatorAllRewards(t, port, seed, name1, pw, addr, fees)
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), &params))
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))
}

View File

@ -52,61 +52,27 @@ func NewRestServer(cdc *codec.Codec) *RestServer {
}
// Start starts the rest server
func (rs *RestServer) Start(listenAddr string, sslHosts string,
certFile string, keyFile string, maxOpen int, secure bool) (err error) {
func (rs *RestServer) Start(listenAddr string, maxOpen int) (err error) {
server.TrapSignal(func() {
err := rs.listener.Close()
rs.log.Error("error closing listener", "err", err)
})
rs.listener, err = rpcserver.Listen(
listenAddr,
rpcserver.Config{MaxOpenConnections: maxOpen},
)
cfg := rpcserver.DefaultConfig()
cfg.MaxOpenConnections = maxOpen
rs.listener, err = rpcserver.Listen(listenAddr, cfg)
if err != nil {
return
}
rs.log.Info(fmt.Sprintf("Starting Gaia Lite REST service (chain-id: %q)...",
viper.GetString(client.FlagChainID)))
// launch rest-server in insecure mode
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,
rs.log.Info(
fmt.Sprintf(
"Starting Gaia Lite REST service (chain-id: %q)...",
viper.GetString(client.FlagChainID),
),
)
return rpcserver.StartHTTPServer(rs.listener, rs.Mux, rs.log, cfg)
}
// 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)
// Start the rest server and return error if one exists
err = rs.Start(
viper.GetString(client.FlagListenAddr),
viper.GetString(client.FlagSSLHosts),
viper.GetString(client.FlagSSLCertFile),
viper.GetString(client.FlagSSLKeyFile),
viper.GetInt(client.FlagMaxOpenConnections),
viper.GetBool(client.FlagTLS))
err = rs.Start(viper.GetString(client.FlagListenAddr),
viper.GetInt(client.FlagMaxOpenConnections))
return err
},

View File

@ -21,7 +21,7 @@ tags:
description: Query app version
schemes:
- https
host: fabo.interblock.io:1317
host: stargate.cosmos.network
securityDefinitions:
kms:
type: basic
@ -65,6 +65,17 @@ paths:
moniker:
type: string
example: validator-name
protocol_version:
properties:
p2p:
type: string
example: 7
block:
type: string
example: 10
app:
type: string
example: 0
network:
type: string
example: gaia-2
@ -79,9 +90,14 @@ paths:
example: 0.15.0
other:
description: more information on versions
type: array
items:
type: string
type: object
properties:
tx_index:
type: string
example: on
rpc_address:
type: string
example: tcp://0.0.0.0:26657
500:
description: Failed to query node status
/syncing:
@ -122,6 +138,7 @@ paths:
description: Block height
required: true
type: number
x-example: 1
responses:
200:
description: The block at a specific height
@ -167,6 +184,7 @@ paths:
description: Block height
required: true
type: number
x-example: 1
responses:
200:
description: The validator set at a specific block height
@ -198,6 +216,7 @@ paths:
description: Tx hash
required: true
type: string
x-example: 88D6B85EAB87D43CDF50F39C22FC2237A37FEDC4CE723200AD0AF48CBEDBC317
responses:
200:
description: Tx with the provided hash
@ -219,14 +238,17 @@ paths:
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'"
required: true
x-example: 'TODO'
- in: query
name: page
description: Pagination page
description: Page number
type: integer
x-example: 1
- in: query
name: size
description: Pagination size
name: limit
description: Maximum number of items per page
type: integer
x-example: 1
responses:
200:
description: All txs matching the provided tags
@ -250,14 +272,14 @@ paths:
parameters:
- in: body
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
schema:
type: object
properties:
tx:
$ref: "#/definitions/StdTx"
return:
mode:
type: string
example: block
responses:
@ -313,6 +335,7 @@ paths:
description: Account address in bech32 format
required: true
type: string
x-example: cosmos16gdxm24ht2mxtpz9cma6tr6a6d47x63hlq4pxt
responses:
200:
description: Account balances
@ -339,6 +362,7 @@ paths:
description: Account address in bech32 format
required: true
type: string
x-example: cosmos16gdxm24ht2mxtpz9cma6tr6a6d47x63hlq4pxt
- in: body
name: account
description: The sender and tx information
@ -374,6 +398,7 @@ paths:
description: Account address
required: true
type: string
x-example: cosmos16gdxm24ht2mxtpz9cma6tr6a6d47x63hlq4pxt
responses:
200:
description: Account information on the blockchain
@ -408,6 +433,7 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
get:
summary: Get all delegations from a delegator
tags:
@ -466,11 +492,13 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
- in: path
name: validatorAddr
description: Bech32 OperatorAddress of validator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Query the current delegation between a delegator and a validator
tags:
@ -493,6 +521,7 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
get:
summary: Get all unbonding delegations from a delegator
tags:
@ -552,11 +581,13 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
- in: path
name: validatorAddr
description: Bech32 OperatorAddress of validator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Query all unbonding delegations between a delegator and a validator
tags:
@ -613,6 +644,7 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
post:
summary: Submit a redelegation
parameters:
@ -655,6 +687,7 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
get:
summary: Query all validators that a delegator is bonded to
tags:
@ -679,11 +712,13 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
- in: path
name: validatorAddr
description: Bech32 ValAddress of Delegator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Query a validator that a delegator is bonded to
tags:
@ -706,6 +741,7 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
get:
summary: Get all staking txs (i.e msgs) from a delegator
tags:
@ -748,6 +784,7 @@ paths:
description: Bech32 OperatorAddress of validator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Query the information from a single validator
tags:
@ -770,6 +807,7 @@ paths:
description: Bech32 OperatorAddress of validator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Get all delegations from a validator
tags:
@ -794,6 +832,7 @@ paths:
description: Bech32 OperatorAddress of validator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Get all unbonding delegations from a validator
tags:
@ -881,26 +920,52 @@ paths:
name: validatorPubKey
required: true
in: path
x-example: cosmosvalconspub1zcjduepq7mft6gfls57a0a42d7uhx656cckhfvtrlmw744jv4q0mvlv0dypskehfk8
responses:
200:
description: OK
schema:
type: object
properties:
start_height:
type: string
index_offset:
type: string
jailed_until:
type: string
missed_blocks_counter:
type: string
$ref: "#/definitions/SigningInfo"
204:
description: No sign info of this validator
400:
description: Invalid validator public key
500:
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:
post:
summary: Unjail a jailed validator
@ -917,6 +982,7 @@ paths:
name: validatorAddr
required: true
in: path
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
- description: ""
name: UnjailBody
in: body
@ -1053,6 +1119,7 @@ paths:
name: proposalId
required: true
in: path
x-example: '1'
responses:
200:
description: OK
@ -1075,6 +1142,7 @@ paths:
name: proposalId
required: true
in: path
x-example: '1'
responses:
200:
description: OK
@ -1097,6 +1165,7 @@ paths:
name: proposalId
required: true
in: path
x-example: '1'
responses:
200:
description: OK
@ -1123,6 +1192,7 @@ paths:
name: proposalId
required: true
in: path
x-example: '1'
- description: ""
name: post_deposit_body
in: body
@ -1163,11 +1233,13 @@ paths:
name: proposalId
required: true
in: path
x-example: '1'
- type: string
description: Bech32 depositor address
name: depositor
required: true
in: path
x-example: cosmos1xl6453f6q6dv5770c9ue6hspdc0vxfuqtudkhz
responses:
200:
description: OK
@ -1193,6 +1265,7 @@ paths:
name: proposalId
required: true
in: path
x-example: '1'
responses:
200:
description: OK
@ -1219,6 +1292,7 @@ paths:
name: proposalId
required: true
in: path
x-example: '1'
- description: valid value of `"option"` field can be `"yes"`, `"no"`, `"no_with_veto"` and `"abstain"`
name: post_vote_body
in: body
@ -1258,11 +1332,13 @@ paths:
name: proposalId
required: true
in: path
x-example: '1'
- type: string
description: Bech32 voter address
name: voter
required: true
in: path
x-example: cosmos1qwl879nx9t6kef4supyazayf7vjhennyjqwjgr
responses:
200:
description: OK
@ -1288,6 +1364,7 @@ paths:
name: proposalId
required: true
in: path
x-example: '1'
responses:
200:
description: OK
@ -1381,6 +1458,7 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
get:
summary: Get the total rewards balance from all delegations
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
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
- in: path
name: validatorAddr
description: Bech32 OperatorAddress of validator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Query a delegation reward
description: Query a single delegation reward by a delegator
@ -1490,6 +1570,7 @@ paths:
description: Bech32 AccAddress of Delegator
required: true
type: string
x-example: cosmos167w96tdvmazakdwkw2u57227eduula2cy572lf
get:
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
@ -1542,6 +1623,7 @@ paths:
description: Bech32 OperatorAddress of validator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Validator distribution information
description: Query the distribution information of a single validator
@ -1565,21 +1647,22 @@ paths:
description: Bech32 OperatorAddress of validator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Fee distribution outstanding rewards of a single validator
tags:
- ICS24
produces:
- application/json
responses:
200:
description: OK
schema:
type: array
items:
$ref: "#/definitions/Coin"
500:
description: Internal Server Error
summary: Fee distribution outstanding rewards of a single validator
tags:
- ICS24
produces:
- application/json
responses:
200:
description: OK
schema:
type: array
items:
$ref: "#/definitions/Coin"
500:
description: Internal Server Error
/distribution/validators/{validatorAddr}/rewards:
parameters:
- in: path
@ -1587,6 +1670,7 @@ paths:
description: Bech32 OperatorAddress of validator
required: true
type: string
x-example: cosmosvaloper1qwl879nx9t6kef4supyazayf7vjhennyh568ys
get:
summary: Commission and self-delegation rewards of a single validator
description: Query the commission and self-delegation rewards of validator.
@ -1632,6 +1716,22 @@ paths:
description: Key password is wrong
500:
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:
get:
summary: Fee distribution parameters
@ -1652,6 +1752,54 @@ paths:
type: string
500:
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:
CheckTxResult:
type: object
@ -1744,7 +1892,7 @@ definitions:
properties:
denom:
type: string
example: steak
example: stake
amount:
type: string
example: "50"
@ -1882,6 +2030,15 @@ definitions:
$ref: "#/definitions/Hash"
proposer_address:
$ref: "#/definitions/Address"
version:
type: object
properties:
block:
type: string
example: 10
app:
type: string
example: 0
Block:
type: object
properties:
@ -1980,7 +2137,7 @@ definitions:
pub_key:
type: string
example: cosmosvalconspub1zcjduepq7sjfglw7ra4mjxpw4ph7dtdhdheh7nz8dfgl6t8u2n5szuuql9mqsrwquu
power:
voting_power:
type: string
example: "1000"
proposer_priority:
@ -2165,3 +2322,14 @@ definitions:
type: array
items:
$ref: "#/definitions/Coin"
SigningInfo:
type: object
properties:
start_height:
type: string
index_offset:
type: string
jailed_until:
type: string
missed_blocks_counter:
type: string

View File

@ -42,6 +42,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov"
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
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"
slashingrest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
"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
// InitializeTestLCD starts Tendermint and the LCD in process, listening on
// 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.
func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress, minting bool) (
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()
db := dbm.NewMemDB()
app := gapp.NewGaiaApp(logger, db, nil, true)
app := gapp.NewGaiaApp(logger, db, nil, true, false)
cdc = gapp.MakeCodec()
genesisFile := config.GenesisFile()
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
require.Nil(t, err)
genDoc.Validators = nil
genDoc.SaveAs(genesisFile)
require.NoError(t, genDoc.SaveAs(genesisFile))
genTxs := []json.RawMessage{}
// 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.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
if minting {
require.Equal(t, sdk.MustNewDecFromStr("15000.0"),
@ -337,7 +341,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
cleanup = func() {
logger.Debug("cleaning up LCD initialization")
node.Stop()
node.Stop() //nolint:errcheck
node.Wait()
lcd.Close()
}
@ -390,11 +394,11 @@ func startTM(
func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing.T) (net.Listener, error) {
rs := NewRestServer(cdc)
registerRoutes(rs)
listener, err := tmrpc.Listen(listenAddr, tmrpc.Config{})
listener, err := tmrpc.Listen(listenAddr, tmrpc.DefaultConfig())
if err != nil {
return nil, err
}
go tmrpc.StartHTTPServer(listener, rs.Mux, logger)
go tmrpc.StartHTTPServer(listener, rs.Mux, logger, tmrpc.DefaultConfig()) //nolint:errcheck
return listener, nil
}
@ -408,6 +412,7 @@ func registerRoutes(rs *RestServer) {
stakingrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashingrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
govrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
mintrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
}
// 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
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)
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
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)
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
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)
require.NoError(t, err)
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
func deleteKey(t *testing.T, port, name, password string) {
dk := clientkeys.DeleteKeyReq{password}
dk := clientkeys.NewDeleteKeyReq(password)
req, err := cdc.MarshalJSON(dk)
require.NoError(t, err)
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
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)
require.Nil(t, err)
@ -668,7 +673,7 @@ func doTransfer(
resp, body, recvAddr := doTransferWithGas(
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
err := cdc.UnmarshalJSON([]byte(body), &txResp)
@ -815,11 +820,11 @@ func doDelegate(
from := acc.GetAddress().String()
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
msg := msgDelegationsInput{
msg := stakingrest.DelegateRequest{
BaseReq: baseReq,
DelegatorAddress: delAddr,
ValidatorAddress: valAddr,
Delegation: sdk.NewCoin(sdk.DefaultBondDenom, amount),
Amount: sdk.NewCoin(sdk.DefaultBondDenom, amount),
}
req, err := cdc.MarshalJSON(msg)
@ -839,13 +844,6 @@ func doDelegate(
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
func doUndelegate(
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress,
@ -859,11 +857,11 @@ func doUndelegate(
from := acc.GetAddress().String()
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
msg := msgUndelegateInput{
msg := stakingrest.UndelegateRequest{
BaseReq: baseReq,
DelegatorAddress: delAddr,
ValidatorAddress: valAddr,
SharesAmount: amount.ToDec(),
Amount: sdk.NewCoin(sdk.DefaultBondDenom, amount),
}
req, err := cdc.MarshalJSON(msg)
@ -882,13 +880,6 @@ func doUndelegate(
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
func doBeginRedelegation(
t *testing.T, port, name, pwd string, delAddr sdk.AccAddress, valSrcAddr,
@ -902,12 +893,12 @@ func doBeginRedelegation(
from := acc.GetAddress().String()
baseReq := rest.NewBaseReq(from, "", chainID, "", "", accnum, sequence, fees, nil, false)
msg := stakingrest.MsgBeginRedelegateInput{
msg := stakingrest.RedelegateRequest{
BaseReq: baseReq,
DelegatorAddress: delAddr,
ValidatorSrcAddress: valSrcAddr,
ValidatorDstAddress: valDstAddr,
SharesAmount: amount.ToDec(),
Amount: sdk.NewCoin(sdk.DefaultBondDenom, amount),
}
req, err := cdc.MarshalJSON(msg)
@ -926,14 +917,6 @@ func doBeginRedelegation(
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
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)
@ -1414,6 +1397,21 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.
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
// POST /slashing/validators/{validatorAddr}/unjail Unjail a jailed validator
func doUnjail(

View File

@ -1,6 +1,7 @@
package rest
import (
"log"
"net/http"
"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.Write(output)
if _, err := w.Write(output); err != nil {
log.Printf("could not write response: %v", err)
}
return
}

View File

@ -115,20 +115,19 @@ func BlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
vars := mux.Vars(r)
height, err := strconv.ParseInt(vars["height"], 10, 64)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/block/{height}'."))
rest.WriteErrorResponse(w, http.StatusBadRequest,
"ERROR: Couldn't parse block height. Assumed format is '/block/{height}'.")
return
}
chainHeight, err := GetChainHeight(cliCtx)
if height > chainHeight {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("ERROR: Requested block height is bigger then the chain length."))
rest.WriteErrorResponse(w, http.StatusNotFound,
"ERROR: Requested block height is bigger then the chain length.")
return
}
output, err := getBlock(cliCtx, &height)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
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) {
height, err := GetChainHeight(cliCtx)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := getBlock(cliCtx, &height)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)

View File

@ -2,6 +2,7 @@ package rpc
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
@ -26,7 +27,9 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
// cli version REST handler endpoint
func CLIVersionRequestHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(fmt.Sprintf("{\"version\": \"%s\"}", version.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
@ -39,6 +42,8 @@ func NodeVersionRequestHandler(cliCtx context.CLIContext) http.HandlerFunc {
}
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)
}
}
}

View File

@ -2,6 +2,7 @@ package rpc
import (
"fmt"
"log"
"net/http"
"strconv"
@ -71,8 +72,7 @@ func NodeInfoRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
status, err := getNodeStatus(cliCtx)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
@ -86,18 +86,18 @@ func NodeSyncingRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
status, err := getNodeStatus(cliCtx)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
syncing := status.SyncInfo.CatchingUp
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
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)
}
}
}

View File

@ -45,7 +45,7 @@ func ValidatorCommand(cdc *codec.Codec) *cobra.Command {
cliCtx := context.NewCLIContext().WithCodec(cdc)
result, err := getValidators(cliCtx, height)
result, err := GetValidators(cliCtx, height)
if err != nil {
return err
}
@ -113,7 +113,7 @@ func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error
}, nil
}
func getValidators(cliCtx context.CLIContext, height *int64) (ResultValidatorsOutput, error) {
func GetValidators(cliCtx context.CLIContext, height *int64) (ResultValidatorsOutput, error) {
// get the node
node, err := cliCtx.GetNode()
if err != nil {
@ -160,22 +160,19 @@ func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
height, err := strconv.ParseInt(vars["height"], 10, 64)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/validatorsets/{height}'."))
rest.WriteErrorResponse(w, http.StatusBadRequest, "ERROR: Couldn't parse block height. Assumed format is '/validatorsets/{height}'.")
return
}
chainHeight, err := GetChainHeight(cliCtx)
if height > chainHeight {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("ERROR: Requested block height is bigger then the chain length."))
rest.WriteErrorResponse(w, http.StatusNotFound, "ERROR: Requested block height is bigger then the chain length.")
return
}
output, err := getValidators(cliCtx, &height)
output, err := GetValidators(cliCtx, &height)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
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) {
height, err := GetChainHeight(cliCtx)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := getValidators(cliCtx, &height)
output, err := GetValidators(cliCtx, &height)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
rest.PostProcessResponse(w, cdc, output, cliCtx.Indent)

View File

@ -18,19 +18,10 @@ import (
"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.
type BroadcastReq struct {
Tx auth.StdTx `json:"tx"`
Return string `json:"return"`
Tx auth.StdTx `json:"tx"`
Mode string `json:"mode"`
}
// BroadcastTxRequest implements a tx broadcasting handler that is responsible
@ -58,23 +49,9 @@ func BroadcastTxRequest(cliCtx context.CLIContext, cdc *codec.Codec) http.Handle
return
}
var res interface{}
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
}
cliCtx = cliCtx.WithBroadcastMode(req.Mode)
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
@ -110,7 +87,7 @@ $ gaiacli tx broadcast ./mytxn.json
}
res, err := cliCtx.BroadcastTx(txBytes)
cliCtx.PrintOutput(res)
cliCtx.PrintOutput(res) // nolint:errcheck
return err
},
}

View File

@ -97,7 +97,7 @@ If you supply a dash (-) argument in place of an input filename, the command rea
txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes)
response := txEncodeRespStr(txBytesBase64)
cliCtx.PrintOutput(response)
cliCtx.PrintOutput(response) // nolint:errcheck
return nil
},

View File

@ -1,14 +1,13 @@
package tx
import (
"encoding/hex"
"fmt"
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types"
"github.com/spf13/viper"
@ -17,14 +16,100 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"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.
func QueryTxCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
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),
RunE: func(cmd *cobra.Command, args []string) error {
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))
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
return cmd
}
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
// ----------------------------------------------------------------------------
// 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 {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)

View File

@ -10,7 +10,7 @@ import (
// register REST routes
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec) {
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/encode", EncodeTxRequestHandlerFn(cdc, cliCtx)).Methods("POST")
}

View File

@ -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
}

173
client/tx/utils.go Normal file
View File

@ -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
}

View File

@ -6,6 +6,8 @@ import (
"io/ioutil"
"os"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
@ -69,7 +71,17 @@ func CompleteAndBroadcastTxCLI(txBldr authtxb.TxBuilder, cliCtx context.CLIConte
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()
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
res, err := cliCtx.BroadcastTx(txBytes)
cliCtx.PrintOutput(res)
return err
if err != nil {
return err
}
return cliCtx.PrintOutput(res)
}
// 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
// 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
// estimate gas and update TxBuilder accordingly
rawRes, err := queryFunc("/app/simulate", txBytes)
@ -149,15 +166,17 @@ func PrintUnsignedStdTx(
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.
// 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
keybase := txBldr.Keybase()
info, err := keybase.Get(name)
info, err := txBldr.Keybase().Get(name)
if err != nil {
return signedStdTx, err
}
@ -170,8 +189,7 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
}
if !offline {
txBldr, err = populateAccountFromState(
txBldr, cliCtx, sdk.AccAddress(addr))
txBldr, err = populateAccountFromState(txBldr, cliCtx, sdk.AccAddress(addr))
if err != nil {
return signedStdTx, err
}
@ -229,25 +247,21 @@ func ReadStdTxFromFile(cdc *amino.Codec, filename string) (stdTx auth.StdTx, err
return
}
func populateAccountFromState(txBldr authtxb.TxBuilder, cliCtx context.CLIContext,
addr sdk.AccAddress) (authtxb.TxBuilder, error) {
if txBldr.AccountNumber() == 0 {
accNum, err := cliCtx.GetAccountNumber(addr)
if err != nil {
return txBldr, err
}
txBldr = txBldr.WithAccountNumber(accNum)
func populateAccountFromState(
txBldr authtxb.TxBuilder, cliCtx context.CLIContext, addr sdk.AccAddress,
) (authtxb.TxBuilder, error) {
accNum, err := cliCtx.GetAccountNumber(addr)
if err != nil {
return txBldr, err
}
if txBldr.Sequence() == 0 {
accSeq, err := cliCtx.GetAccountSequence(addr)
if err != nil {
return txBldr, err
}
txBldr = txBldr.WithSequence(accSeq)
accSeq, err := cliCtx.GetAccountSequence(addr)
if err != nil {
return txBldr, err
}
return txBldr, nil
return txBldr.WithAccountNumber(accNum).WithSequence(accSeq), nil
}
// GetTxEncoder return tx encoder from global sdk configuration if ones is defined.

View File

@ -11,14 +11,12 @@ import (
dbm "github.com/tendermint/tendermint/libs/db"
"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"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
@ -44,6 +42,8 @@ type GaiaApp struct {
*bam.BaseApp
cdc *codec.Codec
assertInvariantsBlockly bool
// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
@ -67,11 +67,14 @@ type GaiaApp struct {
mintKeeper mint.Keeper
distrKeeper distr.Keeper
govKeeper gov.Keeper
crisisKeeper crisis.Keeper
paramsKeeper params.Keeper
}
// 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()
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,
gov.DefaultCodespace,
)
app.crisisKeeper = crisis.NewKeeper(
app.paramsKeeper.Subspace(crisis.DefaultParamspace),
app.distrKeeper,
app.bankKeeper,
app.feeCollectionKeeper,
)
// register the staking hooks
// 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()),
)
// 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
//
// TODO: Use standard bank router once transfers are enabled.
app.Router().
AddRoute(bank.RouterKey, gaiabank.NewHandler(app.bankKeeper)).
AddRoute(bank.RouterKey, bank.NewHandler(app.bankKeeper)).
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)).
AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)).
AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)).
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper))
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper)).
AddRoute(crisis.RouterKey, crisis.NewHandler(app.crisisKeeper))
app.QueryRouter().
AddRoute(auth.QuerierRoute, auth.NewQuerier(app.accountKeeper)).
AddRoute(distr.QuerierRoute, distr.NewQuerier(app.distrKeeper)).
AddRoute(gov.QuerierRoute, gov.NewQuerier(app.govKeeper)).
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
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint, app.keyDistr,
@ -197,6 +211,7 @@ func MakeCodec() *codec.Codec {
slashing.RegisterCodec(cdc)
gov.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
crisis.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(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)
tags = append(tags, endBlockerTags...)
app.assertRuntimeInvariants()
if app.assertInvariantsBlockly {
app.assertRuntimeInvariants()
}
return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates,
@ -262,6 +279,7 @@ func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisSt
bank.InitGenesis(ctx, app.bankKeeper, genesisState.BankData)
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakingData.Validators.ToSDKValidators())
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
crisis.InitGenesis(ctx, app.crisisKeeper, genesisState.CrisisData)
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
// validate genesis state

View File

@ -5,6 +5,7 @@ import (
"testing"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/db"
@ -35,6 +36,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
mint.DefaultGenesisState(),
distr.DefaultGenesisState(),
gov.DefaultGenesisState(),
crisis.DefaultGenesisState(),
slashing.DefaultGenesisState(),
)
@ -53,11 +55,11 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
func TestGaiadExport(t *testing.T) {
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)
// 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{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}

View File

@ -11,6 +11,7 @@ import (
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/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
@ -46,6 +47,7 @@ func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteLis
mint.ExportGenesis(ctx, app.mintKeeper),
distr.ExportGenesis(ctx, app.distrKeeper),
gov.ExportGenesis(ctx, app.govKeeper),
crisis.ExportGenesis(ctx, app.crisisKeeper),
slashing.ExportGenesis(ctx, app.slashingKeeper),
)
appState, err = codec.MarshalJSONIndent(app.cdc, genState)

View File

@ -17,6 +17,7 @@ import (
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/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
@ -39,6 +40,7 @@ type GenesisState struct {
MintData mint.GenesisState `json:"mint"`
DistrData distr.GenesisState `json:"distr"`
GovData gov.GenesisState `json:"gov"`
CrisisData crisis.GenesisState `json:"crisis"`
SlashingData slashing.GenesisState `json:"slashing"`
GenTxs []json.RawMessage `json:"gentxs"`
}
@ -46,7 +48,7 @@ type GenesisState struct {
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
bankData bank.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 {
return GenesisState{
@ -57,6 +59,7 @@ func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
MintData: mintData,
DistrData: distrData,
GovData: govData,
CrisisData: crisisData,
SlashingData: slashingData,
}
}
@ -209,6 +212,7 @@ func NewDefaultGenesisState() GenesisState {
MintData: mint.DefaultGenesisState(),
DistrData: distr.DefaultGenesisState(),
GovData: gov.DefaultGenesisState(),
CrisisData: crisis.DefaultGenesisState(),
SlashingData: slashing.DefaultGenesisState(),
GenTxs: nil,
}
@ -246,6 +250,9 @@ func GaiaValidateGenesisState(genesisState GenesisState) error {
if err := gov.ValidateGenesis(genesisState.GovData); err != nil {
return err
}
if err := crisis.ValidateGenesis(genesisState.CrisisData); err != nil {
return err
}
return slashing.ValidateGenesis(genesisState.SlashingData)
}

View File

@ -41,7 +41,7 @@ func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
msg := msgs[0].(staking.MsgCreateValidator)
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)
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()
addr := sdk.AccAddress(priv.PubKey().Address())
authAcc := auth.NewBaseAccountWithAddress(addr)
authAcc.SetCoins(sdk.Coins{sdk.NewInt64Coin(defaultBondDenom, 150)})
authAcc.SetCoins(sdk.NewCoins(sdk.NewInt64Coin(defaultBondDenom, 150)))
genAcc := NewGenesisAccount(&authAcc)
acc := genAcc.ToAccount()
require.IsType(t, &auth.BaseAccount{}, acc)

View File

@ -7,20 +7,8 @@ import (
abci "github.com/tendermint/tendermint/abci/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() {
ctx := app.NewContext(false, abci.Header{Height: app.LastBlockHeight() + 1})
app.assertRuntimeInvariantsOnContext(ctx)
@ -28,10 +16,12 @@ func (app *GaiaApp) assertRuntimeInvariants() {
func (app *GaiaApp) assertRuntimeInvariantsOnContext(ctx sdk.Context) {
start := time.Now()
invariants := app.runtimeInvariants()
for _, inv := range invariants {
if err := inv(ctx); err != nil {
panic(fmt.Errorf("invariant broken: %s", err))
invarRoutes := app.crisisKeeper.Routes()
for _, ir := range invarRoutes {
if err := ir.Invar(ctx); err != nil {
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()

View File

@ -29,7 +29,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov"
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/cosmos/cosmos-sdk/x/slashing"
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
"github.com/cosmos/cosmos-sdk/x/staking"
@ -43,19 +43,30 @@ var (
blockSize int
enabled bool
verbose bool
lean bool
commit bool
period int
)
func init() {
flag.StringVar(&genesisFile, "SimulationGenesis", "", "Custom simulation genesis file")
flag.Int64Var(&seed, "SimulationSeed", 42, "Simulation random seed")
flag.IntVar(&numBlocks, "SimulationNumBlocks", 500, "Number of blocks")
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "Operations per block")
flag.BoolVar(&enabled, "SimulationEnabled", false, "Enable the simulation")
flag.BoolVar(&verbose, "SimulationVerbose", false, "Verbose log output")
flag.BoolVar(&commit, "SimulationCommit", false, "Have the simulation commit")
flag.IntVar(&period, "SimulationPeriod", 1, "Run slow invariants only once every period assertions")
flag.StringVar(&genesisFile, "SimulationGenesis", "", "custom simulation genesis file")
flag.Int64Var(&seed, "SimulationSeed", 42, "simulation random seed")
flag.IntVar(&numBlocks, "SimulationNumBlocks", 500, "number of blocks")
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "operations per block")
flag.BoolVar(&enabled, "SimulationEnabled", false, "enable the simulation")
flag.BoolVar(&verbose, "SimulationVerbose", false, "verbose log output")
flag.BoolVar(&lean, "SimulationLean", false, "lean simulation log output")
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) {
@ -92,7 +103,7 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
numInitiallyBonded = numAccs
}
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)
// randomly generate some genesis accounts
@ -265,8 +276,8 @@ func randIntBetween(r *rand.Rand, min, max int) int {
func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
return []simulation.WeightedOperation{
{5, authsim.SimulateDeductFee(app.accountKeeper, app.feeCollectionKeeper)},
{100, banksim.SendMsg(app.accountKeeper, app.bankKeeper)},
{10, banksim.SingleInputMsgMultiSend(app.accountKeeper, app.bankKeeper)},
{100, banksim.SimulateMsgSend(app.accountKeeper, app.bankKeeper)},
{10, banksim.SimulateSingleInputMsgMultiSend(app.accountKeeper, app.bankKeeper)},
{50, distrsim.SimulateMsgSetWithdrawAddress(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawDelegatorReward(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 {
return []sdk.Invariant{
simulation.PeriodicInvariant(banksim.NonnegativeBalanceInvariant(app.accountKeeper), period, 0),
simulation.PeriodicInvariant(govsim.AllInvariants(), period, 0),
simulation.PeriodicInvariant(distrsim.AllInvariants(app.distrKeeper, app.stakingKeeper), period, 0),
simulation.PeriodicInvariant(stakingsim.AllInvariants(app.stakingKeeper, app.feeCollectionKeeper,
simulation.PeriodicInvariant(bank.NonnegativeBalanceInvariant(app.accountKeeper), period, 0),
simulation.PeriodicInvariant(distr.AllInvariants(app.distrKeeper, app.stakingKeeper), period, 0),
simulation.PeriodicInvariant(staking.AllInvariants(app.stakingKeeper, app.feeCollectionKeeper,
app.distrKeeper, app.accountKeeper), period, 0),
simulation.PeriodicInvariant(slashingsim.AllInvariants(), period, 0),
}
}
@ -310,18 +319,11 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true)
app := NewGaiaApp(logger, db, nil, true, false)
// Run randomized simulation
// TODO parameterize numbers, save for a later PR
_, err := simulation.SimulateFromSeed(
b, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
invariants(app), // these shouldn't get ran
numBlocks,
blockSize,
commit,
)
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(b, app))
if err != nil {
fmt.Println(err)
b.Fail()
@ -352,18 +354,11 @@ func TestFullGaiaSimulation(t *testing.T) {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, fauxMerkleModeOpt)
app := NewGaiaApp(logger, db, nil, true, false, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
_, err := simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
invariants(app),
numBlocks,
blockSize,
commit,
)
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
@ -393,18 +388,12 @@ func TestGaiaImportExport(t *testing.T) {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, fauxMerkleModeOpt)
app := NewGaiaApp(logger, db, nil, true, false, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
_, err := simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
invariants(app),
numBlocks,
blockSize,
commit,
)
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
@ -426,7 +415,7 @@ func TestGaiaImportExport(t *testing.T) {
newDB.Close()
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())
var genesisState GenesisState
err = app.cdc.UnmarshalJSON(appState, &genesisState)
@ -446,7 +435,8 @@ func TestGaiaImportExport(t *testing.T) {
storeKeysPrefixes := []StoreKeysPrefixes{
{app.keyMain, newApp.keyMain, [][]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.keyMint, newApp.keyMint, [][]byte{}},
{app.keyDistr, newApp.keyDistr, [][]byte{}},
@ -488,18 +478,12 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, fauxMerkleModeOpt)
app := NewGaiaApp(logger, db, nil, true, false, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
stopEarly, err := simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
invariants(app),
numBlocks,
blockSize,
commit,
)
stopEarly, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
@ -530,21 +514,14 @@ func TestGaiaSimulationAfterImport(t *testing.T) {
newDB.Close()
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())
newApp.InitChain(abci.RequestInitChain{
AppStateBytes: appState,
})
// Run randomized simulation on imported app
_, err = simulation.SimulateFromSeed(
t, newApp.BaseApp, appStateFn, seed,
testAndRunTxs(newApp),
invariants(newApp),
numBlocks,
blockSize,
commit,
)
_, err = simulation.SimulateFromSeed(getSimulateFromSeedInput(t, newApp))
require.Nil(t, err)
}
@ -565,7 +542,7 @@ func TestAppStateDeterminism(t *testing.T) {
for j := 0; j < numTimesToRunPerSeed; j++ {
logger := log.NewNopLogger()
db := dbm.NewMemDB()
app := NewGaiaApp(logger, db, nil, true)
app := NewGaiaApp(logger, db, nil, true, false)
// Run randomized simulation
simulation.SimulateFromSeed(
@ -575,6 +552,7 @@ func TestAppStateDeterminism(t *testing.T) {
50,
100,
true,
false,
)
appHash := app.LastCommitID().Hash
appHashList[j] = appHash

View File

@ -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
}

View File

@ -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)})
}

View File

@ -1,3 +1,5 @@
// +build cli_test
package clitest
import (
@ -361,7 +363,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
require.Equal(t, sendTokens, barAcc.GetCoins().AmountOf(denom))
// 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.Empty(f.T, stderr)
@ -394,13 +396,13 @@ func TestGaiaCLICreateValidator(t *testing.T) {
require.NotZero(t, validatorDelegations[0].Shares)
// unbond a single share
unbondTokens := sdk.TokensFromTendermintPower(1)
success = f.TxStakingUnbond(keyBar, unbondTokens.String(), barVal, "-y")
unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromTendermintPower(1))
success = f.TxStakingUnbond(keyBar, unbondAmt.String(), barVal, "-y")
require.True(t, success)
tests.WaitForNextNBlocksTM(1, f.Port)
// Ensure bonded staking is correct
remainingTokens := newValTokens.Sub(unbondTokens)
remainingTokens := newValTokens.Sub(unbondAmt.Amount)
validator = f.QueryStakingValidator(barVal)
require.Equal(t, remainingTokens, validator.Tokens)
@ -437,7 +439,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
// Test submit generate only for submit proposal
proposalTokens := sdk.TokensFromTendermintPower(5)
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.Empty(t, stderr)
msg := unmarshalStdTx(t, stdout)
@ -463,12 +465,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
// Ensure propsal is directly queryable
proposal1 := f.QueryGovProposal(1)
require.Equal(t, uint64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
require.Equal(t, uint64(1), proposal1.ProposalID)
require.Equal(t, gov.StatusDepositPeriod, proposal1.Status)
// Ensure query proposals returns properly
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
deposit := f.QueryGovDeposit(1, fooAddr)
@ -476,7 +478,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
// Test deposit generate only
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.Empty(t, stderr)
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
proposal1 = f.QueryGovProposal(1)
require.Equal(t, uint64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
require.Equal(t, uint64(1), proposal1.ProposalID)
require.Equal(t, gov.StatusVotingPeriod, proposal1.Status)
// 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.Empty(t, stderr)
msg = unmarshalStdTx(t, stdout)
@ -544,7 +546,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
// Ensure the proposal returns as in the voting period
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
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
proposalsQuery = f.QueryGovProposals("--limit=1")
require.Equal(t, uint64(2), proposalsQuery[0].GetProposalID())
require.Equal(t, uint64(2), proposalsQuery[0].ProposalID)
f.Cleanup()
}
@ -618,7 +620,7 @@ func TestGaiaCLIValidateSignatures(t *testing.T) {
barAddr := f.KeyAddress(keyBar)
// 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.Empty(t, stderr)
@ -669,7 +671,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
// Test generate sendTx with default gas
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.Empty(t, stderr)
msg := unmarshalStdTx(t, stdout)
@ -678,7 +680,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
require.Equal(t, 0, len(msg.GetSignatures()))
// 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.Empty(t, stderr)
msg = unmarshalStdTx(t, stdout)
@ -687,7 +689,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
require.Equal(t, 0, len(msg.GetSignatures()))
// 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.NotEmpty(t, stderr)
msg = unmarshalStdTx(t, stdout)
@ -764,7 +766,7 @@ func TestGaiaCLIMultisignInsufficientCosigners(t *testing.T) {
tests.WaitForNextNBlocksTM(1, f.Port)
// 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)
// Write the output to disk
@ -808,8 +810,10 @@ func TestGaiaCLIEncode(t *testing.T) {
// Build a testing transaction and write it to disk
barAddr := f.KeyAddress(keyBar)
keyAddr := f.KeyAddress(keyFoo)
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.Empty(t, stderr)
@ -853,7 +857,7 @@ func TestGaiaCLIMultisignSortSignatures(t *testing.T) {
require.Equal(t, int64(10), fooBarBazAcc.GetCoins().AmountOf(denom).Int64())
// 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)
// Write the output to disk
@ -915,7 +919,7 @@ func TestGaiaCLIMultisign(t *testing.T) {
require.Equal(t, int64(10), fooBarBazAcc.GetCoins().AmountOf(denom).Int64())
// 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.Empty(t, stderr)
@ -963,6 +967,7 @@ func TestGaiaCLIConfig(t *testing.T) {
node := fmt.Sprintf("%s:%s", f.RPCAddr, f.Port)
// Set available configuration options
f.CLIConfig("broadcast-mode", "block")
f.CLIConfig("node", node)
f.CLIConfig("output", "text")
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"))
require.NoError(t, err)
expectedConfig := fmt.Sprintf(`chain-id = "%s"
expectedConfig := fmt.Sprintf(`broadcast-mode = "block"
chain-id = "%s"
indent = true
node = "%s"
output = "text"

View File

@ -104,15 +104,15 @@ func (f Fixtures) GenesisState() app.GenesisState {
return appState
}
// InitFixtures is called at the beginning of a test
// and initializes a chain with 1 validator
// InitFixtures is called at the beginning of a test and initializes a chain
// with 1 validator.
func InitFixtures(t *testing.T) (f *Fixtures) {
f = NewFixtures(t)
// Reset test state
// reset test state
f.UnsafeResetAll()
// Ensure keystore has foo and bar keys
// ensure keystore has foo and bar keys
f.KeysDelete(keyFoo)
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(
"--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")
// NOTE: GDInit sets the ChainID
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(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-end-time=%d", time.Now().Add(60*time.Second).UTC().UnixNano()),
)
f.GenTx(keyFoo)
f.CollectGenTxs()
return
}
@ -163,7 +167,7 @@ func (f *Fixtures) Flags() string {
// UnsafeResetAll is gaiad unsafe-reset-all
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))
err := os.RemoveAll(filepath.Join(f.GDHome, "config", "gentx"))
require.NoError(f.T, err)
@ -172,7 +176,7 @@ func (f *Fixtures) UnsafeResetAll(flags ...string) {
// GDInit is gaiad init
// NOTE: GDInit sets the ChainID for the Fixtures instance
func (f *Fixtures) GDInit(moniker string, flags ...string) {
cmd := fmt.Sprintf("gaiad init -o --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)
var chainID string
@ -189,25 +193,25 @@ func (f *Fixtures) GDInit(moniker string, flags ...string) {
// AddGenesisAccount is gaiad add-genesis-account
func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, flags ...string) {
cmd := fmt.Sprintf("gaiad add-genesis-account %s %s --home=%s", address, coins, f.GDHome)
cmd := fmt.Sprintf("../../../build/gaiad add-genesis-account %s %s --home=%s", address, coins, f.GDHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags))
}
// GenTx is gaiad gentx
func (f *Fixtures) GenTx(name string, flags ...string) {
cmd := fmt.Sprintf("gaiad gentx --name=%s --home=%s --home-client=%s", name, f.GDHome, f.GCLIHome)
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)
}
// CollectGenTxs is gaiad collect-gentxs
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)
}
// GDStart runs gaiad start with the appropriate flags and returns a process
func (f *Fixtures) GDStart(flags ...string) *tests.Process {
cmd := fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", f.GDHome, f.RPCAddr, f.P2PAddr)
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))
tests.WaitForTMStart(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]
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)
require.Empty(f.T, stderr)
require.True(f.T, success)
@ -225,7 +229,7 @@ func (f *Fixtures) GDTendermint(query string) string {
// ValidateGenesis runs gaiad validate-genesis
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)
}
@ -234,31 +238,31 @@ func (f *Fixtures) ValidateGenesis() {
// KeysDelete is gaiacli keys delete
func (f *Fixtures) KeysDelete(name string, flags ...string) {
cmd := fmt.Sprintf("gaiacli keys delete --home=%s %s", f.GCLIHome, name)
cmd := fmt.Sprintf("../../../build/gaiacli keys delete --home=%s %s", f.GCLIHome, name)
executeWrite(f.T, addFlags(cmd, append(append(flags, "-y"), "-f")))
}
// KeysAdd is gaiacli keys add
func (f *Fixtures) KeysAdd(name string, flags ...string) {
cmd := fmt.Sprintf("gaiacli keys add --home=%s %s", f.GCLIHome, name)
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s %s", f.GCLIHome, name)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// KeysAddRecover prepares gaiacli keys add --recover
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)
}
// KeysAddRecoverHDPath prepares gaiacli keys add --recover --account --index
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)
}
// KeysShow is gaiacli keys show
func (f *Fixtures) KeysShow(name string, flags ...string) keys.KeyOutput {
cmd := fmt.Sprintf("gaiacli keys show --home=%s %s", f.GCLIHome, name)
cmd := fmt.Sprintf("../../../build/gaiacli keys show --home=%s %s", f.GCLIHome, name)
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var ko keys.KeyOutput
err := clientkeys.UnmarshalJSON([]byte(out), &ko)
@ -279,7 +283,7 @@ func (f *Fixtures) KeyAddress(name string) sdk.AccAddress {
// CLIConfig is gaiacli config
func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
cmd := fmt.Sprintf("gaiacli config --home=%s %s %s", f.GCLIHome, key, value)
cmd := fmt.Sprintf("../../../build/gaiacli config --home=%s %s %s", f.GCLIHome, key, value)
executeWriteCheckErr(f.T, addFlags(cmd, flags))
}
@ -288,7 +292,7 @@ func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
// TxSend is gaiacli tx send
func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx send %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)
}
@ -296,25 +300,25 @@ func (f *Fixtures) txSendWithConfirm(
from string, to sdk.AccAddress, amount sdk.Coin, confirm string, 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), confirm, app.DefaultKeyPass)
}
// TxSign is gaiacli tx sign
func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx sign %v --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)
}
// TxBroadcast is gaiacli tx broadcast
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)
}
// TxEncode is gaiacli tx encode
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)
}
@ -322,7 +326,7 @@ func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, str
func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string,
flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx multisign %v %s %s %s", f.Flags(),
cmd := fmt.Sprintf("../../../build/gaiacli tx multisign %v %s %s %s", f.Flags(),
fileName, name, strings.Join(signaturesFiles, " "),
)
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
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(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10")
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
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)
}
@ -351,20 +355,20 @@ func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress
// TxGovSubmitProposal is gaiacli tx gov submit-proposal
func (f *Fixtures) TxGovSubmitProposal(from, typ, title, description string, deposit sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx gov submit-proposal %v --from=%s --type=%s", f.Flags(), from, typ)
cmd := fmt.Sprintf("../../../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)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxGovDeposit is gaiacli tx gov deposit
func (f *Fixtures) TxGovDeposit(proposalID int, from string, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx gov deposit %d %s --from=%s %v", proposalID, amount, from, f.Flags())
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)
}
// TxGovVote is gaiacli tx gov vote
func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("gaiacli tx gov vote %d %s --from=%s %v", proposalID, option, from, f.Flags())
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)
}
@ -373,7 +377,7 @@ func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string,
// QueryAccount is gaiacli query account
func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.BaseAccount {
cmd := fmt.Sprintf("gaiacli query account %s %v", address, f.Flags())
cmd := fmt.Sprintf("../../../build/gaiacli query account %s %v", address, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(out), &initRes)
@ -392,7 +396,7 @@ func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.Ba
// QueryTxs is gaiacli query txs
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, "")
var txs []sdk.TxResponse
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
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, "")
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
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), "")
var validator staking.Validator
cdc := app.MakeCodec()
@ -424,7 +428,7 @@ func (f *Fixtures) QueryStakingValidator(valAddr sdk.ValAddress, flags ...string
// QueryStakingUnbondingDelegationsFrom is gaiacli query staking unbonding-delegations-from
func (f *Fixtures) QueryStakingUnbondingDelegationsFrom(valAddr sdk.ValAddress, flags ...string) []staking.UnbondingDelegation {
cmd := fmt.Sprintf("gaiacli query staking unbonding-delegations-from %s %v", valAddr, f.Flags())
cmd := fmt.Sprintf("../../../build/gaiacli query staking unbonding-delegations-from %s %v", valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var ubds []staking.UnbondingDelegation
cdc := app.MakeCodec()
@ -435,7 +439,7 @@ func (f *Fixtures) QueryStakingUnbondingDelegationsFrom(valAddr sdk.ValAddress,
// QueryStakingDelegationsTo is gaiacli query staking delegations-to
func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...string) []staking.Delegation {
cmd := fmt.Sprintf("gaiacli query staking delegations-to %s %v", valAddr, f.Flags())
cmd := fmt.Sprintf("../../../build/gaiacli query staking delegations-to %s %v", valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var delegations []staking.Delegation
cdc := app.MakeCodec()
@ -446,7 +450,7 @@ func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...st
// QueryStakingPool is gaiacli query 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), "")
var pool staking.Pool
cdc := app.MakeCodec()
@ -457,7 +461,7 @@ func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool {
// QueryStakingParameters is gaiacli query staking parameters
func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params {
cmd := fmt.Sprintf("gaiacli query staking params %v", f.Flags())
cmd := fmt.Sprintf("../../../build/gaiacli query staking params %v", f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var params staking.Params
cdc := app.MakeCodec()
@ -471,7 +475,7 @@ func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params {
// QueryGovParamDeposit is gaiacli query gov param deposit
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, "")
var depositParam gov.DepositParams
cdc := app.MakeCodec()
@ -482,7 +486,7 @@ func (f *Fixtures) QueryGovParamDeposit() gov.DepositParams {
// QueryGovParamVoting is gaiacli query gov param voting
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, "")
var votingParam gov.VotingParams
cdc := app.MakeCodec()
@ -493,7 +497,7 @@ func (f *Fixtures) QueryGovParamVoting() gov.VotingParams {
// QueryGovParamTallying is gaiacli query gov param tallying
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, "")
var tallyingParam gov.TallyParams
cdc := app.MakeCodec()
@ -504,7 +508,7 @@ func (f *Fixtures) QueryGovParamTallying() gov.TallyParams {
// QueryGovProposals is gaiacli query 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), "")
if strings.Contains(stderr, "No matching proposals found") {
return gov.Proposals{}
@ -519,7 +523,7 @@ func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals {
// QueryGovProposal is gaiacli query gov proposal
func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposal {
cmd := fmt.Sprintf("gaiacli query gov proposal %d %v", proposalID, f.Flags())
cmd := fmt.Sprintf("../../../build/gaiacli query gov proposal %d %v", proposalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var proposal gov.Proposal
cdc := app.MakeCodec()
@ -530,7 +534,7 @@ func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposa
// QueryGovVote is gaiacli query gov vote
func (f *Fixtures) QueryGovVote(proposalID int, voter sdk.AccAddress, flags ...string) gov.Vote {
cmd := fmt.Sprintf("gaiacli query gov vote %d %s %v", proposalID, voter, f.Flags())
cmd := fmt.Sprintf("../../../build/gaiacli query gov vote %d %s %v", proposalID, voter, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var vote gov.Vote
cdc := app.MakeCodec()
@ -541,7 +545,7 @@ func (f *Fixtures) QueryGovVote(proposalID int, voter sdk.AccAddress, flags ...s
// QueryGovVotes is gaiacli query gov votes
func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote {
cmd := fmt.Sprintf("gaiacli query gov votes %d %v", proposalID, f.Flags())
cmd := fmt.Sprintf("../../../build/gaiacli query gov votes %d %v", proposalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var votes []gov.Vote
cdc := app.MakeCodec()
@ -552,7 +556,7 @@ func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote {
// QueryGovDeposit is gaiacli query gov deposit
func (f *Fixtures) QueryGovDeposit(proposalID int, depositor sdk.AccAddress, flags ...string) gov.Deposit {
cmd := fmt.Sprintf("gaiacli query gov deposit %d %s %v", proposalID, depositor, f.Flags())
cmd := fmt.Sprintf("../../../build/gaiacli query gov deposit %d %s %v", proposalID, depositor, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var deposit gov.Deposit
cdc := app.MakeCodec()
@ -563,7 +567,7 @@ func (f *Fixtures) QueryGovDeposit(proposalID int, depositor sdk.AccAddress, fla
// QueryGovDeposits is gaiacli query gov deposits
func (f *Fixtures) QueryGovDeposits(propsalID int, flags ...string) []gov.Deposit {
cmd := fmt.Sprintf("gaiacli query gov deposits %d %v", propsalID, f.Flags())
cmd := fmt.Sprintf("../../../build/gaiacli query gov deposits %d %v", propsalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var deposits []gov.Deposit
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
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, "")
require.Empty(f.T, errStr)
cdc := app.MakeCodec()
@ -589,7 +593,7 @@ func (f *Fixtures) QuerySigningInfo(val string) slashing.ValidatorSigningInfo {
// QuerySlashingParams is gaiacli query 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, "")
require.Empty(f.T, errStr)
cdc := app.MakeCodec()

View File

@ -6,11 +6,13 @@ import (
"os"
"path"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/rakyll/statik/fs"
"github.com/spf13/cobra"
"github.com/spf13/viper"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/client"
@ -28,6 +30,7 @@ import (
dist "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
gv "github.com/cosmos/cosmos-sdk/x/gov"
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"
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
st "github.com/cosmos/cosmos-sdk/x/staking"
@ -35,11 +38,13 @@ import (
authcmd "github.com/cosmos/cosmos-sdk/x/auth/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"
distClient "github.com/cosmos/cosmos-sdk/x/distribution/client"
govClient "github.com/cosmos/cosmos-sdk/x/gov/client"
slashingClient "github.com/cosmos/cosmos-sdk/x/slashing/client"
stakingClient "github.com/cosmos/cosmos-sdk/x/staking/client"
mintclient "github.com/cosmos/cosmos-sdk/x/mint/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"
)
@ -67,8 +72,10 @@ func main() {
mc := []sdk.ModuleClients{
govClient.NewModuleClient(gv.StoreKey, cdc),
distClient.NewModuleClient(distcmd.StoreKey, cdc),
stakingClient.NewModuleClient(st.StoreKey, cdc),
slashingClient.NewModuleClient(sl.StoreKey, cdc),
stakingclient.NewModuleClient(st.StoreKey, cdc),
mintclient.NewModuleClient(mint.StoreKey, cdc),
slashingclient.NewModuleClient(sl.StoreKey, cdc),
crisisclient.NewModuleClient(sl.StoreKey, cdc),
}
rootCmd := &cobra.Command{
@ -124,7 +131,10 @@ func queryCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
)
for _, m := range mc {
queryCmd.AddCommand(m.GetQueryCmd())
mQueryCmd := m.GetQueryCmd()
if mQueryCmd != nil {
queryCmd.AddCommand(mQueryCmd)
}
}
return queryCmd
@ -166,6 +176,7 @@ func registerRoutes(rs *lcd.RestServer) {
staking.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashing.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
gov.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
mintrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
}
func registerSwaggerUI(rs *lcd.RestServer) {

View File

@ -22,6 +22,11 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// gaiad custom flags
const flagAssertInvariantsBlockly = "assert-invariants-blockly"
var assertInvariantsBlockly bool
func main() {
cdc := app.MakeCodec()
@ -50,6 +55,8 @@ func main() {
// prepare and add flags
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
rootCmd.PersistentFlags().BoolVar(&assertInvariantsBlockly, flagAssertInvariantsBlockly,
false, "Assert registered invariants on a blockly basis")
err := executor.Execute()
if err != nil {
// handle with #870
@ -59,7 +66,7 @@ func main() {
func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application {
return app.NewGaiaApp(
logger, db, traceStore, true,
logger, db, traceStore, true, assertInvariantsBlockly,
baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))),
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(
logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string,
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
if height != -1 {
gApp := app.NewGaiaApp(logger, db, traceStore, false)
gApp := app.NewGaiaApp(logger, db, traceStore, false, false)
err := gApp.LoadHeight(height)
if err != nil {
return nil, nil, err
}
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)
}

View File

@ -107,7 +107,7 @@ func run(rootDir string) {
// Application
fmt.Println("Creating application")
myapp := app.NewGaiaApp(
ctx.Logger, appDB, traceStoreWriter, true,
ctx.Logger, appDB, traceStoreWriter, true, true,
baseapp.SetPruning(store.PruneEverything), // nothing
)

View File

@ -32,8 +32,8 @@ func TestAddGenesisAccount(t *testing.T) {
args{
app.GenesisState{},
addr1,
sdk.Coins{},
sdk.Coins{},
sdk.NewCoins(),
sdk.NewCoins(),
0,
0,
},
@ -44,8 +44,8 @@ func TestAddGenesisAccount(t *testing.T) {
args{
app.GenesisState{Accounts: []app.GenesisAccount{{Address: addr1}}},
addr1,
sdk.Coins{},
sdk.Coins{},
sdk.NewCoins(),
sdk.NewCoins(),
0,
0,
},
@ -56,8 +56,8 @@ func TestAddGenesisAccount(t *testing.T) {
args{
app.GenesisState{},
addr1,
sdk.Coins{sdk.NewInt64Coin("stake", 50)},
sdk.Coins{sdk.NewInt64Coin("stake", 100)},
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
sdk.NewCoins(sdk.NewInt64Coin("stake", 100)),
0,
0,
},
@ -68,8 +68,8 @@ func TestAddGenesisAccount(t *testing.T) {
args{
app.GenesisState{},
addr1,
sdk.Coins{sdk.NewInt64Coin("stake", 50)},
sdk.Coins{sdk.NewInt64Coin("stake", 50)},
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
1654668078,
1554668078,
},

View File

@ -47,6 +47,7 @@ func GenTxCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "gentx",
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'.
It creates a genesis piece carrying a self delegation with the
@ -88,6 +89,10 @@ following delegation and commission default parameters:
return err
}
if err = app.GaiaValidateGenesisState(genesisState); err != nil {
return err
}
kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome))
if err != nil {
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
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey)
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey, website, details, identity)
// Fetch the amount of coins staked
amount := viper.GetString(cli.FlagAmount)
@ -122,9 +131,17 @@ following delegation and commission default parameters:
return err
}
// Run gaiad tx create-validator
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(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)
if err != nil {
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")
cmd.Flags().String(cli.FlagIP, ip, "The node's public IP")
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.FsMinSelfDelegation)
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)
}
func prepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, ip, chainID string,
valPubKey crypto.PubKey) {
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome)) // --home
func prepareFlagsForTxCreateValidator(
config *cfg.Config, nodeID, ip, chainID string, valPubKey crypto.PubKey, website, details, identity string,
) {
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome))
viper.Set(client.FlagChainID, chainID)
viper.Set(client.FlagFrom, viper.GetString(client.FlagName)) // --from
viper.Set(cli.FlagNodeID, nodeID) // --node-id
viper.Set(cli.FlagIP, ip) // --ip
viper.Set(cli.FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey)) // --pubkey
viper.Set(client.FlagGenerateOnly, true) // --genesis-format
viper.Set(cli.FlagMoniker, config.Moniker) // --moniker
viper.Set(client.FlagFrom, viper.GetString(client.FlagName))
viper.Set(cli.FlagNodeID, nodeID)
viper.Set(cli.FlagIP, ip)
viper.Set(cli.FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey))
viper.Set(cli.FlagMoniker, config.Moniker)
viper.Set(cli.FlagWebsite, website)
viper.Set(cli.FlagDetails, details)
viper.Set(cli.FlagIdentity, identity)
if config.Moniker == "" {
viper.Set(cli.FlagMoniker, viper.GetString(client.FlagName))
}

View File

@ -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) })
}
}

27
cmd/gosum/main.go Normal file
View File

@ -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))
}

50
cmd/sdkch/README.md Normal file
View File

@ -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.

378
cmd/sdkch/main.go Normal file
View File

@ -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

28
contrib/export/lib.py Normal file
View File

@ -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))

View File

@ -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)

View File

@ -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}"

View File

@ -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())
}

View File

@ -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()))
}

View File

@ -34,21 +34,22 @@ module.exports = {
]
},
{
title: "Gaia",
title: "Cosmos Hub",
collapsable: true,
children: [
"/gaia/what-is-gaia",
"/gaia/installation",
"/gaia/join-mainnet",
"/gaia/validators/validator-setup",
"/gaia/validators/overview",
"/gaia/validators/security",
"/gaia/validators/validator-faq",
"/gaia/delegator-guide-cli",
"/gaia/ledger",
"/gaia/gaiacli",
"/gaia/join-testnet",
"/gaia/deploy-testnet"
"/cosmos-hub/what-is-gaia",
"/cosmos-hub/installation",
"/cosmos-hub/join-mainnet",
"/cosmos-hub/validators/validator-setup",
"/cosmos-hub/validators/overview",
"/cosmos-hub/validators/security",
"/cosmos-hub/validators/validator-faq",
"/cosmos-hub/delegator-guide-cli",
"/cosmos-hub/genesis",
"/cosmos-hub/ledger",
"/cosmos-hub/gaiacli",
"/cosmos-hub/join-testnet",
"/cosmos-hub/deploy-testnet"
]
},
{

View File

@ -95,7 +95,7 @@ then navigate to localhost:8080 in your browser.
## 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)

View File

@ -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,
redelegation, or delegation of additional tokens to a specific validator. This
transaction withdraws the validators commission rewards, as well as any rewards
earning on their self-delegation.
earning on their self-delegation.
```golang
type TxWithdrawValidator struct {

View File

@ -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.
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
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.
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.Context](https://golang.org/pkg/context/), which has
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.
The Context also contains the

View File

@ -19,18 +19,4 @@ gaiacli rest-server --chain-id=test \
--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/)

View File

@ -121,3 +121,69 @@ mechanism for instance.
In order to generate an unsigned transaction (example with
[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`.
## 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.

View File

@ -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
@ -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)
## Setup your own `gaia` testnet
## Setup Your Own `gaia` Testnet
- [Setup your own `gaia` testnet](./deploy-testnet.md)
## Additional resources
## Additional Resources
- [Intro to validators](./validators/overview.md)
- [Validator FAQ](./validators/validator-faq.md)

View File

@ -27,22 +27,22 @@ of any kind.
Please exercise extreme caution!
## Table of contents
## Table of Contents
- [Installing `gaiacli`](#installing-gaiacli)
- [Cosmos Accounts](#cosmos-accounts)
+ [Restoring an account from the fundrasier](#restoring-an-account-from-the-fundraiser)
+ [Creating an account](#creating-an-account)
- [Accessing the Cosmos Hub network](#accessing-the-cosmos-hub-network)
+ [Running your own full-node](#running-your-own-full-node)
+ [Connecting to a remote full-node](#connecting-to-a-remote-full-node)
- [Setting up `gaiacli`](#setting-up-gaiacli)
- [Querying the state](#querying-the-state)
+ [Restoring an Account from the Fundraiser](#restoring-an-account-from-the-fundraiser)
+ [Creating an Account](#creating-an-account)
- [Accessing the Cosmos Hub Network](#accessing-the-cosmos-hub-network)
+ [Running Your Own Full-Node](#running-your-own-full-node)
+ [Connecting to a Remote Full-Node](#connecting-to-a-remote-full-node)
- [Setting Up `gaiacli`](#setting-up-gaiacli)
- [Querying the State](#querying-the-state)
- [Sending Transactions](#sending-transactions)
+ [A note on gas and fees](#a-note-on-gas-and-fees)
+ [Bonding Atoms and Withdrawing rewards](#bonding-atoms-and-withdrawing-rewards)
+ [A Note on Gas and Fees](#a-note-on-gas-and-fees)
+ [Bonding Atoms and Withdrawing Rewards](#bonding-atoms-and-withdrawing-rewards)
+ [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`
@ -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.
### Restoring an account from the fundraiser
### Restoring an Account from the Fundraiser
::: tip
*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.
#### 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.
@ -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.
#### On a computer
#### On a Computer
::: warning
**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.
- 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
**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.
- 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
**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.
## 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.
@ -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."**.
:::
### 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.
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.
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
**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
```
## Querying the state
## Querying the State
::: tip
**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
::: 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:
@ -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`.
:::
### Bonding Atoms and Withdrawing rewards
### Bonding Atoms and Withdrawing Rewards
::: 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)**
:::
::: 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
@ -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>
// 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
// 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.
## 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:
@ -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).
#### In practice
#### In Practice
::: tip
**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>
```
### 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):

View File

@ -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:
@ -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.
## 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.
@ -29,7 +29,7 @@ This guide helps you create a single validator node that runs a network locally
- [Install gaia](./installation.md)
- [Install `jq`](https://stedolan.github.io/jq/download/) (optional)
### Create genesis file and start the network
### Create Genesis File and Start the Network
```bash
# 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).
## 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):
@ -83,7 +83,7 @@ make build-linux
make build-docker-gaiadnode
```
### Run your testnet
### Run Your Testnet
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
:::
### 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:
@ -190,7 +190,7 @@ If you have multiple binaries with different names, you can specify which one to
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).
@ -216,7 +216,7 @@ export SSH_PUBLIC_FILE="$HOME/.ssh/id_rsa.pub"
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
@ -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
```
### Quickly see the /status endpoint
### Quickly see the /status Endpoint
```
make validators-status
```
### Delete servers
### Delete Servers
```
make validators-stop

View File

@ -1,4 +1,4 @@
# Gaia client
# Gaia Client
## 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.
:::
#### Generate multisig public keys
#### Generate Multisig Public Keys
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
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
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.
#### Query Account balance
#### Query Account Balance
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
#### 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.
@ -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)
:::
#### Matching a transaction's hash
#### Matching a Transaction's Hash
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
```
### 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
#### 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>
```
You can also get previous delegation(s) status by adding the `--height` flag.
#### 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
gaiacli tx staking unbond \
--validator=<account_cosmosval> \
--shares-fraction=0.5 \
<validator_addr> \
10atom \
--from=<key_name> \
--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>
```
To get previous unbonding-delegation(s) status on past blocks, try adding the `--height` flag.
#### Redelegate Tokens
A redelegation is a type delegation that allows you to bond illiquid tokens from one validator to another:
```bash
gaiacli tx staking redelegate \
--addr-validator-source=<account_cosmosval> \
--addr-validator-dest=<account_cosmosval> \
--shares-fraction=50 \
<src-validator-operator-addr> \
<dst-validator-operator-addr> \
10atom \
--from=<key_name> \
--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>
```
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
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>
```
To get previous redelegation(s) status on past blocks, try adding the `--height` flag.
#### Query Parameters
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).
#### 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:
@ -523,7 +551,7 @@ gaiacli tx gov submit-proposal \
--chain-id=<chain_id>
```
##### Query proposals
##### Query Proposals
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>
```
#### 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:
@ -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.
##### Query deposits
##### Query Deposits
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>
```
#### 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:
@ -581,7 +609,7 @@ gaiacli tx gov vote <proposal_id> <Yes/No/NoWithVeto/Abstain> \
--chain-id=<chain_id>
```
##### Query votes
##### Query Votes
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>
```
#### Query governance parameters
#### Query Governance Parameters
To check the current governance parameters run:
@ -621,7 +649,7 @@ gaiacli query gov param deposit
### Fee Distribution
#### Query distribution parameters
#### Query Distribution Parameters
To check the current distribution parameters, run:
@ -629,6 +657,14 @@ To check the current distribution parameters, run:
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
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
```
#### Query validator commission
#### Query Validator Commission
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>
```
#### Query validator slashes
#### Query Validator Slashes
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>
```
#### Query delegator rewards
#### Query Delegator Rewards
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>
```
#### Query all delegator rewards
#### Query All Delegator Rewards
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>
```
### Multisig transactions
### Multisig Transactions
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
@ -761,7 +797,7 @@ The transaction can now be sent to the node:
gaiacli tx broadcast signedTx.json
```
## Shells completion scripts
## Shells Completion Scripts
Completion scripts for popular UNIX shell interpreters such as `Bash` and `Zsh`
can be generated through the `completion` command, which is available for both

332
docs/cosmos-hub/genesis.md Normal file
View File

@ -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).

View File

@ -15,7 +15,7 @@ source ~/.bash_profile
```
::: tip
**Go 1.11.5+** is required for the Cosmos SDK.
**Go 1.12.1+** is required for the Cosmos SDK.
:::
### 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).
::: 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
@ -66,7 +66,7 @@ Build tags indicate special features that have been enabled in the binary.
### 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

View File

@ -56,7 +56,7 @@ Fetch the testnet's `genesis.json` file into `gaiad`'s config directory.
```bash
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.
@ -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).
## A note on gas and fees
## A Note on Gas and Fees
::: warning
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
```
## 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
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).

View File

@ -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**
:::
## 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).
@ -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.
## 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.
@ -59,4 +59,4 @@ make update_tools install
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.
Your full node has been cleanly upgraded!
Your full node has been cleanly upgraded!

View File

@ -1,6 +1,6 @@
# 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:
@ -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.
## 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.

View File

@ -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.
## 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.
@ -37,7 +37,9 @@ pex = false
Sentry Nodes should edit their config.toml:
```bash
# 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

View File

@ -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.
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?
@ -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.
### 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.
@ -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)
## Responsibilites
## Responsibilities
### 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.
### What are the responsiblities of a validator?
### What are the responsibilities of a validator?
Validators have two main responsibilities:

View File

@ -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.
## Participate in genesis as a validator
## Participate in Genesis as a Validator
::: warning
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
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.

View File

@ -3,7 +3,7 @@
`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.
- `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:

View File

@ -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.
- **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)

View File

@ -32,7 +32,7 @@ The Cosmos SDK gives you maximum flexibility to define the state of your applica
## 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).
@ -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:

View File

@ -74,9 +74,9 @@ The power of the Cosmos SDK lies in its modularity. SDK applications are built b
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/bank`: Used to enable tokens and token transfers.

View File

@ -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
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
if the transaction's gas prices, which are determined by the provided fees, meet

View File

@ -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