Merge branch 'develop' into cwgoes/slashing-period-spec
This commit is contained in:
commit
41df6db9ae
|
@ -39,14 +39,6 @@ jobs:
|
|||
paths:
|
||||
- bin
|
||||
- profiles
|
||||
- save_cache:
|
||||
key: v1-pkg-cache
|
||||
paths:
|
||||
- /go/pkg
|
||||
- save_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- /go/src/github.com/cosmos/cosmos-sdk
|
||||
|
||||
lint:
|
||||
<<: *defaults
|
||||
|
@ -54,10 +46,12 @@ jobs:
|
|||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-pkg-cache
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- checkout
|
||||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_vendor_deps
|
||||
- run:
|
||||
name: Get metalinter
|
||||
command: |
|
||||
|
@ -75,32 +69,71 @@ jobs:
|
|||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-pkg-cache
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- checkout
|
||||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_vendor_deps
|
||||
- run:
|
||||
name: Test cli
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make test_cli
|
||||
|
||||
test_sim:
|
||||
test_sim_modules:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-pkg-cache
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- checkout
|
||||
- run:
|
||||
name: Test simulation
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
export GAIA_SIMULATION_SEED=1531897442166404087
|
||||
make test_sim
|
||||
make get_vendor_deps
|
||||
- run:
|
||||
name: Test individual module simulations
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make test_sim_modules
|
||||
|
||||
test_sim_gaia_nondeterminism:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- checkout
|
||||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_vendor_deps
|
||||
- run:
|
||||
name: Test individual module simulations
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make test_sim_gaia_nondeterminism
|
||||
|
||||
test_sim_gaia_fast:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- checkout
|
||||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_vendor_deps
|
||||
- run:
|
||||
name: Test full Gaia simulation
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make test_sim_gaia_fast
|
||||
|
||||
test_cover:
|
||||
<<: *defaults
|
||||
|
@ -108,17 +141,19 @@ jobs:
|
|||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-pkg-cache
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- checkout
|
||||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_vendor_deps
|
||||
- run: mkdir -p /tmp/logs
|
||||
- run:
|
||||
name: Run tests
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make install
|
||||
for pkg in $(go list github.com/cosmos/cosmos-sdk/... | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | circleci tests split --split-by=timings); do
|
||||
for pkg in $(go list github.com/cosmos/cosmos-sdk/... | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | grep -v '/simulation' | circleci tests split --split-by=timings); do
|
||||
id=$(basename "$pkg")
|
||||
GOCACHE=off go test -timeout 8m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" | tee "/tmp/logs/$id-$RANDOM.log"
|
||||
done
|
||||
|
@ -135,8 +170,12 @@ jobs:
|
|||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- checkout
|
||||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_vendor_deps
|
||||
- run:
|
||||
name: gather
|
||||
command: |
|
||||
|
@ -150,6 +189,29 @@ jobs:
|
|||
name: upload
|
||||
command: bash <(curl -s https://codecov.io/bash) -f coverage.txt
|
||||
|
||||
localnet:
|
||||
working_directory: /home/circleci/.go_workspace/src/github.com/cosmos/cosmos-sdk
|
||||
machine:
|
||||
image: circleci/classic:latest
|
||||
environment:
|
||||
GOBIN: /home/circleci/.go_workspace/bin
|
||||
GOPATH: /home/circleci/.go_workspace/
|
||||
GOOS: linux
|
||||
GOARCH: amd64
|
||||
parallelism: 1
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: run localnet and exit on failure
|
||||
command: |
|
||||
set -x
|
||||
make get_tools
|
||||
make get_vendor_deps
|
||||
make build-linux
|
||||
make localnet-start
|
||||
./scripts/localnet-blocks-test.sh 40 5 10 localhost
|
||||
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
test-suite:
|
||||
|
@ -161,12 +223,21 @@ workflows:
|
|||
- test_cli:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_sim:
|
||||
- test_sim_modules:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_sim_gaia_nondeterminism:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_sim_gaia_fast:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_cover:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- localnet:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- upload_coverage:
|
||||
requires:
|
||||
- test_cover
|
||||
|
|
|
@ -5,13 +5,14 @@ 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.
|
||||
- [ ] Updated all relevant documentation (`docs/`)
|
||||
- [ ] Updated all relevant code comments
|
||||
- [ ] Wrote tests
|
||||
- [ ] Added entries in `PENDING.md` that include links to the relevant issue or PR that most accurately describes the change.
|
||||
- [ ] Updated `cmd/gaia` and `examples/`
|
||||
___________________________________
|
||||
- [ ] Updated relevant documentation (`docs/`)
|
||||
- [ ] Added entries in `PENDING.md` with issue #
|
||||
- [ ] rereviewed `Files changed` in the github PR explorer
|
||||
|
||||
______
|
||||
|
||||
For Admin Use:
|
||||
- [ ] Added appropriate labels to PR (ex. wip, ready-for-review, docs)
|
||||
- [ ] Reviewers Assigned
|
||||
- [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr))
|
||||
- Added appropriate labels to PR (ex. wip, ready-for-review, docs)
|
||||
- Reviewers Assigned
|
||||
- Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr))
|
||||
|
|
125
CHANGELOG.md
125
CHANGELOG.md
|
@ -1,5 +1,128 @@
|
|||
# Changelog
|
||||
|
||||
## 0.24.1
|
||||
|
||||
*August 21st, 2018*
|
||||
|
||||
BUG FIXES
|
||||
|
||||
* Gaia
|
||||
- [x/slashing] Evidence tracking now uses validator address instead of validator pubkey
|
||||
|
||||
## 0.24.0
|
||||
|
||||
*August 13th, 2018*
|
||||
|
||||
BREAKING CHANGES
|
||||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
- [x/stake] \#1880 More REST-ful endpoints (large refactor)
|
||||
- [x/slashing] \#1866 `/slashing/signing_info` takes cosmosvalpub instead of cosmosvaladdr
|
||||
- use time.Time instead of int64 for time. See Tendermint v0.23.0
|
||||
- Signatures are no longer Amino encoded with prefixes (just encoded as raw
|
||||
bytes) - see Tendermint v0.23.0
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
- [x/stake] change `--keybase-sig` to `--identity`
|
||||
- [x/stake] \#1828 Force user to specify amount on create-validator command by removing default
|
||||
- [x/gov] Change `--proposalID` to `--proposal-id`
|
||||
- [x/stake, x/gov] \#1606 Use `--from` instead of adhoc flags like `--address-validator`
|
||||
and `--proposer` to indicate the sender address.
|
||||
- \#1551 Remove `--name` completely
|
||||
- Genesis/key creation (`gaiad init`) now supports user-provided key passwords
|
||||
|
||||
* Gaia
|
||||
- [x/stake] Inflation doesn't use rationals in calculation (performance boost)
|
||||
- [x/stake] Persist a map from `addr->pubkey` in the state since BeginBlock
|
||||
doesn't provide pubkeys.
|
||||
- [x/gov] \#1781 Added tags sub-package, changed tags to use dash-case
|
||||
- [x/gov] \#1688 Governance parameters are now stored in globalparams store
|
||||
- [x/gov] \#1859 Slash validators who do not vote on a proposal
|
||||
- [x/gov] \#1914 added TallyResult type that gets stored in Proposal after tallying is finished
|
||||
|
||||
* SDK
|
||||
- [baseapp] Msgs are no longer run on CheckTx, removed `ctx.IsCheckTx()`
|
||||
- [baseapp] NewBaseApp constructor takes sdk.TxDecoder as argument instead of wire.Codec
|
||||
- [types] sdk.NewCoin takes sdk.Int, sdk.NewInt64Coin takes int64
|
||||
- [x/auth] Default TxDecoder can be found in `x/auth` rather than baseapp
|
||||
- [client] \#1551: Refactored `CoreContext` to `TxContext` and `QueryContext`
|
||||
- Removed all tx related fields and logic (building & signing) to separate
|
||||
structure `TxContext` in `x/auth/client/context`
|
||||
|
||||
* Tendermint
|
||||
- v0.22.5 -> See [Tendermint PR](https://github.com/tendermint/tendermint/pull/1966)
|
||||
- change all the cryptography imports.
|
||||
- v0.23.0 -> See
|
||||
[Changelog](https://github.com/tendermint/tendermint/blob/v0.23.0/CHANGELOG.md#0230)
|
||||
and [SDK PR](https://github.com/cosmos/cosmos-sdk/pull/1927)
|
||||
- BeginBlock no longer includes crypto.Pubkey
|
||||
- use time.Time instead of int64 for time.
|
||||
|
||||
FEATURES
|
||||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
- [x/gov] Can now query governance proposals by ProposalStatus
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
- [x/gov] added `query-proposals` command. Can filter by `depositer`, `voter`, and `status`
|
||||
- [x/stake] \#2043 Added staking query cli cmds for unbonding-delegations and redelegations
|
||||
|
||||
* Gaia
|
||||
- [networks] Added ansible scripts to upgrade seed nodes on a network
|
||||
|
||||
* SDK
|
||||
- [x/mock/simulation] Randomized simulation framework
|
||||
- Modules specify invariants and operations, preferably in an x/[module]/simulation package
|
||||
- Modules can test random combinations of their own operations
|
||||
- Applications can integrate operations and invariants from modules together for an integrated simulation
|
||||
- Simulates Tendermint's algorithm for validator set updates
|
||||
- Simulates validator signing/downtime with a Markov chain, and occaisional double-signatures
|
||||
- Includes simulated operations & invariants for staking, slashing, governance, and bank modules
|
||||
- [store] \#1481 Add transient store
|
||||
- [baseapp] Initialize validator set on ResponseInitChain
|
||||
- [baseapp] added BaseApp.Seal - ability to seal baseapp parameters once they've been set
|
||||
- [cosmos-sdk-cli] New `cosmos-sdk-cli` tool to quickly initialize a new
|
||||
SDK-based project
|
||||
- [scripts] added log output monitoring to DataDog using Ansible scripts
|
||||
|
||||
IMPROVEMENTS
|
||||
|
||||
* Gaia
|
||||
- [spec] \#967 Inflation and distribution specs drastically improved
|
||||
- [x/gov] \#1773 Votes on a proposal can now be queried
|
||||
- [x/gov] Initial governance parameters can now be set in the genesis file
|
||||
- [x/stake] \#1815 Sped up the processing of `EditValidator` txs.
|
||||
- [config] \#1930 Transactions indexer indexes all tags by default.
|
||||
- [ci] [#2057](https://github.com/cosmos/cosmos-sdk/pull/2057) Run `make localnet-start` on every commit and ensure network reaches at least 10 blocks
|
||||
|
||||
* SDK
|
||||
- [baseapp] \#1587 Allow any alphanumeric character in route
|
||||
- [baseapp] Allow any alphanumeric character in route
|
||||
- [tools] Remove `rm -rf vendor/` from `make get_vendor_deps`
|
||||
- [x/auth] Recover ErrorOutOfGas panic in order to set sdk.Result attributes correctly
|
||||
- [x/bank] Unit tests are now table-driven
|
||||
- [tests] Add tests to example apps in docs
|
||||
- [tests] Fixes ansible scripts to work with AWS too
|
||||
- [tests] \#1806 CLI tests are now behind the build flag 'cli_test', so go test works on a new repo
|
||||
|
||||
BUG FIXES
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
- \#1766 Fixes bad example for keybase identity
|
||||
- [x/stake] \#2021 Fixed repeated CLI commands in staking
|
||||
|
||||
* Gaia
|
||||
- [x/stake] [#2077](https://github.com/cosmos/cosmos-sdk/pull/2077) Fixed invalid cliff power comparison
|
||||
- \#1804 Fixes gen-tx genesis generation logic temporarily until upstream updates
|
||||
- \#1799 Fix `gaiad export`
|
||||
- \#1839 Fixed bug where intra-tx counter wasn't set correctly for genesis validators
|
||||
- [x/stake] \#1858 Fixed bug where the cliff validator was not updated correctly
|
||||
- [tests] \#1675 Fix non-deterministic `test_cover`
|
||||
- [tests] \#1551 Fixed invalid LCD test JSON payload in `doIBCTransfer`
|
||||
- [basecoin] Fixes coin transaction failure and account query [discussion](https://forum.cosmos.network/t/unmarshalbinarybare-expected-to-read-prefix-bytes-75fbfab8-since-it-is-registered-concrete-but-got-0a141dfa/664/6)
|
||||
- [x/gov] \#1757 Fix VoteOption conversion to String
|
||||
* [x/stake] [#2083] Fix broken invariant of bonded validator power decrease
|
||||
|
||||
## 0.23.1
|
||||
|
||||
*July 27th, 2018*
|
||||
|
@ -167,7 +290,7 @@ FEATURES
|
|||
* [types] Added MinInt and MinUint functions
|
||||
* [gaiad] `unsafe_reset_all` now resets addrbook.json
|
||||
* [democoin] add x/oracle, x/assoc
|
||||
* [tests] created a randomized testing framework.
|
||||
* [tests] created a randomized testing framework.
|
||||
- Currently bank has limited functionality in the framework
|
||||
- Auth has its invariants checked within the framework
|
||||
* [tests] Add WaitForNextNBlocksTM helper method
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
* @jaekwon
|
||||
* @ebuchman
|
|
@ -38,7 +38,7 @@
|
|||
name = "github.com/btcsuite/btcd"
|
||||
packages = ["btcec"]
|
||||
pruneopts = "UT"
|
||||
revision = "cf05f92c3f815bbd5091ed6c73eff51f7b1945e8"
|
||||
revision = "f899737d7f2764dc13e4d01ff00108ec58f766a9"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:386de157f7d19259a7f9c81f26ce011223ce0f090353c1152ffdf730d7d10ac2"
|
||||
|
@ -48,12 +48,12 @@
|
|||
revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
|
||||
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = "UT"
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c7644c73a3d23741fdba8a99b1464e021a224b7e205be497271a8003a15ca41b"
|
||||
|
@ -165,12 +165,13 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:12247a2e99a060cc692f6680e5272c8adf0b8f572e6bce0d7095e624c958a240"
|
||||
digest = "1:a361611b8c8c75a1091f00027767f7779b29cb37c456a71b8f2604c88057ab40"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
|
@ -340,19 +341,19 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:080e5f630945ad754f4b920e60b4d3095ba0237ebf88dc462eb28002932e3805"
|
||||
digest = "1:8a020f916b23ff574845789daee6818daf8d25a4852419aae3f0b12378ba432a"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
|
||||
revision = "14d3d4c518341bea657dd8a226f5121c0ff8c9f2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9424f440bba8f7508b69414634aef3b2b3a877e522d8a4624692412805407bb7"
|
||||
digest = "1:dab83a1bbc7ad3d7a6ba1a1cc1760f25ac38cdf7d96a5cdd55cd915a4f5ceaf9"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
||||
version = "v1.0.1"
|
||||
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f8e1a678a2571e265f4bf91a3e5e32aa6b1474a55cb0ea849750cc177b664d96"
|
||||
|
@ -375,7 +376,7 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b3cfb8d82b1601a846417c3f31c03a7961862cb2c98dcf0959c473843e6d9a2b"
|
||||
digest = "1:f2ffd421680b0a3f7887501b3c6974bcf19217ecd301d0e2c9b681940ec363d5"
|
||||
name = "github.com/syndtr/goleveldb"
|
||||
packages = [
|
||||
"leveldb",
|
||||
|
@ -392,7 +393,7 @@
|
|||
"leveldb/util",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445"
|
||||
revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -407,12 +408,12 @@
|
|||
revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e9113641c839c21d8eaeb2c907c7276af1eddeed988df8322168c56b7e06e0e1"
|
||||
digest = "1:e0a2a4be1e20c305badc2b0a7a9ab7fef6da500763bec23ab81df3b5f9eec9ee"
|
||||
name = "github.com/tendermint/go-amino"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "2106ca61d91029c931fd54968c2bb02dc96b1412"
|
||||
version = "0.10.1"
|
||||
revision = "a8328986c1608950fa5d3d1c0472cccc4f8fc02c"
|
||||
version = "v0.12.0-rc0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d4a15d404afbf591e8be16fcda7f5ac87948d5c7531f9d909fd84cc730ab16e2"
|
||||
|
@ -489,6 +490,14 @@
|
|||
revision = "013b9cef642f875634c614019ab13b17570778ad"
|
||||
version = "v0.23.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:bf6d9a827ea3cad964c2f863302e4f6823170d0b5ed16f72cf1184a7c615067e"
|
||||
name = "github.com/tendermint/tmlibs"
|
||||
packages = ["cli"]
|
||||
pruneopts = "UT"
|
||||
revision = "49596e0a1f48866603813df843c9409fc19805c6"
|
||||
version = "v0.9.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4dcb0dd65feecb068ce23a234d1a07c7868a1e39f52a6defcae0bb371d03abf6"
|
||||
name = "github.com/zondax/ledger-goclient"
|
||||
|
@ -498,7 +507,7 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:7a71fffde456d746c52f9cd09c50b034533a3180fb1f6320abb149f2ccc579e5"
|
||||
digest = "1:27507554c6d4f060d8d700c31c624a43d3a92baa634e178ddc044bdf7d13b44a"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"blowfish",
|
||||
|
@ -517,7 +526,7 @@
|
|||
"salsa20/salsa",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "f027049dab0ad238e394a753dba2d14753473a04"
|
||||
revision = "614d502a4dac94afa3a6ce146bd1736da82514c6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1"
|
||||
|
@ -537,14 +546,14 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:4d64ef38a30b73db6e8e7a2824b7fd356d921e0ee3fdd3248658996821d3b47d"
|
||||
digest = "1:a0e12bc26f317c0e2d497baf767285e1790e526e8dd46553c5a67fcbc8692157"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"cpu",
|
||||
"unix",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "acbc56fc7007d2a01796d5bde54f39e3b3e95945"
|
||||
revision = "3b58ed4ad3395d483fc92d5d14123ce2c3581fec"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
|
||||
|
@ -575,7 +584,7 @@
|
|||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
pruneopts = "UT"
|
||||
revision = "daca94659cb50e9f37c1b834680f2e46358f10b0"
|
||||
revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74"
|
||||
|
@ -665,6 +674,7 @@
|
|||
"github.com/tendermint/tendermint/rpc/lib/server",
|
||||
"github.com/tendermint/tendermint/types",
|
||||
"github.com/tendermint/tendermint/version",
|
||||
"github.com/tendermint/tmlibs/cli",
|
||||
"github.com/zondax/ledger-goclient",
|
||||
"golang.org/x/crypto/blowfish",
|
||||
"golang.org/x/crypto/ripemd160",
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/go-amino"
|
||||
version = "=0.10.1"
|
||||
version = "=v0.12.0-rc0"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/iavl"
|
||||
|
|
40
Makefile
40
Makefile
|
@ -16,20 +16,20 @@ ci: get_tools get_vendor_deps install test_cover test_lint test
|
|||
########################################
|
||||
### Build/Install
|
||||
|
||||
check-ledger:
|
||||
check-ledger:
|
||||
ifeq ($(LEDGER_ENABLED),true)
|
||||
ifeq ($(UNAME_S),OpenBSD)
|
||||
$(info "OpenBSD detected, disabling ledger support (https://github.com/cosmos/cosmos-sdk/issues/1988)")
|
||||
TMP_BUILD_TAGS := $(BUILD_TAGS)
|
||||
BUILD_TAGS = $(filter-out ledger, $(TMP_BUILD_TAGS))
|
||||
TMP_BUILD_TAGS := $(BUILD_TAGS)
|
||||
BUILD_TAGS = $(filter-out ledger, $(TMP_BUILD_TAGS))
|
||||
else
|
||||
ifndef GCC
|
||||
$(error "gcc not installed for ledger support, please install or set LEDGER_ENABLED to false in the Makefile")
|
||||
endif
|
||||
endif
|
||||
else
|
||||
TMP_BUILD_TAGS := $(BUILD_TAGS)
|
||||
BUILD_TAGS = $(filter-out ledger, $(TMP_BUILD_TAGS))
|
||||
TMP_BUILD_TAGS := $(BUILD_TAGS)
|
||||
BUILD_TAGS = $(filter-out ledger, $(TMP_BUILD_TAGS))
|
||||
endif
|
||||
|
||||
build: check-ledger
|
||||
|
@ -138,15 +138,21 @@ test_unit:
|
|||
test_race:
|
||||
@go test -race $(PACKAGES_NOSIMULATION)
|
||||
|
||||
test_sim:
|
||||
@echo "Running individual module simulations."
|
||||
@go test $(PACKAGES_SIMTEST) -v
|
||||
@echo "Running full Gaia simulation. This may take several minutes."
|
||||
@echo "Pass the flag 'SimulationSeed' to run with a constant seed."
|
||||
@echo "Pass the flag 'SimulationNumKeys' to run with the specified number of keys."
|
||||
@echo "Pass the flag 'SimulationNumBlocks' to run with the specified number of blocks."
|
||||
@echo "Pass the flag 'SimulationBlockSize' to run with the specified block size (operations per block)."
|
||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationBlockSize=200 -v
|
||||
test_sim_modules:
|
||||
@echo "Running individual module simulations..."
|
||||
@go test $(PACKAGES_SIMTEST)
|
||||
|
||||
test_sim_gaia_nondeterminism:
|
||||
@echo "Running nondeterminism test..."
|
||||
@go test ./cmd/gaia/app -run TestAppStateDeterminism -SimulationEnabled=true -v -timeout 10m
|
||||
|
||||
test_sim_gaia_fast:
|
||||
@echo "Running quick Gaia simulation. This may take several minutes..."
|
||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=200 -timeout 24h
|
||||
|
||||
test_sim_gaia_slow:
|
||||
@echo "Running full Gaia simulation. This may take awhile!"
|
||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=1000 -SimulationVerbose=true -v -timeout 24h
|
||||
|
||||
test_cover:
|
||||
@bash tests/test_cover.sh
|
||||
|
@ -198,8 +204,8 @@ build-docker-gaiadnode:
|
|||
|
||||
# Run a 4-node testnet locally
|
||||
localnet-start: localnet-stop
|
||||
@if ! [ -f build/node0/gaiad/config/genesis.json ]; then docker run --rm -v $(CURDIR)/build:/gaiad:Z tendermint/gaiadnode testnet --v 4 --o . --starting-ip-address 192.168.10.2 ; fi
|
||||
docker-compose up
|
||||
@if ! [ -f build/node0/gaiad/config/genesis.json ]; then docker run --rm -v $(CURDIR)/build:/gaiad:Z tendermint/gaiadnode testnet --v 4 -o . --starting-ip-address 192.168.10.2 ; fi
|
||||
docker-compose up -d
|
||||
|
||||
# Stop testnet
|
||||
localnet-stop:
|
||||
|
@ -212,4 +218,4 @@ localnet-stop:
|
|||
check_tools check_dev_tools get_tools get_dev_tools get_vendor_deps draw_deps test test_cli test_unit \
|
||||
test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
|
||||
build-linux build-docker-gaiadnode localnet-start localnet-stop \
|
||||
format check-ledger test_sim update_tools update_dev_tools
|
||||
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast test_sim_gaia_slow update_tools update_dev_tools
|
||||
|
|
159
PENDING.md
159
PENDING.md
|
@ -1,101 +1,76 @@
|
|||
## v0.24.0 PENDING
|
||||
^--- PENDING wasn't purged on sdk v0.23.0 release.
|
||||
|
||||
BREAKING CHANGES
|
||||
* Update to tendermint v0.23.0. This involves removing crypto.Pubkey,
|
||||
maintaining a validator address to pubkey map, and using time.Time instead of int64 for time. [SDK PR](https://github.com/cosmos/cosmos-sdk/pull/1927)
|
||||
|
||||
## PENDING
|
||||
|
||||
BREAKING CHANGES
|
||||
* API
|
||||
- \#1880 and \#2000 [x/stake] changed the endpoints to be more REST-ful
|
||||
* Update to tendermint v0.22.5. This involves changing all of the cryptography imports. [Ref](https://github.com/tendermint/tendermint/pull/1966)
|
||||
* [baseapp] Msgs are no longer run on CheckTx, removed `ctx.IsCheckTx()`
|
||||
* [x/gov] CLI flag changed from `proposalID` to `proposal-id`
|
||||
* [x/stake] Fixed the period check for the inflation calculation
|
||||
* [x/stake] Inflation doesn't use rationals in calculation (performance boost)
|
||||
* [x/stake] CLI flags for identity changed from `--keybase-sig` to `--identity`, effects:
|
||||
* `gaiacli stake create-validator`
|
||||
* `gaiacli stake edit-validator`
|
||||
* [baseapp] NewBaseApp constructor now takes sdk.TxDecoder as argument instead of wire.Codec
|
||||
* [x/auth] Default TxDecoder can be found in `x/auth` rather than baseapp
|
||||
* \#1606 The following CLI commands have been switched to use `--from`
|
||||
* `gaiacli stake create-validator --address-validator`
|
||||
* `gaiacli stake edit-validator --address-validator`
|
||||
* `gaiacli stake delegate --address-delegator`
|
||||
* `gaiacli stake unbond begin --address-delegator`
|
||||
* `gaiacli stake unbond complete --address-delegator`
|
||||
* `gaiacli stake redelegate begin --address-delegator`
|
||||
* `gaiacli stake redelegate complete --address-delegator`
|
||||
* `gaiacli stake unrevoke [validator-address]`
|
||||
* `gaiacli gov submit-proposal --proposer`
|
||||
* `gaiacli gov deposit --depositer`
|
||||
* `gaiacli gov vote --voter`
|
||||
* [x/gov] Added tags sub-package, changed tags to use dash-case
|
||||
* [x/gov] Governance parameters are now stored in globalparams store
|
||||
* [lcd] \#1866 Updated lcd /slashing/signing_info endpoint to take cosmosvalpub instead of cosmosvaladdr
|
||||
* [types] sdk.NewCoin now takes sdk.Int, sdk.NewInt64Coin takes int64
|
||||
* [cli] #1551: Officially removed `--name` from CLI commands
|
||||
* [cli] Genesis/key creation (`init`) now supports user-provided key passwords
|
||||
* [cli] unsafe_reset_all, show_validator, and show_node_id have been renamed to unsafe-reset-all, show-validator, and show-node-id
|
||||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
* [x/stake] Validator.Owner renamed to Validator.Operator
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [x/stake] Validator.Owner renamed to Validator.Operator
|
||||
* [cli] unsafe_reset_all, show_validator, and show_node_id have been renamed to unsafe-reset-all, show-validator, and show-node-id
|
||||
* [cli] \#1983 --print-response now defaults to true in commands that create and send a transaction
|
||||
* [cli] \#1983 you can now pass --pubkey or --address to gaiacli keys show to return a plaintext representation of the key's address or public key for use with other commands
|
||||
* [cli] \#2061 changed proposalID in governance REST endpoints to proposal-id
|
||||
* [cli] \#2014 `gaiacli advanced` no longer exists - to access `ibc`, `rest-server`, and `validator-set` commands use `gaiacli ibc`, `gaiacli rest-server`, and `gaiacli tendermint`, respectively
|
||||
|
||||
|
||||
* Gaia
|
||||
* Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013)
|
||||
* [x/stake] \#1901 Validator type's Owner field renamed to Operator; Validator's GetOwner() renamed accordingly to comply with the SDK's Validator interface.
|
||||
|
||||
* SDK
|
||||
* [core] \#1807 Switch from use of rational to decimal
|
||||
* [types] \#1901 Validator interface's GetOwner() renamed to GetOperator()
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
||||
FEATURES
|
||||
* [lcd] Can now query governance proposals by ProposalStatus
|
||||
* [x/mock/simulation] Randomized simulation framework
|
||||
* Modules specify invariants and operations, preferably in an x/[module]/simulation package
|
||||
* Modules can test random combinations of their own operations
|
||||
* Applications can integrate operations and invariants from modules together for an integrated simulation
|
||||
* [baseapp] Initialize validator set on ResponseInitChain
|
||||
* [cosmos-sdk-cli] Added support for cosmos-sdk-cli tool under cosmos-sdk/cmd
|
||||
* This allows SDK users to initialize a new project repository.
|
||||
* [tests] Remotenet commands for AWS (awsnet)
|
||||
* [networks] Added ansible scripts to upgrade seed nodes on a network
|
||||
* [store] Add transient store
|
||||
* [gov] Add slashing for validators who do not vote on a proposal
|
||||
* [cli] added `gov query-proposals` command to CLI. Can filter by `depositer`, `voter`, and `status`
|
||||
* [core] added BaseApp.Seal - ability to seal baseapp parameters once they've been set
|
||||
* [scripts] added log output monitoring to DataDog using Ansible scripts
|
||||
* [gov] added TallyResult type that gets added stored in Proposal after tallying is finished
|
||||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
* [lcd] Endpoints to query staking pool and params
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [cli] Cmds to query staking pool and params
|
||||
* [gov][cli] #2062 added `--proposal` flag to `submit-proposal` that allows a JSON file containing a proposal to be passed in
|
||||
|
||||
* Gaia
|
||||
|
||||
* SDK
|
||||
* [querier] added custom querier functionality, so ABCI query requests can be handled by keepers
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
||||
IMPROVEMENTS
|
||||
* [baseapp] Allow any alphanumeric character in route
|
||||
* [cli] Improve error messages for all txs when the account doesn't exist
|
||||
* [tools] Remove `rm -rf vendor/` from `make get_vendor_deps`
|
||||
* [x/auth] Recover ErrorOutOfGas panic in order to set sdk.Result attributes correctly
|
||||
* [x/stake] Add revoked to human-readable validator
|
||||
* [spec] \#967 Inflation and distribution specs drastically improved
|
||||
* [tests] Add tests to example apps in docs
|
||||
* [x/gov] Votes on a proposal can now be queried
|
||||
* [x/bank] Unit tests are now table-driven
|
||||
* [tests] Fixes ansible scripts to work with AWS too
|
||||
* [tests] \#1806 CLI tests are now behind the build flag 'cli_test', so go test works on a new repo
|
||||
* [x/gov] Initial governance parameters can now be set in the genesis file
|
||||
* [x/stake] \#1815 Sped up the processing of `EditValidator` txs.
|
||||
* [server] \#1930 Transactions indexer indexes all tags by default.
|
||||
* [x/stake] \#2000 Added tests for new staking endpoints
|
||||
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
|
||||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
* [x/stake] \#2000 Added tests for new staking endpoints
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [cli] #2060 removed `--select` from `block` command
|
||||
|
||||
* Gaia
|
||||
* [x/stake] [#2023](https://github.com/cosmos/cosmos-sdk/pull/2023) Terminate iteration loop in `UpdateBondedValidators` and `UpdateBondedValidatorsFull` when the first revoked validator is encountered and perform a sanity check.
|
||||
* [x/auth] Signature verification's gas cost now accounts for pubkey type. [#2046](https://github.com/tendermint/tendermint/pull/2046)
|
||||
|
||||
* SDK
|
||||
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
|
||||
|
||||
* Tendermint
|
||||
|
||||
|
||||
BUG FIXES
|
||||
* \#1988 Make us compile on OpenBSD (disable ledger) [#1988] (https://github.com/cosmos/cosmos-sdk/issues/1988)
|
||||
* \#1666 Add intra-tx counter to the genesis validators
|
||||
* \#1797 Fix off-by-one error in slashing for downtime
|
||||
* \#1787 Fixed bug where Tally fails due to revoked/unbonding validator
|
||||
* \#1766 Fixes bad example for keybase identity
|
||||
* \#1804 Fixes gen-tx genesis generation logic temporarily until upstream updates
|
||||
* \#1799 Fix `gaiad export`
|
||||
* \#1828 Force user to specify amount on create-validator command by removing default
|
||||
* \#1839 Fixed bug where intra-tx counter wasn't set correctly for genesis validators
|
||||
* [staking] [#1858](https://github.com/cosmos/cosmos-sdk/pull/1858) Fixed bug where the cliff validator was not be updated correctly
|
||||
* [tests] \#1675 Fix non-deterministic `test_cover`
|
||||
* [client] \#1551: Refactored `CoreContext`
|
||||
* Renamed `CoreContext` to `QueryContext`
|
||||
* Removed all tx related fields and logic (building & signing) to separate
|
||||
structure `TxContext` in `x/auth/client/context`
|
||||
* Cleaned up documentation and API of what used to be `CoreContext`
|
||||
* Implemented `KeyType` enum for key info
|
||||
* \#1666 Add intra-tx counter to the genesis validators
|
||||
* [tests] \#1551: Fixed invalid LCD test JSON payload in `doIBCTransfer`
|
||||
* \#1787 Fixed bug where Tally fails due to revoked/unbonding validator
|
||||
* \#1787 Fixed bug where Tally fails due to revoked/unbonding validator
|
||||
* [basecoin] Fixes coin transaction failure and account query [discussion](https://forum.cosmos.network/t/unmarshalbinarybare-expected-to-read-prefix-bytes-75fbfab8-since-it-is-registered-concrete-but-got-0a141dfa/664/6)
|
||||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [cli] \#1997 Handle panics gracefully when `gaiacli stake {delegation,unbond}` fail to unmarshal delegation.
|
||||
|
||||
* Gaia
|
||||
|
||||
* SDK
|
||||
* \#1988 Make us compile on OpenBSD (disable ledger) [#1988] (https://github.com/cosmos/cosmos-sdk/issues/1988)
|
||||
* \#2105 Fix DB Iterator leak, which may leak a go routine.
|
||||
|
||||
* Tendermint
|
||||
|
|
|
@ -41,13 +41,14 @@ const (
|
|||
// BaseApp reflects the ABCI application implementation.
|
||||
type BaseApp struct {
|
||||
// initialized on creation
|
||||
Logger log.Logger
|
||||
name string // application name from abci.Info
|
||||
db dbm.DB // common DB backend
|
||||
cms sdk.CommitMultiStore // Main (uncached) state
|
||||
router Router // handle any kind of message
|
||||
codespacer *sdk.Codespacer // handle module codespacing
|
||||
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
|
||||
Logger log.Logger
|
||||
name string // application name from abci.Info
|
||||
db dbm.DB // common DB backend
|
||||
cms sdk.CommitMultiStore // Main (uncached) state
|
||||
router Router // handle any kind of message
|
||||
queryRouter QueryRouter // router for redirecting query calls
|
||||
codespacer *sdk.Codespacer // handle module codespacing
|
||||
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
|
||||
|
||||
anteHandler sdk.AnteHandler // ante handler for fee and auth
|
||||
|
||||
|
@ -84,13 +85,14 @@ var _ abci.Application = (*BaseApp)(nil)
|
|||
// Accepts variable number of option functions, which act on the BaseApp to set configuration choices
|
||||
func NewBaseApp(name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp)) *BaseApp {
|
||||
app := &BaseApp{
|
||||
Logger: logger,
|
||||
name: name,
|
||||
db: db,
|
||||
cms: store.NewCommitMultiStore(db),
|
||||
router: NewRouter(),
|
||||
codespacer: sdk.NewCodespacer(),
|
||||
txDecoder: txDecoder,
|
||||
Logger: logger,
|
||||
name: name,
|
||||
db: db,
|
||||
cms: store.NewCommitMultiStore(db),
|
||||
router: NewRouter(),
|
||||
queryRouter: NewQueryRouter(),
|
||||
codespacer: sdk.NewCodespacer(),
|
||||
txDecoder: txDecoder,
|
||||
}
|
||||
|
||||
// Register the undefined & root codespaces, which should not be used by
|
||||
|
@ -266,6 +268,7 @@ func (app *BaseApp) FilterPeerByPubKey(info string) abci.ResponseQuery {
|
|||
return abci.ResponseQuery{}
|
||||
}
|
||||
|
||||
// Splits a string path using the delimter '/'. i.e. "this/is/funny" becomes []string{"this", "is", "funny"}
|
||||
func splitPath(requestPath string) (path []string) {
|
||||
path = strings.Split(requestPath, "/")
|
||||
// first element is empty string
|
||||
|
@ -291,6 +294,8 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
|
|||
return handleQueryStore(app, path, req)
|
||||
case "p2p":
|
||||
return handleQueryP2P(app, path, req)
|
||||
case "custom":
|
||||
return handleQueryCustom(app, path, req)
|
||||
}
|
||||
|
||||
msg := "unknown query path"
|
||||
|
@ -362,6 +367,33 @@ func handleQueryP2P(app *BaseApp, path []string, req abci.RequestQuery) (res abc
|
|||
return sdk.ErrUnknownRequest(msg).QueryResult()
|
||||
}
|
||||
|
||||
func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) {
|
||||
// path[0] should be "custom" because "/custom" prefix is required for keeper queries.
|
||||
// the queryRouter routes using path[1]. For example, in the path "custom/gov/proposal", queryRouter routes using "gov"
|
||||
if path[1] == "" {
|
||||
sdk.ErrUnknownRequest("No route for custom query specified").QueryResult()
|
||||
}
|
||||
querier := app.queryRouter.Route(path[1])
|
||||
if querier == nil {
|
||||
sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult()
|
||||
}
|
||||
|
||||
ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger)
|
||||
// Passes the rest of the path as an argument to the querier.
|
||||
// For example, in the path "custom/gov/proposal/test", the gov querier gets []string{"proposal", "test"} as the path
|
||||
resBytes, err := querier(ctx, path[2:], req)
|
||||
if err != nil {
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(err.ABCICode()),
|
||||
Log: err.ABCILog(),
|
||||
}
|
||||
}
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(sdk.ABCICodeOK),
|
||||
Value: resBytes,
|
||||
}
|
||||
}
|
||||
|
||||
// BeginBlock implements the ABCI application interface.
|
||||
func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) {
|
||||
if app.cms.TracingEnabled() {
|
||||
|
@ -379,7 +411,7 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
|
|||
} else {
|
||||
// In the first block, app.deliverState.ctx will already be initialized
|
||||
// by InitChain. Context is now updated with Header information.
|
||||
app.deliverState.ctx = app.deliverState.ctx.WithBlockHeader(req.Header)
|
||||
app.deliverState.ctx = app.deliverState.ctx.WithBlockHeader(req.Header).WithBlockHeight(req.Header.Height)
|
||||
}
|
||||
|
||||
if app.beginBlocker != nil {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package baseapp
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// QueryRouter provides queryables for each query path.
|
||||
type QueryRouter interface {
|
||||
AddRoute(r string, h sdk.Querier) (rtr QueryRouter)
|
||||
Route(path string) (h sdk.Querier)
|
||||
}
|
||||
|
||||
type queryrouter struct {
|
||||
routes map[string]sdk.Querier
|
||||
}
|
||||
|
||||
// nolint
|
||||
// NewRouter - create new router
|
||||
// TODO either make Function unexported or make return type (router) Exported
|
||||
func NewQueryRouter() *queryrouter {
|
||||
return &queryrouter{
|
||||
routes: map[string]sdk.Querier{},
|
||||
}
|
||||
}
|
||||
|
||||
// AddRoute - Adds an sdk.Querier to the route provided. Panics on duplicate
|
||||
func (rtr *queryrouter) AddRoute(r string, q sdk.Querier) QueryRouter {
|
||||
if !isAlphaNumeric(r) {
|
||||
panic("route expressions can only contain alphanumeric characters")
|
||||
}
|
||||
if rtr.routes[r] != nil {
|
||||
panic("route has already been initialized")
|
||||
}
|
||||
rtr.routes[r] = q
|
||||
return rtr
|
||||
}
|
||||
|
||||
// Returns the sdk.Querier for a certain route path
|
||||
func (rtr *queryrouter) Route(path string) (h sdk.Querier) {
|
||||
return rtr.routes[path]
|
||||
}
|
|
@ -74,6 +74,9 @@ func (app *BaseApp) Router() Router {
|
|||
}
|
||||
return app.router
|
||||
}
|
||||
func (app *BaseApp) QueryRouter() QueryRouter {
|
||||
return app.queryRouter
|
||||
}
|
||||
func (app *BaseApp) Seal() { app.sealed = true }
|
||||
func (app *BaseApp) IsSealed() bool { return app.sealed }
|
||||
func (app *BaseApp) enforceSeal() {
|
||||
|
|
|
@ -31,6 +31,11 @@ func (ctx CLIContext) Query(path string) (res []byte, err error) {
|
|||
return ctx.query(path, nil)
|
||||
}
|
||||
|
||||
// Query information about the connected node with a data payload
|
||||
func (ctx CLIContext) QueryWithData(path string, data []byte) (res []byte, err error) {
|
||||
return ctx.query(path, data)
|
||||
}
|
||||
|
||||
// QueryStore performs a query from a Tendermint node with the provided key and
|
||||
// store name.
|
||||
func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (res []byte, err error) {
|
||||
|
|
|
@ -52,7 +52,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
|||
c.Flags().Int64(FlagGas, 200000, "gas limit to set per-transaction")
|
||||
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
|
||||
c.Flags().Bool(FlagJson, false, "return output in json format")
|
||||
c.Flags().Bool(FlagPrintResponse, false, "return tx response (only works with async = false)")
|
||||
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
|
||||
}
|
||||
return cmds
|
||||
}
|
||||
|
|
|
@ -4,10 +4,20 @@ import (
|
|||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
keys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
// FlagAddress is the flag for the user's address on the command line.
|
||||
FlagAddress = "address"
|
||||
// FlagPublicKey represents the user's public key on the command line.
|
||||
FlagPublicKey = "pubkey"
|
||||
)
|
||||
|
||||
var showKeysCmd = &cobra.Command{
|
||||
|
@ -18,13 +28,38 @@ var showKeysCmd = &cobra.Command{
|
|||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
name := args[0]
|
||||
info, err := getKey(name)
|
||||
if err == nil {
|
||||
printInfo(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
|
||||
showAddress := viper.GetBool(FlagAddress)
|
||||
showPublicKey := viper.GetBool(FlagPublicKey)
|
||||
outputSet := cmd.Flag(cli.OutputFlag).Changed
|
||||
if showAddress && showPublicKey {
|
||||
return errors.New("cannot use both --address and --pubkey at once")
|
||||
}
|
||||
if outputSet && (showAddress || showPublicKey) {
|
||||
return errors.New("cannot use --output with --address or --pubkey")
|
||||
}
|
||||
if showAddress {
|
||||
printKeyAddress(info)
|
||||
return nil
|
||||
}
|
||||
if showPublicKey {
|
||||
printPubKey(info)
|
||||
return nil
|
||||
}
|
||||
|
||||
printInfo(info)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
showKeysCmd.Flags().Bool(FlagAddress, false, "output the address only (overrides --output)")
|
||||
showKeysCmd.Flags().Bool(FlagPublicKey, false, "output the public key only (overrides --output)")
|
||||
}
|
||||
|
||||
func getKey(name string) (keys.Info, error) {
|
||||
kb, err := GetKeyBase()
|
||||
if err != nil {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
keys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
|
||||
|
@ -173,3 +173,19 @@ func printInfos(infos []keys.Info) {
|
|||
func printKeyOutput(ko KeyOutput) {
|
||||
fmt.Printf("%s\t%s\t%s\t%s\n", ko.Name, ko.Type, ko.Address, ko.PubKey)
|
||||
}
|
||||
|
||||
func printKeyAddress(info keys.Info) {
|
||||
ko, err := Bech32KeyOutput(info)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(ko.Address.String())
|
||||
}
|
||||
|
||||
func printPubKey(info keys.Info) {
|
||||
ko, err := Bech32KeyOutput(info)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(ko.PubKey)
|
||||
}
|
||||
|
|
|
@ -353,6 +353,42 @@ func TestTxs(t *testing.T) {
|
|||
require.Equal(t, resultTx.Height, indexedTxs[0].Height)
|
||||
}
|
||||
|
||||
func TestPoolParamsQuery(t *testing.T) {
|
||||
_, password := "test", "1234567890"
|
||||
addr, _ := CreateAddr(t, "test", password, GetKeyBase(t))
|
||||
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
|
||||
defer cleanup()
|
||||
|
||||
defaultParams := stake.DefaultParams()
|
||||
|
||||
res, body := Request(t, port, "GET", "/stake/parameters", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var params stake.Params
|
||||
err := cdc.UnmarshalJSON([]byte(body), ¶ms)
|
||||
require.Nil(t, err)
|
||||
require.True(t, defaultParams.Equal(params))
|
||||
|
||||
res, body = Request(t, port, "GET", "/stake/pool", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
require.NotNil(t, body)
|
||||
|
||||
initialPool := stake.InitialPool()
|
||||
initialPool.LooseTokens = initialPool.LooseTokens.Add(sdk.NewDec(100))
|
||||
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(100)) // Delegate tx on GaiaAppGenState
|
||||
initialPool.LooseTokens = initialPool.LooseTokens.Add(sdk.NewDec(int64(50))) // freeFermionsAcc = 50 on GaiaAppGenState
|
||||
|
||||
var pool stake.Pool
|
||||
err = cdc.UnmarshalJSON([]byte(body), &pool)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, initialPool.DateLastCommissionReset, pool.DateLastCommissionReset)
|
||||
require.Equal(t, initialPool.PrevBondedShares, pool.PrevBondedShares)
|
||||
require.Equal(t, initialPool.BondedTokens, pool.BondedTokens)
|
||||
require.Equal(t, initialPool.NextInflation(params), pool.Inflation)
|
||||
initialPool = initialPool.ProcessProvisions(params) // provisions are added to the pool every hour
|
||||
require.Equal(t, initialPool.LooseTokens, pool.LooseTokens)
|
||||
}
|
||||
|
||||
func TestValidatorsQuery(t *testing.T) {
|
||||
cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{})
|
||||
defer cleanup()
|
||||
|
@ -361,13 +397,13 @@ func TestValidatorsQuery(t *testing.T) {
|
|||
validators := getValidators(t, port)
|
||||
require.Equal(t, len(validators), 1)
|
||||
|
||||
// make sure all the validators were found (order unknown because sorted by owner addr)
|
||||
// make sure all the validators were found (order unknown because sorted by operator addr)
|
||||
foundVal := false
|
||||
pkBech := sdk.MustBech32ifyValPub(pks[0])
|
||||
if validators[0].PubKey == pkBech {
|
||||
foundVal = true
|
||||
}
|
||||
require.True(t, foundVal, "pkBech %v, owner %v", pkBech, validators[0].Owner)
|
||||
require.True(t, foundVal, "pkBech %v, operator %v", pkBech, validators[0].Operator)
|
||||
}
|
||||
|
||||
func TestValidatorQuery(t *testing.T) {
|
||||
|
@ -375,12 +411,9 @@ func TestValidatorQuery(t *testing.T) {
|
|||
defer cleanup()
|
||||
require.Equal(t, 1, len(pks))
|
||||
|
||||
validator1Owner := sdk.AccAddress(pks[0].Address())
|
||||
|
||||
validator := getValidator(t, port, validator1Owner)
|
||||
bech32ValAddress, err := sdk.Bech32ifyValPub(pks[0])
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, validator.PubKey, bech32ValAddress, "The returned validator does not hold the correct data")
|
||||
validator1Operator := sdk.AccAddress(pks[0].Address())
|
||||
validator := getValidator(t, port, validator1Operator)
|
||||
assert.Equal(t, validator.Operator, validator1Operator, "The returned validator does not hold the correct data")
|
||||
}
|
||||
|
||||
func TestBonding(t *testing.T) {
|
||||
|
@ -389,10 +422,11 @@ func TestBonding(t *testing.T) {
|
|||
cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
|
||||
defer cleanup()
|
||||
|
||||
validator1Owner := sdk.AccAddress(pks[0].Address())
|
||||
validator := getValidator(t, port, validator1Owner)
|
||||
validator1Operator := sdk.AccAddress(pks[0].Address())
|
||||
validator := getValidator(t, port, validator1Operator)
|
||||
|
||||
resultTx := doDelegate(t, port, seed, name, password, addr, validator1Owner, 60)
|
||||
// create bond TX
|
||||
resultTx := doDelegate(t, port, seed, name, password, addr, validator1Operator, 60)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
|
||||
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
|
@ -403,7 +437,8 @@ func TestBonding(t *testing.T) {
|
|||
|
||||
require.Equal(t, int64(40), coins.AmountOf(denom).Int64())
|
||||
|
||||
bond := getDelegation(t, port, addr, validator1Owner)
|
||||
// query validator
|
||||
bond := getDelegation(t, port, addr, validator1Operator)
|
||||
require.Equal(t, "60.0000000000", bond.Shares)
|
||||
|
||||
summary := getDelegationSummary(t, port, addr)
|
||||
|
@ -414,16 +449,17 @@ func TestBonding(t *testing.T) {
|
|||
|
||||
bondedValidators := getDelegatorValidators(t, port, addr)
|
||||
require.Len(t, bondedValidators, 1)
|
||||
require.Equal(t, validator1Owner, bondedValidators[0].Owner)
|
||||
require.Equal(t, validator.DelegatorShares.Add(sdk.NewRat(60)).FloatString(), bondedValidators[0].DelegatorShares.FloatString())
|
||||
require.Equal(t, validator1Operator, bondedValidators[0].Operator)
|
||||
require.Equal(t, validator.DelegatorShares.Add(sdk.NewDec(60)).String(), bondedValidators[0].DelegatorShares.String())
|
||||
|
||||
bondedValidator := getDelegatorValidator(t, port, addr, validator1Owner)
|
||||
require.Equal(t, validator1Owner, bondedValidator.Owner)
|
||||
bondedValidator := getDelegatorValidator(t, port, addr, validator1Operator)
|
||||
require.Equal(t, validator1Operator, bondedValidator.Operator)
|
||||
|
||||
//////////////////////
|
||||
// testing unbonding
|
||||
|
||||
resultTx = doBeginUnbonding(t, port, seed, name, password, addr, validator1Owner, 60)
|
||||
// create unbond TX
|
||||
resultTx = doBeginUnbonding(t, port, seed, name, password, addr, validator1Operator, 60)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
|
||||
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
|
@ -434,7 +470,7 @@ func TestBonding(t *testing.T) {
|
|||
coins = acc.GetCoins()
|
||||
require.Equal(t, int64(40), coins.AmountOf("steak").Int64())
|
||||
|
||||
unbondings := getUndelegations(t, port, addr, validator1Owner)
|
||||
unbondings := getUndelegations(t, port, addr, validator1Operator)
|
||||
require.Len(t, unbondings, 1, "Unbondings holds all unbonding-delegations")
|
||||
require.Equal(t, "60", unbondings[0].Balance.Amount.String())
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
|||
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 100)}
|
||||
acc := gapp.NewGenesisAccount(&accAuth)
|
||||
genesisState.Accounts = append(genesisState.Accounts, acc)
|
||||
genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewRat(100))
|
||||
genesisState.StakeData.Pool.LooseTokens = genesisState.StakeData.Pool.LooseTokens.Add(sdk.NewDec(100))
|
||||
}
|
||||
|
||||
appState, err := wire.MarshalJSONIndent(cdc, genesisState)
|
||||
|
|
|
@ -12,10 +12,6 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
flagSelect = "select"
|
||||
)
|
||||
|
||||
//BlockCommand returns the verified block data for a given heights
|
||||
func BlockCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
|
@ -27,7 +23,6 @@ func BlockCommand() *cobra.Command {
|
|||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||
// TODO: change this to false when we can
|
||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||
cmd.Flags().StringSlice(flagSelect, []string{"header", "tx"}, "Fields to return (header|txs|results)")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -38,7 +33,6 @@ func getBlock(cliCtx context.CLIContext, height *int64) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: actually honor the --select flag!
|
||||
// header -> BlockchainInfo
|
||||
// header, tx -> Block
|
||||
// results -> BlockResults
|
||||
|
|
|
@ -27,7 +27,20 @@ const (
|
|||
func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "txs",
|
||||
Short: "Search for all transactions that match the given tags",
|
||||
Short: "Search for all transactions that match the given tags.",
|
||||
Long: strings.TrimSpace(`
|
||||
Search for transactions that match the given tags. By default, transactions must match ALL tags
|
||||
passed to the --tags option. To match any transaction, use the --any option.
|
||||
|
||||
For example:
|
||||
|
||||
$ gaiacli tendermint txs --tag test1,test2
|
||||
|
||||
will match any transaction tagged with both test1,test2. To match a transaction tagged with either
|
||||
test1 or test2, use:
|
||||
|
||||
$ gaiacli tendermint txs --tag test1,test2 --any
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
tags := viper.GetStringSlice(flagTags)
|
||||
|
||||
|
@ -52,7 +65,7 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
// TODO: change this to false once proofs built in
|
||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||
cmd.Flags().StringSlice(flagTags, nil, "Tags that must match (may provide multiple)")
|
||||
cmd.Flags().StringSlice(flagTags, nil, "Comma-separated list of tags that must match")
|
||||
cmd.Flags().Bool(flagAny, false, "Return transactions that match ANY tag, rather than ALL")
|
||||
return cmd
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
keyGov: sdk.NewKVStoreKey("gov"),
|
||||
keyFeeCollection: sdk.NewKVStoreKey("fee"),
|
||||
keyParams: sdk.NewKVStoreKey("params"),
|
||||
tkeyParams: sdk.NewTransientStoreKey("params"),
|
||||
tkeyParams: sdk.NewTransientStoreKey("transient_params"),
|
||||
}
|
||||
|
||||
// define the accountMapper
|
||||
|
@ -105,6 +105,9 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
AddRoute("slashing", slashing.NewHandler(app.slashingKeeper)).
|
||||
AddRoute("gov", gov.NewHandler(app.govKeeper))
|
||||
|
||||
app.QueryRouter().
|
||||
AddRoute("gov", gov.NewQuerier(app.govKeeper))
|
||||
|
||||
// initialize BaseApp
|
||||
app.SetInitChainer(app.initChainer)
|
||||
app.SetBeginBlocker(app.BeginBlocker)
|
||||
|
@ -185,7 +188,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
// load the address to pubkey map
|
||||
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.StakeData)
|
||||
|
||||
gov.InitGenesis(ctx, app.govKeeper, gov.DefaultGenesisState())
|
||||
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
||||
|
||||
return abci.ResponseInitChain{
|
||||
Validators: validators,
|
||||
|
@ -208,6 +211,7 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val
|
|||
genState := GenesisState{
|
||||
Accounts: accounts,
|
||||
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
|
||||
GovData: gov.WriteGenesis(ctx, app.govKeeper),
|
||||
}
|
||||
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
|
||||
if err != nil {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
@ -32,6 +33,7 @@ var (
|
|||
type GenesisState struct {
|
||||
Accounts []GenesisAccount `json:"accounts"`
|
||||
StakeData stake.GenesisState `json:"stake"`
|
||||
GovData gov.GenesisState `json:"gov"`
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
|
@ -185,7 +187,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState
|
|||
}
|
||||
acc := NewGenesisAccount(&accAuth)
|
||||
genaccs[i] = acc
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewRat(freeFermionsAcc)) // increase the supply
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionsAcc)) // increase the supply
|
||||
|
||||
// add the validator
|
||||
if len(genTx.Name) > 0 {
|
||||
|
@ -193,17 +195,17 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState
|
|||
validator := stake.NewValidator(genTx.Address,
|
||||
sdk.MustGetAccPubKeyBech32(genTx.PubKey), desc)
|
||||
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewRat(freeFermionVal)) // increase the supply
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply
|
||||
|
||||
// add some new shares to the validator
|
||||
var issuedDelShares sdk.Rat
|
||||
var issuedDelShares sdk.Dec
|
||||
validator, stakeData.Pool, issuedDelShares = validator.AddTokensFromDel(stakeData.Pool, freeFermionVal)
|
||||
stakeData.Validators = append(stakeData.Validators, validator)
|
||||
|
||||
// create the self-delegation from the issuedDelShares
|
||||
delegation := stake.Delegation{
|
||||
DelegatorAddr: validator.Owner,
|
||||
ValidatorAddr: validator.Owner,
|
||||
DelegatorAddr: validator.Operator,
|
||||
ValidatorAddr: validator.Operator,
|
||||
Shares: issuedDelShares,
|
||||
Height: 0,
|
||||
}
|
||||
|
@ -216,6 +218,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState
|
|||
genesisState = GenesisState{
|
||||
Accounts: genaccs,
|
||||
StakeData: stakeData,
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -3,52 +3,74 @@ package app
|
|||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
|
||||
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
||||
stake "github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakesim "github.com/cosmos/cosmos-sdk/x/stake/simulation"
|
||||
)
|
||||
|
||||
var (
|
||||
seed int64
|
||||
numKeys int
|
||||
numBlocks int
|
||||
blockSize int
|
||||
enabled bool
|
||||
verbose bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.Int64Var(&seed, "SimulationSeed", 42, "Simulation random seed")
|
||||
flag.IntVar(&numKeys, "SimulationNumKeys", 10, "Number of keys (accounts)")
|
||||
flag.IntVar(&numBlocks, "SimulationNumBlocks", 100, "Number of blocks")
|
||||
flag.IntVar(&blockSize, "SimulationBlockSize", 100, "Operations per block")
|
||||
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")
|
||||
}
|
||||
|
||||
func appStateFn(r *rand.Rand, accs []sdk.AccAddress) json.RawMessage {
|
||||
func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
|
||||
var genesisAccounts []GenesisAccount
|
||||
|
||||
// Randomly generate some genesis accounts
|
||||
for _, addr := range accs {
|
||||
for _, acc := range accs {
|
||||
coins := sdk.Coins{sdk.Coin{"steak", sdk.NewInt(100)}}
|
||||
genesisAccounts = append(genesisAccounts, GenesisAccount{
|
||||
Address: addr,
|
||||
Address: acc,
|
||||
Coins: coins,
|
||||
})
|
||||
}
|
||||
|
||||
// Default genesis state
|
||||
stakeGenesis := stake.DefaultGenesisState()
|
||||
stakeGenesis.Pool.LooseTokens = sdk.NewRat(1000)
|
||||
var validators []stake.Validator
|
||||
var delegations []stake.Delegation
|
||||
// XXX Try different numbers of initially bonded validators
|
||||
numInitiallyBonded := int64(50)
|
||||
for i := 0; i < int(numInitiallyBonded); i++ {
|
||||
validator := stake.NewValidator(accs[i], keys[i].PubKey(), stake.Description{})
|
||||
validator.Tokens = sdk.NewDec(100)
|
||||
validator.DelegatorShares = sdk.NewDec(100)
|
||||
delegation := stake.Delegation{accs[i], accs[i], sdk.NewDec(100), 0}
|
||||
validators = append(validators, validator)
|
||||
delegations = append(delegations, delegation)
|
||||
}
|
||||
stakeGenesis.Pool.LooseTokens = sdk.NewDec(int64(100*250) + (numInitiallyBonded * 100))
|
||||
stakeGenesis.Validators = validators
|
||||
stakeGenesis.Bonds = delegations
|
||||
// No inflation, for now
|
||||
stakeGenesis.Params.InflationMax = sdk.NewDec(0)
|
||||
stakeGenesis.Params.InflationMin = sdk.NewDec(0)
|
||||
genesis := GenesisState{
|
||||
Accounts: genesisAccounts,
|
||||
StakeData: stakeGenesis,
|
||||
|
@ -63,13 +85,46 @@ func appStateFn(r *rand.Rand, accs []sdk.AccAddress) json.RawMessage {
|
|||
return appState
|
||||
}
|
||||
|
||||
func testAndRunTxs(app *GaiaApp) []simulation.TestAndRunTx {
|
||||
return []simulation.TestAndRunTx{
|
||||
banksim.TestAndRunSingleInputMsgSend(app.accountMapper),
|
||||
govsim.SimulateMsgSubmitProposal(app.govKeeper, app.stakeKeeper),
|
||||
govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper),
|
||||
govsim.SimulateMsgVote(app.govKeeper, app.stakeKeeper),
|
||||
stakesim.SimulateMsgCreateValidator(app.accountMapper, app.stakeKeeper),
|
||||
stakesim.SimulateMsgEditValidator(app.stakeKeeper),
|
||||
stakesim.SimulateMsgDelegate(app.accountMapper, app.stakeKeeper),
|
||||
stakesim.SimulateMsgBeginUnbonding(app.accountMapper, app.stakeKeeper),
|
||||
stakesim.SimulateMsgCompleteUnbonding(app.stakeKeeper),
|
||||
stakesim.SimulateMsgBeginRedelegate(app.accountMapper, app.stakeKeeper),
|
||||
stakesim.SimulateMsgCompleteRedelegate(app.stakeKeeper),
|
||||
slashingsim.SimulateMsgUnrevoke(app.slashingKeeper),
|
||||
}
|
||||
}
|
||||
|
||||
func invariants(app *GaiaApp) []simulation.Invariant {
|
||||
return []simulation.Invariant{
|
||||
func(t *testing.T, baseapp *baseapp.BaseApp, log string) {
|
||||
banksim.NonnegativeBalanceInvariant(app.accountMapper)(t, baseapp, log)
|
||||
govsim.AllInvariants()(t, baseapp, log)
|
||||
stakesim.AllInvariants(app.coinKeeper, app.stakeKeeper, app.accountMapper)(t, baseapp, log)
|
||||
slashingsim.AllInvariants()(t, baseapp, log)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestFullGaiaSimulation(t *testing.T) {
|
||||
if !enabled {
|
||||
t.Skip("Skipping Gaia simulation")
|
||||
}
|
||||
|
||||
// Setup Gaia application
|
||||
logger := log.NewNopLogger()
|
||||
var logger log.Logger
|
||||
if verbose {
|
||||
logger = log.TestingLogger()
|
||||
} else {
|
||||
logger = log.NewNopLogger()
|
||||
}
|
||||
db := dbm.NewMemDB()
|
||||
app := NewGaiaApp(logger, db, nil)
|
||||
require.Equal(t, "GaiaApp", app.Name())
|
||||
|
@ -77,24 +132,50 @@ func TestFullGaiaSimulation(t *testing.T) {
|
|||
// Run randomized simulation
|
||||
simulation.SimulateFromSeed(
|
||||
t, app.BaseApp, appStateFn, seed,
|
||||
[]simulation.TestAndRunTx{
|
||||
banksim.TestAndRunSingleInputMsgSend(app.accountMapper),
|
||||
stakesim.SimulateMsgCreateValidator(app.accountMapper, app.stakeKeeper),
|
||||
stakesim.SimulateMsgEditValidator(app.stakeKeeper),
|
||||
stakesim.SimulateMsgDelegate(app.accountMapper, app.stakeKeeper),
|
||||
stakesim.SimulateMsgBeginUnbonding(app.accountMapper, app.stakeKeeper),
|
||||
stakesim.SimulateMsgCompleteUnbonding(app.stakeKeeper),
|
||||
stakesim.SimulateMsgBeginRedelegate(app.accountMapper, app.stakeKeeper),
|
||||
stakesim.SimulateMsgCompleteRedelegate(app.stakeKeeper),
|
||||
},
|
||||
testAndRunTxs(app),
|
||||
[]simulation.RandSetup{},
|
||||
[]simulation.Invariant{
|
||||
banksim.NonnegativeBalanceInvariant(app.accountMapper),
|
||||
stakesim.AllInvariants(app.coinKeeper, app.stakeKeeper, app.accountMapper),
|
||||
},
|
||||
numKeys,
|
||||
invariants(app),
|
||||
numBlocks,
|
||||
blockSize,
|
||||
false,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// TODO: Make another test for the fuzzer itself, which just has noOp txs
|
||||
// and doesn't depend on gaia
|
||||
func TestAppStateDeterminism(t *testing.T) {
|
||||
if !enabled {
|
||||
t.Skip("Skipping Gaia simulation")
|
||||
}
|
||||
|
||||
numSeeds := 5
|
||||
numTimesToRunPerSeed := 5
|
||||
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
|
||||
|
||||
for i := 0; i < numSeeds; i++ {
|
||||
seed := rand.Int63()
|
||||
for j := 0; j < numTimesToRunPerSeed; j++ {
|
||||
logger := log.NewNopLogger()
|
||||
db := dbm.NewMemDB()
|
||||
app := NewGaiaApp(logger, db, nil)
|
||||
|
||||
// Run randomized simulation
|
||||
simulation.SimulateFromSeed(
|
||||
t, app.BaseApp, appStateFn, seed,
|
||||
testAndRunTxs(app),
|
||||
[]simulation.RandSetup{},
|
||||
[]simulation.Invariant{},
|
||||
20,
|
||||
20,
|
||||
true,
|
||||
)
|
||||
appHash := app.LastCommitID().Hash
|
||||
fmt.Printf(">>> APP HASH: %v, %X\n", appHash, appHash)
|
||||
appHashList[j] = appHash
|
||||
}
|
||||
for k := 1; k < numTimesToRunPerSeed; k++ {
|
||||
require.Equal(t, appHashList[0], appHashList[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,6 +117,11 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
|
||||
defaultParams := stake.DefaultParams()
|
||||
initialPool := stake.InitialPool()
|
||||
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(100)) // Delegate tx on GaiaAppGenState
|
||||
initialPool = initialPool.ProcessProvisions(defaultParams) // provisions are added to the pool every hour
|
||||
|
||||
// create validator
|
||||
cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags)
|
||||
cvStr += fmt.Sprintf(" --from=%s", "bar")
|
||||
|
@ -124,6 +129,8 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
cvStr += fmt.Sprintf(" --amount=%v", "2steak")
|
||||
cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
|
||||
|
||||
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(1))
|
||||
|
||||
executeWrite(t, cvStr, app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
|
@ -131,13 +138,13 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc)
|
||||
|
||||
validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags))
|
||||
require.Equal(t, validator.Owner, barAddr)
|
||||
require.True(sdk.RatEq(t, sdk.NewRat(2), validator.Tokens))
|
||||
require.Equal(t, validator.Operator, barAddr)
|
||||
require.True(sdk.DecEq(t, sdk.NewDec(2), validator.Tokens))
|
||||
|
||||
// unbond a single share
|
||||
unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags)
|
||||
unbondStr += fmt.Sprintf(" --from=%s", "bar")
|
||||
unbondStr += fmt.Sprintf(" --address-validator=%s", barAddr)
|
||||
unbondStr += fmt.Sprintf(" --validator=%s", barAddr)
|
||||
unbondStr += fmt.Sprintf(" --shares-amount=%v", "1")
|
||||
|
||||
success := executeWrite(t, unbondStr, app.DefaultKeyPass)
|
||||
|
@ -149,7 +156,15 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc)
|
||||
*/
|
||||
validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags))
|
||||
require.Equal(t, "1/1", validator.Tokens.String())
|
||||
require.Equal(t, "1.0000000000", validator.Tokens.String())
|
||||
|
||||
params := executeGetParams(t, fmt.Sprintf("gaiacli stake parameters --output=json %v", flags))
|
||||
require.True(t, defaultParams.Equal(params))
|
||||
|
||||
pool := executeGetPool(t, fmt.Sprintf("gaiacli stake pool --output=json %v", flags))
|
||||
require.Equal(t, initialPool.DateLastCommissionReset, pool.DateLastCommissionReset)
|
||||
require.Equal(t, initialPool.PrevBondedShares, pool.PrevBondedShares)
|
||||
require.Equal(t, initialPool.BondedTokens, pool.BondedTokens)
|
||||
}
|
||||
|
||||
func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||
|
@ -328,6 +343,9 @@ func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
|||
return acc
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// stake
|
||||
|
||||
func executeGetValidator(t *testing.T, cmdStr string) stake.Validator {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
var validator stake.Validator
|
||||
|
@ -337,6 +355,27 @@ func executeGetValidator(t *testing.T, cmdStr string) stake.Validator {
|
|||
return validator
|
||||
}
|
||||
|
||||
func executeGetPool(t *testing.T, cmdStr string) stake.Pool {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
var pool stake.Pool
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &pool)
|
||||
require.NoError(t, err, "out %v\n, err %v", out, err)
|
||||
return pool
|
||||
}
|
||||
|
||||
func executeGetParams(t *testing.T, cmdStr string) stake.Params {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
var params stake.Params
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), ¶ms)
|
||||
require.NoError(t, err, "out %v\n, err %v", out, err)
|
||||
return params
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// gov
|
||||
|
||||
func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
var proposal gov.Proposal
|
||||
|
|
|
@ -62,18 +62,10 @@ func main() {
|
|||
ibccmd.IBCRelayCmd(cdc),
|
||||
)...)
|
||||
|
||||
advancedCmd := &cobra.Command{
|
||||
Use: "advanced",
|
||||
Short: "Advanced subcommands",
|
||||
}
|
||||
|
||||
advancedCmd.AddCommand(
|
||||
rootCmd.AddCommand(
|
||||
tendermintCmd,
|
||||
ibcCmd,
|
||||
lcd.ServeCommand(cdc),
|
||||
)
|
||||
rootCmd.AddCommand(
|
||||
advancedCmd,
|
||||
client.LineBreak,
|
||||
)
|
||||
|
||||
|
@ -88,6 +80,12 @@ func main() {
|
|||
stakecmd.GetCmdQueryValidators("stake", cdc),
|
||||
stakecmd.GetCmdQueryDelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryDelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryParams("stake", cdc),
|
||||
stakecmd.GetCmdQueryPool("stake", cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryRedelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryRedelegations("stake", cdc),
|
||||
slashingcmd.GetCmdQuerySigningInfo("slashing", cdc),
|
||||
)...)
|
||||
stakeCmd.AddCommand(
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "1ebc5ca705b3ae1c06a0888ff1287ada82149dc3",
|
||||
"ip": "138.68.77.24",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "adrian"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "default",
|
||||
"address": "D9C12CB5186FE0018179742FD3110EE534C63460",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "c272ae3cff7558db2c6195eea38fd43fd08406dc",
|
||||
"ip": "206.189.31.178",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "tJlZJWjOpYvRitYFTWNPTaUtvQVf+hoNjlfI84VPqvI="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "anton"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "default",
|
||||
"address": "E766088FD171906289617F60BF0014C46F0F85EC",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "tJlZJWjOpYvRitYFTWNPTaUtvQVf+hoNjlfI84VPqvI="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "aef085c4bfed0c1ffc6705f2e1e3bf85e5164600",
|
||||
"ip": "45.77.53.208",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "RpX+xkwnCNw5DpBelscz4//TiODyC9RDiyIuD6NEwx0="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "aurel"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "aurel",
|
||||
"address": "10B0899E05A486AE4E5589C39587DF7E9A185872",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "RpX+xkwnCNw5DpBelscz4//TiODyC9RDiyIuD6NEwx0="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "b0dd378c3fbc4c156cd6d302a799f0d2e4227201",
|
||||
"ip": "159.89.121.174",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "0aNTDL49987ZNRi3FtJIi0jk93ybHuYg1FjWrfP9H2o="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "bucky"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "bucky",
|
||||
"address": "935E48ED79F1006ED135553768E1D9A768747CF6",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "0aNTDL49987ZNRi3FtJIi0jk93ybHuYg1FjWrfP9H2o="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "e25603602d8cf8542570ad0e311d50f55f497f85",
|
||||
"ip": "158.69.63.13",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "dcmCn+RZTBdwbCa4YqSnw/Va7xQloBw6vF87ItLwdM0="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "cwgoes"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "cwgoes",
|
||||
"address": "328FBB8EA315D070DF908982A5F91A3618001D20",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "dcmCn+RZTBdwbCa4YqSnw/Va7xQloBw6vF87ItLwdM0="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "aabf05a67b2f399807dc602d05bf97b0ed283ac2",
|
||||
"ip": "116.62.62.39",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "7SaH/LyM+qdz9ovD/pvqIf2q7LC7tc5v0ZJxsA2CGTw="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "iris"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "=suyu",
|
||||
"address": "4B5BE759EB23B0D76C6A60636BD0E3111178794E",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "7SaH/LyM+qdz9ovD/pvqIf2q7LC7tc5v0ZJxsA2CGTw="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "79466a03e9d4b4648a7dd8cead1fa7121ce76ee3",
|
||||
"ip": "34.235.130.1",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "SW12+WpGKUCO9oT2CV0CD5kUclbXjJHV1MjerLWB7Oc="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "lino"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "lino",
|
||||
"address": "5A007B81A25AF34B829B79DA508A26E12180BCDB",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "SW12+WpGKUCO9oT2CV0CD5kUclbXjJHV1MjerLWB7Oc="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "adb290585a2753bf1a520c76802b0dab3dffa895",
|
||||
"ip": "34.201.21.179",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "pY7eLF0Ez3yq495kIjag8mD67Q131np/ssagpEvlV2A="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "pbostrom"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "default",
|
||||
"address": "109720515B4F8C0858DA3521E448262334534FFD",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "pY7eLF0Ez3yq495kIjag8mD67Q131np/ssagpEvlV2A="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "678503e6c8f50db7279c7da3cb9b072aac4bc0d5",
|
||||
"ip": "35.193.188.125",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "RMwWTZsVdkq1heicNJb2fosy9Fls4NHxAHReiJvHl+8="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "polsdam"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "poldsam",
|
||||
"address": "FA929191B04C5DB222AFC6F15C63EF48CCC864C5",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "RMwWTZsVdkq1heicNJb2fosy9Fls4NHxAHReiJvHl+8="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "3519f05985394107e0b2e285361b7e012adb1113",
|
||||
"ip": "54.209.118.64",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "vq0V0BjpmIh6WyNnFpMaO5LyUK2FamkNt65eJYa5AaQ="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "staked"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "default",
|
||||
"address": "935E04662697134905706A4CCDB822AC6FC11C2E",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "vq0V0BjpmIh6WyNnFpMaO5LyUK2FamkNt65eJYa5AaQ="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "8a2802fb25d352f3e7e277559a4f683780c3ef22",
|
||||
"ip": "167.99.191.184",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "NjjEQKUsq8F0gWxl3BoU2Li5n7hEz9H/LX80rfMxVyE="
|
||||
},
|
||||
"power": 100,
|
||||
"name": ""
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "zach",
|
||||
"address": "9D5723057702E2090405AB5D3B48C45B9ABF4377",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "NjjEQKUsq8F0gWxl3BoU2Li5n7hEz9H/LX80rfMxVyE="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"node_id": "30b45459e4881680c0ef1750fde136fefa6c3b98",
|
||||
"ip": "35.184.182.143",
|
||||
"validator": {
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "CDF/8aD8Lt+ikR3LyCg9c7DwWBA51NH+MUkH7tzxrfY="
|
||||
},
|
||||
"power": 100,
|
||||
"name": "zaki"
|
||||
},
|
||||
"app_gen_tx": {
|
||||
"name": "zaki",
|
||||
"address": "ECE57661F0CDCF28EED257B72F86240E57F4A612",
|
||||
"pub_key": {
|
||||
"type": "AC26791624DE60",
|
||||
"value": "CDF/8aD8Lt+ikR3LyCg9c7DwWBA51NH+MUkH7tzxrfY="
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -6,6 +6,6 @@
|
|||
- [ ] 4. Summarize breaking API changes section under “Breaking Changes” section to the `CHANGELOG.md` to bring attention to any breaking API changes that affect RPC consumers.
|
||||
- [ ] 5. Tag the commit `{{ .Release.Name }}-rcN`
|
||||
- [ ] 6. Kick off 1 day of automated fuzz testing
|
||||
- [ ] 7. Release Lead assigns 2 people to perform buddy testing script
|
||||
- [ ] 7. Release Lead assigns 2 people to perform [buddy testing script](/docs/RELEASE_TEST_SCRIPT.md) and update the relevant documentation
|
||||
- [ ] 8. If errors are found in either #6 or #7 go back to #2 (*NOTE*: be sure to increment the `rcN`)
|
||||
- [ ] 9. After #6 and #7 have successfully completed then merge the release PR and push the final release tag
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
This document should contain plain english instructions for testing functionality on `gaiad`. This “Script” is supposed to be run by 2 people who will each spin up a `gaiad` node and run the series of prompts below.
|
||||
|
||||
- [Create a network of 2 nodes](getting-started/create-testnet.md)
|
||||
- [Generate an account](sdk/clients.md)
|
||||
- [Send funds from one account to the other](sdk/clients.md)
|
||||
- [Create a validator](validators/validator-setup.md)
|
||||
- [Edit a validator](validators/validator-setup.md)
|
||||
- [Delegate to validator](sdk/clients.md)
|
||||
- [Unbond from a validator](sdk/clients.md)
|
||||
- [View validators and verify output](validators/validator-setup.md)
|
||||
- [Query network status](getting-started/full-node.md)
|
||||
- [Create a proposal](validators/validator-setup.md)
|
||||
- [Query a proposal](validators/validator-setup.md)
|
||||
- [Vote on a proposal](validators/validator-setup.md)
|
||||
- [Query status of a proposal](validators/validator-setup.md)
|
||||
- [Query the votes on a proposal](validators/validator-setup.md)
|
||||
- [Export state and reload](getting-started/create-testnet.md)
|
|
@ -2,7 +2,7 @@ swagger: '2.0'
|
|||
info:
|
||||
version: '1.1.0'
|
||||
title: Gaia-Lite (former LCD) to interface with Cosmos BaseServer via REST
|
||||
description: Specification for Gaia-lite provided by `gaiacli advanced rest-server`
|
||||
description: Specification for Gaia-lite provided by `gaiacli rest-server`
|
||||
|
||||
tags:
|
||||
- name: keys
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# REST
|
||||
|
||||
See `gaiacli advanced rest-server --help` for more.
|
||||
See `gaiacli rest-server --help` for more.
|
||||
|
||||
Also see the
|
||||
[work in progress API specification](https://github.com/cosmos/cosmos-sdk/pull/1314)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
## Create your Own Testnet
|
||||
|
||||
To create your own testnet, first each validator will need to install gaiad and run gen-tx
|
||||
|
||||
```bash
|
||||
gaiad init gen-tx --name <account_name>
|
||||
```
|
||||
|
||||
This populations `$HOME/.gaiad/gen-tx/` with a json file.
|
||||
|
||||
Now these json files need to be aggregated together via Github, a Google form, pastebin or other methods.
|
||||
|
||||
Place all files on one computer in `$HOME/.gaiad/gen-tx/`
|
||||
|
||||
```bash
|
||||
gaiad init --gen-txs -o --chain=<chain-name>
|
||||
```
|
||||
|
||||
This will generate a `genesis.json` in `$HOME/.gaiad/config/genesis.json` distribute this file to all validators on your testnet.
|
||||
|
||||
### Export state
|
||||
|
||||
To export state and reload (useful for testing purposes):
|
||||
|
||||
```
|
||||
gaiad export > genesis.json; cp genesis.json ~/.gaiad/config/genesis.json; gaiad start
|
||||
```
|
|
@ -0,0 +1,193 @@
|
|||
# ICS 030: Cosmos Signed Messages
|
||||
|
||||
>TODO: Replace with valid ICS number and possibly move to new location.
|
||||
|
||||
* [Changelog](#changelog)
|
||||
* [Abstract](#abstract)
|
||||
* [Preliminary](#preliminary)
|
||||
* [Specification](#specification)
|
||||
* [Future Adaptations](#future-adaptations)
|
||||
* [API](#api)
|
||||
* [References](#references)
|
||||
|
||||
## Status
|
||||
|
||||
Proposed.
|
||||
|
||||
## Changelog
|
||||
|
||||
## Abstract
|
||||
|
||||
Having the ability to sign messages off-chain has proven to be a fundamental aspect
|
||||
of nearly any blockchain. The notion of signing messages off-chain has many
|
||||
added benefits such as saving on computational costs and reducing transaction
|
||||
throughput and overhead. Within the context of the Cosmos, some of the major
|
||||
applications of signing such data includes, but is not limited to, providing a
|
||||
cryptographic secure and verifiable means of proving validator identity and
|
||||
possibly associating it with some other framework or organization. In addition,
|
||||
having the ability to sign Cosmos messages with a Ledger or similar HSM device.
|
||||
|
||||
A standardized protocol for hashing, signing, and verifying messages that can be
|
||||
implemented by the Cosmos SDK and other third-party organizations is needed. Such a
|
||||
standardized protocol subscribes to the following:
|
||||
|
||||
* Contains a specification of human-readable and machine-verifiable typed structured data
|
||||
* Contains a framework for deterministic and injective encoding of structured data
|
||||
* Utilizes cryptographic secure hashing and signing algorithms
|
||||
* A framework for supporting extensions and domain separation
|
||||
* Is invulnerable to chosen ciphertext attacks
|
||||
* Has protection against potentially signing transactions a user did not intend to
|
||||
|
||||
This specification is only concerned with the rationale and the standardized
|
||||
implementation of Cosmos signed messages. It does **not** concern itself with the
|
||||
concept of replay attacks as that will be left up to the higher-level application
|
||||
implementation. If you view signed messages in the means of authorizing some
|
||||
action or data, then such an application would have to either treat this as
|
||||
idempotent or have mechanisms in place to reject known signed messages.
|
||||
|
||||
## Preliminary
|
||||
|
||||
The Cosmos message signing protocol will be parameterized with a cryptographic
|
||||
secure hashing algorithm `SHA-256` and a signing algorithm `S` that contains
|
||||
the operations `sign` and `verify` which provide a digital signature over a set
|
||||
of bytes and verification of a signature respectively.
|
||||
|
||||
Note, our goal here is not to provide context and reasoning about why necessarily
|
||||
these algorithms were chosen apart from the fact they are the defacto algorithms
|
||||
used in Tendermint and the Cosmos SDK and that they satisfy our needs for such
|
||||
cryptographic algorithms such as having resistance to collision and second
|
||||
pre-image attacks, as well as being [deterministic](https://en.wikipedia.org/wiki/Hash_function#Determinism) and [uniform](https://en.wikipedia.org/wiki/Hash_function#Uniformity).
|
||||
|
||||
## Specification
|
||||
|
||||
Tendermint has a well established protocol for signing messages using a canonical
|
||||
JSON representation as defined [here](https://github.com/tendermint/tendermint/blob/master/types/canonical_json.go).
|
||||
|
||||
An example of such a canonical JSON structure is Tendermint's vote structure:
|
||||
|
||||
```golang
|
||||
type CanonicalJSONVote struct {
|
||||
ChainID string `json:"@chain_id"`
|
||||
Type string `json:"@type"`
|
||||
BlockID CanonicalJSONBlockID `json:"block_id"`
|
||||
Height int64 `json:"height"`
|
||||
Round int `json:"round"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
VoteType byte `json:"type"`
|
||||
}
|
||||
```
|
||||
|
||||
With such canonical JSON structures, the specification requires that they include
|
||||
meta fields: `@chain_id` and `@type`. These meta fields are reserved and must be
|
||||
included. They are both of type `string`. In addition, fields must be ordered
|
||||
in lexicographically ascending order.
|
||||
|
||||
For the purposes of signing Cosmos messages, the `@chain_id` field must correspond
|
||||
to the Cosmos chain identifier. The user-agent should **refuse** signing if the
|
||||
`@chain_id` field does not match the currently active chain! The `@type` field
|
||||
must equal the constant `"message"`. The `@type` field corresponds to the type of
|
||||
structure the user will be signing in an application. For now, a user is only
|
||||
allowed to sign bytes of valid ASCII text ([see here](https://github.com/tendermint/tendermint/blob/master/libs/common/string.go#L61-L74)).
|
||||
However, this will change and evolve to support additional application-specific
|
||||
structures that are human-readable and machine-verifiable ([see Future Adaptations](#futureadaptations)).
|
||||
|
||||
Thus, we can have a canonical JSON structure for signing Cosmos messages using
|
||||
the [JSON schema](http://json-schema.org/) specification as such:
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"$id": "cosmos/signing/typeData/schema",
|
||||
"title": "The Cosmos signed message typed data schema.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"@chain_id": {
|
||||
"type": "string",
|
||||
"description": "The corresponding Cosmos chain identifier.",
|
||||
"minLength": 1
|
||||
},
|
||||
"@type": {
|
||||
"type": "string",
|
||||
"description": "The message type. It must be 'message'.",
|
||||
"enum": [
|
||||
"message"
|
||||
]
|
||||
},
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "The valid ASCII text to sign.",
|
||||
"pattern": "^[\\x20-\\x7E]+$",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"@chain_id",
|
||||
"@type",
|
||||
"text"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
e.g.
|
||||
|
||||
```json
|
||||
{
|
||||
"@chain_id": "1",
|
||||
"@type": "message",
|
||||
"text": "Hello, you can identify me as XYZ on keybase."
|
||||
}
|
||||
```
|
||||
|
||||
## Future Adaptations
|
||||
|
||||
As applications can vary greatly in domain, it will be vital to support both
|
||||
domain separation and human-readable and machine-verifiable structures.
|
||||
|
||||
Domain separation will allow for application developers to prevent collisions of
|
||||
otherwise identical structures. It should be designed to be unique per application
|
||||
use and should directly be used in the signature encoding itself.
|
||||
|
||||
Human-readable and machine-verifiable structures will allow end users to sign
|
||||
more complex structures, apart from just string messages, and still be able to
|
||||
know exactly what they are signing (opposed to signing a bunch of arbitrary bytes).
|
||||
|
||||
Thus, in the future, the Cosmos signing message specification will be expected
|
||||
to expand upon it's canonical JSON structure to include such functionality.
|
||||
|
||||
|
||||
## API
|
||||
|
||||
Application developers and designers should formalize a standard set of APIs that
|
||||
adhere to the following specification:
|
||||
|
||||
-----
|
||||
|
||||
### **cosmosSignBytes**
|
||||
|
||||
Params:
|
||||
|
||||
* `data`: the Cosmos signed message canonical JSON structure
|
||||
* `address`: the Bech32 Cosmos account address to sign data with
|
||||
|
||||
Returns:
|
||||
|
||||
* `signature`: the Cosmos signature derived using signing algorithm `S`
|
||||
|
||||
-----
|
||||
|
||||
### Examples
|
||||
|
||||
Using the `secp256k1` as the DSA, `S`:
|
||||
|
||||
```javascript
|
||||
data = {
|
||||
"@chain_id": "1",
|
||||
"@type": "message",
|
||||
"text": "I hereby claim I am ABC on Keybase!"
|
||||
}
|
||||
|
||||
cosmosSignBytes(data, "cosmosaccaddr1pvsch6cddahhrn5e8ekw0us50dpnugwnlfngt3")
|
||||
> "0x7fc4a495473045022100dec81a9820df0102381cdbf7e8b0f1e2cb64c58e0ecda1324543742e0388e41a02200df37905a6505c1b56a404e23b7473d2c0bc5bcda96771d2dda59df6ed2b98f8"
|
||||
```
|
||||
|
||||
## References
|
1024
docs/light/api.md
1024
docs/light/api.md
File diff suppressed because it is too large
Load Diff
|
@ -12,27 +12,25 @@
|
|||
|
||||
`gaiacli` is the command line interface to manage accounts and transactions on Cosmos testnets. Here is a list of useful `gaiacli` commands, including usage examples.
|
||||
|
||||
### Key Types
|
||||
### Keys
|
||||
|
||||
#### Key Types
|
||||
|
||||
There are three types of key representations that are used:
|
||||
|
||||
- `cosmosaccaddr`
|
||||
|
||||
- Derived from account keys generated by `gaiacli keys add`
|
||||
- Used to receive funds
|
||||
- e.g. `cosmosaccaddr15h6vd5f0wqps26zjlwrc6chah08ryu4hzzdwhc`
|
||||
|
||||
- `cosmosaccpub`
|
||||
|
||||
- Derived from account keys generated by `gaiacli keys add`
|
||||
- e.g. `cosmosaccpub1zcjduc3q7fu03jnlu2xpl75s2nkt7krm6grh4cc5aqth73v0zwmea25wj2hsqhlqzm`
|
||||
|
||||
- `cosmosvalpub`
|
||||
- Generated when the node is created with `gaiad init`.
|
||||
- Get this value with `gaiad tendermint show-validator`
|
||||
- e.g. `cosmosvalpub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c`
|
||||
|
||||
### Generate Keys
|
||||
#### Generate Keys
|
||||
|
||||
You'll need an account private and public key pair \(a.k.a. `sk, pk` respectively\) to be able to receive funds, send txs, bond tx, etc.
|
||||
|
||||
|
@ -66,10 +64,14 @@ gaiad tendermint show-validator
|
|||
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.
|
||||
:::
|
||||
|
||||
### Get Tokens
|
||||
### Account
|
||||
|
||||
#### Get Tokens
|
||||
|
||||
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 `cosmosaccaddr` from the account you wish to use for staking.
|
||||
|
||||
#### Query Account balance
|
||||
|
||||
After receiving tokens to your address, you can view your account's balance by typing:
|
||||
|
||||
```bash
|
||||
|
@ -79,7 +81,6 @@ gaiacli account <account_cosmosaccaddr>
|
|||
::: warning Note
|
||||
When you query an account balance with zero tokens, you will get this error: `No account with address <account_cosmosaccaddr> was found in the state.` This can also happen if you fund the account before your node has fully synced with the chain. These are both normal.
|
||||
|
||||
We're working on improving our error messages!
|
||||
:::
|
||||
|
||||
### Send Tokens
|
||||
|
@ -87,7 +88,7 @@ We're working on improving our error messages!
|
|||
```bash
|
||||
gaiacli send \
|
||||
--amount=10faucetToken \
|
||||
--chain-id=gaia-7005 \
|
||||
--chain-id=<chain_id> \
|
||||
--name=<key_name> \
|
||||
--to=<destination_cosmosaccaddr>
|
||||
```
|
||||
|
@ -109,20 +110,40 @@ You can also check your balance at a given block by using the `--block` flag:
|
|||
gaiacli account <account_cosmosaccaddr> --block=<block_height>
|
||||
```
|
||||
|
||||
### Delegate
|
||||
### Staking
|
||||
|
||||
#### Set up a Validator
|
||||
|
||||
Please refer to the [Validator Setup](https://cosmos.network/docs/validators/validator-setup.html) section for a more complete guide on how to set up a validator-candidate.
|
||||
|
||||
#### Delegate to a Validator
|
||||
|
||||
On the upcoming mainnet, you can delegate `atom` to a validator. These [delegators](/resources/delegators-faq) can receive part of the validator's fee revenue. Read more about the [Cosmos Token Model](https://github.com/cosmos/cosmos/raw/master/Cosmos_Token_Model.pdf).
|
||||
|
||||
### Bond Tokens
|
||||
##### Query Validators
|
||||
|
||||
On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond tokens to a testnet validator:
|
||||
You can query the list of all validators of a specific chain:
|
||||
|
||||
```bash
|
||||
gaiacli stake validators
|
||||
```
|
||||
|
||||
If you want to get the information of a single validator you can check it with:
|
||||
|
||||
```bash
|
||||
gaiacli stake validator <account_cosmosaccaddr>
|
||||
```
|
||||
|
||||
#### Bond Tokens
|
||||
|
||||
On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond tokens to a testnet validator (*i.e.* delegate):
|
||||
|
||||
```bash
|
||||
gaiacli stake delegate \
|
||||
--amount=10steak \
|
||||
--address-validator=$(gaiad tendermint show-validator) \
|
||||
--validator=$(gaiad tendermint show-validator) \
|
||||
--name=<key_name> \
|
||||
--chain-id=gaia-7005
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
While tokens are bonded, they are pooled with all the other bonded tokens in the network. Validators and delegators obtain a percentage of shares that equal their stake in this pool.
|
||||
|
@ -131,33 +152,232 @@ While tokens are bonded, they are pooled with all the other bonded tokens in the
|
|||
Don't use more `steak` thank you have! You can always get more by using the [Faucet](https://faucetcosmos.network/)!
|
||||
:::
|
||||
|
||||
### Unbond Tokens
|
||||
##### Query Delegations
|
||||
|
||||
If for any reason the validator misbehaves, or you want to unbond a certain amount of tokens, use this following command. You can unbond a specific amount of`shares`\(eg:`12.1`\) or all of them \(`MAX`\).
|
||||
Once submitted a delegation to a validator, you can see it's information by using the following command:
|
||||
|
||||
```bash
|
||||
gaiacli stake delegation \
|
||||
--address-delegator=<account_cosmosaccaddr> \
|
||||
--address-validator=$(gaiad tendermint show-validator)
|
||||
```
|
||||
|
||||
Or if you want to check all your current delegations with disctinct validators:
|
||||
|
||||
```bash
|
||||
gaiacli stake delegations <account_cosmosaccaddr>
|
||||
```
|
||||
|
||||
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-percent` (eg:`25`) with the corresponding flags.
|
||||
|
||||
```bash
|
||||
gaiacli stake unbond begin \
|
||||
--address-validator=$(gaiad tendermint show-validator) \
|
||||
--shares=MAX \
|
||||
--name=<key_name> \
|
||||
--chain-id=gaia-7005
|
||||
--shares-percent=100 \
|
||||
--from=<key_name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
Later you must use the `gaiacli stake unbond complete` command to finish
|
||||
unbonding at which point you can can check your balance and your stake
|
||||
delegation to see that the unbonding went through successfully.
|
||||
Later you must complete the unbonding process by using the `gaiacli stake unbond complete` command:
|
||||
|
||||
```bash
|
||||
gaiacli account <account_cosmosaccaddr>
|
||||
|
||||
gaiacli stake delegation \
|
||||
--address-delegator=<account_cosmosaccaddr> \
|
||||
gaiacli stake unbond complete \
|
||||
--address-validator=$(gaiad tendermint show-validator) \
|
||||
--chain-id=gaia-7005
|
||||
--from=<key_name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
## Light Client Daemon
|
||||
##### Query Unbonding-Delegations
|
||||
|
||||
Once you begin an unbonding-delegation, you can see it's information by using the following command:
|
||||
|
||||
```bash
|
||||
gaiacli stake unbonding-delegation \
|
||||
--address-delegator=<account_cosmosaccaddr> \
|
||||
--address-validator=$(gaiad tendermint show-validator) \
|
||||
```
|
||||
|
||||
Or if you want to check all your current unbonding-delegations with disctinct validators:
|
||||
|
||||
```bash
|
||||
gaiacli stake unbonding-delegations <account_cosmosaccaddr>
|
||||
```
|
||||
|
||||
You can also get previous unbonding-delegation(s) status by 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 stake redelegate begin \
|
||||
--address-validator-source=$(gaiad tendermint show-validator) \
|
||||
--address-validator-dest=<account_cosmosaccaddr> \
|
||||
--shares-percent=50 \
|
||||
--from=<key_name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
Here you can also redelegate a specific `shares-amount` or a `shares-percent` with the corresponding flags.
|
||||
|
||||
Later you must complete the redelegation process by using the `gaiacli stake redelegate complete` command:
|
||||
|
||||
```bash
|
||||
gaiacli stake unbond complete \
|
||||
--address-validator=$(gaiad tendermint show-validator) \
|
||||
--from=<key_name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
##### Query Redelegations
|
||||
|
||||
Once you begin an redelegation, you can see it's information by using the following command:
|
||||
|
||||
```bash
|
||||
gaiacli stake redelegation \
|
||||
--address-delegator=<account_cosmosaccaddr> \
|
||||
--address-validator-source=$(gaiad tendermint show-validator) \
|
||||
--address-validator-dest=<account_cosmosaccaddr> \
|
||||
```
|
||||
|
||||
Or if you want to check all your current unbonding-delegations with disctinct validators:
|
||||
|
||||
```bash
|
||||
gaiacli stake redelegations <account_cosmosaccaddr>
|
||||
```
|
||||
|
||||
You can also get previous redelegation(s) status by adding the `--height` flag.
|
||||
|
||||
### Governance
|
||||
|
||||
Governance is the process from which users in the Cosmos Hub can come to consensus on software upgrades, parameters of the mainnet or on custom text proposals. This is done through voting on proposals, which will be submitted by `Atom` holders on the mainnet.
|
||||
|
||||
Some considerations about the voting process:
|
||||
|
||||
- Voting is done by bonded `Atom` holders on a 1 bonded `Atom` 1 vote basis
|
||||
- Delegators inherit the vote of their validator if they don't vote
|
||||
- **Validators MUST vote on every proposal**. If a validator does not vote on a proposal, they will be **partially slashed**
|
||||
- Votes are tallied at the end of the voting period (2 weeks on mainnet). Each address can vote multiple times to update its `Option` value (paying the transaction fee each time), only the last casted vote will count as valid
|
||||
- Voters can choose between options `Yes`, `No`, `NoWithVeto` and `Abstain`
|
||||
At the end of the voting period, a proposal is accepted if `(YesVotes/(YesVotes+NoVotes+NoWithVetoVotes))>1/2` and `(NoWithVetoVotes/(YesVotes+NoVotes+NoWithVetoVotes))<1/3`. It is rejected otherwise
|
||||
|
||||
For more information about the governance process and how it works, please check out the Governance module [specification](https://github.com/cosmos/cosmos-sdk/tree/develop/docs/spec/governance).
|
||||
|
||||
#### Create a Governance proposal
|
||||
|
||||
In order to create a governance proposal, you must submit an initial deposit along with the proposal details:
|
||||
|
||||
- `title`: Title of the proposal
|
||||
- `description`: Description of the proposal
|
||||
- `type`: Type of proposal. Must be of value _Text_ (types _SoftwareUpgrade_ and _ParameterChange_ not supported yet).
|
||||
|
||||
```bash
|
||||
gaiacli gov submit-proposal \
|
||||
--title=<title> \
|
||||
--description=<description> \
|
||||
--type=<Text/ParameterChange/SoftwareUpgrade> \
|
||||
--proposer=<account_cosmosaccaddr> \
|
||||
--deposit=<40steak> \
|
||||
--from=<name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
##### Query proposals
|
||||
|
||||
Once created, you can now query information of the proposal:
|
||||
|
||||
```bash
|
||||
gaiacli gov query-proposal \
|
||||
--proposal-id=<proposal_id>
|
||||
```
|
||||
|
||||
Or query all available proposals:
|
||||
|
||||
```bash
|
||||
gaiacli gov query-proposals
|
||||
```
|
||||
|
||||
You can also query proposals filtered by `voter` or `depositer` by using the corresponding flags.
|
||||
|
||||
#### Increase deposit
|
||||
|
||||
In order for a proposal to be broadcasted to the network, the amount deposited must be above a `minDeposit` value (default: `10 steak`). 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:
|
||||
|
||||
```bash
|
||||
gaiacli gov deposit \
|
||||
--proposal-id=<proposal_id> \
|
||||
--depositer=<account_cosmosaccaddr> \
|
||||
--deposit=<200steak> \
|
||||
--from=<name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
> _NOTE_: Proposals that don't meet this requirement will be deleted after `MaxDepositPeriod` is reached.
|
||||
|
||||
#### 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:
|
||||
|
||||
```bash
|
||||
gaiacli gov vote \
|
||||
--proposal-id=<proposal_id> \
|
||||
--voter=<account_cosmosaccaddr> \
|
||||
--option=<Yes/No/NoWithVeto/Abstain> \
|
||||
--from=<name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
##### Query vote
|
||||
|
||||
Check the vote with the option you just submitted:
|
||||
|
||||
```bash
|
||||
gaiacli gov query-vote \
|
||||
--proposal-id=<proposal_id> \
|
||||
--voter=<account_cosmosaccaddr>
|
||||
```
|
||||
|
||||
#### Query Parameters
|
||||
|
||||
You can get the current parameters that define high level settings for staking:
|
||||
|
||||
```
|
||||
gaiacli stake parameters
|
||||
```
|
||||
|
||||
With the above command you will get the values for:
|
||||
|
||||
- Maximum and minumum Inflation rate
|
||||
- Maximum annual change in inflation rate,
|
||||
- Goal of bonded tokens (%)
|
||||
- Unbonding time
|
||||
- Maximum numbers of validators
|
||||
- Coin denomination for staking
|
||||
|
||||
All this values can be updated though a `governance` process by submitting a parameter change `proposal`.
|
||||
|
||||
#### Query Pool
|
||||
|
||||
A staking `Pool` defines the dynamic parameters of the current state. You can query them with the following command:
|
||||
|
||||
```
|
||||
gaiacli stake pool
|
||||
```
|
||||
|
||||
With the `pool` command you will get the values for:
|
||||
|
||||
- Loose and bonded tokens
|
||||
- Token supply
|
||||
- Current anual inflation and the block in which the last inflation was processed
|
||||
- Last recorded bonded shares
|
||||
|
||||
|
||||
## Gaia-Lite
|
||||
|
||||
::: tip Note
|
||||
🚧 We are actively working on documentation for the LCD.
|
||||
🚧 We are actively working on documentation for Gaia-lite.
|
||||
:::
|
||||
|
|
|
@ -469,7 +469,7 @@ Tendermint consensus engine. It would be initialized by a Genesis file, and it
|
|||
would be driven by blocks of transactions committed by the underlying Tendermint
|
||||
consensus. We'll talk more about ABCI and how this all works a bit later, but
|
||||
feel free to check the
|
||||
[specification](https://github.com/tendermint/tendermint/blob/master/docs/abci-spec.md).
|
||||
[specification](https://github.com/tendermint/tendermint/blob/master/docs/app-dev/abci-spec.md).
|
||||
We'll also see how to connect our app to a complete suite of components
|
||||
for running and using a live blockchain application.
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ here we will introduce the other ABCI requests sent by Tendermint, and
|
|||
how we can use them to build more advanced applications. For a more complete
|
||||
depiction of the ABCI and how its used, see
|
||||
[the
|
||||
specification](https://github.com/tendermint/tendermint/blob/master/docs/abci-spec.md)
|
||||
specification](https://github.com/tendermint/tendermint/blob/master/docs/app-dev/abci-spec.md)
|
||||
|
||||
## InitChain
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
The Cosmos SDK has all the necessary pre-built modules to add functionality on top of a `BaseApp`, which is the template to build a blockchain dApp in Cosmos. In this context, a `module` is a fundamental unit in the Cosmos SDK.
|
||||
|
||||
Each module is an extension of the `BaseApp`'s functionalities that defines transactions, handles application state and manages the state transition logic. Each module also contains handlers for messages and transactions, as well as REST and CLI for secure user interactions.
|
||||
Each module is an extension of the `BaseApp`'s functionalities that defines transactions, handles application state and manages the state transition logic. Each module also contains handlers for messages and transactions, queriers for handling query requests, as well as REST and CLI for secure user interactions.
|
||||
|
||||
Some of the most important modules in the SDK are:
|
||||
|
||||
|
|
|
@ -6,6 +6,23 @@ Uuse the CLI to create a new proposal:
|
|||
simplegovcli propose --title="Voting Period update" --description="Should we change the proposal voting period to 3 weeks?" --deposit=300Atoms
|
||||
```
|
||||
|
||||
Or, via a json file:
|
||||
|
||||
```bash
|
||||
simplegovcli propose --proposal="path/to/proposal.json"
|
||||
```
|
||||
|
||||
Where proposal.json contains:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Voting Period Update",
|
||||
"description": "Should we change the proposal voting period to 3 weeks?",
|
||||
"type": "Text",
|
||||
"deposit": "300Atoms"
|
||||
}
|
||||
```
|
||||
|
||||
Get the details of your newly created proposal:
|
||||
|
||||
```bash
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
## Vesting
|
||||
|
||||
### Intro and Requirements
|
||||
|
||||
This paper specifies vesting account implementation for the Cosmos Hub.
|
||||
The requirements for this vesting account is that it should be initialized during genesis with
|
||||
a starting balance X coins and a vesting endtime T. The owner of this account should be able to delegate to validators
|
||||
and vote with locked coins, however they cannot send locked coins to other accounts until those coins have been unlocked.
|
||||
The vesting account should also be able to spend any coins it receives from other users.
|
||||
Thus, the bank module's `MsgSend` handler should error if a vesting account is trying to send an amount that exceeds their
|
||||
unlocked coin amount.
|
||||
|
||||
### Implementation
|
||||
|
||||
##### Vesting Account implementation
|
||||
|
||||
NOTE: `Now = ctx.BlockHeader().Time`
|
||||
|
||||
```go
|
||||
type VestingAccount interface {
|
||||
Account
|
||||
AssertIsVestingAccount() // existence implies that account is vesting.
|
||||
|
||||
// Calculates amount of coins that can be sent to other accounts given the current time
|
||||
SendableCoins(sdk.Context) sdk.Coins
|
||||
}
|
||||
|
||||
// Implements Vesting Account
|
||||
// Continuously vests by unlocking coins linearly with respect to time
|
||||
type ContinuousVestingAccount struct {
|
||||
BaseAccount
|
||||
OriginalVestingCoins sdk.Coins // Coins in account on Initialization
|
||||
ReceivedCoins sdk.Coins // Coins received from other accounts
|
||||
SentCoins sdk.Coins // Coins sent to other accounts
|
||||
|
||||
// StartTime and EndTime used to calculate how much of OriginalCoins is unlocked at any given point
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
}
|
||||
|
||||
// Uses time in context to calculate total unlocked coins
|
||||
SendableCoins(vacc ContinuousVestingAccount, ctx sdk.Context) sdk.Coins:
|
||||
|
||||
// Coins unlocked by vesting schedule
|
||||
unlockedCoins := ReceivedCoins - SentCoins + OriginalVestingCoins * (Now - StartTime) / (EndTime - StartTime)
|
||||
|
||||
// Must still check for currentCoins constraint since some unlocked coins may have been delegated.
|
||||
currentCoins := vacc.BaseAccount.GetCoins()
|
||||
|
||||
// min will return sdk.Coins with each denom having the minimum amount from unlockedCoins and currentCoins
|
||||
return min(unlockedCoins, currentCoins)
|
||||
|
||||
```
|
||||
|
||||
The `VestingAccount` interface is used to assert that an account is a vesting account like so:
|
||||
|
||||
```go
|
||||
vacc, ok := acc.(VestingAccount); ok
|
||||
```
|
||||
|
||||
as well as to calculate the SendableCoins at any given moment.
|
||||
|
||||
The `ContinuousVestingAccount` struct implements the Vesting account interface. It uses `OriginalVestingCoins`, `ReceivedCoins`,
|
||||
`SentCoins`, `StartTime`, and `EndTime` to calculate how many coins are sendable at any given point.
|
||||
Since the vesting restrictions need to be implemented on a per-module basis, the `ContinuousVestingAccount` implements
|
||||
the `Account` interface exactly like `BaseAccount`. Thus, `ContinuousVestingAccount.GetCoins()` will return the total of
|
||||
both locked coins and unlocked coins currently in the account. Delegated coins are deducted from `Account.GetCoins()`, but do not count against unlocked coins because they are still at stake and will be reinstated (partially if slashed) after waiting the full unbonding period.
|
||||
|
||||
##### Changes to Keepers/Handler
|
||||
|
||||
Since a vesting account should be capable of doing everything but sending with its locked coins, the restriction should be
|
||||
handled at the `bank.Keeper` level. Specifically in methods that are explicitly used for sending like
|
||||
`sendCoins` and `inputOutputCoins`. These methods must check that an account is a vesting account using the check described above.
|
||||
|
||||
```go
|
||||
if acc is VestingAccount and Now < vestingAccount.EndTime:
|
||||
// Check if amount is less than currently allowed sendable coins
|
||||
if msg.Amount > vestingAccount.SendableCoins(ctx) then fail
|
||||
else:
|
||||
vestingAccount.SentCoins += msg.Amount
|
||||
|
||||
else:
|
||||
// Account has fully vested, treat like regular account
|
||||
if msg.Amount > account.GetCoins() then fail
|
||||
|
||||
// All checks passed, send the coins
|
||||
SendCoins(inputs, outputs)
|
||||
|
||||
```
|
||||
|
||||
Coins that are sent to a vesting account after initialization by users sending them coins should be spendable
|
||||
immediately after receiving them. Thus, handlers (like staking or bank) that send coins that a vesting account did not
|
||||
originally own should increment `ReceivedCoins` by the amount sent.
|
||||
Unlocked coins that are sent to other accounts will increment the vesting account's `SentCoins` attribute.
|
||||
|
||||
CONTRACT: Handlers SHOULD NOT update `ReceivedCoins` if they were originally sent from the vesting account. For example, if a vesting account unbonds from a validator, their tokens should be added back to account but staking handlers SHOULD NOT update `ReceivedCoins`.
|
||||
However when a user sends coins to vesting account, then `ReceivedCoins` SHOULD be incremented.
|
||||
|
||||
### Initializing at Genesis
|
||||
|
||||
To initialize both vesting accounts and base accounts, the `GenesisAccount` struct will include an EndTime. Accounts meant to be
|
||||
BaseAccounts will have `EndTime = 0`. The `initChainer` method will parse the GenesisAccount into BaseAccounts and VestingAccounts
|
||||
as appropriate.
|
||||
|
||||
```go
|
||||
type GenesisAccount struct {
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
GenesisCoins sdk.Coins `json:"coins"`
|
||||
EndTime int64 `json:"lock"`
|
||||
}
|
||||
|
||||
initChainer:
|
||||
for gacc in GenesisAccounts:
|
||||
baseAccount := BaseAccount{
|
||||
Address: gacc.Address,
|
||||
Coins: gacc.GenesisCoins,
|
||||
}
|
||||
if gacc.EndTime != 0:
|
||||
vestingAccount := ContinuouslyVestingAccount{
|
||||
BaseAccount: baseAccount,
|
||||
OriginalVestingCoins: gacc.GenesisCoins,
|
||||
StartTime: RequestInitChain.Time,
|
||||
EndTime: gacc.EndTime,
|
||||
}
|
||||
AddAccountToState(vestingAccount)
|
||||
else:
|
||||
AddAccountToState(baseAccount)
|
||||
|
||||
```
|
||||
|
||||
### Formulas
|
||||
|
||||
`OriginalVestingCoins`: Amount of coins in account at Genesis
|
||||
|
||||
`CurrentCoins`: Coins currently in the baseaccount (both locked and unlocked: `vestingAccount.GetCoins`)
|
||||
|
||||
`ReceivedCoins`: Coins received from other accounts (always unlocked)
|
||||
|
||||
`LockedCoins`: Coins that are currently locked
|
||||
|
||||
`Delegated`: Coins that have been delegated (no longer in account; may be locked or unlocked)
|
||||
|
||||
`Sent`: Coins sent to other accounts (MUST be unlocked)
|
||||
|
||||
Maximum amount of coins vesting schedule allows to be sent:
|
||||
|
||||
`ReceivedCoins - SentCoins + OriginalVestingCoins * (Now - StartTime) / (EndTime - StartTime)`
|
||||
|
||||
`ReceivedCoins - SentCoins + OriginalVestingCoins - LockedCoins`
|
||||
|
||||
Coins currently in Account:
|
||||
|
||||
`CurrentCoins = OriginalVestingCoins + ReceivedCoins - Delegated - Sent`
|
||||
|
||||
`CurrentCoins = vestingAccount.GetCoins()`
|
||||
|
||||
**Maximum amount of coins spendable right now:**
|
||||
|
||||
`min( ReceivedCoins - SentCoins + OriginalVestingCoins - LockedCoins, CurrentCoins )`
|
|
@ -25,9 +25,9 @@ type VotingProcedure struct {
|
|||
|
||||
```go
|
||||
type TallyingProcedure struct {
|
||||
Threshold rational.Rational // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5
|
||||
Veto rational.Rational // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
|
||||
GovernancePenalty sdk.Rat // Penalty if validator does not vote
|
||||
Threshold sdk.Dec // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5
|
||||
Veto sdk.Dec // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
|
||||
GovernancePenalty sdk.Dec // Penalty if validator does not vote
|
||||
GracePeriod int64 // If validator entered validator set in this period of blocks before vote ended, governance penalty does not apply
|
||||
}
|
||||
```
|
||||
|
@ -81,7 +81,7 @@ This type is used in a temp map when tallying
|
|||
|
||||
```go
|
||||
type ValidatorGovInfo struct {
|
||||
Minus sdk.Rat
|
||||
Minus sdk.Dec
|
||||
Vote Vote
|
||||
}
|
||||
```
|
||||
|
@ -103,17 +103,17 @@ type Proposal struct {
|
|||
VotingStartBlock int64 // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached
|
||||
CurrentStatus ProposalStatus // Current status of the proposal
|
||||
|
||||
YesVotes sdk.Rat
|
||||
NoVotes sdk.Rat
|
||||
NoWithVetoVotes sdk.Rat
|
||||
AbstainVotes sdk.Rat
|
||||
YesVotes sdk.Dec
|
||||
NoVotes sdk.Dec
|
||||
NoWithVetoVotes sdk.Dec
|
||||
AbstainVotes sdk.Dec
|
||||
}
|
||||
```
|
||||
|
||||
We also mention a method to update the tally for a given proposal:
|
||||
|
||||
```go
|
||||
func (proposal Proposal) updateTally(vote byte, amount sdk.Rat)
|
||||
func (proposal Proposal) updateTally(vote byte, amount sdk.Dec)
|
||||
```
|
||||
|
||||
### Stores
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
The current annual inflation rate.
|
||||
|
||||
```golang
|
||||
type Inflation sdk.Rat
|
||||
type Inflation sdk.Dec
|
||||
```
|
||||
|
||||
### InflationLastTime
|
||||
|
|
|
@ -16,4 +16,3 @@ EndBlock() ValidatorSetChanges
|
|||
ClearTendermintUpdates()
|
||||
return vsc
|
||||
```
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ type Pool struct {
|
|||
LooseTokens int64 // tokens not associated with any bonded validator
|
||||
BondedTokens int64 // reserve of bonded tokens
|
||||
InflationLastTime int64 // block which the last inflation was processed // TODO make time
|
||||
Inflation sdk.Rat // current annual inflation rate
|
||||
Inflation sdk.Dec // current annual inflation rate
|
||||
|
||||
DateLastCommissionReset int64 // unix timestamp for last commission accounting reset (daily)
|
||||
}
|
||||
|
@ -28,10 +28,10 @@ overall functioning of the stake module.
|
|||
|
||||
```golang
|
||||
type Params struct {
|
||||
InflationRateChange sdk.Rat // maximum annual change in inflation rate
|
||||
InflationMax sdk.Rat // maximum inflation rate
|
||||
InflationMin sdk.Rat // minimum inflation rate
|
||||
GoalBonded sdk.Rat // Goal of percent bonded atoms
|
||||
InflationRateChange sdk.Dec // maximum annual change in inflation rate
|
||||
InflationMax sdk.Dec // maximum inflation rate
|
||||
InflationMin sdk.Dec // minimum inflation rate
|
||||
GoalBonded sdk.Dec // Goal of percent bonded atoms
|
||||
|
||||
MaxValidators uint16 // maximum number of validators
|
||||
BondDenom string // bondable coin denomination
|
||||
|
@ -74,9 +74,9 @@ type Validator struct {
|
|||
Revoked bool // has the validator been revoked?
|
||||
|
||||
Status sdk.BondStatus // validator status (bonded/unbonding/unbonded)
|
||||
Tokens sdk.Rat // delegated tokens (incl. self-delegation)
|
||||
DelegatorShares sdk.Rat // total shares issued to a validator's delegators
|
||||
SlashRatio sdk.Rat // increases each time the validator is slashed
|
||||
Tokens sdk.Dec // delegated tokens (incl. self-delegation)
|
||||
DelegatorShares sdk.Dec // total shares issued to a validator's delegators
|
||||
SlashRatio sdk.Dec // increases each time the validator is slashed
|
||||
|
||||
Description Description // description terms for the validator
|
||||
|
||||
|
@ -88,10 +88,10 @@ type Validator struct {
|
|||
}
|
||||
|
||||
type CommissionInfo struct {
|
||||
Rate sdk.Rat // the commission rate of fees charged to any delegators
|
||||
Max sdk.Rat // maximum commission rate which this validator can ever charge
|
||||
ChangeRate sdk.Rat // maximum daily increase of the validator commission
|
||||
ChangeToday sdk.Rat // commission rate change today, reset each day (UTC time)
|
||||
Rate sdk.Dec // the commission rate of fees charged to any delegators
|
||||
Max sdk.Dec // maximum commission rate which this validator can ever charge
|
||||
ChangeRate sdk.Dec // maximum daily increase of the validator commission
|
||||
ChangeToday sdk.Dec // commission rate change today, reset each day (UTC time)
|
||||
LastChange int64 // unix timestamp of last commission change
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ the transaction is the owner of the bond.
|
|||
|
||||
```golang
|
||||
type Delegation struct {
|
||||
Shares sdk.Rat // delegation shares recieved
|
||||
Shares sdk.Dec // delegation shares recieved
|
||||
Height int64 // last height bond updated
|
||||
}
|
||||
```
|
||||
|
@ -178,8 +178,8 @@ the original redelegation has been completed.
|
|||
|
||||
```golang
|
||||
type Redelegation struct {
|
||||
SourceShares sdk.Rat // amount of source shares redelegating
|
||||
DestinationShares sdk.Rat // amount of destination shares created at redelegation
|
||||
SourceShares sdk.Dec // amount of source shares redelegating
|
||||
DestinationShares sdk.Dec // amount of destination shares created at redelegation
|
||||
CompleteTime int64 // unix time to complete redelegation
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
## Transaction Overview
|
||||
|
||||
In this section we describe the processing of the transactions and the
|
||||
corresponding updates to the state. Transactions:
|
||||
corresponding updates to the state. Transactions:
|
||||
- TxCreateValidator
|
||||
- TxEditValidator
|
||||
- TxDelegation
|
||||
|
@ -18,8 +18,8 @@ Other notes:
|
|||
- `sender` denotes the address of the sender of the transaction
|
||||
- `getXxx`, `setXxx`, and `removeXxx` functions are used to retrieve and
|
||||
modify objects from the store
|
||||
- `sdk.Rat` refers to a rational numeric type specified by the SDK.
|
||||
|
||||
- `sdk.Dec` refers to a decimal type specified by the SDK.
|
||||
|
||||
### TxCreateValidator
|
||||
|
||||
- triggers: `distribution.CreateValidatorDistribution`
|
||||
|
@ -28,74 +28,74 @@ A validator is created using the `TxCreateValidator` transaction.
|
|||
|
||||
```golang
|
||||
type TxCreateValidator struct {
|
||||
OwnerAddr sdk.Address
|
||||
Operator sdk.Address
|
||||
ConsensusPubKey crypto.PubKey
|
||||
GovernancePubKey crypto.PubKey
|
||||
SelfDelegation coin.Coin
|
||||
SelfDelegation coin.Coin
|
||||
|
||||
Description Description
|
||||
Commission sdk.Rat
|
||||
CommissionMax sdk.Rat
|
||||
CommissionMaxChange sdk.Rat
|
||||
Commission sdk.Dec
|
||||
CommissionMax sdk.Dec
|
||||
CommissionMaxChange sdk.Dec
|
||||
}
|
||||
|
||||
|
||||
|
||||
createValidator(tx TxCreateValidator):
|
||||
validator = getValidator(tx.OwnerAddr)
|
||||
validator = getValidator(tx.Operator)
|
||||
if validator != nil return // only one validator per address
|
||||
|
||||
validator = NewValidator(OwnerAddr, ConsensusPubKey, GovernancePubKey, Description)
|
||||
|
||||
validator = NewValidator(operatorAddr, ConsensusPubKey, GovernancePubKey, Description)
|
||||
init validator poolShares, delegatorShares set to 0
|
||||
init validator commision fields from tx
|
||||
validator.PoolShares = 0
|
||||
|
||||
|
||||
setValidator(validator)
|
||||
|
||||
txDelegate = TxDelegate(tx.OwnerAddr, tx.OwnerAddr, tx.SelfDelegation)
|
||||
|
||||
txDelegate = TxDelegate(tx.Operator, tx.Operator, tx.SelfDelegation)
|
||||
delegate(txDelegate, validator) // see delegate function in [TxDelegate](TxDelegate)
|
||||
return
|
||||
```
|
||||
```
|
||||
|
||||
### TxEditValidator
|
||||
|
||||
If either the `Description` (excluding `DateBonded` which is constant),
|
||||
`Commission`, or the `GovernancePubKey` need to be updated, the
|
||||
`TxEditCandidacy` transaction should be sent from the owner account:
|
||||
`TxEditCandidacy` transaction should be sent from the operator account:
|
||||
|
||||
```golang
|
||||
type TxEditCandidacy struct {
|
||||
GovernancePubKey crypto.PubKey
|
||||
Commission sdk.Rat
|
||||
Commission sdk.Dec
|
||||
Description Description
|
||||
}
|
||||
|
||||
|
||||
editCandidacy(tx TxEditCandidacy):
|
||||
validator = getValidator(tx.ValidatorAddr)
|
||||
|
||||
if tx.Commission > CommissionMax || tx.Commission < 0 then fail
|
||||
|
||||
if tx.Commission > CommissionMax || tx.Commission < 0 then fail
|
||||
if rateChange(tx.Commission) > CommissionMaxChange then fail
|
||||
validator.Commission = tx.Commission
|
||||
|
||||
if tx.GovernancePubKey != nil validator.GovernancePubKey = tx.GovernancePubKey
|
||||
if tx.Description != nil validator.Description = tx.Description
|
||||
|
||||
|
||||
setValidator(store, validator)
|
||||
return
|
||||
```
|
||||
|
||||
|
||||
### TxDelegate
|
||||
|
||||
|
||||
- triggers: `distribution.CreateOrModDelegationDistribution`
|
||||
|
||||
Within this transaction the delegator provides coins, and in return receives
|
||||
some amount of their validator's delegator-shares that are assigned to
|
||||
`Delegation.Shares`.
|
||||
`Delegation.Shares`.
|
||||
|
||||
```golang
|
||||
type TxDelegate struct {
|
||||
DelegatorAddr sdk.Address
|
||||
ValidatorAddr sdk.Address
|
||||
Amount sdk.Coin
|
||||
DelegatorAddr sdk.Address
|
||||
ValidatorAddr sdk.Address
|
||||
Amount sdk.Coin
|
||||
}
|
||||
|
||||
delegate(tx TxDelegate):
|
||||
|
@ -104,14 +104,14 @@ delegate(tx TxDelegate):
|
|||
|
||||
delegation = getDelegatorBond(DelegatorAddr, ValidatorAddr)
|
||||
if delegation == nil then delegation = NewDelegation(DelegatorAddr, ValidatorAddr)
|
||||
|
||||
|
||||
validator, pool, issuedDelegatorShares = validator.addTokensFromDel(tx.Amount, pool)
|
||||
delegation.Shares += issuedDelegatorShares
|
||||
|
||||
|
||||
setDelegation(delegation)
|
||||
updateValidator(validator)
|
||||
setPool(pool)
|
||||
return
|
||||
return
|
||||
```
|
||||
|
||||
### TxStartUnbonding
|
||||
|
@ -120,28 +120,28 @@ Delegator unbonding is defined with the following transaction:
|
|||
|
||||
```golang
|
||||
type TxStartUnbonding struct {
|
||||
DelegatorAddr sdk.Address
|
||||
ValidatorAddr sdk.Address
|
||||
Shares string
|
||||
DelegatorAddr sdk.Address
|
||||
ValidatorAddr sdk.Address
|
||||
Shares string
|
||||
}
|
||||
|
||||
startUnbonding(tx TxStartUnbonding):
|
||||
startUnbonding(tx TxStartUnbonding):
|
||||
delegation, found = getDelegatorBond(store, sender, tx.PubKey)
|
||||
if !found == nil return
|
||||
|
||||
if !found == nil return
|
||||
|
||||
if bond.Shares < tx.Shares
|
||||
return ErrNotEnoughBondShares
|
||||
|
||||
validator, found = GetValidator(tx.ValidatorAddr)
|
||||
if !found {
|
||||
return err
|
||||
return err
|
||||
|
||||
bond.Shares -= tx.Shares
|
||||
|
||||
revokeCandidacy = false
|
||||
if bond.Shares.IsZero() {
|
||||
|
||||
if bond.DelegatorAddr == validator.Owner && validator.Revoked == false
|
||||
if bond.DelegatorAddr == validator.Operator && validator.Revoked == false
|
||||
revokeCandidacy = true
|
||||
|
||||
removeDelegation( bond)
|
||||
|
@ -162,7 +162,7 @@ startUnbonding(tx TxStartUnbonding):
|
|||
validator = updateValidator(validator)
|
||||
|
||||
if validator.DelegatorShares == 0 {
|
||||
removeValidator(validator.Owner)
|
||||
removeValidator(validator.Operator)
|
||||
|
||||
return
|
||||
```
|
||||
|
@ -185,7 +185,7 @@ redelegationComplete(tx TxRedelegate):
|
|||
returnTokens = ExpectedTokens * tx.startSlashRatio/validator.SlashRatio
|
||||
AddCoins(unbonding.DelegatorAddr, returnTokens)
|
||||
removeUnbondingDelegation(unbonding)
|
||||
return
|
||||
return
|
||||
```
|
||||
|
||||
### TxRedelegation
|
||||
|
@ -199,27 +199,27 @@ type TxRedelegate struct {
|
|||
DelegatorAddr Address
|
||||
ValidatorFrom Validator
|
||||
ValidatorTo Validator
|
||||
Shares sdk.Rat
|
||||
Shares sdk.Dec
|
||||
CompletedTime int64
|
||||
}
|
||||
|
||||
redelegate(tx TxRedelegate):
|
||||
|
||||
pool = getPool()
|
||||
delegation = getDelegatorBond(tx.DelegatorAddr, tx.ValidatorFrom.Owner)
|
||||
delegation = getDelegatorBond(tx.DelegatorAddr, tx.ValidatorFrom.Operator)
|
||||
if delegation == nil
|
||||
return
|
||||
|
||||
if delegation.Shares < tx.Shares
|
||||
return
|
||||
return
|
||||
|
||||
if delegation.Shares < tx.Shares
|
||||
return
|
||||
delegation.shares -= Tx.Shares
|
||||
validator, pool, createdCoins = validator.RemoveShares(pool, tx.Shares)
|
||||
setPool(pool)
|
||||
|
||||
redelegation = newRedelegation(tx.DelegatorAddr, tx.validatorFrom,
|
||||
|
||||
redelegation = newRedelegation(tx.DelegatorAddr, tx.validatorFrom,
|
||||
tx.validatorTo, tx.Shares, createdCoins, tx.CompletedTime)
|
||||
setRedelegation(redelegation)
|
||||
return
|
||||
return
|
||||
```
|
||||
|
||||
### TxCompleteRedelegation
|
||||
|
@ -239,7 +239,7 @@ redelegationComplete(tx TxRedelegate):
|
|||
redelegation = getRedelegation(tx.DelegatorAddr, tx.validatorFrom, tx.validatorTo)
|
||||
if redelegation.CompleteTime >= CurrentBlockTime && redelegation.CompleteHeight >= CurrentBlockHeight
|
||||
removeRedelegation(redelegation)
|
||||
return
|
||||
return
|
||||
```
|
||||
|
||||
### Update Validators
|
||||
|
@ -273,11 +273,11 @@ updateBondedValidators(newValidator Validator) (updatedVal Validator)
|
|||
// use the validator provided because it has not yet been updated
|
||||
// in the main validator store
|
||||
|
||||
ownerAddr = iterator.Value()
|
||||
if bytes.Equal(ownerAddr, newValidator.Owner) {
|
||||
operatorAddr = iterator.Value()
|
||||
if bytes.Equal(operatorAddr, newValidator.Operator) {
|
||||
validator = newValidator
|
||||
else
|
||||
validator = getValidator(ownerAddr)
|
||||
validator = getValidator(operatorAddr)
|
||||
|
||||
// if not previously a validator (and unrevoked),
|
||||
// kick the cliff validator / bond this new validator
|
||||
|
@ -285,7 +285,7 @@ updateBondedValidators(newValidator Validator) (updatedVal Validator)
|
|||
kickCliffValidator = true
|
||||
|
||||
validator = bondValidator(ctx, store, validator)
|
||||
if bytes.Equal(ownerAddr, newValidator.Owner) {
|
||||
if bytes.Equal(operatorAddr, newValidator.Operator) {
|
||||
updatedVal = validator
|
||||
|
||||
bondedValidatorsCount++
|
||||
|
@ -316,7 +316,7 @@ unbondValidator(ctx Context, store KVStore, validator Validator)
|
|||
}
|
||||
|
||||
// perform all the store operations for when a validator status becomes bonded
|
||||
bondValidator(ctx Context, store KVStore, validator Validator) Validator
|
||||
bondValidator(ctx Context, store KVStore, validator Validator) Validator
|
||||
pool = GetPool(ctx)
|
||||
|
||||
// set the status
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# Validator Setup
|
||||
|
||||
::: warning Current Testnet
|
||||
The current testnet is `gaia-7005`.
|
||||
The current testnet is `gaia-8000`.
|
||||
:::
|
||||
|
||||
Before setting up your validator node, make sure you've already gone through the [Full Node Setup](/getting-started/full-node.md) guide.
|
||||
Before setting up your validator node, make sure you've already gone through the [Full Node Setup](/docs/getting-started/full-node.md) guide.
|
||||
|
||||
## Running a Validator Node
|
||||
|
||||
|
@ -34,7 +34,7 @@ gaiacli stake create-validator \
|
|||
--pubkey=$(gaiad tendermint show-validator) \
|
||||
--address-validator=<account_cosmosaccaddr>
|
||||
--moniker="choose a moniker" \
|
||||
--chain-id=gaia-7005 \
|
||||
--chain-id=<chain_id> \
|
||||
--name=<key_name>
|
||||
```
|
||||
|
||||
|
@ -46,12 +46,12 @@ The `--identity` can be used as to verify identity with systems like Keybase or
|
|||
|
||||
```bash
|
||||
gaiacli stake edit-validator
|
||||
--address-validator=<account_cosmosaccaddr>
|
||||
--validator=<account_cosmosaccaddr>
|
||||
--moniker="choose a moniker" \
|
||||
--website="https://cosmos.network" \
|
||||
--identity=6A0D65E29A4CBC8E
|
||||
--details="To infinity and beyond!"
|
||||
--chain-id=gaia-7005 \
|
||||
--chain-id=<chain_id> \
|
||||
--name=<key_name>
|
||||
```
|
||||
|
||||
|
@ -60,9 +60,28 @@ gaiacli stake edit-validator
|
|||
View the validator's information with this command:
|
||||
|
||||
```bash
|
||||
gaiacli stake validator \
|
||||
--address-validator=<account_cosmosaccaddr> \
|
||||
--chain-id=gaia-7005
|
||||
gaiacli stake validator <account_cosmosaccaddr>
|
||||
```
|
||||
|
||||
### Track Validator Signing Information
|
||||
|
||||
In order to keep track of a validator's signatures in the past you can do so by using the `signing-info` command:
|
||||
|
||||
```bash
|
||||
gaiacli stake signing-information <validator-pubkey>\
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
||||
### Unrevoke Validator
|
||||
|
||||
When a validator is `Revoked` for downtime, you must submit an `Unrevoke` transaction in order to be able to get block proposer rewards again (depends on the zone fee distribution).
|
||||
|
||||
```bash
|
||||
gaiacli stake unrevoke \
|
||||
--from=<key_name> \
|
||||
--chain-id=<chain_id>
|
||||
--validator=<account_cosmosaccaddr> \
|
||||
--chain-id=gaia-6002
|
||||
```
|
||||
|
||||
### Confirm Your Validator is Running
|
||||
|
@ -70,12 +89,11 @@ gaiacli stake validator \
|
|||
Your validator is active if the following command returns anything:
|
||||
|
||||
```bash
|
||||
gaiacli advanced tendermint validator-set | grep "$(gaiad tendermint show-validator)"
|
||||
gaiacli tendermint validator-set | grep "$(gaiad tendermint show-validator)"
|
||||
```
|
||||
|
||||
You should also be able to see your validator on the [Explorer](https://explorecosmos.network/validators). You are looking for the `bech32` encoded `address` in the `~/.gaiad/config/priv_validator.json` file.
|
||||
|
||||
|
||||
::: warning Note
|
||||
To be in the validator set, you need to have more total voting power than the 100th validator.
|
||||
:::
|
||||
|
@ -84,7 +102,7 @@ To be in the validator set, you need to have more total voting power than the 10
|
|||
|
||||
### Problem #1: My validator has `voting_power: 0`
|
||||
|
||||
Your validator has become auto-unbonded. In `gaia-7005`, we unbond validators if they do not vote on `50` of the last `100` blocks. Since blocks are proposed every ~2 seconds, a validator unresponsive for ~100 seconds will become unbonded. This usually happens when your `gaiad` process crashes.
|
||||
Your validator has become auto-unbonded. In `gaia-8000`, we unbond validators if they do not vote on `50` of the last `100` blocks. Since blocks are proposed every ~2 seconds, a validator unresponsive for ~100 seconds will become unbonded. This usually happens when your `gaiad` process crashes.
|
||||
|
||||
Here's how you can return the voting power back to your validator. First, if `gaiad` is not running, start it up again:
|
||||
|
||||
|
@ -95,7 +113,7 @@ gaiad start
|
|||
Wait for your full node to catch up to the latest block. Next, run the following command. Note that `<cosmosaccaddr>` is the address of your validator account, and `<name>` is the name of the validator account. You can find this info by running `gaiacli keys list`.
|
||||
|
||||
```bash
|
||||
gaiacli stake unrevoke <cosmosaccaddr> --chain-id=gaia-7005 --name=<name>
|
||||
gaiacli stake unrevoke <cosmosaccaddr> --chain-id=<chain_id> --name=<name>
|
||||
```
|
||||
|
||||
::: danger Warning
|
||||
|
|
|
@ -104,9 +104,9 @@ You should now see alice, bob and charlie's account all show up.
|
|||
|
||||
```
|
||||
NAME: ADDRESS: PUBKEY:
|
||||
alice 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD 1624DE62201D47E63694448665F5D0217EA8458177728C91C373047A42BD3C0FB78BD0BFA7
|
||||
bob 29D721F054537C91F618A0FDBF770DA51EF8C48D 1624DE6220F54B2A2CA9EB4EE30DE23A73D15902E087C09CC5616456DDDD3814769E2E0A16
|
||||
charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F88A155BD6EB973509AE5595EFDE1AF05B4964836A53
|
||||
alice cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f cosmosaccpub1addwnpepq0w037u5g7y7lvdvsred2dehg90j84k0weyss5ynysf0nnnax74agrsxns6
|
||||
bob cosmosaccaddr18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz cosmosaccpub1addwnpepqwe97n8lryxrzvamrvjfj24jys3uzf8wndfvqa2l7mh5nsv4jrvdznvyeg6
|
||||
charlie cosmosaccaddr13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q cosmosaccpub1addwnpepqdmtxv35rrmv2dvcr3yhfyxj7dzrd4z4rnhmclksq4g55a4wpl54clvx33l
|
||||
```
|
||||
|
||||
|
||||
|
@ -115,15 +115,15 @@ charlie 2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E 1624DE6220F8C9FB8B07855FD94126F
|
|||
Lets send bob and charlie some tokens. First, lets query alice's account so we can see what kind of tokens she has:
|
||||
|
||||
```
|
||||
basecli account 90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD
|
||||
basecli account cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f
|
||||
```
|
||||
|
||||
Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alice's address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some!
|
||||
Where `cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f` is alice's address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some!
|
||||
|
||||
The following command will send coins from alice, to bob:
|
||||
|
||||
```
|
||||
basecli send --from=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D
|
||||
basecli send --from=alice --amount=10000mycoin --to=cosmosaccaddr18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz
|
||||
--sequence=0 --chain-id=test-chain-AE4XQo
|
||||
```
|
||||
|
||||
|
@ -136,13 +136,13 @@ Flag Descriptions:
|
|||
Now if we check bobs account, it should have `10000 mycoin`. You can do so by running :
|
||||
|
||||
```
|
||||
basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D
|
||||
basecli account cosmosaccaddr18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz
|
||||
```
|
||||
|
||||
Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail:
|
||||
|
||||
```
|
||||
basecli send --from=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E
|
||||
basecli send --from=bob --amount=5000mycoin --to=cosmosaccaddr13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q
|
||||
--sequence=0 --chain-id=test-chain-AE4XQo
|
||||
```
|
||||
|
||||
|
@ -151,7 +151,7 @@ Note how we use the ``--from`` flag to select a different account to send from.
|
|||
Lets now try to send from bob back to alice:
|
||||
|
||||
```
|
||||
basecli send --from=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD
|
||||
basecli send --from=bob --amount=3000mycoin --to=cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f
|
||||
--sequence=1 --chain-id=test-chain-AE4XQo
|
||||
```
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
|
||||
slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
|
||||
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
@ -51,6 +52,13 @@ func main() {
|
|||
stakecmd.GetCmdQueryValidators("stake", cdc),
|
||||
stakecmd.GetCmdQueryDelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryDelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryPool("stake", cdc),
|
||||
stakecmd.GetCmdQueryParams("stake", cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryRedelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryRedelegations("stake", cdc),
|
||||
slashingcmd.GetCmdQuerySigningInfo("slashing", cdc),
|
||||
authcmd.GetAccountCmd("acc", cdc, types.GetAccountDecoder(cdc)),
|
||||
)...)
|
||||
|
||||
|
@ -63,6 +71,8 @@ func main() {
|
|||
stakecmd.GetCmdEditValidator(cdc),
|
||||
stakecmd.GetCmdDelegate(cdc),
|
||||
stakecmd.GetCmdUnbond("stake", cdc),
|
||||
stakecmd.GetCmdRedelegate("stake", cdc),
|
||||
slashingcmd.GetCmdUnrevoke(cdc),
|
||||
)...)
|
||||
|
||||
// add proxy, version and key info
|
||||
|
|
|
@ -10,7 +10,7 @@ var _ auth.Account = (*AppAccount)(nil)
|
|||
|
||||
// AppAccount is a custom extension for this application. It is an example of
|
||||
// extending auth.BaseAccount with custom fields. It is compatible with the
|
||||
// stock auth.AccountStore, since auth.AccountStore uses the flexible go-amino
|
||||
// stock auth.AccountMapper, since auth.AccountMapper uses the flexible go-amino
|
||||
// library.
|
||||
type AppAccount struct {
|
||||
auth.BaseAccount
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
// Validator implements sdk.Validator
|
||||
type Validator struct {
|
||||
Address sdk.AccAddress
|
||||
Power sdk.Rat
|
||||
Power sdk.Dec
|
||||
}
|
||||
|
||||
// Implements sdk.Validator
|
||||
|
@ -19,7 +19,7 @@ func (v Validator) GetStatus() sdk.BondStatus {
|
|||
}
|
||||
|
||||
// Implements sdk.Validator
|
||||
func (v Validator) GetOwner() sdk.AccAddress {
|
||||
func (v Validator) GetOperator() sdk.AccAddress {
|
||||
return v.Address
|
||||
}
|
||||
|
||||
|
@ -29,18 +29,18 @@ func (v Validator) GetPubKey() crypto.PubKey {
|
|||
}
|
||||
|
||||
// Implements sdk.Validator
|
||||
func (v Validator) GetTokens() sdk.Rat {
|
||||
return sdk.ZeroRat()
|
||||
func (v Validator) GetTokens() sdk.Dec {
|
||||
return sdk.ZeroDec()
|
||||
}
|
||||
|
||||
// Implements sdk.Validator
|
||||
func (v Validator) GetPower() sdk.Rat {
|
||||
func (v Validator) GetPower() sdk.Dec {
|
||||
return v.Power
|
||||
}
|
||||
|
||||
// Implements sdk.Validator
|
||||
func (v Validator) GetDelegatorShares() sdk.Rat {
|
||||
return sdk.ZeroRat()
|
||||
func (v Validator) GetDelegatorShares() sdk.Dec {
|
||||
return sdk.ZeroDec()
|
||||
}
|
||||
|
||||
// Implements sdk.Validator
|
||||
|
@ -93,8 +93,8 @@ func (vs *ValidatorSet) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey)
|
|||
}
|
||||
|
||||
// TotalPower implements sdk.ValidatorSet
|
||||
func (vs *ValidatorSet) TotalPower(ctx sdk.Context) sdk.Rat {
|
||||
res := sdk.ZeroRat()
|
||||
func (vs *ValidatorSet) TotalPower(ctx sdk.Context) sdk.Dec {
|
||||
res := sdk.ZeroDec()
|
||||
for _, val := range vs.Validators {
|
||||
res = res.Add(val.Power)
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ func (vs *ValidatorSet) RemoveValidator(addr sdk.AccAddress) {
|
|||
}
|
||||
|
||||
// Implements sdk.ValidatorSet
|
||||
func (vs *ValidatorSet) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, power int64, amt sdk.Rat) {
|
||||
func (vs *ValidatorSet) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, power int64, amt sdk.Dec) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.AccAddress, asso
|
|||
func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.AccAddress) (res []sdk.AccAddress) {
|
||||
res = make([]sdk.AccAddress, valset.maxAssoc)
|
||||
iter := sdk.KVStorePrefixIterator(valset.store, GetAssocPrefix(base))
|
||||
defer iter.Close()
|
||||
i := 0
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
key := iter.Key()
|
||||
|
|
|
@ -32,8 +32,8 @@ func TestValidatorSet(t *testing.T) {
|
|||
addr2 := []byte("addr2")
|
||||
|
||||
base := &mock.ValidatorSet{[]mock.Validator{
|
||||
{addr1, sdk.NewRat(1)},
|
||||
{addr2, sdk.NewRat(2)},
|
||||
{addr1, sdk.NewDec(1)},
|
||||
{addr2, sdk.NewDec(2)},
|
||||
}}
|
||||
|
||||
valset := NewValidatorSet(wire.NewCodec(), ctx.KVStore(key).Prefix([]byte("assoc")), base, 1, 5)
|
||||
|
|
|
@ -38,7 +38,7 @@ func NewHandler(keeper Keeper) sdk.Handler {
|
|||
In the previous example, the keeper has an `oracle.Keeper`. `oracle.Keeper`s are generated by `NewKeeper`.
|
||||
|
||||
```go
|
||||
func NewKeeper(key sdk.StoreKey, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Rat, timeout int64) Keeper {
|
||||
func NewKeeper(key sdk.StoreKey, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Dec, timeout int64) Keeper {
|
||||
return Keeper {
|
||||
cdc: cdc,
|
||||
key: key,
|
||||
|
|
|
@ -23,11 +23,12 @@ func (keeper Keeper) update(ctx sdk.Context, val sdk.Validator, valset sdk.Valid
|
|||
// and recalculate voted power
|
||||
hash := ctx.BlockHeader().ValidatorsHash
|
||||
if !bytes.Equal(hash, info.Hash) {
|
||||
info.Power = sdk.ZeroRat()
|
||||
info.Power = sdk.ZeroDec()
|
||||
info.Hash = hash
|
||||
prefix := GetSignPrefix(p, keeper.cdc)
|
||||
store := ctx.KVStore(keeper.key)
|
||||
iter := sdk.KVStorePrefixIterator(store, prefix)
|
||||
defer iter.Close()
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
if valset.Validator(ctx, iter.Value()) != nil {
|
||||
store.Delete(iter.Key())
|
||||
|
|
|
@ -13,12 +13,12 @@ type Keeper struct {
|
|||
|
||||
valset sdk.ValidatorSet
|
||||
|
||||
supermaj sdk.Rat
|
||||
supermaj sdk.Dec
|
||||
timeout int64
|
||||
}
|
||||
|
||||
// NewKeeper constructs a new keeper
|
||||
func NewKeeper(key sdk.StoreKey, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Rat, timeout int64) Keeper {
|
||||
func NewKeeper(key sdk.StoreKey, cdc *wire.Codec, valset sdk.ValidatorSet, supermaj sdk.Dec, timeout int64) Keeper {
|
||||
if timeout < 0 {
|
||||
panic("Timeout should not be negative")
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ const (
|
|||
|
||||
// Info for each payload
|
||||
type Info struct {
|
||||
Power sdk.Rat
|
||||
Power sdk.Dec
|
||||
Hash []byte
|
||||
LastSigned int64
|
||||
Status InfoStatus
|
||||
|
@ -55,7 +55,7 @@ type Info struct {
|
|||
// EmptyInfo construct an empty Info
|
||||
func EmptyInfo(ctx sdk.Context) Info {
|
||||
return Info{
|
||||
Power: sdk.ZeroRat(),
|
||||
Power: sdk.ZeroDec(),
|
||||
Hash: ctx.BlockHeader().ValidatorsHash,
|
||||
LastSigned: ctx.BlockHeight(),
|
||||
Status: Pending,
|
||||
|
|
|
@ -107,9 +107,9 @@ func TestOracle(t *testing.T) {
|
|||
addr3 := []byte("addr3")
|
||||
addr4 := []byte("addr4")
|
||||
valset := &mock.ValidatorSet{[]mock.Validator{
|
||||
{addr1, sdk.NewRat(7)},
|
||||
{addr2, sdk.NewRat(7)},
|
||||
{addr3, sdk.NewRat(1)},
|
||||
{addr1, sdk.NewDec(7)},
|
||||
{addr2, sdk.NewDec(7)},
|
||||
{addr3, sdk.NewDec(1)},
|
||||
}}
|
||||
|
||||
key := sdk.NewKVStoreKey("testkey")
|
||||
|
@ -119,7 +119,7 @@ func TestOracle(t *testing.T) {
|
|||
require.Nil(t, err)
|
||||
ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz})
|
||||
|
||||
ork := NewKeeper(key, cdc, valset, sdk.NewRat(2, 3), 100)
|
||||
ork := NewKeeper(key, cdc, valset, sdk.NewDecWithPrec(667, 3), 100) // 66.7%
|
||||
h := seqHandler(ork, key, sdk.CodespaceRoot)
|
||||
|
||||
// Nonmock.Validator signed, transaction failed
|
||||
|
@ -171,7 +171,7 @@ func TestOracle(t *testing.T) {
|
|||
require.Equal(t, 1, getSequence(ctx, key))
|
||||
|
||||
// Should handle mock.Validator set change
|
||||
valset.AddValidator(mock.Validator{addr4, sdk.NewRat(12)})
|
||||
valset.AddValidator(mock.Validator{addr4, sdk.NewDec(12)})
|
||||
bz, err = json.Marshal(valset)
|
||||
require.Nil(t, err)
|
||||
ctx = ctx.WithBlockHeader(abci.Header{ValidatorsHash: bz})
|
||||
|
|
|
@ -61,7 +61,7 @@ rm -rf ./build
|
|||
make build-linux
|
||||
|
||||
# Create configuration
|
||||
docker run -v `pwd`/build:/gaiad tendermint/gaiadnode testnet --o . --v 1
|
||||
docker run -v `pwd`/build:/gaiad tendermint/gaiadnode testnet -o . --v 1
|
||||
|
||||
#Run the node
|
||||
docker run -v `pwd`/build:/gaiad tendermint/gaiadnode
|
||||
|
|
|
@ -8,7 +8,7 @@ Restart=on-failure
|
|||
User=gaiad
|
||||
Group=gaiad
|
||||
PermissionsStartOnly=true
|
||||
ExecStart=/usr/bin/gaiacli advanced rest-server --laddr {{GAIAD_ADDRESS}}
|
||||
ExecStart=/usr/bin/gaiacli rest-server --laddr {{GAIAD_ADDRESS}}
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
KillSignal=SIGTERM
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash
|
||||
|
||||
CNT=0
|
||||
ITER=$1
|
||||
SLEEP=$2
|
||||
NUMBLOCKS=$3
|
||||
NODEADDR=$4
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Need to input number of iterations to run..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$2" ]; then
|
||||
echo "Need to input number of seconds to sleep between iterations"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$3" ]; then
|
||||
echo "Need to input block height to declare completion..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$4" ]; then
|
||||
echo "Need to input node address to poll..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while [ ${CNT} -lt $ITER ]; do
|
||||
var=$(curl -s $NODEADDR:26657/status | jq -r '.result.sync_info.latest_block_height')
|
||||
echo "Number of Blocks: ${var}"
|
||||
if [ ! -z ${var} ] && [ ${var} -gt ${NUMBLOCKS} ]; then
|
||||
echo "Number of blocks reached, exiting success..."
|
||||
exit 0
|
||||
fi
|
||||
let CNT=CNT+1
|
||||
sleep $SLEEP
|
||||
done
|
||||
|
||||
echo "Timeout reached, exiting failure..."
|
||||
exit 1
|
|
@ -20,7 +20,7 @@ import (
|
|||
var (
|
||||
nodeDirPrefix = "node-dir-prefix"
|
||||
nValidators = "v"
|
||||
outputDir = "o"
|
||||
outputDir = "output-dir"
|
||||
|
||||
startingIPAddress = "starting-ip-address"
|
||||
)
|
||||
|
@ -49,7 +49,7 @@ Example:
|
|||
}
|
||||
cmd.Flags().Int(nValidators, 4,
|
||||
"Number of validators to initialize the testnet with")
|
||||
cmd.Flags().String(outputDir, "./mytestnet",
|
||||
cmd.Flags().StringP(outputDir, "o", "./mytestnet",
|
||||
"Directory to store initialization data for the testnet")
|
||||
cmd.Flags().String(nodeDirPrefix, "node",
|
||||
"Prefix the directory name for each node with (node results in node0, node1, ...)")
|
||||
|
|
|
@ -69,7 +69,7 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
|
|||
func UnsafeResetAllCmd(ctx *Context) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "unsafe-reset-all",
|
||||
Short: "Reset blockchain database, priv_validator.json file, and the logger",
|
||||
Short: "Resets the blockchain database, removes address book files, and resets priv_validator.json to the genesis state",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg := ctx.Config
|
||||
tcmd.ResetAll(cfg.DBDir(), cfg.P2P.AddrBookFile(), cfg.PrivValidatorFile(), ctx.Logger)
|
||||
|
|
|
@ -168,6 +168,7 @@ func TestIAVLSubspaceIterator(t *testing.T) {
|
|||
require.EqualValues(t, value, expectedKey)
|
||||
i++
|
||||
}
|
||||
iter.Close()
|
||||
require.Equal(t, len(expected), i)
|
||||
|
||||
iter = sdk.KVStorePrefixIterator(iavlStore, []byte{byte(55), byte(255), byte(255)})
|
||||
|
@ -183,6 +184,7 @@ func TestIAVLSubspaceIterator(t *testing.T) {
|
|||
require.EqualValues(t, value, []byte("test4"))
|
||||
i++
|
||||
}
|
||||
iter.Close()
|
||||
require.Equal(t, len(expected), i)
|
||||
|
||||
iter = sdk.KVStorePrefixIterator(iavlStore, []byte{byte(255), byte(255)})
|
||||
|
@ -198,6 +200,7 @@ func TestIAVLSubspaceIterator(t *testing.T) {
|
|||
require.EqualValues(t, value, []byte("test4"))
|
||||
i++
|
||||
}
|
||||
iter.Close()
|
||||
require.Equal(t, len(expected), i)
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,9 @@ func (rs *rootMultiStore) MountStoreWithDB(key StoreKey, typ StoreType, db dbm.D
|
|||
if _, ok := rs.storesParams[key]; ok {
|
||||
panic(fmt.Sprintf("rootMultiStore duplicate store key %v", key))
|
||||
}
|
||||
if _, ok := rs.keysByName[key.Name()]; ok {
|
||||
panic(fmt.Sprintf("rootMultiStore duplicate store key name %v", key))
|
||||
}
|
||||
rs.storesParams[key] = storeParams{
|
||||
key: key,
|
||||
typ: typ,
|
||||
|
|
|
@ -21,6 +21,21 @@ func TestStoreType(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestStoreMount(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
store := NewCommitMultiStore(db)
|
||||
|
||||
key1 := sdk.NewKVStoreKey("store1")
|
||||
key2 := sdk.NewKVStoreKey("store2")
|
||||
dup1 := sdk.NewKVStoreKey("store1")
|
||||
|
||||
require.NotPanics(t, func() { store.MountStoreWithDB(key1, sdk.StoreTypeIAVL, db) })
|
||||
require.NotPanics(t, func() { store.MountStoreWithDB(key2, sdk.StoreTypeIAVL, db) })
|
||||
|
||||
require.Panics(t, func() { store.MountStoreWithDB(key1, sdk.StoreTypeIAVL, db) })
|
||||
require.Panics(t, func() { store.MountStoreWithDB(dup1, sdk.StoreTypeIAVL, db) })
|
||||
}
|
||||
|
||||
func TestMultistoreCommitLoad(t *testing.T) {
|
||||
var db dbm.DB = dbm.NewMemDB()
|
||||
if useDebugDB {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
PKGS=$(go list ./... | grep -v /vendor/ | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test)
|
||||
PKGS=$(go list ./... | grep -v /vendor/ | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | grep -v '/simulation')
|
||||
|
||||
set -e
|
||||
echo "mode: atomic" > coverage.txt
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
@ -108,6 +109,23 @@ func (bz AccAddress) Format(s fmt.State, verb rune) {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns boolean for whether two AccAddresses are Equal
|
||||
func (bz AccAddress) Equals(bz2 AccAddress) bool {
|
||||
if bz.Empty() && bz2.Empty() {
|
||||
return true
|
||||
}
|
||||
return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0
|
||||
}
|
||||
|
||||
// Returns boolean for whether an AccAddress is empty
|
||||
func (bz AccAddress) Empty() bool {
|
||||
if bz == nil {
|
||||
return true
|
||||
}
|
||||
bz2 := AccAddress{}
|
||||
return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0
|
||||
}
|
||||
|
||||
//__________________________________________________________
|
||||
|
||||
// AccAddress a wrapper around bytes meant to represent a validator address
|
||||
|
@ -192,6 +210,23 @@ func (bz ValAddress) Format(s fmt.State, verb rune) {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns boolean for whether two ValAddresses are Equal
|
||||
func (bz ValAddress) Equals(bz2 ValAddress) bool {
|
||||
if bz.Empty() && bz2.Empty() {
|
||||
return true
|
||||
}
|
||||
return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0
|
||||
}
|
||||
|
||||
// Returns boolean for whether an AccAddress is empty
|
||||
func (bz ValAddress) Empty() bool {
|
||||
if bz == nil {
|
||||
return true
|
||||
}
|
||||
bz2 := ValAddress{}
|
||||
return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0
|
||||
}
|
||||
|
||||
// Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string
|
||||
func Bech32ifyAccPub(pub crypto.PubKey) (string, error) {
|
||||
return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
|
||||
|
|
|
@ -0,0 +1,421 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// NOTE: never use new(Dec) or else we will panic unmarshalling into the
|
||||
// nil embedded big.Int
|
||||
type Dec struct {
|
||||
*big.Int `json:"int"`
|
||||
}
|
||||
|
||||
// number of decimal places
|
||||
const (
|
||||
Precision = 10
|
||||
|
||||
// bytes required to represent the above precision
|
||||
// ceil(log2(9999999999))
|
||||
DecimalPrecisionBits = 34
|
||||
)
|
||||
|
||||
var (
|
||||
precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil)
|
||||
fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2))
|
||||
precisionMultipliers []*big.Int
|
||||
zeroInt = big.NewInt(0)
|
||||
oneInt = big.NewInt(1)
|
||||
tenInt = big.NewInt(10)
|
||||
)
|
||||
|
||||
// Set precision multipliers
|
||||
func init() {
|
||||
precisionMultipliers = make([]*big.Int, Precision+1)
|
||||
for i := 0; i <= Precision; i++ {
|
||||
precisionMultipliers[i] = calcPrecisionMultiplier(int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
func precisionInt() *big.Int {
|
||||
return new(big.Int).Set(precisionReuse)
|
||||
}
|
||||
|
||||
// nolint - common values
|
||||
func ZeroDec() Dec { return Dec{new(big.Int).Set(zeroInt)} }
|
||||
func OneDec() Dec { return Dec{precisionInt()} }
|
||||
|
||||
// calculate the precision multiplier
|
||||
func calcPrecisionMultiplier(prec int64) *big.Int {
|
||||
if prec > Precision {
|
||||
panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec))
|
||||
}
|
||||
zerosToAdd := Precision - prec
|
||||
multiplier := new(big.Int).Exp(tenInt, big.NewInt(zerosToAdd), nil)
|
||||
return multiplier
|
||||
}
|
||||
|
||||
// get the precision multiplier, do not mutate result
|
||||
func precisionMultiplier(prec int64) *big.Int {
|
||||
if prec > Precision {
|
||||
panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec))
|
||||
}
|
||||
return precisionMultipliers[prec]
|
||||
}
|
||||
|
||||
//______________________________________________________________________________________________
|
||||
|
||||
// create a new Dec from integer assuming whole number
|
||||
func NewDec(i int64) Dec {
|
||||
return NewDecWithPrec(i, 0)
|
||||
}
|
||||
|
||||
// create a new Dec from integer with decimal place at prec
|
||||
// CONTRACT: prec <= Precision
|
||||
func NewDecWithPrec(i, prec int64) Dec {
|
||||
return Dec{
|
||||
new(big.Int).Mul(big.NewInt(i), precisionMultiplier(prec)),
|
||||
}
|
||||
}
|
||||
|
||||
// create a new Dec from big integer assuming whole numbers
|
||||
// CONTRACT: prec <= Precision
|
||||
func NewDecFromBigInt(i *big.Int) Dec {
|
||||
return NewDecFromBigIntWithPrec(i, 0)
|
||||
}
|
||||
|
||||
// create a new Dec from big integer assuming whole numbers
|
||||
// CONTRACT: prec <= Precision
|
||||
func NewDecFromBigIntWithPrec(i *big.Int, prec int64) Dec {
|
||||
return Dec{
|
||||
new(big.Int).Mul(i, precisionMultiplier(prec)),
|
||||
}
|
||||
}
|
||||
|
||||
// create a new Dec from big integer assuming whole numbers
|
||||
// CONTRACT: prec <= Precision
|
||||
func NewDecFromInt(i Int) Dec {
|
||||
return NewDecFromIntWithPrec(i, 0)
|
||||
}
|
||||
|
||||
// create a new Dec from big integer with decimal place at prec
|
||||
// CONTRACT: prec <= Precision
|
||||
func NewDecFromIntWithPrec(i Int, prec int64) Dec {
|
||||
return Dec{
|
||||
new(big.Int).Mul(i.BigInt(), precisionMultiplier(prec)),
|
||||
}
|
||||
}
|
||||
|
||||
// create a decimal from an input decimal string.
|
||||
// valid must come in the form:
|
||||
// (-) whole integers (.) decimal integers
|
||||
// examples of acceptable input include:
|
||||
// -123.456
|
||||
// 456.7890
|
||||
// 345
|
||||
// -456789
|
||||
//
|
||||
// NOTE - An error will return if more decimal places
|
||||
// are provided in the string than the constant Precision.
|
||||
//
|
||||
// CONTRACT - This function does not mutate the input str.
|
||||
func NewDecFromStr(str string) (d Dec, err Error) {
|
||||
if len(str) == 0 {
|
||||
return d, ErrUnknownRequest("decimal string is empty")
|
||||
}
|
||||
|
||||
// first extract any negative symbol
|
||||
neg := false
|
||||
if str[0] == '-' {
|
||||
neg = true
|
||||
str = str[1:]
|
||||
}
|
||||
|
||||
if len(str) == 0 {
|
||||
return d, ErrUnknownRequest("decimal string is empty")
|
||||
}
|
||||
|
||||
strs := strings.Split(str, ".")
|
||||
lenDecs := 0
|
||||
combinedStr := strs[0]
|
||||
if len(strs) == 2 {
|
||||
lenDecs = len(strs[1])
|
||||
if lenDecs == 0 || len(combinedStr) == 0 {
|
||||
return d, ErrUnknownRequest("bad decimal length")
|
||||
}
|
||||
combinedStr = combinedStr + strs[1]
|
||||
} else if len(strs) > 2 {
|
||||
return d, ErrUnknownRequest("too many periods to be a decimal string")
|
||||
}
|
||||
|
||||
if lenDecs > Precision {
|
||||
return d, ErrUnknownRequest(
|
||||
fmt.Sprintf("too much precision, maximum %v, len decimal %v", Precision, lenDecs))
|
||||
}
|
||||
|
||||
// add some extra zero's to correct to the Precision factor
|
||||
zerosToAdd := Precision - lenDecs
|
||||
zeros := fmt.Sprintf(`%0`+strconv.Itoa(zerosToAdd)+`s`, "")
|
||||
combinedStr = combinedStr + zeros
|
||||
|
||||
combined, ok := new(big.Int).SetString(combinedStr, 10)
|
||||
if !ok {
|
||||
return d, ErrUnknownRequest(fmt.Sprintf("bad string to integer conversion, combinedStr: %v", combinedStr))
|
||||
}
|
||||
if neg {
|
||||
combined = new(big.Int).Neg(combined)
|
||||
}
|
||||
return Dec{combined}, nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________________________________
|
||||
//nolint
|
||||
func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // Is equal to zero
|
||||
func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 }
|
||||
func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) > 0 } // greater than
|
||||
func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal
|
||||
func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) < 0 } // less than
|
||||
func (d Dec) LTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) <= 0 } // less than or equal
|
||||
func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // reverse the decimal sign
|
||||
|
||||
// addition
|
||||
func (d Dec) Add(d2 Dec) Dec {
|
||||
res := new(big.Int).Add(d.Int, d2.Int)
|
||||
|
||||
if res.BitLen() > 255+DecimalPrecisionBits {
|
||||
panic("Int overflow")
|
||||
}
|
||||
return Dec{res}
|
||||
}
|
||||
|
||||
// subtraction
|
||||
func (d Dec) Sub(d2 Dec) Dec {
|
||||
res := new(big.Int).Sub(d.Int, d2.Int)
|
||||
|
||||
if res.BitLen() > 255+DecimalPrecisionBits {
|
||||
panic("Int overflow")
|
||||
}
|
||||
return Dec{res}
|
||||
}
|
||||
|
||||
// multiplication
|
||||
func (d Dec) Mul(d2 Dec) Dec {
|
||||
mul := new(big.Int).Mul(d.Int, d2.Int)
|
||||
chopped := chopPrecisionAndRound(mul)
|
||||
|
||||
if chopped.BitLen() > 255+DecimalPrecisionBits {
|
||||
panic("Int overflow")
|
||||
}
|
||||
return Dec{chopped}
|
||||
}
|
||||
|
||||
// quotient
|
||||
func (d Dec) Quo(d2 Dec) Dec {
|
||||
|
||||
// multiply precision twice
|
||||
mul := new(big.Int).Mul(d.Int, precisionReuse)
|
||||
mul.Mul(mul, precisionReuse)
|
||||
|
||||
quo := new(big.Int).Quo(mul, d2.Int)
|
||||
chopped := chopPrecisionAndRound(quo)
|
||||
|
||||
if chopped.BitLen() > 255+DecimalPrecisionBits {
|
||||
panic("Int overflow")
|
||||
}
|
||||
return Dec{chopped}
|
||||
}
|
||||
|
||||
func (d Dec) String() string {
|
||||
str := d.ToLeftPaddedWithDecimals(Precision)
|
||||
placement := len(str) - Precision
|
||||
if placement < 0 {
|
||||
panic("too few decimal digits")
|
||||
}
|
||||
return str[:placement] + "." + str[placement:]
|
||||
}
|
||||
|
||||
// TODO panic if negative or if totalDigits < len(initStr)???
|
||||
// evaluate as an integer and return left padded string
|
||||
func (d Dec) ToLeftPaddedWithDecimals(totalDigits int8) string {
|
||||
intStr := d.Int.String()
|
||||
fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s`
|
||||
return fmt.Sprintf(fcode, intStr)
|
||||
}
|
||||
|
||||
// TODO panic if negative or if totalDigits < len(initStr)???
|
||||
// evaluate as an integer and return left padded string
|
||||
func (d Dec) ToLeftPadded(totalDigits int8) string {
|
||||
chopped := chopPrecisionAndRoundNonMutative(d.Int)
|
||||
intStr := chopped.String()
|
||||
fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s`
|
||||
return fmt.Sprintf(fcode, intStr)
|
||||
}
|
||||
|
||||
// ____
|
||||
// __| |__ "chop 'em
|
||||
// ` \ round!"
|
||||
// ___|| ~ _ -bankers
|
||||
// | | __
|
||||
// | | | __|__|__
|
||||
// |_____: / | $$$ |
|
||||
// |________|
|
||||
|
||||
// nolint - go-cyclo
|
||||
// Remove a Precision amount of rightmost digits and perform bankers rounding
|
||||
// on the remainder (gaussian rounding) on the digits which have been removed.
|
||||
//
|
||||
// Mutates the input. Use the non-mutative version if that is undesired
|
||||
func chopPrecisionAndRound(d *big.Int) *big.Int {
|
||||
|
||||
// remove the negative and add it back when returning
|
||||
if d.Sign() == -1 {
|
||||
// make d positive, compute chopped value, and then un-mutate d
|
||||
d = d.Neg(d)
|
||||
d = chopPrecisionAndRound(d)
|
||||
d = d.Neg(d)
|
||||
return d
|
||||
}
|
||||
|
||||
// get the trucated quotient and remainder
|
||||
quo, rem := d, big.NewInt(0)
|
||||
quo, rem = quo.QuoRem(d, precisionReuse, rem)
|
||||
|
||||
if rem.Sign() == 0 { // remainder is zero
|
||||
return quo
|
||||
}
|
||||
|
||||
switch rem.Cmp(fivePrecision) {
|
||||
case -1:
|
||||
return quo
|
||||
case 1:
|
||||
return quo.Add(quo, oneInt)
|
||||
default: // bankers rounding must take place
|
||||
// always round to an even number
|
||||
if quo.Bit(0) == 0 {
|
||||
return quo
|
||||
}
|
||||
return quo.Add(quo, oneInt)
|
||||
}
|
||||
}
|
||||
|
||||
func chopPrecisionAndRoundNonMutative(d *big.Int) *big.Int {
|
||||
tmp := new(big.Int).Set(d)
|
||||
return chopPrecisionAndRound(tmp)
|
||||
}
|
||||
|
||||
// RoundInt64 rounds the decimal using bankers rounding
|
||||
func (d Dec) RoundInt64() int64 {
|
||||
chopped := chopPrecisionAndRoundNonMutative(d.Int)
|
||||
if !chopped.IsInt64() {
|
||||
panic("Int64() out of bound")
|
||||
}
|
||||
return chopped.Int64()
|
||||
}
|
||||
|
||||
// RoundInt round the decimal using bankers rounding
|
||||
func (d Dec) RoundInt() Int {
|
||||
return NewIntFromBigInt(chopPrecisionAndRoundNonMutative(d.Int))
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
|
||||
// reuse nil values
|
||||
var (
|
||||
nilAmino string
|
||||
nilJSON []byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
empty := new(big.Int)
|
||||
bz, err := empty.MarshalText()
|
||||
if err != nil {
|
||||
panic("bad nil amino init")
|
||||
}
|
||||
nilAmino = string(bz)
|
||||
|
||||
nilJSON, err = json.Marshal(string(bz))
|
||||
if err != nil {
|
||||
panic("bad nil json init")
|
||||
}
|
||||
}
|
||||
|
||||
// wraps d.MarshalText()
|
||||
func (d Dec) MarshalAmino() (string, error) {
|
||||
if d.Int == nil {
|
||||
return nilAmino, nil
|
||||
}
|
||||
bz, err := d.Int.MarshalText()
|
||||
return string(bz), err
|
||||
}
|
||||
|
||||
// requires a valid JSON string - strings quotes and calls UnmarshalText
|
||||
func (d *Dec) UnmarshalAmino(text string) (err error) {
|
||||
tempInt := new(big.Int)
|
||||
err = tempInt.UnmarshalText([]byte(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Int = tempInt
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON defines custom encoding scheme
|
||||
func (d Dec) MarshalJSON() ([]byte, error) {
|
||||
if d.Int == nil {
|
||||
return nilJSON, nil
|
||||
}
|
||||
|
||||
bz, err := d.Int.MarshalText()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(string(bz))
|
||||
}
|
||||
|
||||
// UnmarshalJSON defines custom decoding scheme
|
||||
func (d *Dec) UnmarshalJSON(bz []byte) error {
|
||||
if d.Int == nil {
|
||||
d.Int = new(big.Int)
|
||||
}
|
||||
|
||||
var text string
|
||||
err := json.Unmarshal(bz, &text)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.Int.UnmarshalText([]byte(text))
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// helpers
|
||||
|
||||
// test if two decimal arrays are equal
|
||||
func DecsEqual(d1s, d2s []Dec) bool {
|
||||
if len(d1s) != len(d2s) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, d1 := range d1s {
|
||||
if !d1.Equal(d2s[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// minimum decimal between two
|
||||
func MinDec(d1, d2 Dec) Dec {
|
||||
if d1.LT(d2) {
|
||||
return d1
|
||||
}
|
||||
return d2
|
||||
}
|
||||
|
||||
// intended to be used with require/assert: require.True(DecEq(...))
|
||||
func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) {
|
||||
return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// create a decimal from a decimal string (ex. "1234.5678")
|
||||
func mustNewDecFromStr(t *testing.T, str string) (d Dec) {
|
||||
d, err := NewDecFromStr(str)
|
||||
require.NoError(t, err)
|
||||
return d
|
||||
}
|
||||
|
||||
//_______________________________________
|
||||
|
||||
func TestPrecisionMultiplier(t *testing.T) {
|
||||
res := precisionMultiplier(5)
|
||||
exp := big.NewInt(100000)
|
||||
require.Equal(t, 0, res.Cmp(exp), "equality was incorrect, res %v, exp %v", res, exp)
|
||||
}
|
||||
|
||||
func TestNewDecFromStr(t *testing.T) {
|
||||
largeBigInt, success := new(big.Int).SetString("3144605511029693144278234343371835", 10)
|
||||
require.True(t, success)
|
||||
tests := []struct {
|
||||
decimalStr string
|
||||
expErr bool
|
||||
exp Dec
|
||||
}{
|
||||
{"", true, Dec{}},
|
||||
{"0.-75", true, Dec{}},
|
||||
{"0", false, NewDec(0)},
|
||||
{"1", false, NewDec(1)},
|
||||
{"1.1", false, NewDecWithPrec(11, 1)},
|
||||
{"0.75", false, NewDecWithPrec(75, 2)},
|
||||
{"0.8", false, NewDecWithPrec(8, 1)},
|
||||
{"0.11111", false, NewDecWithPrec(11111, 5)},
|
||||
{"314460551102969.3144278234343371835", true, NewDec(3141203149163817869)},
|
||||
{"314460551102969314427823434337.1835718092488231350",
|
||||
true, NewDecFromBigIntWithPrec(largeBigInt, 4)},
|
||||
{"314460551102969314427823434337.1835",
|
||||
false, NewDecFromBigIntWithPrec(largeBigInt, 4)},
|
||||
{".", true, Dec{}},
|
||||
{".0", true, NewDec(0)},
|
||||
{"1.", true, NewDec(1)},
|
||||
{"foobar", true, Dec{}},
|
||||
{"0.foobar", true, Dec{}},
|
||||
{"0.foobar.", true, Dec{}},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
res, err := NewDecFromStr(tc.decimalStr)
|
||||
if tc.expErr {
|
||||
require.NotNil(t, err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex)
|
||||
} else {
|
||||
require.Nil(t, err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex)
|
||||
require.True(t, res.Equal(tc.exp), "equality was incorrect, res %v, exp %v, tc %v", res, tc.exp, tcIndex)
|
||||
}
|
||||
|
||||
// negative tc
|
||||
res, err = NewDecFromStr("-" + tc.decimalStr)
|
||||
if tc.expErr {
|
||||
require.NotNil(t, err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex)
|
||||
} else {
|
||||
require.Nil(t, err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex)
|
||||
exp := tc.exp.Mul(NewDec(-1))
|
||||
require.True(t, res.Equal(exp), "equality was incorrect, res %v, exp %v, tc %v", res, exp, tcIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqualities(t *testing.T) {
|
||||
tests := []struct {
|
||||
d1, d2 Dec
|
||||
gt, lt, eq bool
|
||||
}{
|
||||
{NewDec(0), NewDec(0), false, false, true},
|
||||
{NewDecWithPrec(0, 2), NewDecWithPrec(0, 4), false, false, true},
|
||||
{NewDecWithPrec(100, 0), NewDecWithPrec(100, 0), false, false, true},
|
||||
{NewDecWithPrec(-100, 0), NewDecWithPrec(-100, 0), false, false, true},
|
||||
{NewDecWithPrec(-1, 1), NewDecWithPrec(-1, 1), false, false, true},
|
||||
{NewDecWithPrec(3333, 3), NewDecWithPrec(3333, 3), false, false, true},
|
||||
|
||||
{NewDecWithPrec(0, 0), NewDecWithPrec(3333, 3), false, true, false},
|
||||
{NewDecWithPrec(0, 0), NewDecWithPrec(100, 0), false, true, false},
|
||||
{NewDecWithPrec(-1, 0), NewDecWithPrec(3333, 3), false, true, false},
|
||||
{NewDecWithPrec(-1, 0), NewDecWithPrec(100, 0), false, true, false},
|
||||
{NewDecWithPrec(1111, 3), NewDecWithPrec(100, 0), false, true, false},
|
||||
{NewDecWithPrec(1111, 3), NewDecWithPrec(3333, 3), false, true, false},
|
||||
{NewDecWithPrec(-3333, 3), NewDecWithPrec(-1111, 3), false, true, false},
|
||||
|
||||
{NewDecWithPrec(3333, 3), NewDecWithPrec(0, 0), true, false, false},
|
||||
{NewDecWithPrec(100, 0), NewDecWithPrec(0, 0), true, false, false},
|
||||
{NewDecWithPrec(3333, 3), NewDecWithPrec(-1, 0), true, false, false},
|
||||
{NewDecWithPrec(100, 0), NewDecWithPrec(-1, 0), true, false, false},
|
||||
{NewDecWithPrec(100, 0), NewDecWithPrec(1111, 3), true, false, false},
|
||||
{NewDecWithPrec(3333, 3), NewDecWithPrec(1111, 3), true, false, false},
|
||||
{NewDecWithPrec(-1111, 3), NewDecWithPrec(-3333, 3), true, false, false},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
require.Equal(t, tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc %d", tcIndex)
|
||||
require.Equal(t, tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc %d", tcIndex)
|
||||
require.Equal(t, tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc %d", tcIndex)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDecsEqual(t *testing.T) {
|
||||
tests := []struct {
|
||||
d1s, d2s []Dec
|
||||
eq bool
|
||||
}{
|
||||
{[]Dec{NewDec(0)}, []Dec{NewDec(0)}, true},
|
||||
{[]Dec{NewDec(0)}, []Dec{NewDec(1)}, false},
|
||||
{[]Dec{NewDec(0)}, []Dec{}, false},
|
||||
{[]Dec{NewDec(0), NewDec(1)}, []Dec{NewDec(0), NewDec(1)}, true},
|
||||
{[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(1), NewDec(0)}, true},
|
||||
{[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(0), NewDec(1)}, false},
|
||||
{[]Dec{NewDec(1), NewDec(0)}, []Dec{NewDec(1)}, false},
|
||||
{[]Dec{NewDec(1), NewDec(2)}, []Dec{NewDec(2), NewDec(4)}, false},
|
||||
{[]Dec{NewDec(3), NewDec(18)}, []Dec{NewDec(1), NewDec(6)}, false},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
require.Equal(t, tc.eq, DecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex)
|
||||
require.Equal(t, tc.eq, DecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArithmetic(t *testing.T) {
|
||||
tests := []struct {
|
||||
d1, d2 Dec
|
||||
expMul, expDiv, expAdd, expSub Dec
|
||||
}{
|
||||
// d1 d2 MUL DIV ADD SUB
|
||||
{NewDec(0), NewDec(0), NewDec(0), NewDec(0), NewDec(0), NewDec(0)},
|
||||
{NewDec(1), NewDec(0), NewDec(0), NewDec(0), NewDec(1), NewDec(1)},
|
||||
{NewDec(0), NewDec(1), NewDec(0), NewDec(0), NewDec(1), NewDec(-1)},
|
||||
{NewDec(0), NewDec(-1), NewDec(0), NewDec(0), NewDec(-1), NewDec(1)},
|
||||
{NewDec(-1), NewDec(0), NewDec(0), NewDec(0), NewDec(-1), NewDec(-1)},
|
||||
|
||||
{NewDec(1), NewDec(1), NewDec(1), NewDec(1), NewDec(2), NewDec(0)},
|
||||
{NewDec(-1), NewDec(-1), NewDec(1), NewDec(1), NewDec(-2), NewDec(0)},
|
||||
{NewDec(1), NewDec(-1), NewDec(-1), NewDec(-1), NewDec(0), NewDec(2)},
|
||||
{NewDec(-1), NewDec(1), NewDec(-1), NewDec(-1), NewDec(0), NewDec(-2)},
|
||||
|
||||
{NewDec(3), NewDec(7), NewDec(21), NewDecWithPrec(4285714286, 10), NewDec(10), NewDec(-4)},
|
||||
{NewDec(2), NewDec(4), NewDec(8), NewDecWithPrec(5, 1), NewDec(6), NewDec(-2)},
|
||||
{NewDec(100), NewDec(100), NewDec(10000), NewDec(1), NewDec(200), NewDec(0)},
|
||||
|
||||
{NewDecWithPrec(15, 1), NewDecWithPrec(15, 1), NewDecWithPrec(225, 2),
|
||||
NewDec(1), NewDec(3), NewDec(0)},
|
||||
{NewDecWithPrec(3333, 4), NewDecWithPrec(333, 4), NewDecWithPrec(1109889, 8),
|
||||
NewDecWithPrec(10009009009, 9), NewDecWithPrec(3666, 4), NewDecWithPrec(3, 1)},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
resAdd := tc.d1.Add(tc.d2)
|
||||
resSub := tc.d1.Sub(tc.d2)
|
||||
resMul := tc.d1.Mul(tc.d2)
|
||||
require.True(t, tc.expAdd.Equal(resAdd), "exp %v, res %v, tc %d", tc.expAdd, resAdd, tcIndex)
|
||||
require.True(t, tc.expSub.Equal(resSub), "exp %v, res %v, tc %d", tc.expSub, resSub, tcIndex)
|
||||
require.True(t, tc.expMul.Equal(resMul), "exp %v, res %v, tc %d", tc.expMul, resMul, tcIndex)
|
||||
|
||||
if tc.d2.IsZero() { // panic for divide by zero
|
||||
require.Panics(t, func() { tc.d1.Quo(tc.d2) })
|
||||
} else {
|
||||
resDiv := tc.d1.Quo(tc.d2)
|
||||
require.True(t, tc.expDiv.Equal(resDiv), "exp %v, res %v, tc %d", tc.expDiv.String(), resDiv.String(), tcIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBankerRoundChop(t *testing.T) {
|
||||
tests := []struct {
|
||||
d1 Dec
|
||||
exp int64
|
||||
}{
|
||||
{mustNewDecFromStr(t, "0.25"), 0},
|
||||
{mustNewDecFromStr(t, "0"), 0},
|
||||
{mustNewDecFromStr(t, "1"), 1},
|
||||
{mustNewDecFromStr(t, "0.75"), 1},
|
||||
{mustNewDecFromStr(t, "0.5"), 0},
|
||||
{mustNewDecFromStr(t, "7.5"), 8},
|
||||
{mustNewDecFromStr(t, "1.5"), 2},
|
||||
{mustNewDecFromStr(t, "2.5"), 2},
|
||||
{mustNewDecFromStr(t, "0.545"), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even
|
||||
{mustNewDecFromStr(t, "1.545"), 2},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
resNeg := tc.d1.Neg().RoundInt64()
|
||||
require.Equal(t, -1*tc.exp, resNeg, "negative tc %d", tcIndex)
|
||||
|
||||
resPos := tc.d1.RoundInt64()
|
||||
require.Equal(t, tc.exp, resPos, "positive tc %d", tcIndex)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToLeftPadded(t *testing.T) {
|
||||
tests := []struct {
|
||||
dec Dec
|
||||
digits int8
|
||||
exp string
|
||||
}{
|
||||
{mustNewDecFromStr(t, "33.3"), 8, "00000033"},
|
||||
{mustNewDecFromStr(t, "50"), 8, "00000050"},
|
||||
{mustNewDecFromStr(t, "333"), 8, "00000333"},
|
||||
{mustNewDecFromStr(t, "333"), 12, "000000000333"},
|
||||
{mustNewDecFromStr(t, "0.3333"), 8, "00000000"},
|
||||
}
|
||||
for tcIndex, tc := range tests {
|
||||
res := tc.dec.ToLeftPadded(tc.digits)
|
||||
require.Equal(t, tc.exp, res, "incorrect left padding, tc %d", tcIndex)
|
||||
}
|
||||
}
|
||||
|
||||
var cdc = wire.NewCodec()
|
||||
|
||||
func TestZeroDeserializationJSON(t *testing.T) {
|
||||
d := Dec{new(big.Int)}
|
||||
err := cdc.UnmarshalJSON([]byte(`"0"`), &d)
|
||||
require.Nil(t, err)
|
||||
err = cdc.UnmarshalJSON([]byte(`"{}"`), &d)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestSerializationText(t *testing.T) {
|
||||
d := mustNewDecFromStr(t, "0.333")
|
||||
|
||||
bz, err := d.MarshalText()
|
||||
require.NoError(t, err)
|
||||
|
||||
d2 := Dec{new(big.Int)}
|
||||
err = d2.UnmarshalText(bz)
|
||||
require.NoError(t, err)
|
||||
require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2)
|
||||
}
|
||||
|
||||
func TestSerializationGoWireJSON(t *testing.T) {
|
||||
d := mustNewDecFromStr(t, "0.333")
|
||||
|
||||
bz, err := cdc.MarshalJSON(d)
|
||||
require.NoError(t, err)
|
||||
|
||||
d2 := Dec{new(big.Int)}
|
||||
err = cdc.UnmarshalJSON(bz, &d2)
|
||||
require.NoError(t, err)
|
||||
require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2)
|
||||
}
|
||||
|
||||
func TestSerializationGoWireBinary(t *testing.T) {
|
||||
d := mustNewDecFromStr(t, "0.333")
|
||||
|
||||
bz, err := cdc.MarshalBinary(d)
|
||||
require.NoError(t, err)
|
||||
|
||||
var d2 Dec
|
||||
err = cdc.UnmarshalBinary(bz, &d2)
|
||||
require.NoError(t, err)
|
||||
require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2)
|
||||
}
|
||||
|
||||
type testDEmbedStruct struct {
|
||||
Field1 string `json:"f1"`
|
||||
Field2 int `json:"f2"`
|
||||
Field3 Dec `json:"f3"`
|
||||
}
|
||||
|
||||
// TODO make work for UnmarshalJSON
|
||||
func TestEmbeddedStructSerializationGoWire(t *testing.T) {
|
||||
obj := testDEmbedStruct{"foo", 10, NewDecWithPrec(1, 3)}
|
||||
bz, err := cdc.MarshalBinary(obj)
|
||||
require.Nil(t, err)
|
||||
|
||||
var obj2 testDEmbedStruct
|
||||
err = cdc.UnmarshalBinary(bz, &obj2)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, obj.Field1, obj2.Field1)
|
||||
require.Equal(t, obj.Field2, obj2.Field2)
|
||||
require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2)
|
||||
}
|
||||
|
||||
func TestStringOverflow(t *testing.T) {
|
||||
// two random 64 bit primes
|
||||
dec1, err := NewDecFromStr("51643150036226787134389711697696177267")
|
||||
require.NoError(t, err)
|
||||
dec2, err := NewDecFromStr("-31798496660535729618459429845579852627")
|
||||
require.NoError(t, err)
|
||||
dec3 := dec1.Add(dec2)
|
||||
require.Equal(t,
|
||||
"19844653375691057515930281852116324640.0000000000",
|
||||
dec3.String(),
|
||||
)
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package types
|
||||
|
||||
import abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
// Type for querier functions on keepers to implement to handle custom queries
|
||||
type Querier = func(ctx Context, path []string, req abci.RequestQuery) (res []byte, err Error)
|
|
@ -1,262 +0,0 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// "that's one big rat!"
|
||||
// ______
|
||||
// / / /\ \____oo
|
||||
// __ /___...._____ _\o
|
||||
// __| |_ |_
|
||||
|
||||
// NOTE: never use new(Rat) or else
|
||||
// we will panic unmarshalling into the
|
||||
// nil embedded big.Rat
|
||||
type Rat struct {
|
||||
*big.Rat `json:"rat"`
|
||||
}
|
||||
|
||||
// nolint - common values
|
||||
func ZeroRat() Rat { return Rat{big.NewRat(0, 1)} }
|
||||
func OneRat() Rat { return Rat{big.NewRat(1, 1)} }
|
||||
|
||||
// New - create a new Rat from integers
|
||||
func NewRat(Numerator int64, Denominator ...int64) Rat {
|
||||
switch len(Denominator) {
|
||||
case 0:
|
||||
return Rat{big.NewRat(Numerator, 1)}
|
||||
case 1:
|
||||
return Rat{big.NewRat(Numerator, Denominator[0])}
|
||||
default:
|
||||
panic("improper use of New, can only have one denominator")
|
||||
}
|
||||
}
|
||||
|
||||
func getNumeratorDenominator(str []string, prec int) (numerator string, denom int64, err Error) {
|
||||
switch len(str) {
|
||||
case 1:
|
||||
if len(str[0]) == 0 {
|
||||
return "", 0, ErrUnknownRequest("not a decimal string")
|
||||
}
|
||||
numerator = str[0]
|
||||
return numerator, 1, nil
|
||||
case 2:
|
||||
if len(str[0]) == 0 || len(str[1]) == 0 {
|
||||
return "", 0, ErrUnknownRequest("not a decimal string")
|
||||
}
|
||||
if len(str[1]) > prec {
|
||||
return "", 0, ErrUnknownRequest("string has too many decimals")
|
||||
}
|
||||
numerator = str[0] + str[1]
|
||||
len := int64(len(str[1]))
|
||||
denom = new(big.Int).Exp(big.NewInt(10), big.NewInt(len), nil).Int64()
|
||||
return numerator, denom, nil
|
||||
default:
|
||||
return "", 0, ErrUnknownRequest("not a decimal string")
|
||||
}
|
||||
}
|
||||
|
||||
// create a rational from decimal string or integer string
|
||||
// precision is the number of values after the decimal point which should be read
|
||||
func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) {
|
||||
// first extract any negative symbol
|
||||
if len(decimalStr) == 0 {
|
||||
return f, ErrUnknownRequest("decimal string is empty")
|
||||
}
|
||||
|
||||
neg := false
|
||||
if string(decimalStr[0]) == "-" {
|
||||
neg = true
|
||||
decimalStr = decimalStr[1:]
|
||||
}
|
||||
|
||||
str := strings.Split(decimalStr, ".")
|
||||
|
||||
numStr, denom, err := getNumeratorDenominator(str, prec)
|
||||
if err != nil {
|
||||
return f, err
|
||||
}
|
||||
|
||||
num, errConv := strconv.Atoi(numStr)
|
||||
if errConv != nil && strings.HasSuffix(errConv.Error(), "value out of range") {
|
||||
// resort to big int, don't make this default option for efficiency
|
||||
numBig, success := new(big.Int).SetString(numStr, 10)
|
||||
if success != true {
|
||||
return f, ErrUnknownRequest("not a decimal string")
|
||||
}
|
||||
|
||||
if neg {
|
||||
numBig.Neg(numBig)
|
||||
}
|
||||
|
||||
return NewRatFromBigInt(numBig, big.NewInt(denom)), nil
|
||||
} else if errConv != nil {
|
||||
return f, ErrUnknownRequest("not a decimal string")
|
||||
}
|
||||
|
||||
if neg {
|
||||
num *= -1
|
||||
}
|
||||
|
||||
return NewRat(int64(num), denom), nil
|
||||
}
|
||||
|
||||
// NewRatFromBigInt constructs Rat from big.Int
|
||||
func NewRatFromBigInt(num *big.Int, denom ...*big.Int) Rat {
|
||||
switch len(denom) {
|
||||
case 0:
|
||||
return Rat{new(big.Rat).SetInt(num)}
|
||||
case 1:
|
||||
return Rat{new(big.Rat).SetFrac(num, denom[0])}
|
||||
default:
|
||||
panic("improper use of NewRatFromBigInt, can only have one denominator")
|
||||
}
|
||||
}
|
||||
|
||||
// NewRatFromInt constructs Rat from Int
|
||||
func NewRatFromInt(num Int, denom ...Int) Rat {
|
||||
switch len(denom) {
|
||||
case 0:
|
||||
return Rat{new(big.Rat).SetInt(num.BigInt())}
|
||||
case 1:
|
||||
return Rat{new(big.Rat).SetFrac(num.BigInt(), denom[0].BigInt())}
|
||||
default:
|
||||
panic("improper use of NewRatFromBigInt, can only have one denominator")
|
||||
}
|
||||
}
|
||||
|
||||
//nolint
|
||||
func (r Rat) Num() Int { return Int{r.Rat.Num()} } // Num - return the numerator
|
||||
func (r Rat) Denom() Int { return Int{r.Rat.Denom()} } // Denom - return the denominator
|
||||
func (r Rat) IsZero() bool { return r.Num().IsZero() } // IsZero - Is the Rat equal to zero
|
||||
func (r Rat) Equal(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == 0 }
|
||||
func (r Rat) GT(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == 1 } // greater than
|
||||
func (r Rat) GTE(r2 Rat) bool { return !r.LT(r2) } // greater than or equal
|
||||
func (r Rat) LT(r2 Rat) bool { return (r.Rat).Cmp(r2.Rat) == -1 } // less than
|
||||
func (r Rat) LTE(r2 Rat) bool { return !r.GT(r2) } // less than or equal
|
||||
func (r Rat) Mul(r2 Rat) Rat { return Rat{new(big.Rat).Mul(r.Rat, r2.Rat)} } // Mul - multiplication
|
||||
func (r Rat) Quo(r2 Rat) Rat { return Rat{new(big.Rat).Quo(r.Rat, r2.Rat)} } // Quo - quotient
|
||||
func (r Rat) Add(r2 Rat) Rat { return Rat{new(big.Rat).Add(r.Rat, r2.Rat)} } // Add - addition
|
||||
func (r Rat) Sub(r2 Rat) Rat { return Rat{new(big.Rat).Sub(r.Rat, r2.Rat)} } // Sub - subtraction
|
||||
func (r Rat) String() string { return r.Rat.String() }
|
||||
func (r Rat) FloatString() string { return r.Rat.FloatString(10) } // a human-friendly string format. The last digit is rounded to nearest, with halves rounded away from zero.
|
||||
|
||||
var (
|
||||
zero = big.NewInt(0)
|
||||
one = big.NewInt(1)
|
||||
two = big.NewInt(2)
|
||||
five = big.NewInt(5)
|
||||
nFive = big.NewInt(-5)
|
||||
ten = big.NewInt(10)
|
||||
)
|
||||
|
||||
// evaluate the rational using bankers rounding
|
||||
func (r Rat) EvaluateBig() *big.Int {
|
||||
|
||||
num := r.Rat.Num()
|
||||
denom := r.Rat.Denom()
|
||||
|
||||
d, rem := new(big.Int), new(big.Int)
|
||||
d.QuoRem(num, denom, rem)
|
||||
if rem.Cmp(zero) == 0 { // is the remainder zero
|
||||
return d
|
||||
}
|
||||
|
||||
// evaluate the remainder using bankers rounding
|
||||
tenNum := new(big.Int).Mul(num, ten)
|
||||
tenD := new(big.Int).Mul(d, ten)
|
||||
remainderDigit := new(big.Int).Sub(new(big.Int).Quo(tenNum, denom), tenD) // get the first remainder digit
|
||||
isFinalDigit := (new(big.Int).Rem(tenNum, denom).Cmp(zero) == 0) // is this the final digit in the remainder?
|
||||
|
||||
switch {
|
||||
case isFinalDigit && (remainderDigit.Cmp(five) == 0 || remainderDigit.Cmp(nFive) == 0):
|
||||
dRem2 := new(big.Int).Rem(d, two)
|
||||
return new(big.Int).Add(d, dRem2) // always rounds to the even number
|
||||
case remainderDigit.Cmp(five) != -1: //remainderDigit >= 5:
|
||||
d.Add(d, one)
|
||||
case remainderDigit.Cmp(nFive) != 1: //remainderDigit <= -5:
|
||||
d.Sub(d, one)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// RoundInt64 rounds the rational using bankers rounding
|
||||
func (r Rat) RoundInt64() int64 {
|
||||
return r.EvaluateBig().Int64()
|
||||
}
|
||||
|
||||
// RoundInt round the rational using bankers rounding
|
||||
func (r Rat) RoundInt() Int {
|
||||
return NewIntFromBigInt(r.EvaluateBig())
|
||||
}
|
||||
|
||||
// round Rat with the provided precisionFactor
|
||||
func (r Rat) Round(precisionFactor int64) Rat {
|
||||
rTen := Rat{new(big.Rat).Mul(r.Rat, big.NewRat(precisionFactor, 1))}
|
||||
return Rat{big.NewRat(rTen.RoundInt64(), precisionFactor)}
|
||||
}
|
||||
|
||||
// TODO panic if negative or if totalDigits < len(initStr)???
|
||||
// evaluate as an integer and return left padded string
|
||||
func (r Rat) ToLeftPadded(totalDigits int8) string {
|
||||
intStr := r.EvaluateBig().String()
|
||||
fcode := `%0` + strconv.Itoa(int(totalDigits)) + `s`
|
||||
return fmt.Sprintf(fcode, intStr)
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
|
||||
//Wraps r.MarshalText().
|
||||
func (r Rat) MarshalAmino() (string, error) {
|
||||
if r.Rat == nil {
|
||||
r.Rat = new(big.Rat)
|
||||
}
|
||||
bz, err := r.Rat.MarshalText()
|
||||
return string(bz), err
|
||||
}
|
||||
|
||||
// Requires a valid JSON string - strings quotes and calls UnmarshalText
|
||||
func (r *Rat) UnmarshalAmino(text string) (err error) {
|
||||
tempRat := big.NewRat(0, 1)
|
||||
err = tempRat.UnmarshalText([]byte(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Rat = tempRat
|
||||
return nil
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// helpers
|
||||
|
||||
// test if two rat arrays are equal
|
||||
func RatsEqual(r1s, r2s []Rat) bool {
|
||||
if len(r1s) != len(r2s) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, r1 := range r1s {
|
||||
if !r1.Equal(r2s[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// intended to be used with require/assert: require.True(RatEq(...))
|
||||
func RatEq(t *testing.T, exp, got Rat) (*testing.T, bool, string, Rat, Rat) {
|
||||
return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got
|
||||
}
|
||||
|
||||
// minimum rational between two
|
||||
func MinRat(r1, r2 Rat) Rat {
|
||||
if r1.LT(r2) {
|
||||
return r1
|
||||
}
|
||||
return r2
|
||||
}
|
|
@ -1,402 +0,0 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
require.Equal(t, NewRat(1), NewRat(1, 1))
|
||||
require.Equal(t, NewRat(100), NewRat(100, 1))
|
||||
require.Equal(t, NewRat(-1), NewRat(-1, 1))
|
||||
require.Equal(t, NewRat(-100), NewRat(-100, 1))
|
||||
require.Equal(t, NewRat(0), NewRat(0, 1))
|
||||
|
||||
// do not allow for more than 2 variables
|
||||
require.Panics(t, func() { NewRat(1, 1, 1) })
|
||||
}
|
||||
|
||||
func TestNewFromDecimal(t *testing.T) {
|
||||
largeBigInt, success := new(big.Int).SetString("3109736052979742687701388262607869", 10)
|
||||
require.True(t, success)
|
||||
tests := []struct {
|
||||
decimalStr string
|
||||
expErr bool
|
||||
exp Rat
|
||||
}{
|
||||
{"", true, Rat{}},
|
||||
{"0", false, NewRat(0)},
|
||||
{"1", false, NewRat(1)},
|
||||
{"1.1", false, NewRat(11, 10)},
|
||||
{"0.75", false, NewRat(3, 4)},
|
||||
{"0.8", false, NewRat(4, 5)},
|
||||
{"0.11111", true, NewRat(1111, 10000)},
|
||||
{"628240629832763.5738930323617075341", true, NewRat(3141203149163817869, 5000)},
|
||||
{"621947210595948537540277652521.5738930323617075341",
|
||||
true, NewRatFromBigInt(largeBigInt, big.NewInt(5000))},
|
||||
{"628240629832763.5738", false, NewRat(3141203149163817869, 5000)},
|
||||
{"621947210595948537540277652521.5738",
|
||||
false, NewRatFromBigInt(largeBigInt, big.NewInt(5000))},
|
||||
{".", true, Rat{}},
|
||||
{".0", true, Rat{}},
|
||||
{"1.", true, Rat{}},
|
||||
{"foobar", true, Rat{}},
|
||||
{"0.foobar", true, Rat{}},
|
||||
{"0.foobar.", true, Rat{}},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
res, err := NewRatFromDecimal(tc.decimalStr, 4)
|
||||
if tc.expErr {
|
||||
require.NotNil(t, err, tc.decimalStr, "error expected, tc #%d", tcIndex)
|
||||
} else {
|
||||
require.Nil(t, err, tc.decimalStr, "unexpected error, tc #%d", tcIndex)
|
||||
require.True(t, res.Equal(tc.exp), tc.decimalStr, "equality was incorrect, tc #%d", tcIndex)
|
||||
}
|
||||
|
||||
// negative tc
|
||||
res, err = NewRatFromDecimal("-"+tc.decimalStr, 4)
|
||||
if tc.expErr {
|
||||
require.NotNil(t, err, tc.decimalStr, "error expected (negative case), tc #%d", tcIndex)
|
||||
} else {
|
||||
require.Nil(t, err, tc.decimalStr, "unexpected error (negative case), tc #%d", tcIndex)
|
||||
require.True(t, res.Equal(tc.exp.Mul(NewRat(-1))), tc.decimalStr, "equality was incorrect (negative case), tc #%d", tcIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqualities(t *testing.T) {
|
||||
tests := []struct {
|
||||
r1, r2 Rat
|
||||
gt, lt, eq bool
|
||||
}{
|
||||
{NewRat(0), NewRat(0), false, false, true},
|
||||
{NewRat(0, 100), NewRat(0, 10000), false, false, true},
|
||||
{NewRat(100), NewRat(100), false, false, true},
|
||||
{NewRat(-100), NewRat(-100), false, false, true},
|
||||
{NewRat(-100, -1), NewRat(100), false, false, true},
|
||||
{NewRat(-1, 1), NewRat(1, -1), false, false, true},
|
||||
{NewRat(1, -1), NewRat(-1, 1), false, false, true},
|
||||
{NewRat(3, 7), NewRat(3, 7), false, false, true},
|
||||
|
||||
{NewRat(0), NewRat(3, 7), false, true, false},
|
||||
{NewRat(0), NewRat(100), false, true, false},
|
||||
{NewRat(-1), NewRat(3, 7), false, true, false},
|
||||
{NewRat(-1), NewRat(100), false, true, false},
|
||||
{NewRat(1, 7), NewRat(100), false, true, false},
|
||||
{NewRat(1, 7), NewRat(3, 7), false, true, false},
|
||||
{NewRat(-3, 7), NewRat(-1, 7), false, true, false},
|
||||
|
||||
{NewRat(3, 7), NewRat(0), true, false, false},
|
||||
{NewRat(100), NewRat(0), true, false, false},
|
||||
{NewRat(3, 7), NewRat(-1), true, false, false},
|
||||
{NewRat(100), NewRat(-1), true, false, false},
|
||||
{NewRat(100), NewRat(1, 7), true, false, false},
|
||||
{NewRat(3, 7), NewRat(1, 7), true, false, false},
|
||||
{NewRat(-1, 7), NewRat(-3, 7), true, false, false},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
require.Equal(t, tc.gt, tc.r1.GT(tc.r2), "GT result is incorrect, tc #%d", tcIndex)
|
||||
require.Equal(t, tc.lt, tc.r1.LT(tc.r2), "LT result is incorrect, tc #%d", tcIndex)
|
||||
require.Equal(t, tc.eq, tc.r1.Equal(tc.r2), "equality result is incorrect, tc #%d", tcIndex)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestArithmetic(t *testing.T) {
|
||||
tests := []struct {
|
||||
r1, r2 Rat
|
||||
resMul, resDiv, resAdd, resSub Rat
|
||||
}{
|
||||
// r1 r2 MUL DIV ADD SUB
|
||||
{NewRat(0), NewRat(0), NewRat(0), NewRat(0), NewRat(0), NewRat(0)},
|
||||
{NewRat(1), NewRat(0), NewRat(0), NewRat(0), NewRat(1), NewRat(1)},
|
||||
{NewRat(0), NewRat(1), NewRat(0), NewRat(0), NewRat(1), NewRat(-1)},
|
||||
{NewRat(0), NewRat(-1), NewRat(0), NewRat(0), NewRat(-1), NewRat(1)},
|
||||
{NewRat(-1), NewRat(0), NewRat(0), NewRat(0), NewRat(-1), NewRat(-1)},
|
||||
|
||||
{NewRat(1), NewRat(1), NewRat(1), NewRat(1), NewRat(2), NewRat(0)},
|
||||
{NewRat(-1), NewRat(-1), NewRat(1), NewRat(1), NewRat(-2), NewRat(0)},
|
||||
{NewRat(1), NewRat(-1), NewRat(-1), NewRat(-1), NewRat(0), NewRat(2)},
|
||||
{NewRat(-1), NewRat(1), NewRat(-1), NewRat(-1), NewRat(0), NewRat(-2)},
|
||||
|
||||
{NewRat(3), NewRat(7), NewRat(21), NewRat(3, 7), NewRat(10), NewRat(-4)},
|
||||
{NewRat(2), NewRat(4), NewRat(8), NewRat(1, 2), NewRat(6), NewRat(-2)},
|
||||
{NewRat(100), NewRat(100), NewRat(10000), NewRat(1), NewRat(200), NewRat(0)},
|
||||
|
||||
{NewRat(3, 2), NewRat(3, 2), NewRat(9, 4), NewRat(1), NewRat(3), NewRat(0)},
|
||||
{NewRat(3, 7), NewRat(7, 3), NewRat(1), NewRat(9, 49), NewRat(58, 21), NewRat(-40, 21)},
|
||||
{NewRat(1, 21), NewRat(11, 5), NewRat(11, 105), NewRat(5, 231), NewRat(236, 105), NewRat(-226, 105)},
|
||||
{NewRat(-21), NewRat(3, 7), NewRat(-9), NewRat(-49), NewRat(-144, 7), NewRat(-150, 7)},
|
||||
{NewRat(100), NewRat(1, 7), NewRat(100, 7), NewRat(700), NewRat(701, 7), NewRat(699, 7)},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
require.True(t, tc.resMul.Equal(tc.r1.Mul(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex)
|
||||
require.True(t, tc.resAdd.Equal(tc.r1.Add(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex)
|
||||
require.True(t, tc.resSub.Equal(tc.r1.Sub(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex)
|
||||
|
||||
if tc.r2.Num().IsZero() { // panic for divide by zero
|
||||
require.Panics(t, func() { tc.r1.Quo(tc.r2) })
|
||||
} else {
|
||||
require.True(t, tc.resDiv.Equal(tc.r1.Quo(tc.r2)), "r1 %v, r2 %v. tc #%d", tc.r1.Rat, tc.r2.Rat, tcIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluate(t *testing.T) {
|
||||
tests := []struct {
|
||||
r1 Rat
|
||||
res int64
|
||||
}{
|
||||
{NewRat(0), 0},
|
||||
{NewRat(1), 1},
|
||||
{NewRat(1, 4), 0},
|
||||
{NewRat(1, 2), 0},
|
||||
{NewRat(3, 4), 1},
|
||||
{NewRat(5, 6), 1},
|
||||
{NewRat(3, 2), 2},
|
||||
{NewRat(5, 2), 2},
|
||||
{NewRat(6, 11), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even
|
||||
{NewRat(17, 11), 2}, // 1.545
|
||||
{NewRat(5, 11), 0},
|
||||
{NewRat(16, 11), 1},
|
||||
{NewRat(113, 12), 9},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
require.Equal(t, tc.res, tc.r1.RoundInt64(), "%v. tc #%d", tc.r1, tcIndex)
|
||||
require.Equal(t, tc.res*-1, tc.r1.Mul(NewRat(-1)).RoundInt64(), "%v. tc #%d", tc.r1.Mul(NewRat(-1)), tcIndex)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRound(t *testing.T) {
|
||||
many3 := "333333333333333333333333333333333333333333333"
|
||||
many7 := "777777777777777777777777777777777777777777777"
|
||||
big3, worked := new(big.Int).SetString(many3, 10)
|
||||
require.True(t, worked)
|
||||
big7, worked := new(big.Int).SetString(many7, 10)
|
||||
require.True(t, worked)
|
||||
|
||||
tests := []struct {
|
||||
r, res Rat
|
||||
precFactor int64
|
||||
}{
|
||||
{NewRat(333, 777), NewRat(429, 1000), 1000},
|
||||
{Rat{new(big.Rat).SetFrac(big3, big7)}, NewRat(429, 1000), 1000},
|
||||
{Rat{new(big.Rat).SetFrac(big3, big7)}, Rat{big.NewRat(4285714286, 10000000000)}, 10000000000},
|
||||
{NewRat(1, 2), NewRat(1, 2), 1000},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
require.Equal(t, tc.res, tc.r.Round(tc.precFactor), "%v", tc.r, "incorrect rounding, tc #%d", tcIndex)
|
||||
negR1, negRes := tc.r.Mul(NewRat(-1)), tc.res.Mul(NewRat(-1))
|
||||
require.Equal(t, negRes, negR1.Round(tc.precFactor), "%v", negR1, "incorrect rounding (negative case), tc #%d", tcIndex)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToLeftPadded(t *testing.T) {
|
||||
tests := []struct {
|
||||
rat Rat
|
||||
digits int8
|
||||
res string
|
||||
}{
|
||||
{NewRat(100, 3), 8, "00000033"},
|
||||
{NewRat(1, 3), 8, "00000000"},
|
||||
{NewRat(100, 2), 8, "00000050"},
|
||||
{NewRat(1000, 3), 8, "00000333"},
|
||||
{NewRat(1000, 3), 12, "000000000333"},
|
||||
}
|
||||
for tcIndex, tc := range tests {
|
||||
require.Equal(t, tc.res, tc.rat.ToLeftPadded(tc.digits), "incorrect left padding, tc #%d", tcIndex)
|
||||
}
|
||||
}
|
||||
|
||||
var cdc = wire.NewCodec() //var jsonCdc JSONCodec // TODO wire.Codec
|
||||
|
||||
func TestZeroSerializationJSON(t *testing.T) {
|
||||
r := NewRat(0, 1)
|
||||
err := cdc.UnmarshalJSON([]byte(`"0/1"`), &r)
|
||||
require.Nil(t, err)
|
||||
err = cdc.UnmarshalJSON([]byte(`"0/0"`), &r)
|
||||
require.NotNil(t, err)
|
||||
err = cdc.UnmarshalJSON([]byte(`"1/0"`), &r)
|
||||
require.NotNil(t, err)
|
||||
err = cdc.UnmarshalJSON([]byte(`"{}"`), &r)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestSerializationText(t *testing.T) {
|
||||
r := NewRat(1, 3)
|
||||
|
||||
bz, err := r.MarshalText()
|
||||
require.NoError(t, err)
|
||||
|
||||
var r2 = Rat{new(big.Rat)}
|
||||
err = r2.UnmarshalText(bz)
|
||||
require.NoError(t, err)
|
||||
require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2)
|
||||
}
|
||||
|
||||
func TestSerializationGoWireJSON(t *testing.T) {
|
||||
r := NewRat(1, 3)
|
||||
bz, err := cdc.MarshalJSON(r)
|
||||
require.NoError(t, err)
|
||||
|
||||
var r2 Rat
|
||||
err = cdc.UnmarshalJSON(bz, &r2)
|
||||
require.NoError(t, err)
|
||||
require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2)
|
||||
}
|
||||
|
||||
func TestSerializationGoWireBinary(t *testing.T) {
|
||||
r := NewRat(1, 3)
|
||||
bz, err := cdc.MarshalBinary(r)
|
||||
require.NoError(t, err)
|
||||
|
||||
var r2 Rat
|
||||
err = cdc.UnmarshalBinary(bz, &r2)
|
||||
require.NoError(t, err)
|
||||
require.True(t, r.Equal(r2), "original: %v, unmarshalled: %v", r, r2)
|
||||
}
|
||||
|
||||
type testEmbedStruct struct {
|
||||
Field1 string `json:"f1"`
|
||||
Field2 int `json:"f2"`
|
||||
Field3 Rat `json:"f3"`
|
||||
}
|
||||
|
||||
func TestEmbeddedStructSerializationGoWire(t *testing.T) {
|
||||
obj := testEmbedStruct{"foo", 10, NewRat(1, 3)}
|
||||
bz, err := cdc.MarshalJSON(obj)
|
||||
require.Nil(t, err)
|
||||
|
||||
var obj2 testEmbedStruct
|
||||
err = cdc.UnmarshalJSON(bz, &obj2)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, obj.Field1, obj2.Field1)
|
||||
require.Equal(t, obj.Field2, obj2.Field2)
|
||||
require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2)
|
||||
}
|
||||
|
||||
func TestRatsEqual(t *testing.T) {
|
||||
tests := []struct {
|
||||
r1s, r2s []Rat
|
||||
eq bool
|
||||
}{
|
||||
{[]Rat{NewRat(0)}, []Rat{NewRat(0)}, true},
|
||||
{[]Rat{NewRat(0)}, []Rat{NewRat(1)}, false},
|
||||
{[]Rat{NewRat(0)}, []Rat{}, false},
|
||||
{[]Rat{NewRat(0), NewRat(1)}, []Rat{NewRat(0), NewRat(1)}, true},
|
||||
{[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1), NewRat(0)}, true},
|
||||
{[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(0), NewRat(1)}, false},
|
||||
{[]Rat{NewRat(1), NewRat(0)}, []Rat{NewRat(1)}, false},
|
||||
{[]Rat{NewRat(1), NewRat(2)}, []Rat{NewRat(2), NewRat(4)}, false},
|
||||
{[]Rat{NewRat(3), NewRat(18)}, []Rat{NewRat(1), NewRat(6)}, false},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range tests {
|
||||
require.Equal(t, tc.eq, RatsEqual(tc.r1s, tc.r2s), "equality of rational arrays is incorrect, tc #%d", tcIndex)
|
||||
require.Equal(t, tc.eq, RatsEqual(tc.r2s, tc.r1s), "equality of rational arrays is incorrect (converse), tc #%d", tcIndex)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestStringOverflow(t *testing.T) {
|
||||
// two random 64 bit primes
|
||||
rat1 := NewRat(5164315003622678713, 4389711697696177267)
|
||||
rat2 := NewRat(-3179849666053572961, 8459429845579852627)
|
||||
rat3 := rat1.Add(rat2)
|
||||
require.Equal(t,
|
||||
"29728537197630860939575850336935951464/37134458148982045574552091851127630409",
|
||||
rat3.String(),
|
||||
)
|
||||
}
|
||||
|
||||
// Tests below uses randomness
|
||||
// Since we are using *big.Rat as underlying value
|
||||
// and (U/)Int is immutable value(see TestImmutability(U/)Int)
|
||||
// it is safe to use randomness in the tests
|
||||
func TestArithRat(t *testing.T) {
|
||||
for i := 0; i < 20; i++ {
|
||||
n1 := NewInt(int64(rand.Int31()))
|
||||
d1 := NewInt(int64(rand.Int31()))
|
||||
rat1 := NewRatFromInt(n1, d1)
|
||||
|
||||
n2 := NewInt(int64(rand.Int31()))
|
||||
d2 := NewInt(int64(rand.Int31()))
|
||||
rat2 := NewRatFromInt(n2, d2)
|
||||
|
||||
n1d2 := n1.Mul(d2)
|
||||
n2d1 := n2.Mul(d1)
|
||||
|
||||
cases := []struct {
|
||||
nres Int
|
||||
dres Int
|
||||
rres Rat
|
||||
}{
|
||||
{n1d2.Add(n2d1), d1.Mul(d2), rat1.Add(rat2)},
|
||||
{n1d2.Sub(n2d1), d1.Mul(d2), rat1.Sub(rat2)},
|
||||
{n1.Mul(n2), d1.Mul(d2), rat1.Mul(rat2)},
|
||||
{n1d2, n2d1, rat1.Quo(rat2)},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
require.Equal(t, NewRatFromInt(tc.nres, tc.dres), tc.rres)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompRat(t *testing.T) {
|
||||
for i := 0; i < 20; i++ {
|
||||
n1 := NewInt(int64(rand.Int31()))
|
||||
d1 := NewInt(int64(rand.Int31()))
|
||||
rat1 := NewRatFromInt(n1, d1)
|
||||
|
||||
n2 := NewInt(int64(rand.Int31()))
|
||||
d2 := NewInt(int64(rand.Int31()))
|
||||
rat2 := NewRatFromInt(n2, d2)
|
||||
|
||||
n1d2 := n1.Mul(d2)
|
||||
n2d1 := n2.Mul(d1)
|
||||
|
||||
cases := []struct {
|
||||
ires bool
|
||||
rres bool
|
||||
}{
|
||||
{n1d2.Equal(n2d1), rat1.Equal(rat2)},
|
||||
{n1d2.GT(n2d1), rat1.GT(rat2)},
|
||||
{n1d2.LT(n2d1), rat1.LT(rat2)},
|
||||
{n1d2.GT(n2d1) || n1d2.Equal(n2d1), rat1.GTE(rat2)},
|
||||
{n1d2.LT(n2d1) || n1d2.Equal(n2d1), rat1.LTE(rat2)},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
require.Equal(t, tc.ires, tc.rres)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImmutabilityRat(t *testing.T) {
|
||||
for i := 0; i < 20; i++ {
|
||||
n := int64(rand.Int31())
|
||||
r := NewRat(n)
|
||||
z := ZeroRat()
|
||||
o := OneRat()
|
||||
|
||||
r.Add(z)
|
||||
r.Sub(z)
|
||||
r.Mul(o)
|
||||
r.Quo(o)
|
||||
|
||||
require.Equal(t, n, r.RoundInt64())
|
||||
require.True(t, NewRat(n).Equal(r))
|
||||
}
|
||||
|
||||
}
|
|
@ -40,19 +40,20 @@ type Validator interface {
|
|||
GetRevoked() bool // whether the validator is revoked
|
||||
GetMoniker() string // moniker of the validator
|
||||
GetStatus() BondStatus // status of the validator
|
||||
GetOwner() AccAddress // owner AccAddress to receive/return validators coins
|
||||
GetOperator() AccAddress // owner AccAddress to receive/return validators coins
|
||||
GetPubKey() crypto.PubKey // validation pubkey
|
||||
GetPower() Rat // validation power
|
||||
GetTokens() Rat // validation tokens
|
||||
GetDelegatorShares() Rat // Total out standing delegator shares
|
||||
GetPower() Dec // validation power
|
||||
GetTokens() Dec // validation tokens
|
||||
GetDelegatorShares() Dec // Total out standing delegator shares
|
||||
GetBondHeight() int64 // height in which the validator became active
|
||||
}
|
||||
|
||||
// validator which fulfills abci validator interface for use in Tendermint
|
||||
func ABCIValidator(v Validator) abci.Validator {
|
||||
return abci.Validator{
|
||||
PubKey: tmtypes.TM2PB.PubKey(v.GetPubKey()),
|
||||
Power: v.GetPower().RoundInt64(),
|
||||
PubKey: tmtypes.TM2PB.PubKey(v.GetPubKey()),
|
||||
Address: v.GetPubKey().Address(),
|
||||
Power: v.GetPower().RoundInt64(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,10 +69,10 @@ type ValidatorSet interface {
|
|||
|
||||
Validator(Context, AccAddress) Validator // get a particular validator by owner AccAddress
|
||||
ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by signing PubKey
|
||||
TotalPower(Context) Rat // total power of the validator set
|
||||
TotalPower(Context) Dec // total power of the validator set
|
||||
|
||||
// slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction
|
||||
Slash(Context, crypto.PubKey, int64, int64, Rat)
|
||||
Slash(Context, crypto.PubKey, int64, int64, Dec)
|
||||
Revoke(Context, crypto.PubKey) // revoke a validator
|
||||
Unrevoke(Context, crypto.PubKey) // unrevoke a validator
|
||||
}
|
||||
|
@ -82,7 +83,7 @@ type ValidatorSet interface {
|
|||
type Delegation interface {
|
||||
GetDelegator() AccAddress // delegator AccAddress for the bond
|
||||
GetValidator() AccAddress // validator owner AccAddress for the bond
|
||||
GetBondShares() Rat // amount of validator's shares
|
||||
GetBondShares() Dec // amount of validator's shares
|
||||
}
|
||||
|
||||
// properties for the set of all delegations for a particular
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
package version
|
||||
|
||||
const Maj = "0"
|
||||
const Min = "23"
|
||||
const Min = "24"
|
||||
const Fix = "1"
|
||||
|
||||
const Version = "0.23.1"
|
||||
const Version = "0.24.1"
|
||||
|
||||
// GitCommit set by build flags
|
||||
var GitCommit = ""
|
||||
|
|
|
@ -5,13 +5,17 @@ import (
|
|||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
)
|
||||
|
||||
const (
|
||||
deductFeesCost sdk.Gas = 10
|
||||
memoCostPerByte sdk.Gas = 1
|
||||
verifyCost = 100
|
||||
maxMemoCharacters = 100
|
||||
deductFeesCost sdk.Gas = 10
|
||||
memoCostPerByte sdk.Gas = 1
|
||||
ed25519VerifyCost = 59
|
||||
secp256k1VerifyCost = 100
|
||||
maxMemoCharacters = 100
|
||||
)
|
||||
|
||||
// NewAnteHandler returns an AnteHandler that checks
|
||||
|
@ -187,7 +191,7 @@ func processSig(
|
|||
}
|
||||
|
||||
// Check sig.
|
||||
ctx.GasMeter().ConsumeGas(verifyCost, "ante verify")
|
||||
consumeSignatureVerificationGas(ctx.GasMeter(), pubKey)
|
||||
if !pubKey.VerifyBytes(signBytes, sig.Signature) {
|
||||
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
|
||||
}
|
||||
|
@ -195,6 +199,17 @@ func processSig(
|
|||
return
|
||||
}
|
||||
|
||||
func consumeSignatureVerificationGas(meter sdk.GasMeter, pubkey crypto.PubKey) {
|
||||
switch pubkey.(type) {
|
||||
case ed25519.PubKeyEd25519:
|
||||
meter.ConsumeGas(ed25519VerifyCost, "ante verify: ed25519")
|
||||
case secp256k1.PubKeySecp256k1:
|
||||
meter.ConsumeGas(secp256k1VerifyCost, "ante verify: secp256k1")
|
||||
default:
|
||||
panic("Unrecognized signature type")
|
||||
}
|
||||
}
|
||||
|
||||
// Deduct the fee from the account.
|
||||
// We could use the CoinKeeper (in addition to the AccountMapper,
|
||||
// because the CoinKeeper doesn't give us accounts), but it seems easier to do this.
|
||||
|
|
|
@ -87,6 +87,7 @@ func (am AccountMapper) SetAccount(ctx sdk.Context, acc Account) {
|
|||
func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(Account) (stop bool)) {
|
||||
store := ctx.KVStore(am.key)
|
||||
iter := sdk.KVStorePrefixIterator(store, []byte("account:"))
|
||||
defer iter.Close()
|
||||
for {
|
||||
if !iter.Valid() {
|
||||
return
|
||||
|
|
|
@ -35,6 +35,10 @@ func TestAndRunSingleInputMsgSend(mapper auth.AccountMapper) simulation.TestAndR
|
|||
toAddr := sdk.AccAddress(toKey.PubKey().Address())
|
||||
initFromCoins := mapper.GetAccount(ctx, fromAddr).GetCoins()
|
||||
|
||||
if len(initFromCoins) == 0 {
|
||||
return "skipping, no coins at all", nil
|
||||
}
|
||||
|
||||
denomIndex := r.Intn(len(initFromCoins))
|
||||
amt, goErr := randPositiveInt(r, initFromCoins[denomIndex].Amount)
|
||||
if goErr != nil {
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
|
@ -24,7 +26,7 @@ func TestBankWithRandomMessages(t *testing.T) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
appStateFn := func(r *rand.Rand, accs []sdk.AccAddress) json.RawMessage {
|
||||
appStateFn := func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
|
||||
mock.RandomSetGenesis(r, mapp, accs, []string{"stake"})
|
||||
return json.RawMessage("{}")
|
||||
}
|
||||
|
@ -39,6 +41,7 @@ func TestBankWithRandomMessages(t *testing.T) {
|
|||
NonnegativeBalanceInvariant(mapper),
|
||||
TotalCoinsInvariant(mapper, func() sdk.Coins { return mapp.TotalCoinsSupply }),
|
||||
},
|
||||
100, 30, 30,
|
||||
30, 30,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@ package stake
|
|||
////_________________________________________________________________________
|
||||
|
||||
//// cummulative power of the non-absent prevotes
|
||||
//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Rat {
|
||||
//func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Dec {
|
||||
//store := ctx.KVStore(k.storeKey)
|
||||
|
||||
//// get absent prevote indexes
|
||||
//absents := ctx.AbsentValidators()
|
||||
|
||||
//TotalPower := sdk.ZeroRat()
|
||||
//TotalPower := sdk.ZeroDec()
|
||||
//i := int32(0)
|
||||
//iterator := store.SubspaceIterator(ValidatorsBondedKey)
|
||||
//for ; iterator.Valid(); iterator.Next() {
|
||||
|
|
|
@ -8,8 +8,8 @@ package stake
|
|||
//var candidatesIn [5]Candidate
|
||||
//for i, amt := range amts {
|
||||
//candidatesIn[i] = NewCandidate(addrVals[i], pks[i], Description{})
|
||||
//candidatesIn[i].BondedShares = sdk.NewRat(amt)
|
||||
//candidatesIn[i].DelegatorShares = sdk.NewRat(amt)
|
||||
//candidatesIn[i].BondedShares = sdk.NewDec(amt)
|
||||
//candidatesIn[i].DelegatorShares = sdk.NewDec(amt)
|
||||
//keeper.setCandidate(ctx, candidatesIn[i])
|
||||
//}
|
||||
|
||||
|
@ -18,7 +18,7 @@ package stake
|
|||
//require.Equal(t, 5, len(gotValidators))
|
||||
|
||||
//totPow := keeper.GetTotalPrecommitVotingPower(ctx)
|
||||
//exp := sdk.NewRat(11111)
|
||||
//exp := sdk.NewDec(11111)
|
||||
//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow)
|
||||
|
||||
//// set absent gotValidators to be the 1st and 3rd record sorted by pubKey address
|
||||
|
@ -26,6 +26,6 @@ package stake
|
|||
//totPow = keeper.GetTotalPrecommitVotingPower(ctx)
|
||||
|
||||
//// XXX verify that this order should infact exclude these two records
|
||||
//exp = sdk.NewRat(11100)
|
||||
//exp = sdk.NewDec(11100)
|
||||
//require.True(t, exp.Equal(totPow), "exp %v, got %v", exp, totPow)
|
||||
//}
|
||||
|
|
|
@ -17,7 +17,7 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {}
|
|||
|
||||
//// calculate the proposer reward
|
||||
//precommitPower := k.GetTotalPrecommitVotingPower(ctx)
|
||||
//toProposer := coinsMulRat(collectedFees, (sdk.NewRat(1, 100).Add(sdk.NewRat(4, 100).Mul(precommitPower).Quo(pool.BondedShares))))
|
||||
//toProposer := coinsMulRat(collectedFees, (sdk.NewDec(1, 100).Add(sdk.NewDec(4, 100).Mul(precommitPower).Quo(pool.BondedShares))))
|
||||
//candidate.ProposerRewardPool = candidate.ProposerRewardPool.Plus(toProposer)
|
||||
|
||||
//toReservePool := coinsMulRat(collectedFees, params.ReservePoolFee)
|
||||
|
@ -34,10 +34,10 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {}
|
|||
//k.setPool(ctx, pool)
|
||||
//}
|
||||
|
||||
//func coinsMulRat(coins sdk.Coins, rat sdk.Rat) sdk.Coins {
|
||||
//func coinsMulRat(coins sdk.Coins, rat sdk.Dec) sdk.Coins {
|
||||
//var res sdk.Coins
|
||||
//for _, coin := range coins {
|
||||
//coinMulAmt := rat.Mul(sdk.NewRat(coin.Amount)).Evaluate()
|
||||
//coinMulAmt := rat.Mul(sdk.NewDec(coin.Amount)).Evaluate()
|
||||
//coinMul := sdk.Coins{{coin.Denom, coinMulAmt}}
|
||||
//res = res.Plus(coinMul)
|
||||
//}
|
||||
|
@ -49,14 +49,14 @@ func BurnFeeHandler(ctx sdk.Context, _ sdk.Tx, collectedFees sdk.Coins) {}
|
|||
//// calculate adjustment changes for a candidate at a height
|
||||
//func CalculateAdjustmentChange(candidate Candidate, pool Pool, denoms []string, height int64) (Candidate, Pool) {
|
||||
|
||||
//heightRat := sdk.NewRat(height)
|
||||
//lastHeightRat := sdk.NewRat(height - 1)
|
||||
//heightRat := sdk.NewDec(height)
|
||||
//lastHeightRat := sdk.NewDec(height - 1)
|
||||
//candidateFeeCount := candidate.BondedShares.Mul(heightRat)
|
||||
//poolFeeCount := pool.BondedShares.Mul(heightRat)
|
||||
|
||||
//for i, denom := range denoms {
|
||||
//poolFeeSumReceived := sdk.NewRat(pool.FeeSumReceived.AmountOf(denom))
|
||||
//poolFeeRecent := sdk.NewRat(pool.FeeRecent.AmountOf(denom))
|
||||
//poolFeeSumReceived := sdk.NewDec(pool.FeeSumReceived.AmountOf(denom))
|
||||
//poolFeeRecent := sdk.NewDec(pool.FeeRecent.AmountOf(denom))
|
||||
//// calculate simple and projected pools
|
||||
//simplePool := candidateFeeCount.Quo(poolFeeCount).Mul(poolFeeSumReceived)
|
||||
//calc1 := candidate.PrevBondedShares.Mul(lastHeightRat).Quo(pool.PrevBondedShares.Mul(lastHeightRat)).Mul(poolFeeRecent)
|
||||
|
|
|
@ -23,8 +23,8 @@ package stake
|
|||
|
||||
//// fee information for a validator
|
||||
//type Validator struct {
|
||||
//Adjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms
|
||||
//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools
|
||||
//Adjustments []sdk.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms
|
||||
//PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // total shares of a global hold pools
|
||||
//}
|
||||
|
||||
////_________________________________________________________________________
|
||||
|
@ -32,7 +32,7 @@ package stake
|
|||
//// Params defines the high level settings for staking
|
||||
//type Params struct {
|
||||
//FeeDenoms []string `json:"fee_denoms"` // accepted fee denoms
|
||||
//ReservePoolFee sdk.Rat `json:"reserve_pool_fee"` // percent of fees which go to reserve pool
|
||||
//ReservePoolFee sdk.Dec `json:"reserve_pool_fee"` // percent of fees which go to reserve pool
|
||||
//}
|
||||
|
||||
//func (p Params) equal(p2 Params) bool {
|
||||
|
@ -43,7 +43,7 @@ package stake
|
|||
//func defaultParams() Params {
|
||||
//return Params{
|
||||
//FeeDenoms: []string{"steak"},
|
||||
//ReservePoolFee: sdk.NewRat(5, 100),
|
||||
//ReservePoolFee: sdk.NewDec(5, 100),
|
||||
//}
|
||||
//}
|
||||
|
||||
|
@ -55,8 +55,8 @@ package stake
|
|||
//FeePool sdk.Coins `json:"fee_pool"` // XXX fee pool for all the fee shares which have already been distributed
|
||||
//FeeSumReceived sdk.Coins `json:"fee_sum_received"` // XXX sum of all fees received, post reserve pool `json:"fee_sum_received"`
|
||||
//FeeRecent sdk.Coins `json:"fee_recent"` // XXX most recent fee collected
|
||||
//FeeAdjustments []sdk.Rat `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms
|
||||
//PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // XXX last recorded bonded shares
|
||||
//FeeAdjustments []sdk.Dec `json:"fee_adjustments"` // XXX Adjustment factors for lazy fee accounting, couples with Params.BondDenoms
|
||||
//PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // XXX last recorded bonded shares
|
||||
//}
|
||||
|
||||
//func (p Pool) equal(p2 Pool) bool {
|
||||
|
@ -64,7 +64,7 @@ package stake
|
|||
//p.FeePool.IsEqual(p2.FeePool) &&
|
||||
//p.FeeSumReceived.IsEqual(p2.FeeSumReceived) &&
|
||||
//p.FeeRecent.IsEqual(p2.FeeRecent) &&
|
||||
//sdk.RatsEqual(p.FeeAdjustments, p2.FeeAdjustments) &&
|
||||
//sdk.DecsEqual(p.FeeAdjustments, p2.FeeAdjustments) &&
|
||||
//p.PrevBondedShares.Equal(p2.PrevBondedShares)
|
||||
//}
|
||||
|
||||
|
@ -75,8 +75,8 @@ package stake
|
|||
//FeePool: sdk.Coins(nil),
|
||||
//FeeSumReceived: sdk.Coins(nil),
|
||||
//FeeRecent: sdk.Coins(nil),
|
||||
//FeeAdjustments: []sdk.Rat{sdk.ZeroRat()},
|
||||
//PrevBondedShares: sdk.ZeroRat(),
|
||||
//FeeAdjustments: []sdk.Dec{sdk.ZeroDec()},
|
||||
//PrevBondedShares: sdk.ZeroDec(),
|
||||
//}
|
||||
//}
|
||||
|
||||
|
@ -85,8 +85,8 @@ package stake
|
|||
//// Used in calculation of fee shares, added to a queue for each block where a power change occures
|
||||
//type PowerChange struct {
|
||||
//Height int64 `json:"height"` // block height at change
|
||||
//Power sdk.Rat `json:"power"` // total power at change
|
||||
//PrevPower sdk.Rat `json:"prev_power"` // total power at previous height-1
|
||||
//Power sdk.Dec `json:"power"` // total power at change
|
||||
//PrevPower sdk.Dec `json:"prev_power"` // total power at previous height-1
|
||||
//FeesIn sdk.Coins `json:"fees_in"` // fees in at block height
|
||||
//PrevFeePool sdk.Coins `json:"prev_fee_pool"` // total fees in at previous block height
|
||||
//}
|
||||
|
|
|
@ -15,6 +15,9 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"io/ioutil"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -28,18 +31,51 @@ const (
|
|||
flagDepositer = "depositer"
|
||||
flagStatus = "status"
|
||||
flagLatestProposalIDs = "latest"
|
||||
flagProposal = "proposal"
|
||||
)
|
||||
|
||||
type proposal struct {
|
||||
Title string
|
||||
Description string
|
||||
Type string
|
||||
Deposit string
|
||||
}
|
||||
|
||||
var proposalFlags = []string{
|
||||
flagTitle,
|
||||
flagDescription,
|
||||
flagProposalType,
|
||||
flagDeposit,
|
||||
}
|
||||
|
||||
// GetCmdSubmitProposal implements submitting a proposal transaction command.
|
||||
func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "submit-proposal",
|
||||
Short: "Submit a proposal along with an initial deposit",
|
||||
Long: strings.TrimSpace(`
|
||||
Submit a proposal along with an initial deposit. Proposal title, description, type and deposit can be given directly or through a proposal JSON file. For example:
|
||||
|
||||
$ gaiacli gov submit-proposal --proposal="path/to/proposal.json"
|
||||
|
||||
where proposal.json contains:
|
||||
|
||||
{
|
||||
"title": "Test Proposal",
|
||||
"description": "My awesome proposal",
|
||||
"type": "Text",
|
||||
"deposit": "1000test"
|
||||
}
|
||||
|
||||
is equivalent to
|
||||
|
||||
$ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="1000test"
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
title := viper.GetString(flagTitle)
|
||||
description := viper.GetString(flagDescription)
|
||||
strProposalType := viper.GetString(flagProposalType)
|
||||
initialDeposit := viper.GetString(flagDeposit)
|
||||
proposal, err := parseSubmitProposalFlags()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
|
@ -52,17 +88,17 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
amount, err := sdk.ParseCoins(initialDeposit)
|
||||
amount, err := sdk.ParseCoins(proposal.Deposit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proposalType, err := gov.ProposalTypeFromString(strProposalType)
|
||||
proposalType, err := gov.ProposalTypeFromString(proposal.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := gov.NewMsgSubmitProposal(title, description, proposalType, fromAddr, amount)
|
||||
msg := gov.NewMsgSubmitProposal(proposal.Title, proposal.Description, proposalType, fromAddr, amount)
|
||||
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
|
@ -80,10 +116,42 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
|
|||
cmd.Flags().String(flagDescription, "", "description of proposal")
|
||||
cmd.Flags().String(flagProposalType, "", "proposalType of proposal")
|
||||
cmd.Flags().String(flagDeposit, "", "deposit of proposal")
|
||||
cmd.Flags().String(flagProposal, "", "proposal file path (if this path is given, other proposal flags are ignored)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseSubmitProposalFlags() (*proposal, error) {
|
||||
proposal := &proposal{}
|
||||
proposalFile := viper.GetString(flagProposal)
|
||||
|
||||
if proposalFile == "" {
|
||||
proposal.Title = viper.GetString(flagTitle)
|
||||
proposal.Description = viper.GetString(flagDescription)
|
||||
proposal.Type = viper.GetString(flagProposalType)
|
||||
proposal.Deposit = viper.GetString(flagDeposit)
|
||||
return proposal, nil
|
||||
}
|
||||
|
||||
for _, flag := range proposalFlags {
|
||||
if viper.GetString(flag) != "" {
|
||||
return nil, fmt.Errorf("--%s flag provided alongside --proposal, which is a noop", flag)
|
||||
}
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadFile(proposalFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(contents, proposal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return proposal, nil
|
||||
}
|
||||
|
||||
// GetCmdDeposit implements depositing tokens for an active proposal.
|
||||
func GetCmdDeposit(cdc *wire.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/spf13/viper"
|
||||
"io/ioutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseSubmitProposalFlags(t *testing.T) {
|
||||
okJSON, err := ioutil.TempFile("", "proposal")
|
||||
require.Nil(t, err, "unexpected error")
|
||||
okJSON.WriteString(`
|
||||
{
|
||||
"title": "Test Proposal",
|
||||
"description": "My awesome proposal",
|
||||
"type": "Text",
|
||||
"deposit": "1000test"
|
||||
}
|
||||
`)
|
||||
|
||||
badJSON, err := ioutil.TempFile("", "proposal")
|
||||
require.Nil(t, err, "unexpected error")
|
||||
badJSON.WriteString("bad json")
|
||||
|
||||
// nonexistent json
|
||||
viper.Set(flagProposal, "fileDoesNotExist")
|
||||
_, err = parseSubmitProposalFlags()
|
||||
require.Error(t, err)
|
||||
|
||||
// invalid json
|
||||
viper.Set(flagProposal, badJSON.Name())
|
||||
_, err = parseSubmitProposalFlags()
|
||||
require.Error(t, err)
|
||||
|
||||
// ok json
|
||||
viper.Set(flagProposal, okJSON.Name())
|
||||
proposal1, err := parseSubmitProposalFlags()
|
||||
require.Nil(t, err, "unexpected error")
|
||||
require.Equal(t, "Test Proposal", proposal1.Title)
|
||||
require.Equal(t, "My awesome proposal", proposal1.Description)
|
||||
require.Equal(t, "Text", proposal1.Type)
|
||||
require.Equal(t, "1000test", proposal1.Deposit)
|
||||
|
||||
// flags that can't be used with --proposal
|
||||
for _, incompatibleFlag := range proposalFlags {
|
||||
viper.Set(incompatibleFlag, "some value")
|
||||
_, err := parseSubmitProposalFlags()
|
||||
require.Error(t, err)
|
||||
viper.Set(incompatibleFlag, "")
|
||||
}
|
||||
|
||||
// no --proposal, only flags
|
||||
viper.Set(flagProposal, "")
|
||||
viper.Set(flagTitle, proposal1.Title)
|
||||
viper.Set(flagDescription, proposal1.Description)
|
||||
viper.Set(flagProposalType, proposal1.Type)
|
||||
viper.Set(flagDeposit, proposal1.Deposit)
|
||||
proposal2, err := parseSubmitProposalFlags()
|
||||
require.Nil(t, err, "unexpected error")
|
||||
require.Equal(t, proposal1.Title, proposal2.Title)
|
||||
require.Equal(t, proposal1.Description, proposal2.Description)
|
||||
require.Equal(t, proposal1.Type, proposal2.Type)
|
||||
require.Equal(t, proposal1.Deposit, proposal2.Deposit)
|
||||
|
||||
err = okJSON.Close()
|
||||
require.Nil(t, err, "unexpected error")
|
||||
err = badJSON.Close()
|
||||
require.Nil(t, err, "unexpected error")
|
||||
}
|
|
@ -3,7 +3,6 @@ package rest
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -17,10 +16,11 @@ import (
|
|||
// REST Variable names
|
||||
// nolint
|
||||
const (
|
||||
RestProposalID = "proposalID"
|
||||
RestProposalID = "proposal-id"
|
||||
RestDepositer = "depositer"
|
||||
RestVoter = "voter"
|
||||
RestProposalStatus = "status"
|
||||
RestNumLatest = "latest"
|
||||
storeName = "gov"
|
||||
)
|
||||
|
||||
|
@ -97,16 +97,13 @@ func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFu
|
|||
return
|
||||
}
|
||||
|
||||
proposalID, err := strconv.ParseInt(strProposalID, 10, 64)
|
||||
if err != nil {
|
||||
err := errors.Errorf("proposalID [%d] is not positive", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req depositReq
|
||||
err = buildReq(w, r, cdc, &req)
|
||||
err := buildReq(w, r, cdc, &req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -139,15 +136,13 @@ func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc
|
|||
return
|
||||
}
|
||||
|
||||
proposalID, err := strconv.ParseInt(strProposalID, 10, 64)
|
||||
if err != nil {
|
||||
err := errors.Errorf("proposalID [%d] is not positive", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req voteReq
|
||||
err = buildReq(w, r, cdc, &req)
|
||||
err := buildReq(w, r, cdc, &req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -180,36 +175,33 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
proposalID, err := strconv.ParseInt(strProposalID, 10, 64)
|
||||
if err != nil {
|
||||
err := errors.Errorf("proposalID [%d] is not positive", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
|
||||
if err != nil || len(res) == 0 {
|
||||
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
params := gov.QueryProposalParams{
|
||||
ProposalID: proposalID,
|
||||
}
|
||||
|
||||
var proposal gov.Proposal
|
||||
cdc.MustUnmarshalBinary(res, &proposal)
|
||||
|
||||
output, err := wire.MarshalJSONIndent(cdc, proposal)
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.QueryWithData("custom/gov/proposal", bz)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(output)
|
||||
w.Write(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,12 +219,8 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
proposalID, err := strconv.ParseInt(strProposalID, 10, 64)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err := errors.Errorf("proposalID [%d] is not positive", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -255,36 +243,43 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
res, err := cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName)
|
||||
if err != nil || len(res) == 0 {
|
||||
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
|
||||
if err != nil || len(res) == 0 {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
params := gov.QueryDepositParams{
|
||||
ProposalID: proposalID,
|
||||
Depositer: depositerAddr,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID)
|
||||
res, err := cliCtx.QueryWithData("custom/gov/deposit", bz)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var deposit gov.Deposit
|
||||
cdc.MustUnmarshalBinary(res, &deposit)
|
||||
|
||||
output, err := wire.MarshalJSONIndent(cdc, deposit)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
cdc.UnmarshalJSON(res, &deposit)
|
||||
if deposit.Empty() {
|
||||
res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(gov.QueryProposalParams{params.ProposalID}))
|
||||
if err != nil || len(res) == 0 {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(output)
|
||||
w.Write(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,12 +296,8 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
proposalID, err := strconv.ParseInt(strProposalID, 10, 64)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err := errors.Errorf("proposalID [%s] is not positive", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -328,36 +319,47 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
res, err := cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
|
||||
if err != nil || len(res) == 0 {
|
||||
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
|
||||
if err != nil || len(res) == 0 {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
params := gov.QueryVoteParams{
|
||||
Voter: voterAddr,
|
||||
ProposalID: proposalID,
|
||||
}
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
err = errors.Errorf("voter [%s] did not vote on proposalID [%d]", bechVoterAddr, proposalID)
|
||||
res, err := cliCtx.QueryWithData("custom/gov/vote", bz)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var vote gov.Vote
|
||||
cdc.MustUnmarshalBinary(res, &vote)
|
||||
|
||||
output, err := wire.MarshalJSONIndent(cdc, vote)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
cdc.UnmarshalJSON(res, &vote)
|
||||
if vote.Empty() {
|
||||
bz, err := cdc.MarshalJSON(gov.QueryProposalParams{params.ProposalID})
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
res, err := cliCtx.QueryWithData("custom/gov/proposal", bz)
|
||||
if err != nil || len(res) == 0 {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
err = errors.Errorf("voter [%s] did not deposit on proposalID [%d]", bechVoterAddr, proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(output)
|
||||
w.Write(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,59 +378,31 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
proposalID, err := strconv.ParseInt(strProposalID, 10, 64)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err := errors.Errorf("proposalID [%s] is not positive", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
|
||||
if err != nil || len(res) == 0 {
|
||||
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
params := gov.QueryVotesParams{
|
||||
ProposalID: proposalID,
|
||||
}
|
||||
|
||||
var proposal gov.Proposal
|
||||
cdc.MustUnmarshalBinary(res, &proposal)
|
||||
|
||||
if proposal.GetStatus() != gov.StatusVotingPeriod {
|
||||
err := errors.Errorf("proposal is not in Voting Period", proposalID)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
res2, err := cliCtx.QuerySubspace(gov.KeyVotesSubspace(proposalID), storeName)
|
||||
if err != nil {
|
||||
err = errors.New("ProposalID doesn't exist")
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
var votes []gov.Vote
|
||||
|
||||
for i := 0; i < len(res2); i++ {
|
||||
var vote gov.Vote
|
||||
cdc.MustUnmarshalBinary(res2[i].Value, &vote)
|
||||
votes = append(votes, vote)
|
||||
}
|
||||
|
||||
output, err := wire.MarshalJSONIndent(cdc, votes)
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(output)
|
||||
res, err := cliCtx.QueryWithData("custom/gov/votes", bz)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,24 +413,23 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
bechVoterAddr := r.URL.Query().Get(RestVoter)
|
||||
bechDepositerAddr := r.URL.Query().Get(RestDepositer)
|
||||
strProposalStatus := r.URL.Query().Get(RestProposalStatus)
|
||||
strNumLatest := r.URL.Query().Get(RestNumLatest)
|
||||
|
||||
var err error
|
||||
var voterAddr sdk.AccAddress
|
||||
var depositerAddr sdk.AccAddress
|
||||
var proposalStatus gov.ProposalStatus
|
||||
params := gov.QueryProposalsParams{}
|
||||
|
||||
if len(bechVoterAddr) != 0 {
|
||||
voterAddr, err = sdk.AccAddressFromBech32(bechVoterAddr)
|
||||
voterAddr, err := sdk.AccAddressFromBech32(bechVoterAddr)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
params.Voter = voterAddr
|
||||
}
|
||||
|
||||
if len(bechDepositerAddr) != 0 {
|
||||
depositerAddr, err = sdk.AccAddressFromBech32(bechDepositerAddr)
|
||||
depositerAddr, err := sdk.AccAddressFromBech32(bechDepositerAddr)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer)
|
||||
|
@ -464,10 +437,11 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
return
|
||||
}
|
||||
params.Depositer = depositerAddr
|
||||
}
|
||||
|
||||
if len(strProposalStatus) != 0 {
|
||||
proposalStatus, err = gov.ProposalStatusFromString(strProposalStatus)
|
||||
proposalStatus, err := gov.ProposalStatusFromString(strProposalStatus)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err := errors.Errorf("'%s' is not a valid Proposal Status", strProposalStatus)
|
||||
|
@ -475,63 +449,33 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
return
|
||||
}
|
||||
params.ProposalStatus = proposalStatus
|
||||
}
|
||||
if len(strNumLatest) != 0 {
|
||||
numLatest, ok := parseInt64OrReturnBadRequest(strNumLatest, w)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
params.NumLatestProposals = numLatest
|
||||
}
|
||||
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
res, err := cliCtx.QueryStore(gov.KeyNextProposalID, storeName)
|
||||
res, err := cliCtx.QueryWithData("custom/gov/proposals", bz)
|
||||
if err != nil {
|
||||
err = errors.New("no proposals exist yet and proposalID has not been set")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var maxProposalID int64
|
||||
cdc.MustUnmarshalBinary(res, &maxProposalID)
|
||||
|
||||
matchingProposals := []gov.Proposal{}
|
||||
|
||||
for proposalID := int64(0); proposalID < maxProposalID; proposalID++ {
|
||||
if voterAddr != nil {
|
||||
res, err = cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
|
||||
if err != nil || len(res) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if depositerAddr != nil {
|
||||
res, err = cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName)
|
||||
if err != nil || len(res) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
res, err = cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
|
||||
if err != nil || len(res) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var proposal gov.Proposal
|
||||
cdc.MustUnmarshalBinary(res, &proposal)
|
||||
|
||||
if len(strProposalStatus) != 0 {
|
||||
if proposal.GetStatus() != proposalStatus {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
matchingProposals = append(matchingProposals, proposal)
|
||||
}
|
||||
|
||||
output, err := wire.MarshalJSONIndent(cdc, matchingProposals)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(output)
|
||||
w.Write(res)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -100,3 +102,15 @@ func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq base
|
|||
|
||||
w.Write(output)
|
||||
}
|
||||
|
||||
func parseInt64OrReturnBadRequest(s string, w http.ResponseWriter) (n int64, ok bool) {
|
||||
var err error
|
||||
n, err = strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err := fmt.Errorf("'%s' is not a valid int64", s)
|
||||
w.Write([]byte(err.Error()))
|
||||
return 0, false
|
||||
}
|
||||
return n, true
|
||||
}
|
|
@ -15,6 +15,17 @@ type Vote struct {
|
|||
Option VoteOption `json:"option"` // option from OptionSet chosen by the voter
|
||||
}
|
||||
|
||||
// Returns whether 2 votes are equal
|
||||
func (voteA Vote) Equals(voteB Vote) bool {
|
||||
return voteA.Voter.Equals(voteB.Voter) && voteA.ProposalID == voteB.ProposalID && voteA.Option == voteB.Option
|
||||
}
|
||||
|
||||
// Returns whether a vote is empty
|
||||
func (voteA Vote) Empty() bool {
|
||||
voteB := Vote{}
|
||||
return voteA.Equals(voteB)
|
||||
}
|
||||
|
||||
// Deposit
|
||||
type Deposit struct {
|
||||
Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer
|
||||
|
@ -22,6 +33,17 @@ type Deposit struct {
|
|||
Amount sdk.Coins `json:"amount"` // Deposit amount
|
||||
}
|
||||
|
||||
// Returns whether 2 deposits are equal
|
||||
func (depositA Deposit) Equals(depositB Deposit) bool {
|
||||
return depositA.Depositer.Equals(depositB.Depositer) && depositA.ProposalID == depositB.ProposalID && depositA.Amount.IsEqual(depositB.Amount)
|
||||
}
|
||||
|
||||
// Returns whether a deposit is empty
|
||||
func (depositA Deposit) Empty() bool {
|
||||
depositB := Deposit{}
|
||||
return depositA.Equals(depositB)
|
||||
}
|
||||
|
||||
// Type that represents VoteOption as a byte
|
||||
type VoteOption byte
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue