Merge branch 'develop' into bianjie/lcd-lite-swagger-ui

This commit is contained in:
HaoyangLiu 2018-09-13 22:47:01 +08:00 committed by GitHub
commit 0c171ec761
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
176 changed files with 4251 additions and 2006 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
# Build
vendor
.vendor-new
build
tools/bin/*
examples/build/*

72
Gopkg.lock generated
View File

@ -1,6 +1,14 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
digest = "1:7736fc6da04620727f8f3aa2ced8d77be8e074a302820937aa5993848c769b27"
name = "github.com/ZondaX/hid-go"
packages = ["."]
pruneopts = "UT"
revision = "48b08affede2cea076a3cf13b2e3f72ed262b743"
[[projects]]
digest = "1:09a7f74eb6bb3c0f14d8926610c87f569c5cff68e978d30e9a3540aeb626fdf0"
name = "github.com/bartekn/go-bip39"
@ -26,15 +34,7 @@
[[projects]]
branch = "master"
digest = "1:70f6b224a59b2fa453debffa85c77f71063d8754b90c8c4fbad5794e2c382b0f"
name = "github.com/brejski/hid"
packages = ["."]
pruneopts = "UT"
revision = "06112dcfcc50a7e0e4fd06e17f9791e788fdaafc"
[[projects]]
branch = "master"
digest = "1:2c00f064ba355903866cbfbf3f7f4c0fe64af6638cc7d1b8bdcf3181bc67f1d8"
digest = "1:6aabc1566d6351115d561d038da82a4c19b46c3b6e17f4a0a2fa60260663dc79"
name = "github.com/btcsuite/btcd"
packages = ["btcec"]
pruneopts = "UT"
@ -71,7 +71,7 @@
version = "v1.4.7"
[[projects]]
digest = "1:fdf5169073fb0ad6dc12a70c249145e30f4058647bea25f0abd48b6d9f228a11"
digest = "1:fa30c0652956e159cdb97dcb2ef8b8db63ed668c02a5c3a40961c8f0641252fe"
name = "github.com/go-kit/kit"
packages = [
"log",
@ -103,7 +103,7 @@
version = "v1.7.0"
[[projects]]
digest = "1:35621fe20f140f05a0c4ef662c26c0ab4ee50bca78aa30fe87d33120bd28165e"
digest = "1:212285efb97b9ec2e20550d81f0446cb7897e57cbdfd7301b1363ab113d8be45"
name = "github.com/gogo/protobuf"
packages = [
"gogoproto",
@ -118,7 +118,7 @@
version = "v1.1.1"
[[projects]]
digest = "1:17fe264ee908afc795734e8c4e63db2accabaf57326dbf21763a7d6b86096260"
digest = "1:cb22af0ed7c72d495d8be1106233ee553898950f15fd3f5404406d44c2e86888"
name = "github.com/golang/protobuf"
packages = [
"proto",
@ -165,7 +165,7 @@
[[projects]]
branch = "master"
digest = "1:12247a2e99a060cc692f6680e5272c8adf0b8f572e6bce0d7095e624c958a240"
digest = "1:8951fe6e358876736d8fa1f3992624fdbb2dec6bc49401c1381d1ef8abbb544f"
name = "github.com/hashicorp/hcl"
packages = [
".",
@ -262,7 +262,7 @@
version = "v1.0.0"
[[projects]]
digest = "1:c1a04665f9613e082e1209cf288bf64f4068dcd6c87a64bf1c4ff006ad422ba0"
digest = "1:98225904b7abff96c052b669b25788f18225a36673fba022fb93514bb9a2a64e"
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
@ -273,7 +273,7 @@
[[projects]]
branch = "master"
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
digest = "1:0f37e09b3e92aaeda5991581311f8dbf38944b36a3edec61cc2d1991f527554a"
name = "github.com/prometheus/client_model"
packages = ["go"]
pruneopts = "UT"
@ -281,7 +281,7 @@
[[projects]]
branch = "master"
digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5"
digest = "1:dad2e5a2153ee7a6c9ab8fc13673a16ee4fb64434a7da980965a3741b0c981a3"
name = "github.com/prometheus/common"
packages = [
"expfmt",
@ -293,7 +293,7 @@
[[projects]]
branch = "master"
digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290"
digest = "1:a37c98f4b7a66bb5c539c0539f0915a74ef1c8e0b3b6f45735289d94cae92bfd"
name = "github.com/prometheus/procfs"
packages = [
".",
@ -320,7 +320,7 @@
revision = "e2704e165165ec55d062f5919b4b29494e9fa790"
[[projects]]
digest = "1:bd1ae00087d17c5a748660b8e89e1043e1e5479d0fea743352cda2f8dd8c4f84"
digest = "1:37ace7f35375adec11634126944bdc45a673415e2fcc07382d03b75ec76ea94c"
name = "github.com/spf13/afero"
packages = [
".",
@ -339,7 +339,7 @@
version = "v1.2.0"
[[projects]]
digest = "1:7ffc0983035bc7e297da3688d9fe19d60a420e9c38bef23f845c53788ed6a05e"
digest = "1:627ab2f549a6a55c44f46fa24a4307f4d0da81bfc7934ed0473bf38b24051d26"
name = "github.com/spf13/cobra"
packages = ["."]
pruneopts = "UT"
@ -371,7 +371,7 @@
version = "v1.0.0"
[[projects]]
digest = "1:7e8d267900c7fa7f35129a2a37596e38ed0f11ca746d6d9ba727980ee138f9f6"
digest = "1:73697231b93fb74a73ebd8384b68b9a60c57ea6b13c56d2425414566a72c8e6d"
name = "github.com/stretchr/testify"
packages = [
"assert",
@ -383,7 +383,7 @@
[[projects]]
branch = "master"
digest = "1:f2ffd421680b0a3f7887501b3c6974bcf19217ecd301d0e2c9b681940ec363d5"
digest = "1:442d2ffa75ffae302ce8800bf4144696b92bef02917923ea132ce2d39efe7d65"
name = "github.com/syndtr/goleveldb"
packages = [
"leveldb",
@ -404,7 +404,7 @@
[[projects]]
branch = "master"
digest = "1:087aaa7920e5d0bf79586feb57ce01c35c830396ab4392798112e8aae8c47722"
digest = "1:203b409c21115233a576f99e8f13d8e07ad82b25500491f7e1cca12588fb3232"
name = "github.com/tendermint/ed25519"
packages = [
".",
@ -423,15 +423,15 @@
version = "v0.12.0-rc0"
[[projects]]
digest = "1:d4a15d404afbf591e8be16fcda7f5ac87948d5c7531f9d909fd84cc730ab16e2"
digest = "1:53397098d6acb7613358683cc84ae59281a60c6033f0bff62fa8d3f279c6c430"
name = "github.com/tendermint/iavl"
packages = ["."]
pruneopts = "UT"
revision = "35f66e53d9b01e83b30de68b931f54b2477a94c9"
version = "v0.9.2"
revision = "3acc91fb8811db2c5409a855ae1f8e441fe98e2d"
version = "v0.11.0"
[[projects]]
digest = "1:4f15e95fe3888cc75dd34f407d6394cbc7fd3ff24920851b92b295f6a8b556e6"
digest = "1:963f6c04345ce36f900c1d6367200eebc3cc2db6ee632ff865ea8dcf64b748a0"
name = "github.com/tendermint/tendermint"
packages = [
"abci/client",
@ -498,7 +498,7 @@
version = "v0.23.1-rc0"
[[projects]]
digest = "1:bf6d9a827ea3cad964c2f863302e4f6823170d0b5ed16f72cf1184a7c615067e"
digest = "1:ad879bb8c71020a3f92f0c61f414d93eae1d5dc2f37023b6abaa3cc84b00165e"
name = "github.com/tendermint/tmlibs"
packages = ["cli"]
pruneopts = "UT"
@ -506,15 +506,16 @@
version = "v0.9.0"
[[projects]]
digest = "1:4dcb0dd65feecb068ce23a234d1a07c7868a1e39f52a6defcae0bb371d03abf6"
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"
name = "github.com/zondax/ledger-goclient"
packages = ["."]
pruneopts = "UT"
revision = "4296ee5701e945f9b3a7dbe51f402e0b9be57259"
revision = "58598458c11bc0ad1c1b8dac3dc3e11eaf270b79"
version = "v0.1.0"
[[projects]]
branch = "master"
digest = "1:27507554c6d4f060d8d700c31c624a43d3a92baa634e178ddc044bdf7d13b44a"
digest = "1:2a3ce1f08dcae8bac666deb6e4c88b5d7170c510da38fd746231144cac351704"
name = "golang.org/x/crypto"
packages = [
"blowfish",
@ -536,7 +537,7 @@
revision = "614d502a4dac94afa3a6ce146bd1736da82514c6"
[[projects]]
digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1"
digest = "1:04dda8391c3e2397daf254ac68003f30141c069b228d06baec8324a5f81dc1e9"
name = "golang.org/x/net"
packages = [
"context",
@ -553,17 +554,17 @@
[[projects]]
branch = "master"
digest = "1:86171d21d59449dcf7cee0b7d2da83dff989dab9b9b69bfe0a3d59c3c1ca6081"
digest = "1:9d9e5fc87553258c36ee18d38023587edd61e4b2521f4473da34b47a83a492e5"
name = "golang.org/x/sys"
packages = [
"cpu",
"unix",
]
pruneopts = "UT"
revision = "11551d06cbcc94edc80a0facaccbda56473c19c1"
revision = "4ea2f632f6e912459fe60b26b1749377f0d889d5"
[[projects]]
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
digest = "1:7509ba4347d1f8de6ae9be8818b0cd1abc3deeffe28aeaf4be6d4b6b5178d9ca"
name = "golang.org/x/text"
packages = [
"collate",
@ -594,7 +595,7 @@
revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4"
[[projects]]
digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74"
digest = "1:4515e3030c440845b046354fd5d57671238428b820deebce2e9dabb5cd3c51ac"
name = "google.golang.org/grpc"
packages = [
".",
@ -687,7 +688,6 @@
"github.com/tendermint/tmlibs/cli",
"github.com/zondax/ledger-goclient",
"golang.org/x/crypto/blowfish",
"golang.org/x/crypto/ripemd160",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -53,7 +53,7 @@
[[override]]
name = "github.com/tendermint/iavl"
version = "=v0.9.2"
version = "=v0.11.0"
[[override]]
name = "github.com/tendermint/tendermint"
@ -65,7 +65,7 @@
[[constraint]]
name = "github.com/zondax/ledger-goclient"
revision = "4296ee5701e945f9b3a7dbe51f402e0b9be57259"
version = "=v0.1.0"
[[constraint]]
name = "github.com/rakyll/statik"

View File

@ -160,11 +160,22 @@ test_sim_gaia_nondeterminism:
test_sim_gaia_fast:
@echo "Running quick Gaia simulation. This may take several minutes..."
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=50 -v -timeout 24h
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=400 -SimulationBlockSize=200 -SimulationCommit=true -v -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
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=1000 -SimulationVerbose=true -SimulationCommit=true -v -timeout 24h
SIM_NUM_BLOCKS ?= 210
SIM_BLOCK_SIZE ?= 200
SIM_COMMIT ?= true
test_sim_gaia_benchmark:
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ -SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h
test_sim_gaia_profile:
@echo "Running Gaia benchmark for numBlocks=$(SIM_NUM_BLOCKS), blockSize=$(SIM_BLOCK_SIZE). This may take awhile!"
@go test -benchmem -run=^$$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$$ -SimulationEnabled=true -SimulationNumBlocks=$(SIM_NUM_BLOCKS) -SimulationBlockSize=$(SIM_BLOCK_SIZE) -SimulationCommit=$(SIM_COMMIT) -timeout 24h -cpuprofile cpu.out -memprofile mem.out
test_cover:
@bash tests/test_cover.sh

View File

@ -8,58 +8,76 @@ BREAKING CHANGES
* 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
* [cli] [\#1983](https://github.com/cosmos/cosmos-sdk/issues/1983) --print-response now defaults to true in commands that create and send a transaction
* [cli] [\#1983](https://github.com/cosmos/cosmos-sdk/issues/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](https://github.com/cosmos/cosmos-sdk/issues/2061) changed proposalID in governance REST endpoints to proposal-id
* [cli] [\#2014](https://github.com/cosmos/cosmos-sdk/issues/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
* [makefile] `get_vendor_deps` no longer updates lock file it just updates vendor directory. Use `update_vendor_deps` to update the lock file. [#2152](https://github.com/cosmos/cosmos-sdk/pull/2152)
* [cli] \#2190 `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion
* \#2040 All commands that utilize a validator's address must now use the new
bech32 prefix, `cosmosval`. A validator's Tendermint signing key and address
now use a new bech32 prefix, `cosmoscons`.
* [cli] [\#2221](https://github.com/cosmos/cosmos-sdk/issues/2221) All commands that
utilize a validator's operator address must now use the new Bech32 prefix,
`cosmosvaloper`.
* [cli] [\#2190](https://github.com/cosmos/cosmos-sdk/issues/2190) `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion
* 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.
* [x/stake] [\#1901](https://github.com/cosmos/cosmos-sdk/issues/1901) Validator type's Owner field renamed to Operator; Validator's GetOwner() renamed accordingly to comply with the SDK's Validator interface.
* [docs] [#2001](https://github.com/cosmos/cosmos-sdk/pull/2001) Update slashing spec for slashing period
* [x/stake, x/slashing] [#1305](https://github.com/cosmos/cosmos-sdk/issues/1305) - Rename "revoked" to "jailed"
* [x/stake] [#1676] Revoked and jailed validators put into the unbonding state
* [x/stake] [#1877] Redelegations/unbonding-delegation from unbonding validator have reduced time
* [x/stake] \#2040 Validator operator type has now changed to `sdk.ValAddress`
* A new bech32 prefix has been introduced for Tendermint signing keys and
addresses, `cosmosconspub` and `cosmoscons` respectively.
* [x/stake] [\#2040](https://github.com/cosmos/cosmos-sdk/issues/2040) Validator
operator type has now changed to `sdk.ValAddress`
* [x/stake] [\#2221](https://github.com/cosmos/cosmos-sdk/issues/2221) New
Bech32 prefixes have been introduced for a validator's consensus address and
public key: `cosmosvalcons` and `cosmosvalconspub` respectively. Also, existing Bech32 prefixes have been
renamed for accounts and validator operators:
* `cosmosaccaddr` / `cosmosaccpub` => `cosmos` / `cosmospub`
* `cosmosvaladdr` / `cosmosvalpub` => `cosmosvaloper` / `cosmosvaloperpub`
* [x/stake] [#1013] TendermintUpdates now uses transient store
* SDK
* [core] \#1807 Switch from use of rational to decimal
* [types] \#1901 Validator interface's GetOwner() renamed to GetOperator()
* [core] [\#1807](https://github.com/cosmos/cosmos-sdk/issues/1807) Switch from use of rational to decimal
* [types] [\#1901](https://github.com/cosmos/cosmos-sdk/issues/1901) Validator interface's GetOwner() renamed to GetOperator()
* [x/slashing] [#2122](https://github.com/cosmos/cosmos-sdk/pull/2122) - Implement slashing period
* [types] \#2119 Parsed error messages and ABCI log errors to make them more human readable.
* [types] [\#2119](https://github.com/cosmos/cosmos-sdk/issues/2119) Parsed error messages and ABCI log errors to make them more human readable.
* [simulation] Rename TestAndRunTx to Operation [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
* [simulation] Remove log and testing.TB from Operation and Invariants, in favor of using errors \#2282
* [tools] Removed gocyclo [#2211](https://github.com/cosmos/cosmos-sdk/issues/2211)
* [baseapp] Remove `SetTxDecoder` in favor of requiring the decoder be set in baseapp initialization. [#1441](https://github.com/cosmos/cosmos-sdk/issues/1441)
* [store] Change storeInfo within the root multistore to use tmhash instead of ripemd160 \#2308
* Tendermint
FEATURES
* Gaia REST API (`gaiacli advanced rest-server`)
* [lcd] Endpoints to query staking pool and params
* [lcd] \#2110 Add support for `simulate=true` requests query argument to endpoints that send txs to run simulations of transactions
* [gaia-lite] Endpoints to query staking pool and params
* [gaia-lite] [\#2110](https://github.com/cosmos/cosmos-sdk/issues/2110) Add support for `simulate=true` requests query argument to endpoints that send txs to run simulations of transactions
* [gaia-lite] [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add support for `generate_only=true` query argument to generate offline unsigned transactions
* [gaia-lite] [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) Add /sign endpoint to sign transactions generated with `generate_only=true`.
* [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint.
* 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
* \#2040 Add `--bech` to `gaiacli keys show` and respective REST endpoint to
* [\#2040](https://github.com/cosmos/cosmos-sdk/issues/2040) Add `--bech` to `gaiacli keys show` and respective REST endpoint to
provide desired Bech32 prefix encoding
* [cli] \#2047 Setting the --gas flag value to 0 triggers a simulation of the tx before the actual execution. The gas estimate obtained via the simulation will be used as gas limit in the actual execution.
* [cli] \#2047 The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0.
* [cli] \#2110 Add --dry-run flag to perform a simulation of a transaction without broadcasting it. The --gas flag is ignored as gas would be automatically estimated.
* [cli] [\#2047](https://github.com/cosmos/cosmos-sdk/issues/2047) [\#2306](https://github.com/cosmos/cosmos-sdk/pull/2306) Passing --gas=simulate triggers a simulation of the tx before the actual execution.
The gas estimate obtained via the simulation will be used as gas limit in the actual execution.
* [cli] [\#2047](https://github.com/cosmos/cosmos-sdk/issues/2047) The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=simulate.
* [cli] [\#2110](https://github.com/cosmos/cosmos-sdk/issues/2110) Add --dry-run flag to perform a simulation of a transaction without broadcasting it. The --gas flag is ignored as gas would be automatically estimated.
* [cli] [\#2204](https://github.com/cosmos/cosmos-sdk/issues/2204) Support generating and broadcasting messages with multiple signatures via command line:
* [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add --generate-only flag to build an unsigned transaction and write it to STDOUT.
* [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) New `sign` command to sign transactions generated with the --generate-only flag.
* [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) New `broadcast` command to broadcast transactions generated offline and signed with the `sign` command.
* Gaia
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
* SDK
* [querier] added custom querier functionality, so ABCI query requests can be handled by keepers
* [simulation] \#1924 allow operations to specify future operations
* [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) allow operations to specify future operations
* [simulation] [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) Add benchmarking capabilities, with makefile commands "test_sim_gaia_benchmark, test_sim_gaia_profile"
* Tendermint
@ -69,7 +87,7 @@ IMPROVEMENTS
* [tools] Added ansible script to enable process core dumps
* Gaia REST API (`gaiacli advanced rest-server`)
* [x/stake] \#2000 Added tests for new staking endpoints
* [x/stake] [\#2000](https://github.com/cosmos/cosmos-sdk/issues/2000) Added tests for new staking endpoints
* Gaia CLI (`gaiacli`)
* [cli] #2060 removed `--select` from `block` command
@ -79,12 +97,21 @@ IMPROVEMENTS
* [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)
* [x/stake] [x/slashing] Ensure delegation invariants to jailed validators [#1883](https://github.com/cosmos/cosmos-sdk/issues/1883).
* [x/stake] Improve speed of GetValidator, which was shown to be a performance bottleneck. [#2046](https://github.com/tendermint/tendermint/pull/2200)
* [genesis] \#2229 Ensure that there are no duplicate accounts or validators in the genesis state.
* Add SDK validation to `config.toml` (namely disabling `create_empty_blocks`) \#1571
* SDK
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
* [cli] \#1632 Add integration tests to ensure `basecoind init && basecoind` start sequences run successfully for both `democoin` and `basecoin` examples.
* [spec] Added simple piggy bank distribution spec
* [cli] [\#1632](https://github.com/cosmos/cosmos-sdk/issues/1632) Add integration tests to ensure `basecoind init && basecoind` start sequences run successfully for both `democoin` and `basecoin` examples.
* [store] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)
* [store] \#1952, \#2281 Update IAVL dependency to v0.11.0
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
* [simulation] Make logs not just pure strings, speeding it up by a large factor at greater block heights \#2282
* [simulation] Add a concept of weighting the operations \#2303
* [simulation] Logs get written to file if large, and also get printed on panics \#2285
* [gaiad] \#1992 Add optional flag to `gaiad testnet` to make config directory of daemon (default `gaiad`) and cli (default `gaiacli`) configurable
* Tendermint
@ -93,15 +120,19 @@ BUG FIXES
* Gaia REST API (`gaiacli advanced rest-server`)
* Gaia CLI (`gaiacli`)
* [cli] \#1997 Handle panics gracefully when `gaiacli stake {delegation,unbond}` fail to unmarshal delegation.
* [cli] [\#1997](https://github.com/cosmos/cosmos-sdk/issues/1997) Handle panics gracefully when `gaiacli stake {delegation,unbond}` fail to unmarshal delegation.
* [cli] [\#2265](https://github.com/cosmos/cosmos-sdk/issues/2265) Fix JSON formatting of the `gaiacli send` command.
* Gaia
* [x/stake] Return correct Tendermint validator update set on `EndBlocker` by not
including non previously bonded validators that have zero power. [#2189](https://github.com/cosmos/cosmos-sdk/issues/2189)
* 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.
* [ledger] \#2064 Fix inability to sign and send transactions via the LCD by
* [\#1988](https://github.com/cosmos/cosmos-sdk/issues/1988) Make us compile on OpenBSD (disable ledger) [#1988] (https://github.com/cosmos/cosmos-sdk/issues/1988)
* [\#2105](https://github.com/cosmos/cosmos-sdk/issues/2105) Fix DB Iterator leak, which may leak a go routine.
* [ledger] [\#2064](https://github.com/cosmos/cosmos-sdk/issues/2064) Fix inability to sign and send transactions via the LCD by
loading a Ledger device at runtime.
* \#2158 Fix non-deterministic ordering of validator iteration when slashing in `gov EndBlocker`
* [\#2158](https://github.com/cosmos/cosmos-sdk/issues/2158) Fix non-deterministic ordering of validator iteration when slashing in `gov EndBlocker`
* [simulation] \#1924 Make simulation stop on SIGTERM
* Tendermint

View File

@ -120,13 +120,20 @@ func (app *BaseApp) RegisterCodespace(codespace sdk.CodespaceType) sdk.Codespace
return app.codespacer.RegisterNext(codespace)
}
// Mount a store to the provided key in the BaseApp multistore
// Mount IAVL stores to the provided keys in the BaseApp multistore
func (app *BaseApp) MountStoresIAVL(keys ...*sdk.KVStoreKey) {
for _, key := range keys {
app.MountStore(key, sdk.StoreTypeIAVL)
}
}
// Mount stores to the provided keys in the BaseApp multistore
func (app *BaseApp) MountStoresTransient(keys ...*sdk.TransientStoreKey) {
for _, key := range keys {
app.MountStore(key, sdk.StoreTypeTransient)
}
}
// Mount a store to the provided key in the BaseApp multistore, using a specified DB
func (app *BaseApp) MountStoreWithDB(key sdk.StoreKey, typ sdk.StoreType, db dbm.DB) {
app.cms.MountStoreWithDB(key, typ, db)
@ -345,6 +352,7 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) (res a
return queryable.Query(req)
}
// nolint: unparam
func handleQueryP2P(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) {
// "/p2p" prefix for p2p queries
if len(path) >= 4 {

View File

@ -626,12 +626,12 @@ func TestSimulateTx(t *testing.T) {
// simulate a message, check gas reported
result := app.Simulate(tx)
require.True(t, result.IsOK(), result.Log)
require.Equal(t, int64(gasConsumed), result.GasUsed)
require.Equal(t, gasConsumed, result.GasUsed)
// simulate again, same result
result = app.Simulate(tx)
require.True(t, result.IsOK(), result.Log)
require.Equal(t, int64(gasConsumed), result.GasUsed)
require.Equal(t, gasConsumed, result.GasUsed)
// simulate by calling Query with encoded tx
txBytes, err := codec.MarshalBinary(tx)

View File

@ -26,12 +26,6 @@ func (app *BaseApp) SetCMS(cms store.CommitMultiStore) {
}
app.cms = cms
}
func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) {
if app.sealed {
panic("SetTxDecoder() on sealed BaseApp")
}
app.txDecoder = txDecoder
}
func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) {
if app.sealed {
panic("SetInitChainer() on sealed BaseApp")

View File

@ -3,10 +3,11 @@ package context
import (
"bytes"
"fmt"
"io"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"io"
"github.com/spf13/viper"
@ -26,8 +27,6 @@ type CLIContext struct {
Client rpcclient.Client
Logger io.Writer
Height int64
Gas int64
GasAdjustment float64
NodeURI string
FromAddressName string
AccountStore string
@ -38,6 +37,7 @@ type CLIContext struct {
PrintResponse bool
Certifier tmlite.Certifier
DryRun bool
GenerateOnly bool
}
// NewCLIContext returns a new initialized CLIContext with parameters from the
@ -56,8 +56,6 @@ func NewCLIContext() CLIContext {
AccountStore: ctxAccStoreName,
FromAddressName: viper.GetString(client.FlagFrom),
Height: viper.GetInt64(client.FlagHeight),
Gas: viper.GetInt64(client.FlagGas),
GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment),
TrustNode: viper.GetBool(client.FlagTrustNode),
UseLedger: viper.GetBool(client.FlagUseLedger),
Async: viper.GetBool(client.FlagAsync),
@ -65,6 +63,7 @@ func NewCLIContext() CLIContext {
PrintResponse: viper.GetBool(client.FlagPrintResponse),
Certifier: createCertifier(),
DryRun: viper.GetBool(client.FlagDryRun),
GenerateOnly: viper.GetBool(client.FlagGenerateOnly),
}
}
@ -161,9 +160,3 @@ func (ctx CLIContext) WithCertifier(certifier tmlite.Certifier) CLIContext {
ctx.Certifier = certifier
return ctx
}
// WithGasAdjustment returns a copy of the context with an updated GasAdjustment flag.
func (ctx CLIContext) WithGasAdjustment(adjustment float64) CLIContext {
ctx.GasAdjustment = adjustment
return ctx
}

View File

@ -10,6 +10,8 @@ import (
"github.com/pkg/errors"
"strings"
"github.com/cosmos/cosmos-sdk/store"
"github.com/cosmos/cosmos-sdk/wire"
abci "github.com/tendermint/tendermint/abci/types"
@ -17,7 +19,6 @@ import (
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"strings"
)
// GetNode returns an RPC client. If the context's client is not defined, an
@ -270,11 +271,11 @@ func (ctx CLIContext) ensureBroadcastTx(txBytes []byte) error {
type toJSON struct {
Height int64
TxHash string
Response string
Response abci.ResponseDeliverTx
}
if ctx.Logger != nil {
resJSON := toJSON{res.Height, res.Hash.String(), fmt.Sprintf("%+v", res.DeliverTx)}
resJSON := toJSON{res.Height, res.Hash.String(), res.DeliverTx}
bz, err := ctx.Codec.MarshalJSON(resJSON)
if err != nil {
return err
@ -339,6 +340,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
}
// verifyProof perform response proof verification
// nolint: unparam
func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
if ctx.Certifier == nil {

View File

@ -1,6 +1,11 @@
package client
import "github.com/spf13/cobra"
import (
"fmt"
"strconv"
"github.com/spf13/cobra"
)
// nolint
const (
@ -9,6 +14,7 @@ const (
// occur between the tx simulation and the actual run.
DefaultGasAdjustment = 1.0
DefaultGasLimit = 200000
GasFlagSimulate = "simulate"
FlagUseLedger = "ledger"
FlagChainID = "chain-id"
@ -27,11 +33,15 @@ const (
FlagJson = "json"
FlagPrintResponse = "print-response"
FlagDryRun = "dry-run"
FlagGenerateOnly = "generate-only"
)
// LineBreak can be included in a command list to provide a blank line
// to help with readability
var LineBreak = &cobra.Command{Run: func(*cobra.Command, []string) {}}
var (
LineBreak = &cobra.Command{Run: func(*cobra.Command, []string) {}}
GasFlagVar = GasSetting{Gas: DefaultGasLimit}
)
// GetCommands adds common flags to query commands
func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
@ -57,13 +67,57 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device")
c.Flags().Int64(FlagGas, DefaultGasLimit, "gas limit to set per-transaction; set to 0 to calculate required gas automatically")
c.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ")
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
c.Flags().Bool(FlagJson, false, "return output in json format")
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for query responses")
c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
c.Flags().Bool(FlagGenerateOnly, false, "build an unsigned transaction and write it to STDOUT")
// --gas can accept integers and "simulate"
c.Flags().Var(&GasFlagVar, "gas", fmt.Sprintf(
"gas limit to set per-transaction; set to %q to calculate required gas automatically (default %d)", GasFlagSimulate, DefaultGasLimit))
}
return cmds
}
// Gas flag parsing functions
// GasSetting encapsulates the possible values passed through the --gas flag.
type GasSetting struct {
Simulate bool
Gas int64
}
// Type returns the flag's value type.
func (v *GasSetting) Type() string { return "string" }
// Set parses and sets the value of the --gas flag.
func (v *GasSetting) Set(s string) (err error) {
v.Simulate, v.Gas, err = ReadGasFlag(s)
return
}
func (v *GasSetting) String() string {
if v.Simulate {
return GasFlagSimulate
}
return strconv.FormatInt(v.Gas, 10)
}
// ParseGasFlag parses the value of the --gas flag.
func ReadGasFlag(s string) (simulate bool, gas int64, err error) {
switch s {
case "":
gas = DefaultGasLimit
case GasFlagSimulate:
simulate = true
default:
gas, err = strconv.ParseInt(s, 10, 64)
if err != nil {
err = fmt.Errorf("gas must be either integer or %q", GasFlagSimulate)
return
}
}
return
}

View File

@ -24,7 +24,7 @@ func BufferStdin() *bufio.Reader {
// It enforces the password length
func GetPassword(prompt string, buf *bufio.Reader) (pass string, err error) {
if inputIsTty() {
pass, err = speakeasy.Ask(prompt)
pass, err = speakeasy.FAsk(os.Stderr, prompt)
} else {
pass, err = readLineFromBuf(buf)
}

View File

@ -4,9 +4,7 @@ import (
"fmt"
"net/http"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -18,7 +16,7 @@ const (
FlagAddress = "address"
// FlagPublicKey represents the user's public key on the command line.
FlagPublicKey = "pubkey"
// FlagBechPrefix defines a desired Bech32 prefix encoding for a key
// FlagBechPrefix defines a desired Bech32 prefix encoding for a key.
FlagBechPrefix = "bech"
)
@ -28,39 +26,7 @@ func showKeysCmd() *cobra.Command {
Short: "Show key info for the given name",
Long: `Return public details of one local key.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
info, err := getKey(name)
if err != nil {
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")
}
bechKeyOut, err := getBechKeyOut(viper.GetString(FlagBechPrefix))
if err != nil {
return err
}
switch {
case showAddress:
printKeyAddress(info, bechKeyOut)
case showPublicKey:
printPubKey(info, bechKeyOut)
default:
printKeyInfo(info, bechKeyOut)
}
return nil
},
RunE: runShowCmd,
}
cmd.Flags().String(FlagBechPrefix, "acc", "The Bech32 prefix encoding for a key (acc|val|cons)")
@ -70,6 +36,43 @@ func showKeysCmd() *cobra.Command {
return cmd
}
func runShowCmd(cmd *cobra.Command, args []string) error {
name := args[0]
info, err := GetKeyInfo(name)
if err != nil {
return err
}
isShowAddr := viper.GetBool(FlagAddress)
isShowPubKey := viper.GetBool(FlagPublicKey)
isOutputSet := cmd.Flag(cli.OutputFlag).Changed
if isShowAddr && isShowPubKey {
return errors.New("cannot use both --address and --pubkey at once")
}
if isOutputSet && (isShowAddr || isShowPubKey) {
return errors.New("cannot use --output with --address or --pubkey")
}
bechKeyOut, err := getBechKeyOut(viper.GetString(FlagBechPrefix))
if err != nil {
return err
}
switch {
case isShowAddr:
printKeyAddress(info, bechKeyOut)
case isShowPubKey:
printPubKey(info, bechKeyOut)
default:
printKeyInfo(info, bechKeyOut)
}
return nil
}
func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) {
switch bechPrefix {
case "acc":
@ -83,15 +86,6 @@ func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) {
return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix)
}
func getKey(name string) (keys.Info, error) {
kb, err := GetKeyBase()
if err != nil {
return nil, err
}
return kb.Get(name)
}
///////////////////////////
// REST
@ -112,7 +106,7 @@ func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
return
}
info, err := getKey(name)
info, err := GetKeyInfo(name)
// TODO: check for the error if key actually does not exist, instead of
// assuming this as the reason
if err != nil {

View File

@ -26,6 +26,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/stake"
@ -207,8 +208,8 @@ func TestValidators(t *testing.T) {
require.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
require.Contains(t, resultVals.Validators[0].Address.String(), "cosmosval")
require.Contains(t, resultVals.Validators[0].PubKey, "cosmosconspub")
require.Contains(t, resultVals.Validators[0].Address.String(), "cosmosvaloper")
require.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalconspub")
// --
@ -268,21 +269,29 @@ func TestCoinSend(t *testing.T) {
require.Equal(t, int64(1), mycoins.Amount.Int64())
// test failure with too little gas
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 100, 0, "")
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, "100", 0, "")
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
// test failure with negative gas
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, "-200", 0, "")
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
// test failure with 0 gas
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, "0", 0, "")
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
// test failure with wrong adjustment
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, 0.1, "")
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, "simulate", 0.1, "")
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
// run simulation and test success with estimated gas
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, 0, "?simulate=true")
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, "", 0, "?simulate=true")
require.Equal(t, http.StatusOK, res.StatusCode, body)
var responseBody struct {
GasEstimate int64 `json:"gas_estimate"`
}
require.Nil(t, json.Unmarshal([]byte(body), &responseBody))
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, responseBody.GasEstimate, 0, "")
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, fmt.Sprintf("%v", responseBody.GasEstimate), 0, "")
require.Equal(t, http.StatusOK, res.StatusCode, body)
}
@ -315,6 +324,65 @@ func TestIBCTransfer(t *testing.T) {
// TODO: query ibc egress packet state
}
func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()
acc := getAccount(t, port, addr)
// generate TX
res, body, _ := doSendWithGas(t, port, seed, name, password, addr, "simulate", 0, "?generate_only=true")
require.Equal(t, http.StatusOK, res.StatusCode, body)
var msg auth.StdTx
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &msg))
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, msg.Msgs[0].Type(), "bank")
require.Equal(t, msg.Msgs[0].GetSigners(), []sdk.AccAddress{addr})
require.Equal(t, 0, len(msg.Signatures))
gasEstimate := msg.Fee.Gas
// sign tx
var signedMsg auth.StdTx
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
payload := authrest.SignBody{
Tx: msg,
LocalAccountName: name,
Password: password,
ChainID: viper.GetString(client.FlagChainID),
AccountNumber: accnum,
Sequence: sequence,
}
json, err := cdc.MarshalJSON(payload)
require.Nil(t, err)
res, body = Request(t, port, "POST", "/tx/sign", json)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &signedMsg))
require.Equal(t, len(msg.Msgs), len(signedMsg.Msgs))
require.Equal(t, msg.Msgs[0].Type(), signedMsg.Msgs[0].Type())
require.Equal(t, msg.Msgs[0].GetSigners(), signedMsg.Msgs[0].GetSigners())
require.Equal(t, 1, len(signedMsg.Signatures))
// broadcast tx
broadcastPayload := struct {
Tx auth.StdTx `json:"tx"`
}{Tx: signedMsg}
json, err = cdc.MarshalJSON(broadcastPayload)
require.Nil(t, err)
res, body = Request(t, port, "POST", "/tx/broadcast", json)
require.Equal(t, http.StatusOK, res.StatusCode, body)
// check if tx was committed
var resultTx ctypes.ResultBroadcastTxCommit
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &resultTx))
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
require.Equal(t, gasEstimate, resultTx.DeliverTx.GasWanted)
require.Equal(t, gasEstimate, resultTx.DeliverTx.GasUsed)
}
func TestTxs(t *testing.T) {
name, password := "test", "1234567890"
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
@ -420,11 +488,12 @@ func TestValidatorsQuery(t *testing.T) {
// make sure all the validators were found (order unknown because sorted by operator addr)
foundVal := false
pkBech := sdk.MustBech32ifyConsPub(pks[0])
if validators[0].PubKey == pkBech {
if validators[0].ConsPubKey == pks[0] {
foundVal = true
}
require.True(t, foundVal, "pkBech %v, operator %v", pkBech, validators[0].Operator)
require.True(t, foundVal, "pk %v, operator %v", pks[0], validators[0].OperatorAddr)
}
func TestValidatorQuery(t *testing.T) {
@ -434,7 +503,7 @@ func TestValidatorQuery(t *testing.T) {
validator1Operator := sdk.ValAddress(pks[0].Address())
validator := getValidator(t, port, validator1Operator)
assert.Equal(t, validator.Operator, validator1Operator, "The returned validator does not hold the correct data")
assert.Equal(t, validator.OperatorAddr, validator1Operator, "The returned validator does not hold the correct data")
}
func TestBonding(t *testing.T) {
@ -470,11 +539,11 @@ func TestBonding(t *testing.T) {
bondedValidators := getDelegatorValidators(t, port, addr)
require.Len(t, bondedValidators, 1)
require.Equal(t, validator1Operator, bondedValidators[0].Operator)
require.Equal(t, validator1Operator, bondedValidators[0].OperatorAddr)
require.Equal(t, validator.DelegatorShares.Add(sdk.NewDec(60)).String(), bondedValidators[0].DelegatorShares.String())
bondedValidator := getDelegatorValidator(t, port, addr, validator1Operator)
require.Equal(t, validator1Operator, bondedValidator.Operator)
require.Equal(t, validator1Operator, bondedValidator.OperatorAddr)
//////////////////////
// testing unbonding
@ -733,7 +802,7 @@ func getAccount(t *testing.T, port string, addr sdk.AccAddress) auth.Account {
return acc
}
func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas int64, gasAdjustment float64, queryStr string) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas string, gasAdjustment float64, queryStr string) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
// create receive address
kb := client.MockKeyBase()
@ -752,14 +821,14 @@ func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.Acc
}
gasStr := ""
if gas > 0 {
if len(gas) != 0 {
gasStr = fmt.Sprintf(`
"gas":"%v",
"gas":%q,
`, gas)
}
gasAdjustmentStr := ""
if gasAdjustment > 0 {
gasStr = fmt.Sprintf(`
gasAdjustmentStr = fmt.Sprintf(`
"gas_adjustment":"%v",
`, gasAdjustment)
}
@ -778,7 +847,7 @@ func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.Acc
}
func doSend(t *testing.T, port, seed, name, password string, addr sdk.AccAddress) (receiveAddr sdk.AccAddress, resultTx ctypes.ResultBroadcastTxCommit) {
res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, 0, 0, "")
res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, "", 0, "")
require.Equal(t, http.StatusOK, res.StatusCode, body)
err := cdc.UnmarshalJSON([]byte(body), &resultTx)
@ -900,11 +969,11 @@ func getBondingTxs(t *testing.T, port string, delegatorAddr sdk.AccAddress, quer
return txs
}
func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddress) []stake.BechValidator {
func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddress) []stake.Validator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators", delegatorAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bondedValidators []stake.BechValidator
var bondedValidators []stake.Validator
err := cdc.UnmarshalJSON([]byte(body), &bondedValidators)
require.Nil(t, err)
@ -912,11 +981,11 @@ func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddr
return bondedValidators
}
func getDelegatorValidator(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) stake.BechValidator {
func getDelegatorValidator(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) stake.Validator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delAddr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bondedValidator stake.BechValidator
var bondedValidator stake.Validator
err := cdc.UnmarshalJSON([]byte(body), &bondedValidator)
require.Nil(t, err)
@ -1036,19 +1105,19 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string,
return results[0]
}
func getValidators(t *testing.T, port string) []stake.BechValidator {
func getValidators(t *testing.T, port string) []stake.Validator {
res, body := Request(t, port, "GET", "/stake/validators", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var validators []stake.BechValidator
var validators []stake.Validator
err := cdc.UnmarshalJSON([]byte(body), &validators)
require.Nil(t, err)
return validators
}
func getValidator(t *testing.T, port string, valAddr sdk.ValAddress) stake.BechValidator {
func getValidator(t *testing.T, port string, valAddr sdk.ValAddress) stake.Validator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", valAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var validator stake.BechValidator
var validator stake.Validator
err := cdc.UnmarshalJSON([]byte(body), &validator)
require.Nil(t, err)
return validator

View File

@ -151,7 +151,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
var validatorsPKs []crypto.PubKey
// NOTE: It's bad practice to reuse public key address for the owner
// NOTE: It's bad practice to reuse public key address for the operator
// address but doing in the test for simplicity.
var appGenTxs []json.RawMessage
for _, gdValidator := range genDoc.Validators {

View File

@ -3,11 +3,17 @@ package utils
import (
"fmt"
"net/http"
"net/url"
"strconv"
sdk "github.com/cosmos/cosmos-sdk/types"
auth "github.com/cosmos/cosmos-sdk/x/auth"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
const (
queryArgDryRun = "simulate"
queryArgDryRun = "simulate"
queryArgGenerateOnly = "generate_only"
)
// WriteErrorResponse prepares and writes a HTTP error
@ -26,9 +32,10 @@ func WriteSimulationResponse(w http.ResponseWriter, gas int64) {
// HasDryRunArg returns true if the request's URL query contains
// the dry run argument and its value is set to "true".
func HasDryRunArg(r *http.Request) bool {
return r.URL.Query().Get(queryArgDryRun) == "true"
}
func HasDryRunArg(r *http.Request) bool { return urlQueryHasArg(r.URL, queryArgDryRun) }
// HasGenerateOnlyArg returns whether a URL's query "generate-only" parameter is set to "true".
func HasGenerateOnlyArg(r *http.Request) bool { return urlQueryHasArg(r.URL, queryArgGenerateOnly) }
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a default
// value if the string is empty. Write
@ -43,3 +50,21 @@ func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEm
}
return n, true
}
// WriteGenerateStdTxResponse writes response for the generate_only mode.
func WriteGenerateStdTxResponse(w http.ResponseWriter, txBldr authtxb.TxBuilder, msgs []sdk.Msg) {
stdMsg, err := txBldr.Build(msgs)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
output, err := txBldr.Codec.MarshalJSON(auth.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo))
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
return
}
func urlQueryHasArg(url *url.URL, arg string) bool { return url.Query().Get(arg) == "true" }

View File

@ -1,34 +1,36 @@
package utils
import (
"bytes"
"fmt"
"os"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
auth "github.com/cosmos/cosmos-sdk/x/auth"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/libs/common"
)
// SendTx implements a auxiliary handler that facilitates sending a series of
// messages in a signed transaction given a TxContext and a QueryContext. It
// messages in a signed transaction given a TxBuilder and a QueryContext. It
// ensures that the account exists, has a proper number and sequence set. In
// addition, it builds and signs a transaction with the supplied messages.
// Finally, it broadcasts the signed transaction to a node.
func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) error {
txCtx, err := prepareTxContext(txCtx, cliCtx)
func SendTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) error {
txBldr, err := prepareTxContext(txBldr, cliCtx)
if err != nil {
return err
}
autogas := cliCtx.DryRun || (cliCtx.Gas == 0)
if autogas {
txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, msgs)
if txBldr.SimulateGas || cliCtx.DryRun {
txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, cliCtx.FromAddressName, msgs)
if err != nil {
return err
}
fmt.Fprintf(os.Stdout, "estimated gas = %v\n", txCtx.Gas)
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.Gas)
}
if cliCtx.DryRun {
return nil
@ -40,7 +42,7 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg)
}
// build and sign the transaction
txBytes, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs)
txBytes, err := txBldr.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs)
if err != nil {
return err
}
@ -48,31 +50,21 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg)
return cliCtx.EnsureBroadcastTx(txBytes)
}
// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value.
func SimulateMsgs(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, msgs []sdk.Msg, gas int64) (estimated, adjusted int64, err error) {
txBytes, err := txCtx.WithGas(gas).BuildWithPubKey(name, msgs)
if err != nil {
return
}
estimated, adjusted, err = CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment)
return
}
// EnrichCtxWithGas calculates the gas estimate that would be consumed by the
// transaction and set the transaction's respective value accordingly.
func EnrichCtxWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (authctx.TxContext, error) {
_, adjusted, err := SimulateMsgs(txCtx, cliCtx, name, msgs, 0)
func EnrichCtxWithGas(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (authtxb.TxBuilder, error) {
_, adjusted, err := simulateMsgs(txBldr, cliCtx, name, msgs)
if err != nil {
return txCtx, err
return txBldr, err
}
return txCtx.WithGas(adjusted), nil
return txBldr.WithGas(adjusted), nil
}
// CalculateGas simulates the execution of a transaction and returns
// both the estimate obtained by the query and the adjusted amount.
func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *amino.Codec, txBytes []byte, adjustment float64) (estimate, adjusted int64, err error) {
// run a simulation (via /app/simulate query) to
// estimate gas and update TxContext accordingly
// estimate gas and update TxBuilder accordingly
rawRes, err := queryFunc("/app/simulate", txBytes)
if err != nil {
return
@ -85,6 +77,72 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *
return
}
// PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (err error) {
stdTx, err := buildUnsignedStdTx(txBldr, cliCtx, msgs)
if err != nil {
return
}
json, err := txBldr.Codec.MarshalJSON(stdTx)
if err == nil {
fmt.Printf("%s\n", json)
}
return
}
// SignStdTx appends a signature to a StdTx and returns a copy of a it. If appendSig
// is false, it replaces the signatures already attached with the new signature.
func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, stdTx auth.StdTx, appendSig bool) (auth.StdTx, error) {
var signedStdTx auth.StdTx
keybase, err := keys.GetKeyBase()
if err != nil {
return signedStdTx, err
}
info, err := keybase.Get(name)
if err != nil {
return signedStdTx, err
}
addr := info.GetPubKey().Address()
// Check whether the address is a signer
if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) {
fmt.Fprintf(os.Stderr, "WARNING: The generated transaction's intended signer does not match the given signer: '%v'", name)
}
if txBldr.AccountNumber == 0 {
accNum, err := cliCtx.GetAccountNumber(addr)
if err != nil {
return signedStdTx, err
}
txBldr = txBldr.WithAccountNumber(accNum)
}
if txBldr.Sequence == 0 {
accSeq, err := cliCtx.GetAccountSequence(addr)
if err != nil {
return signedStdTx, err
}
txBldr = txBldr.WithSequence(accSeq)
}
passphrase, err := keys.GetPassphrase(name)
if err != nil {
return signedStdTx, err
}
return txBldr.SignStdTx(name, passphrase, stdTx, appendSig)
}
// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value.
func simulateMsgs(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (estimated, adjusted int64, err error) {
txBytes, err := txBldr.BuildWithPubKey(name, msgs)
if err != nil {
return
}
estimated, adjusted, err = CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, txBldr.GasAdjustment)
return
}
func adjustGasEstimate(estimate int64, adjustment float64) int64 {
return int64(adjustment * float64(estimate))
}
@ -97,34 +155,64 @@ func parseQueryResponse(cdc *amino.Codec, rawRes []byte) (int64, error) {
return simulationResult.GasUsed, nil
}
func prepareTxContext(txCtx authctx.TxContext, cliCtx context.CLIContext) (authctx.TxContext, error) {
func prepareTxContext(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (authtxb.TxBuilder, error) {
if err := cliCtx.EnsureAccountExists(); err != nil {
return txCtx, err
return txBldr, err
}
from, err := cliCtx.GetFromAddress()
if err != nil {
return txCtx, err
return txBldr, err
}
// TODO: (ref #1903) Allow for user supplied account number without
// automatically doing a manual lookup.
if txCtx.AccountNumber == 0 {
if txBldr.AccountNumber == 0 {
accNum, err := cliCtx.GetAccountNumber(from)
if err != nil {
return txCtx, err
return txBldr, err
}
txCtx = txCtx.WithAccountNumber(accNum)
txBldr = txBldr.WithAccountNumber(accNum)
}
// TODO: (ref #1903) Allow for user supplied account sequence without
// automatically doing a manual lookup.
if txCtx.Sequence == 0 {
if txBldr.Sequence == 0 {
accSeq, err := cliCtx.GetAccountSequence(from)
if err != nil {
return txCtx, err
return txBldr, err
}
txCtx = txCtx.WithSequence(accSeq)
txBldr = txBldr.WithSequence(accSeq)
}
return txCtx, nil
return txBldr, nil
}
// buildUnsignedStdTx builds a StdTx as per the parameters passed in the
// contexts. Gas is automatically estimated if gas wanted is set to 0.
func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) {
txBldr, err = prepareTxContext(txBldr, cliCtx)
if err != nil {
return
}
if txBldr.SimulateGas {
txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, cliCtx.FromAddressName, msgs)
if err != nil {
return
}
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.Gas)
}
stdSignMsg, err := txBldr.Build(msgs)
if err != nil {
return
}
return auth.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil
}
func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool {
for _, s := range signers {
if bytes.Equal(user.Bytes(), s.Bytes()) {
return true
}
}
return false
}

View File

@ -60,6 +60,7 @@ func resolveProjectPath(remoteProjectPath string) string {
return gopath + string(os.PathSeparator) + "src" + string(os.PathSeparator) + remoteProjectPath
}
// nolint: unparam, errcheck
func copyBasecoinTemplate(projectName string, projectPath string, remoteProjectPath string) {
basecoinProjectPath := resolveProjectPath(remoteBasecoinPath)
filepath.Walk(basecoinProjectPath, func(path string, f os.FileInfo, err error) error {
@ -88,6 +89,7 @@ func copyBasecoinTemplate(projectName string, projectPath string, remoteProjectP
})
}
// nolint: errcheck
func createGopkg(projectPath string) {
// Create gopkg.toml file
dependencies := map[string]string{
@ -111,6 +113,7 @@ func createGopkg(projectPath string) {
ioutil.WriteFile(projectPath+"/Gopkg.toml", []byte(contents), os.ModePerm)
}
// nolint: errcheck
func createMakefile(projectPath string) {
// Create makefile
// TODO: Should we use tools/ directory as in Cosmos-SDK to get tools for linting etc.

View File

@ -43,6 +43,7 @@ type GaiaApp struct {
keyAccount *sdk.KVStoreKey
keyIBC *sdk.KVStoreKey
keyStake *sdk.KVStoreKey
tkeyStake *sdk.TransientStoreKey
keySlashing *sdk.KVStoreKey
keyGov *sdk.KVStoreKey
keyFeeCollection *sdk.KVStoreKey
@ -52,7 +53,7 @@ type GaiaApp struct {
// Manage getting and setting accounts
accountMapper auth.AccountMapper
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper
bankKeeper bank.Keeper
ibcMapper ibc.Mapper
stakeKeeper stake.Keeper
slashingKeeper slashing.Keeper
@ -74,6 +75,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
keyAccount: sdk.NewKVStoreKey("acc"),
keyIBC: sdk.NewKVStoreKey("ibc"),
keyStake: sdk.NewKVStoreKey("stake"),
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
keySlashing: sdk.NewKVStoreKey("slashing"),
keyGov: sdk.NewKVStoreKey("gov"),
keyFeeCollection: sdk.NewKVStoreKey("fee"),
@ -89,19 +91,19 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
)
// add handlers
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams)
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace))
app.stakeKeeper = app.stakeKeeper.WithValidatorHooks(app.slashingKeeper.ValidatorHooks())
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper.Setter(), app.coinKeeper, app.stakeKeeper, app.RegisterCodespace(gov.DefaultCodespace))
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper.Setter(), app.bankKeeper, app.stakeKeeper, app.RegisterCodespace(gov.DefaultCodespace))
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection)
// register message routes
app.Router().
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.bankKeeper)).
AddRoute("stake", stake.NewHandler(app.stakeKeeper)).
AddRoute("slashing", slashing.NewHandler(app.slashingKeeper)).
AddRoute("gov", gov.NewHandler(app.govKeeper))
@ -114,8 +116,9 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams)
app.MountStore(app.tkeyParams, sdk.StoreTypeTransient)
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake,
app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams)
app.MountStoresTransient(app.tkeyParams, app.tkeyStake)
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())
@ -190,6 +193,11 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.StakeData)
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
err = GaiaValidateGenesisState(genesisState)
if err != nil {
// TODO find a way to do this w/o panics
panic(err)
}
return abci.ResponseInitChain{
Validators: validators,

View File

@ -13,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/stake"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/spf13/pflag"
@ -180,38 +181,12 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState
}
// create the genesis account, give'm few steaks and a buncha token with there name
accAuth := auth.NewBaseAccountWithAddress(genTx.Address)
accAuth.Coins = sdk.Coins{
{genTx.Name + "Token", sdk.NewInt(1000)},
{"steak", freeFermionsAcc},
}
acc := NewGenesisAccount(&accAuth)
genaccs[i] = acc
genaccs[i] = genesisAccountFromGenTx(genTx)
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
// add the validator
if len(genTx.Name) > 0 {
desc := stake.NewDescription(genTx.Name, "", "", "")
validator := stake.NewValidator(
sdk.ValAddress(genTx.Address), sdk.MustGetConsPubKeyBech32(genTx.PubKey), desc,
)
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply
// add some new shares to the validator
var issuedDelShares sdk.Dec
validator, stakeData.Pool, issuedDelShares = validator.AddTokensFromDel(stakeData.Pool, sdk.NewInt(freeFermionVal))
stakeData.Validators = append(stakeData.Validators, validator)
// create the self-delegation from the issuedDelShares
delegation := stake.Delegation{
DelegatorAddr: sdk.AccAddress(validator.Operator),
ValidatorAddr: validator.Operator,
Shares: issuedDelShares,
Height: 0,
}
stakeData.Bonds = append(stakeData.Bonds, delegation)
stakeData = addValidatorToStakeData(genTx, stakeData)
}
}
@ -224,6 +199,86 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState
return
}
func addValidatorToStakeData(genTx GaiaGenTx, stakeData stake.GenesisState) stake.GenesisState {
desc := stake.NewDescription(genTx.Name, "", "", "")
validator := stake.NewValidator(
sdk.ValAddress(genTx.Address), sdk.MustGetConsPubKeyBech32(genTx.PubKey), desc,
)
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply
// add some new shares to the validator
var issuedDelShares sdk.Dec
validator, stakeData.Pool, issuedDelShares = validator.AddTokensFromDel(stakeData.Pool, sdk.NewInt(freeFermionVal))
stakeData.Validators = append(stakeData.Validators, validator)
// create the self-delegation from the issuedDelShares
delegation := stake.Delegation{
DelegatorAddr: sdk.AccAddress(validator.OperatorAddr),
ValidatorAddr: validator.OperatorAddr,
Shares: issuedDelShares,
Height: 0,
}
stakeData.Bonds = append(stakeData.Bonds, delegation)
return stakeData
}
func genesisAccountFromGenTx(genTx GaiaGenTx) GenesisAccount {
accAuth := auth.NewBaseAccountWithAddress(genTx.Address)
accAuth.Coins = sdk.Coins{
{genTx.Name + "Token", sdk.NewInt(1000)},
{"steak", freeFermionsAcc},
}
return NewGenesisAccount(&accAuth)
}
// GaiaValidateGenesisState ensures that the genesis state obeys the expected invariants
// TODO: No validators are both bonded and revoked (#2088)
// TODO: Error if there is a duplicate validator (#1708)
// TODO: Ensure all state machine parameters are in genesis (#1704)
func GaiaValidateGenesisState(genesisState GenesisState) (err error) {
err = validateGenesisStateAccounts(genesisState.Accounts)
if err != nil {
return
}
err = validateGenesisStateValidators(genesisState.StakeData.Validators)
if err != nil {
return
}
return
}
func validateGenesisStateValidators(validators []stakeTypes.Validator) (err error) {
addrMap := make(map[string]bool, len(validators))
for i := 0; i < len(validators); i++ {
val := validators[i]
strKey := string(val.ConsPubKey.Bytes())
if _, ok := addrMap[strKey]; ok {
return fmt.Errorf("Duplicate validator in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
}
if val.Jailed && val.Status == sdk.Bonded {
return fmt.Errorf("Validator is bonded and revoked in genesis state: moniker %v, Address %v", val.Description.Moniker, val.ConsAddress())
}
addrMap[strKey] = true
}
return
}
// Ensures that there are no duplicate accounts in the genesis state,
func validateGenesisStateAccounts(accs []GenesisAccount) (err error) {
addrMap := make(map[string]bool, len(accs))
for i := 0; i < len(accs); i++ {
acc := accs[i]
strAddr := string(acc.Address)
if _, ok := addrMap[strAddr]; ok {
return fmt.Errorf("Duplicate account in genesis state: Address %v", acc.Address)
}
addrMap[strAddr] = true
}
return
}
// GaiaAppGenState but with JSON
func GaiaAppGenStateJSON(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {

View File

@ -5,10 +5,50 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/stake"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
)
var (
pk1 = ed25519.GenPrivKey().PubKey()
pk2 = ed25519.GenPrivKey().PubKey()
pk3 = ed25519.GenPrivKey().PubKey()
addr1 = sdk.ValAddress(pk1.Address())
addr2 = sdk.ValAddress(pk2.Address())
addr3 = sdk.ValAddress(pk3.Address())
emptyAddr sdk.ValAddress
emptyPubkey crypto.PubKey
)
func makeGenesisState(genTxs []GaiaGenTx) GenesisState {
// start with the default staking genesis state
stakeData := stake.DefaultGenesisState()
// get genesis flag account information
genaccs := make([]GenesisAccount, len(genTxs))
for i, genTx := range genTxs {
genaccs[i] = genesisAccountFromGenTx(genTx)
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
// add the validator
if len(genTx.Name) > 0 {
stakeData = addValidatorToStakeData(genTx, stakeData)
}
}
// create the final app state
return GenesisState{
Accounts: genaccs,
StakeData: stakeData,
GovData: gov.DefaultGenesisState(),
}
}
func TestToAccount(t *testing.T) {
priv := ed25519.GenPrivKey()
addr := sdk.AccAddress(priv.PubKey().Address())
@ -34,3 +74,30 @@ func TestGaiaAppGenState(t *testing.T) {
// TODO test with both one and two genesis transactions:
// TODO correct: genesis account created, canididates created, pool token variance
}
func TestGaiaGenesisValidation(t *testing.T) {
genTxs := make([]GaiaGenTx, 2)
addr := pk1.Address()
// Test duplicate accounts fails
genTxs[0] = GaiaGenTx{"", sdk.AccAddress(addr), ""}
genTxs[1] = GaiaGenTx{"", sdk.AccAddress(addr), ""}
genesisState := makeGenesisState(genTxs)
err := GaiaValidateGenesisState(genesisState)
require.NotNil(t, err)
// Test bonded + revoked validator fails
genesisState = makeGenesisState(genTxs[:1])
val1 := stakeTypes.NewValidator(addr1, pk1, stakeTypes.Description{Moniker: "test #2"})
val1.Jailed = true
val1.Status = sdk.Bonded
genesisState.StakeData.Validators = append(genesisState.StakeData.Validators, val1)
err = GaiaValidateGenesisState(genesisState)
require.NotNil(t, err)
// Test duplicate validator fails
val1.Jailed = false
genesisState = makeGenesisState(genTxs[:1])
val2 := stakeTypes.NewValidator(addr1, pk1, stakeTypes.Description{Moniker: "test #3"})
genesisState.StakeData.Validators = append(genesisState.StakeData.Validators, val1)
genesisState.StakeData.Validators = append(genesisState.StakeData.Validators, val2)
err = GaiaValidateGenesisState(genesisState)
require.NotNil(t, err)
}

View File

@ -3,7 +3,9 @@ package app
import (
"encoding/json"
"flag"
"fmt"
"math/rand"
"os"
"testing"
"github.com/stretchr/testify/require"
@ -12,9 +14,9 @@ import (
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"
"github.com/cosmos/cosmos-sdk/x/gov"
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"
@ -28,6 +30,7 @@ var (
blockSize int
enabled bool
verbose bool
commit bool
)
func init() {
@ -36,6 +39,7 @@ func init() {
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "Operations per block")
flag.BoolVar(&enabled, "SimulationEnabled", false, "Enable the simulation")
flag.BoolVar(&verbose, "SimulationVerbose", false, "Verbose log output")
flag.BoolVar(&commit, "SimulationCommit", false, "Have the simulation commit")
}
func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
@ -49,7 +53,7 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
Coins: coins,
})
}
govGenesis := gov.DefaultGenesisState()
// Default genesis state
stakeGenesis := stake.DefaultGenesisState()
var validators []stake.Validator
@ -73,6 +77,7 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
genesis := GenesisState{
Accounts: genesisAccounts,
StakeData: stakeGenesis,
GovData: govGenesis,
}
// Marshal genesis
@ -84,31 +89,65 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
return appState
}
func testAndRunTxs(app *GaiaApp) []simulation.Operation {
return []simulation.Operation{
banksim.SimulateSingleInputMsgSend(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.SimulateMsgUnjail(app.slashingKeeper),
func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
return []simulation.WeightedOperation{
{100, banksim.SimulateSingleInputMsgSend(app.accountMapper)},
{5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakeKeeper)},
{100, govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper)},
{100, stakesim.SimulateMsgCreateValidator(app.accountMapper, app.stakeKeeper)},
{5, stakesim.SimulateMsgEditValidator(app.stakeKeeper)},
{100, stakesim.SimulateMsgDelegate(app.accountMapper, app.stakeKeeper)},
{100, stakesim.SimulateMsgBeginUnbonding(app.accountMapper, app.stakeKeeper)},
{100, stakesim.SimulateMsgCompleteUnbonding(app.stakeKeeper)},
{100, stakesim.SimulateMsgBeginRedelegate(app.accountMapper, app.stakeKeeper)},
{100, stakesim.SimulateMsgCompleteRedelegate(app.stakeKeeper)},
{100, slashingsim.SimulateMsgUnjail(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)
},
banksim.NonnegativeBalanceInvariant(app.accountMapper),
govsim.AllInvariants(),
stakesim.AllInvariants(app.bankKeeper, app.stakeKeeper, app.accountMapper),
slashingsim.AllInvariants(),
}
}
// Profile with:
// /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$ -SimulationCommit=true -cpuprofile cpu.out
func BenchmarkFullGaiaSimulation(b *testing.B) {
// Setup Gaia application
var logger log.Logger
logger = log.NewNopLogger()
var db dbm.DB
dir := os.TempDir()
db, _ = dbm.NewGoLevelDB("Simulation", dir)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil)
// Run randomized simulation
// TODO parameterize numbers, save for a later PR
err := simulation.SimulateFromSeed(
b, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]simulation.RandSetup{},
invariants(app), // these shouldn't get ran
numBlocks,
blockSize,
commit,
)
if err != nil {
fmt.Println(err)
b.Fail()
}
if commit {
fmt.Println("GoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
}
}
@ -129,16 +168,19 @@ func TestFullGaiaSimulation(t *testing.T) {
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
simulation.SimulateFromSeed(
err := simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]simulation.RandSetup{},
invariants(app),
numBlocks,
blockSize,
false,
commit,
)
if commit {
fmt.Println("Database Size", db.Stats()["database.size"])
}
require.Nil(t, err)
}
// TODO: Make another test for the fuzzer itself, which just has noOp txs
@ -148,7 +190,7 @@ func TestAppStateDeterminism(t *testing.T) {
t.Skip("Skipping Gaia simulation")
}
numSeeds := 5
numSeeds := 3
numTimesToRunPerSeed := 5
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
@ -165,10 +207,11 @@ func TestAppStateDeterminism(t *testing.T) {
testAndRunTxs(app),
[]simulation.RandSetup{},
[]simulation.Invariant{},
20,
20,
50,
100,
true,
)
//app.Commit()
appHash := app.LastCommitID().Hash
appHashList[j] = appHash
}

View File

@ -5,14 +5,17 @@ package clitest
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
@ -109,9 +112,26 @@ func TestGaiaCLIGasAuto(t *testing.T) {
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
// Enable auto gas
// Test failure with negative gas
success = executeWrite(t, fmt.Sprintf("gaiacli send %v --gas=-100 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
require.False(t, success)
// Test failure with 0 gas
success = executeWrite(t, fmt.Sprintf("gaiacli send %v --gas=0 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
require.False(t, success)
// Enable auto gas
success, stdout, _ := executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli send %v --json --gas=simulate --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
require.True(t, success)
// check that gas wanted == gas used
cdc := app.MakeCodec()
jsonOutput := struct {
Height int64
TxHash string
Response abci.ResponseDeliverTx
}{}
require.Nil(t, cdc.UnmarshalJSON([]byte(stdout), &jsonOutput))
require.Equal(t, jsonOutput.Response.GasWanted, jsonOutput.Response.GasUsed)
tests.WaitForNextNBlocksTM(2, port)
// Check state has changed accordingly
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
@ -155,8 +175,18 @@ func TestGaiaCLICreateValidator(t *testing.T) {
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(1))
// Test --generate-only
success, stdout, stderr := executeWriteRetStdStreams(t, cvStr+" --generate-only", app.DefaultKeyPass)
require.True(t, success)
require.True(t, success)
require.Empty(t, stderr)
msg := unmarshalStdTx(t, stdout)
require.NotZero(t, msg.Fee.Gas)
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, 0, len(msg.GetSignatures()))
// Test --dry-run
success := executeWrite(t, cvStr+" --dry-run", app.DefaultKeyPass)
success = executeWrite(t, cvStr+" --dry-run", app.DefaultKeyPass)
require.True(t, success)
executeWrite(t, cvStr, app.DefaultKeyPass)
@ -166,7 +196,7 @@ 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", sdk.ValAddress(barAddr), flags))
require.Equal(t, validator.Operator, sdk.ValAddress(barAddr))
require.Equal(t, validator.OperatorAddr, sdk.ValAddress(barAddr))
require.True(sdk.DecEq(t, sdk.NewDec(2), validator.Tokens))
// unbond a single share
@ -222,8 +252,18 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
spStr += fmt.Sprintf(" --title=%s", "Test")
spStr += fmt.Sprintf(" --description=%s", "test")
// Test generate only
success, stdout, stderr := executeWriteRetStdStreams(t, spStr+" --generate-only", app.DefaultKeyPass)
require.True(t, success)
require.True(t, success)
require.Empty(t, stderr)
msg := unmarshalStdTx(t, stdout)
require.NotZero(t, msg.Fee.Gas)
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, 0, len(msg.GetSignatures()))
// Test --dry-run
success := executeWrite(t, spStr+" --dry-run", app.DefaultKeyPass)
success = executeWrite(t, spStr+" --dry-run", app.DefaultKeyPass)
require.True(t, success)
executeWrite(t, spStr, app.DefaultKeyPass)
@ -244,6 +284,16 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
depositStr += fmt.Sprintf(" --deposit=%s", "10steak")
depositStr += fmt.Sprintf(" --proposal-id=%s", "1")
// Test generate only
success, stdout, stderr = executeWriteRetStdStreams(t, depositStr+" --generate-only", app.DefaultKeyPass)
require.True(t, success)
require.True(t, success)
require.Empty(t, stderr)
msg = unmarshalStdTx(t, stdout)
require.NotZero(t, msg.Fee.Gas)
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, 0, len(msg.GetSignatures()))
executeWrite(t, depositStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
@ -258,6 +308,16 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
voteStr += fmt.Sprintf(" --proposal-id=%s", "1")
voteStr += fmt.Sprintf(" --option=%s", "Yes")
// Test generate only
success, stdout, stderr = executeWriteRetStdStreams(t, voteStr+" --generate-only", app.DefaultKeyPass)
require.True(t, success)
require.True(t, success)
require.Empty(t, stderr)
msg = unmarshalStdTx(t, stdout)
require.NotZero(t, msg.Fee.Gas)
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, 0, len(msg.GetSignatures()))
executeWrite(t, voteStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
@ -291,6 +351,101 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
require.Equal(t, " 2 - Apples", proposalsQuery)
}
func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
chainID, servAddr, port := initializeFixtures(t)
flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID)
// start gaiad server
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr))
defer proc.Stop(false)
tests.WaitForTMStart(port)
tests.WaitForNextNBlocksTM(2, port)
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
// Test generate sendTx with default gas
success, stdout, stderr := executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli send %v --amount=10steak --to=%s --from=foo --generate-only",
flags, barAddr), []string{}...)
require.True(t, success)
require.Empty(t, stderr)
msg := unmarshalStdTx(t, stdout)
require.Equal(t, msg.Fee.Gas, int64(client.DefaultGasLimit))
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, 0, len(msg.GetSignatures()))
// Test generate sendTx with --gas=$amount
success, stdout, stderr = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli send %v --amount=10steak --to=%s --from=foo --gas=100 --generate-only",
flags, barAddr), []string{}...)
require.True(t, success)
require.Empty(t, stderr)
msg = unmarshalStdTx(t, stdout)
require.Equal(t, msg.Fee.Gas, int64(100))
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, 0, len(msg.GetSignatures()))
// Test generate sendTx, estimate gas
success, stdout, stderr = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli send %v --amount=10steak --to=%s --from=foo --gas=simulate --generate-only",
flags, barAddr), []string{}...)
require.True(t, success)
require.NotEmpty(t, stderr)
msg = unmarshalStdTx(t, stdout)
require.True(t, msg.Fee.Gas > 0)
require.Equal(t, len(msg.Msgs), 1)
// Write the output to disk
unsignedTxFile := writeToNewTempFile(t, stdout)
defer os.Remove(unsignedTxFile.Name())
// Test sign --print-sigs
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli sign %v --print-sigs %v", flags, unsignedTxFile.Name()))
require.True(t, success)
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n", fooAddr.String()), stdout)
// Test sign
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli sign %v --name=foo %v", flags, unsignedTxFile.Name()), app.DefaultKeyPass)
require.True(t, success)
msg = unmarshalStdTx(t, stdout)
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, 1, len(msg.GetSignatures()))
require.Equal(t, fooAddr.String(), msg.GetSigners()[0].String())
// Write the output to disk
signedTxFile := writeToNewTempFile(t, stdout)
defer os.Remove(signedTxFile.Name())
// Test sign --print-signatures
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli sign %v --print-sigs %v", flags, signedTxFile.Name()))
require.True(t, success)
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n 0: %v\n", fooAddr.String(), fooAddr.String()), stdout)
// Test broadcast
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli broadcast %v --json %v", flags, signedTxFile.Name()))
require.True(t, success)
var result struct {
Response abci.ResponseDeliverTx
}
require.Nil(t, app.MakeCodec().UnmarshalJSON([]byte(stdout), &result))
require.Equal(t, msg.Fee.Gas, result.Response.GasUsed)
require.Equal(t, msg.Fee.Gas, result.Response.GasWanted)
tests.WaitForNextNBlocksTM(2, port)
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags))
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64())
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
}
//___________________________________________________________________________________
// helper methods
@ -315,6 +470,20 @@ func initializeFixtures(t *testing.T) (chainID, servAddr, port string) {
return
}
func unmarshalStdTx(t *testing.T, s string) (stdTx auth.StdTx) {
cdc := app.MakeCodec()
require.Nil(t, cdc.UnmarshalJSON([]byte(s), &stdTx))
return
}
func writeToNewTempFile(t *testing.T, s string) *os.File {
fp, err := ioutil.TempFile(os.TempDir(), "cosmos_cli_test_")
require.Nil(t, err)
_, err = fp.WriteString(s)
require.Nil(t, err)
return fp
}
//___________________________________________________________________________________
// executors

View File

@ -129,10 +129,12 @@ func main() {
rootCmd.AddCommand(
client.GetCommands(
authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)),
authcmd.GetSignCommand(cdc, authcmd.GetAccountDecoder(cdc)),
)...)
rootCmd.AddCommand(
client.PostCommands(
bankcmd.SendTxCmd(cdc),
bankcmd.GetBroadcastCommand(cdc),
)...)
// add proxy, version and key info

View File

@ -65,7 +65,7 @@ func runHackCmd(cmd *cobra.Command, args []string) error {
// The following powerKey was there, but the corresponding "trouble" validator did not exist.
// So here we do a binary search on the past states to find when the powerKey first showed up ...
// owner of the validator the bonds, gets revoked, later unbonds, and then later is still found in the bypower store
// operator of the validator the bonds, gets revoked, later unbonds, and then later is still found in the bypower store
trouble := hexToBytes("D3DC0FF59F7C3B548B7AFA365561B87FD0208AF8")
// this is his "bypower" key
powerKey := hexToBytes("05303030303030303030303033FFFFFFFFFFFF4C0C0000FFFED3DC0FF59F7C3B548B7AFA365561B87FD0208AF8")
@ -134,13 +134,14 @@ type GaiaApp struct {
keyAccount *sdk.KVStoreKey
keyIBC *sdk.KVStoreKey
keyStake *sdk.KVStoreKey
tkeyStake *sdk.TransientStoreKey
keySlashing *sdk.KVStoreKey
keyParams *sdk.KVStoreKey
// Manage getting and setting accounts
accountMapper auth.AccountMapper
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper
bankKeeper bank.Keeper
ibcMapper ibc.Mapper
stakeKeeper stake.Keeper
slashingKeeper slashing.Keeper
@ -161,6 +162,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
keyAccount: sdk.NewKVStoreKey("acc"),
keyIBC: sdk.NewKVStoreKey("ibc"),
keyStake: sdk.NewKVStoreKey("stake"),
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
keySlashing: sdk.NewKVStoreKey("slashing"),
keyParams: sdk.NewKVStoreKey("params"),
}
@ -173,16 +175,16 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
)
// add handlers
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams)
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace))
// register message routes
app.Router().
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.bankKeeper)).
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
// initialize BaseApp

View File

@ -224,9 +224,15 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t
}
case offlineInfo:
linfo := info.(offlineInfo)
fmt.Printf("Bytes to sign:\n%s", msg)
_, err := fmt.Fprintf(os.Stderr, "Bytes to sign:\n%s", msg)
if err != nil {
return nil, nil, err
}
buf := bufio.NewReader(os.Stdin)
fmt.Printf("\nEnter Amino-encoded signature:\n")
_, err = fmt.Fprintf(os.Stderr, "\nEnter Amino-encoded signature:\n")
if err != nil {
return nil, nil, err
}
// Will block until user inputs the signature
signed, err := buf.ReadString('\n')
if err != nil {

View File

@ -5,7 +5,8 @@
- [ ] 3. Merge items in `PENDING.md` into the `CHANGELOG.md`. While doing this make sure that each entry contains links to issues/PRs for each item
- [ ] 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](/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
- [ ] 6. Open a branch & PR to merge the pending release back into `develop`. If any changes are made to the release branch, they must also be made to the pending develop merge, and both must pass tests.
- [ ] 7. Kick off 1 day of automated fuzz testing
- [ ] 8. Release Lead assigns 2 people to perform [buddy testing script](/docs/RELEASE_TEST_SCRIPT.md) and update the relevant documentation
- [ ] 9. If errors are found in either #6 or #7 go back to #2 (*NOTE*: be sure to increment the `rcN`)
- [ ] 10. After #6 and #7 have successfully completed then merge the release PR and push the final release tag

View File

@ -0,0 +1,2 @@
Please note that this folder is a WIP specification for an advanced fee distribution
mechanism which is not set to be implemented.

View File

@ -0,0 +1,36 @@
# End Block
At each endblock, the fees received are sorted to the proposer, community fund,
and global pool. When the validator is the proposer of the round, that
validator (and their delegators) receives between 1% and 5% of fee rewards, the
reserve tax is then charged, then the remainder is distributed proportionally
by voting power to all bonded validators independent of whether they voted
(social distribution). Note the social distribution is applied to proposer
validator in addition to the proposer reward.
The amount of proposer reward is calculated from pre-commits Tendermint
messages in order to incentivize validators to wait and include additional
pre-commits in the block. All provision rewards are added to a provision reward
pool which validator holds individually
(`ValidatorDistribution.ProvisionsRewardPool`).
```
func SortFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
sumPowerPrecommitValidators, totalBondedTokens, communityTax sdk.Dec)
feesCollectedDec = MakeDecCoins(feesCollected)
proposerReward = feesCollectedDec * (0.01 + 0.04
* sumPowerPrecommitValidators / totalBondedTokens)
proposer.ProposerPool += proposerReward
communityFunding = feesCollectedDec * communityTax
global.CommunityFund += communityFunding
poolReceived = feesCollectedDec - proposerReward - communityFunding
global.Pool += poolReceived
global.EverReceivedPool += poolReceived
global.LastReceivedPool = poolReceived
SetValidatorDistribution(proposer)
SetGlobal(global)
```

View File

@ -0,0 +1,54 @@
# Distribution
## Overview
Collected fees are pooled globally and divided out passively to validators and
delegators. Each validator has the opportunity to charge commission to the
delegators on the fees collected on behalf of the delegators by the validators.
Fees are paid directly into a global fee pool, and validator proposer-reward
pool. Due to the nature of passive accounting whenever changes to parameters
which affect the rate of fee distribution occurs, withdrawal of fees must also
occur when:
- withdrawing one must withdrawal the maximum amount they are entitled
too, leaving nothing in the pool,
- bonding, unbonding, or re-delegating tokens to an existing account a
full withdrawal of the fees must occur (as the rules for lazy accounting
change),
- a validator chooses to change the commission on fees, all accumulated
commission fees must be simultaneously withdrawn.
The above scenarios are covered in `triggers.md`.
The distribution mechanism outlines herein is used to lazily distribute the
following between validators and associated delegators:
- multi-token fees to be socially distributed,
- proposer reward pool,
- inflated atom provisions, and
- validator commission on all rewards earned by their delegators stake
Fees are pooled within a global pool, as well as validator specific
proposer-reward pools. The mechanisms used allow for validators and delegators
to independently and lazily withdrawn their rewards. As a part of the lazy
computations adjustment factors must be maintained for each validator and
delegator to determine the true proportion of fees in each pool which they are
entitled too. Adjustment factors are updated every time a validator or
delegator's voting power changes. Validators and delegators must withdraw all
fees they are entitled too before they can change their portion of bonded
Atoms.
## Affect on Staking
Charging commission on Atom provisions while also allowing for Atom-provisions
to be auto-bonded (distributed directly to the validators bonded stake) is
problematic within DPoS. Fundamentally these two mechnisms are mutually
exclusive. If there are atoms commissions and auto-bonding Atoms, the portion
of Atoms the fee distribution calculation would become very large as the Atom
portion for each delegator would change each block making a withdrawal of fees
for a delegator require a calculation for every single block since the last
withdrawal. In conclusion we can only have atom commission and unbonded atoms
provisions, or bonded atom provisions with no Atom commission, and we elect to
implement the former. Stakeholders wishing to rebond their provisions may elect
to set up a script to periodically withdraw and rebond fees.

View File

@ -0,0 +1,100 @@
## State
### Global
All globally tracked parameters for distribution are stored within
`Global`. Rewards are collected and added to the reward pool and
distributed to validators/delegators from here.
Note that the reward pool holds decimal coins (`DecCoins`) to allow
for fractions of coins to be received from operations like inflation.
When coins are distributed from the pool they are truncated back to
`sdk.Coins` which are non-decimal.
- Global: `0x00 -> amino(global)`
```golang
// coins with decimal
type DecCoins []DecCoin
type DecCoin struct {
Amount sdk.Dec
Denom string
}
type Global struct {
PrevBondedTokens sdk.Dec // bonded token amount for the global pool on the previous block
Adjustment sdk.Dec // global adjustment factor for lazy calculations
Pool DecCoins // funds for all validators which have yet to be withdrawn
PrevReceivedPool DecCoins // funds added to the pool on the previous block
EverReceivedPool DecCoins // total funds ever added to the pool
CommunityFund DecCoins // pool for community funds yet to be spent
}
```
### Validator Distribution
Validator distribution information for the relevant validator is updated each time:
1. delegation amount to a validator are updated,
2. a validator successfully proposes a block and receives a reward,
3. any delegator withdraws from a validator, or
4. the validator withdraws it's commission.
- ValidatorDistribution: `0x02 | ValOwnerAddr -> amino(validatorDistribution)`
```golang
type ValidatorDistribution struct {
CommissionWithdrawalHeight int64 // last time this validator withdrew commission
Adjustment sdk.Dec // global pool adjustment factor
ProposerAdjustment DecCoins // proposer pool adjustment factor
ProposerPool DecCoins // reward pool collected from being the proposer
EverReceivedProposerReward DecCoins // all rewards ever collected from being the proposer
PrevReceivedProposerReward DecCoins // previous rewards collected from being the proposer
PrevBondedTokens sdk.Dec // bonded token amount on the previous block
PrevDelegatorShares sdk.Dec // amount of delegator shares for the validator on the previous block
}
```
### Delegation Distribution
Each delegation holds multiple adjustment factors to specify its entitlement to
the rewards from a validator. `AdjustmentPool` is used to passively calculate
each bonds entitled fees from the `RewardPool`. `AdjustmentPool` is used to
passively calculate each bonds entitled fees from
`ValidatorDistribution.ProposerRewardPool`
- DelegatorDistribution: ` 0x02 | DelegatorAddr | ValOwnerAddr -> amino(delegatorDist)`
```golang
type DelegatorDist struct {
WithdrawalHeight int64 // last time this delegation withdrew rewards
Adjustment sdk.Dec // fee provisioning adjustment factor
AdjustmentProposer DecCoins // proposers pool adjustment factor
PrevTokens sdk.Dec // bonded tokens held by the delegation on the previous block
PrevShares sdk.Dec // delegator shares held by the delegation on the previous block
}
```
### Power Change
Every instance that the voting power changes, information about the state of
the validator set during the change must be recorded as a `PowerChange` for
other validators to run through. Each power change is indexed by its block
height.
- PowerChange: `0x03 | amino(Height) -> amino(validatorDist)`
```golang
type PowerChange struct {
Height int64 // block height at change
ValidatorBondedTokens sdk.Dec // following used to create distribution scenarios
ValidatorDelegatorShares sdk.Dec
ValidatorDelegatorShareExRate sdk.Dec
ValidatorCommission sdk.Dec
PoolBondedTokens sdk.Dec
Global Global
ValDistr ValidatorDistribution
DelegationShares sdk.Dec
DelDistr DelegatorDistribution
}
```

View File

@ -0,0 +1,399 @@
# Transactions
## TxWithdrawDelegation
When a delegator wishes to withdraw their transaction fees it must send
`TxWithdrawDelegation`. Note that parts of this transaction logic are also
triggered each with any change in individual delegations, such as an unbond,
redelegation, or delegation of additional tokens to a specific validator.
Each time a withdrawal is made by a recipient the adjustment term must be
modified for each block with a change in distributors shares since the time of
last withdrawal. This is accomplished by iterating over all relevant
`PowerChange`'s stored in distribution state.
```golang
type TxWithdrawDelegation struct {
delegatorAddr sdk.AccAddress
withdrawAddr sdk.AccAddress // address to make the withdrawal to
}
func WithdrawDelegator(delegatorAddr, withdrawAddr sdk.AccAddress)
entitlement = GetDelegatorEntitlement(delegatorAddr)
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
func GetDelegatorEntitlement(delegatorAddr sdk.AccAddress) DecCoins
// compile all the distribution scenarios
delegations = GetDelegations(delegatorAddr)
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
delegation.ValidatorAddr)
pcs = GetPowerChanges(DelDistr.WithdrawalHeight)
// update all adjustment factors for each delegation since last withdrawal
for pc = range pcs
for delegation = range delegations
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
delegation.ValidatorAddr)
pc.ProcessPowerChangeDelegation(delegation, DelDistr)
// collect all entitled fees
entitlement = 0
for delegation = range delegations
global = GetGlobal()
pool = GetPool()
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
delegation.ValidatorAddr)
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
validator = GetValidator(delegation.ValidatorAddr)
scenerio1 = NewDelegationFromGlobalPool(delegation, validator,
pool, global, ValDistr, DelDistr)
scenerio2 = NewDelegationFromProvisionPool(delegation, validator,
ValDistr, DelDistr)
entitlement += scenerio1.WithdrawalEntitlement()
entitlement += scenerio2.WithdrawalEntitlement()
return entitlement
func (pc PowerChange) ProcessPowerChangeDelegation(delegation sdk.Delegation,
DelDistr DelegationDistribution)
// get the historical scenarios
scenario1 = pc.DelegationFromGlobalPool(delegation, DelDistr)
scenario2 = pc.DelegationFromProvisionPool(delegation, DelDistr)
// process the adjustment factors
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
```
## TxWithdrawValidator
When a validator wishes to withdraw their transaction fees it must send
`TxWithdrawDelegation`. Note that parts of this transaction logic is also
triggered each with any change in individual delegations, such as an unbond,
redelegation, or delegation of additional tokens to a specific validator. This
transaction withdraws the validators commission rewards, as well as any rewards
earning on their self-delegation.
```golang
type TxWithdrawValidator struct {
ownerAddr sdk.AccAddress // validator address to withdraw from
withdrawAddr sdk.AccAddress // address to make the withdrawal to
}
func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress)
// update the delegator adjustment factors and also withdrawal delegation fees
entitlement = GetDelegatorEntitlement(ownerAddr)
// update the validator adjustment factors for commission
ValDistr = GetValidatorDistribution(ownerAddr.ValidatorAddr)
pcs = GetPowerChanges(ValDistr.CommissionWithdrawalHeight)
for pc = range pcs
pc.ProcessPowerChangeCommission()
// withdrawal validator commission rewards
global = GetGlobal()
pool = GetPool()
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
validator = GetValidator(delegation.ValidatorAddr)
scenerio1 = NewCommissionFromGlobalPool(validator,
pool, global, ValDistr)
scenerio2 = CommissionFromProposerPool(validator, ValDistr)
entitlement += scenerio1.WithdrawalEntitlement()
entitlement += scenerio2.WithdrawalEntitlement()
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
func (pc PowerChange) ProcessPowerChangeCommission()
// get the historical scenarios
scenario1 = pc.CommissionFromGlobalPool()
scenario2 = pc.CommissionFromProposerPool()
// process the adjustment factors
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
```
## Common Calculations
### Distribution scenario
A common form of abstracted calculations exists between validators and
delegations attempting to withdrawal their rewards, either from `Global.Pool`
or from `ValidatorDistribution.ProposerPool`. With the following interface
fulfilled the entitled fees for the various scenarios can be calculated.
```golang
type DistributionScenario interface {
DistributorTokens() DecCoins // current tokens from distributor
DistributorCumulativeTokens() DecCoins // total tokens ever received
DistributorPrevReceivedTokens() DecCoins // last value of tokens received
DistributorShares() sdk.Dec // current shares
DistributorPrevShares() sdk.Dec // shares last block
RecipientAdjustment() sdk.Dec
RecipientShares() sdk.Dec // current shares
RecipientPrevShares() sdk.Dec // shares last block
ModifyAdjustments(withdrawal sdk.Dec) // proceedure to modify adjustment factors
}
```
#### Entitled reward from distribution scenario
The entitlement to the distributor's tokens held can be accounted for lazily.
To begin this calculation we must determine the recipient's _simple pool_ and
_projected pool_. The simple pool represents a lazy accounting of what a
recipient's entitlement to the distributor's tokens would be if all recipients
for that distributor had static shares (equal to the current shares), and no
recipients had ever withdrawn their entitled rewards. The projected pool
represents the anticipated recipient's entitlement to the distributors tokens
based on the current blocks token input (for example fees reward received) to
the distributor, and the distributor's tokens and shares of the previous block
assuming that neither had changed in the current block. Using the simple and
projected pools we can determine all cumulative changes which have taken place
outside of the recipient and adjust the recipient's _adjustment factor_ to
account for these changes and ultimately keep track of the correct entitlement
to the distributors tokens.
```
func (d DistributionScenario) RecipientCount(height int64) sdk.Dec
return v.RecipientShares() * height
func (d DistributionScenario) GlobalCount(height int64) sdk.Dec
return d.DistributorShares() * height
func (d DistributionScenario) SimplePool() DecCoins
return d.RecipientCount() / d.GlobalCount() * d.DistributorCumulativeTokens
func (d DistributionScenario) ProjectedPool(height int64) DecCoins
return d.RecipientPrevShares() * (height-1)
/ (d.DistributorPrevShares() * (height-1))
* d.DistributorCumulativeTokens
+ d.RecipientShares() / d.DistributorShares()
* d.DistributorPrevReceivedTokens()
```
The `DistributionScenario` _adjustment_ terms account for changes in
recipient/distributor shares and recipient withdrawals. The adjustment factor
must be modified whenever the recipient withdraws from the distributor or the
distributor's/recipient's shares are changed.
- When the shares of the recipient is changed the adjustment factor is
increased/decreased by the difference between the _simple_ and _projected_
pools. In other words, the cumulative difference in the shares if the shares
has been the new shares as opposed to the old shares for the entire duration of
the blockchain up the previous block.
- When a recipient makes a withdrawal the adjustment factor is increased by the
withdrawal amount.
```
func (d DistributionScenario) UpdateAdjustmentForPowerChange(height int64)
simplePool = d.SimplePool()
projectedPool = d.ProjectedPool(height)
AdjustmentChange = simplePool - projectedPool
if AdjustmentChange > 0
d.ModifyAdjustments(AdjustmentChange)
func (d DistributionScenario) WithdrawalEntitlement() DecCoins
entitlement = d.SimplePool() - d.RecipientAdjustment()
d.ModifyAdjustments(entitlement)
return entitlement
```
### Distribution scenarios
Note that the distribution scenario structures are found in `state.md`.
#### Delegation's entitlement to Global.Pool
For delegations (including validator's self-delegation) all fees from fee pool
are subject to commission rate from the operator of the validator. The global
shares should be taken as true number of global bonded shares. The recipients
shares should be taken as the bonded tokens less the validator's commission.
```
type DelegationFromGlobalPool struct {
DelegationShares sdk.Dec
ValidatorCommission sdk.Dec
ValidatorBondedTokens sdk.Dec
ValidatorDelegatorShareExRate sdk.Dec
PoolBondedTokens sdk.Dec
Global Global
ValDistr ValidatorDistribution
DelDistr DelegatorDistribution
}
func (d DelegationFromGlobalPool) DistributorTokens() DecCoins
return d.Global.Pool
func (d DelegationFromGlobalPool) DistributorCumulativeTokens() DecCoins
return d.Global.EverReceivedPool
func (d DelegationFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
return d.Global.PrevReceivedPool
func (d DelegationFromGlobalPool) DistributorShares() sdk.Dec
return d.PoolBondedTokens
func (d DelegationFromGlobalPool) DistributorPrevShares() sdk.Dec
return d.Global.PrevBondedTokens
func (d DelegationFromGlobalPool) RecipientShares() sdk.Dec
return d.DelegationShares * d.ValidatorDelegatorShareExRate() *
d.ValidatorBondedTokens() * (1 - d.ValidatorCommission)
func (d DelegationFromGlobalPool) RecipientPrevShares() sdk.Dec
return d.DelDistr.PrevTokens
func (d DelegationFromGlobalPool) RecipientAdjustment() sdk.Dec
return d.DelDistr.Adjustment
func (d DelegationFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
d.ValDistr.Adjustment += withdrawal
d.DelDistr.Adjustment += withdrawal
d.global.Adjustment += withdrawal
SetValidatorDistribution(d.ValDistr)
SetDelegatorDistribution(d.DelDistr)
SetGlobal(d.Global)
```
#### Delegation's entitlement to ValidatorDistribution.ProposerPool
Delegations (including validator's self-delegation) are still subject
commission on the rewards gained from the proposer pool. Global shares in this
context is actually the validators total delegations shares. The recipient's
shares is taken as the effective delegation shares less the validator's
commission.
```
type DelegationFromProposerPool struct {
DelegationShares sdk.Dec
ValidatorCommission sdk.Dec
ValidatorDelegatorShares sdk.Dec
ValDistr ValidatorDistribution
DelDistr DelegatorDistribution
}
func (d DelegationFromProposerPool) DistributorTokens() DecCoins
return d.ValDistr.ProposerPool
func (d DelegationFromProposerPool) DistributorCumulativeTokens() DecCoins
return d.ValDistr.EverReceivedProposerReward
func (d DelegationFromProposerPool) DistributorPrevReceivedTokens() DecCoins
return d.ValDistr.PrevReceivedProposerReward
func (d DelegationFromProposerPool) DistributorShares() sdk.Dec
return d.ValidatorDelegatorShares
func (d DelegationFromProposerPool) DistributorPrevShares() sdk.Dec
return d.ValDistr.PrevDelegatorShares
func (d DelegationFromProposerPool) RecipientShares() sdk.Dec
return d.DelegationShares * (1 - d.ValidatorCommission)
func (d DelegationFromProposerPool) RecipientPrevShares() sdk.Dec
return d.DelDistr.PrevShares
func (d DelegationFromProposerPool) RecipientAdjustment() sdk.Dec
return d.DelDistr.AdjustmentProposer
func (d DelegationFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
d.ValDistr.AdjustmentProposer += withdrawal
d.DelDistr.AdjustmentProposer += withdrawal
SetValidatorDistribution(d.ValDistr)
SetDelegatorDistribution(d.DelDistr)
```
#### Validators's commission entitlement to Global.Pool
Similar to a delegator's entitlement, but with recipient shares based on the
commission portion of bonded tokens.
```
type CommissionFromGlobalPool struct {
ValidatorBondedTokens sdk.Dec
ValidatorCommission sdk.Dec
PoolBondedTokens sdk.Dec
Global Global
ValDistr ValidatorDistribution
}
func (c CommissionFromGlobalPool) DistributorTokens() DecCoins
return c.Global.Pool
func (c CommissionFromGlobalPool) DistributorCumulativeTokens() DecCoins
return c.Global.EverReceivedPool
func (c CommissionFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
return c.Global.PrevReceivedPool
func (c CommissionFromGlobalPool) DistributorShares() sdk.Dec
return c.PoolBondedTokens
func (c CommissionFromGlobalPool) DistributorPrevShares() sdk.Dec
return c.Global.PrevBondedTokens
func (c CommissionFromGlobalPool) RecipientShares() sdk.Dec
return c.ValidatorBondedTokens() * c.ValidatorCommission
func (c CommissionFromGlobalPool) RecipientPrevShares() sdk.Dec
return c.ValDistr.PrevBondedTokens * c.ValidatorCommission
func (c CommissionFromGlobalPool) RecipientAdjustment() sdk.Dec
return c.ValDistr.Adjustment
func (c CommissionFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
c.ValDistr.Adjustment += withdrawal
c.Global.Adjustment += withdrawal
SetValidatorDistribution(c.ValDistr)
SetGlobal(c.Global)
```
#### Validators's commission entitlement to ValidatorDistribution.ProposerPool
Similar to a delegators entitlement to the proposer pool, but with recipient
shares based on the commission portion of the total delegator shares.
```
type CommissionFromProposerPool struct {
ValidatorDelegatorShares sdk.Dec
ValidatorCommission sdk.Dec
ValDistr ValidatorDistribution
}
func (c CommissionFromProposerPool) DistributorTokens() DecCoins
return c.ValDistr.ProposerPool
func (c CommissionFromProposerPool) DistributorCumulativeTokens() DecCoins
return c.ValDistr.EverReceivedProposerReward
func (c CommissionFromProposerPool) DistributorPrevReceivedTokens() DecCoins
return c.ValDistr.PrevReceivedProposerReward
func (c CommissionFromProposerPool) DistributorShares() sdk.Dec
return c.ValidatorDelegatorShares
func (c CommissionFromProposerPool) DistributorPrevShares() sdk.Dec
return c.ValDistr.PrevDelegatorShares
func (c CommissionFromProposerPool) RecipientShares() sdk.Dec
return c.ValidatorDelegatorShares * (c.ValidatorCommission)
func (c CommissionFromProposerPool) RecipientPrevShares() sdk.Dec
return c.ValDistr.PrevDelegatorShares * (c.ValidatorCommission)
func (c CommissionFromProposerPool) RecipientAdjustment() sdk.Dec
return c.ValDistr.AdjustmentProposer
func (c CommissionFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
c.ValDistr.AdjustmentProposer += withdrawal
SetValidatorDistribution(c.ValDistr)
```

View File

@ -714,7 +714,7 @@ definitions:
ValidatorAddress:
type: string
description: bech32 encoded addres
example: cosmosval:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
example: cosmosvaloper:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
PubKey:
type: string
description: bech32 encoded public key
@ -722,7 +722,7 @@ definitions:
ValidatorPubKey:
type: string
description: bech32 encoded public key
example: cosmosvalpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
example: cosmosvalconspub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
Coins:
type: object
properties:

View File

@ -57,7 +57,9 @@ module.exports = {
{
title: "Lotion JS",
collapsable: false,
children: [["/lotion/overview", "Overview"], "/lotion/building-an-app"]
children: [
["/lotion/overview", "Overview"]
]
},
{
title: "Validators",

View File

@ -226,6 +226,113 @@ Returns on success:
"sequence": 7
}
}
```
### POST /auth/tx/sign
- **URL**: `/auth/tx/sign`
- **Functionality**: Sign a transaction without broadcasting it.
- Returns on success:
```json
{
"rest api": "1.0",
"code": 200,
"error": "",
"result": {
"type": "auth/StdTx",
"value": {
"msg": [
{
"type": "cosmos-sdk/Send",
"value": {
"inputs": [
{
"address": "cosmos1ql4ekxkujf3xllk8h5ldhhgh4ylpu7kwec6q3d",
"coins": [
{
"denom": "steak",
"amount": "1"
}
]
}
],
"outputs": [
{
"address": "cosmos1dhyqhg4px33ed3erqymls0hc7q2lxw9hhfwklj",
"coins": [
{
"denom": "steak",
"amount": "1"
}
]
}
]
}
}
],
"fee": {
"amount": [
{
"denom": "",
"amount": "0"
}
],
"gas": "2742"
},
"signatures": [
{
"pub_key": {
"type": "tendermint/PubKeySecp256k1",
"value": "A2A/f2IYnrPUMTMqhwN81oas9jurtfcsvxdeLlNw3gGy"
},
"signature": "MEQCIGVn73y9QLwBa3vmsAD1bs3ygX75Wo+lAFSAUDs431ZPAiBWAf2amyqTCDXE9J87rL9QF9sd5JvVMt7goGSuamPJwg==",
"account_number": "1",
"sequence": "0"
}
],
"memo": ""
}
}
}
```
### POST /auth/tx/broadcast
- **URL**: `/auth/broadcast`
- **Functionality**: Broadcast a transaction.
- Returns on success:
```json
{
"rest api": "1.0",
"code": 200,
"error": "",
"result":
{
"check_tx": {
"log": "Msg 0: ",
"gasWanted": "2742",
"gasUsed": "1002"
},
"deliver_tx": {
"log": "Msg 0: ",
"gasWanted": "2742",
"gasUsed": "2742",
"tags": [
{
"key": "c2VuZGVy",
"value": "Y29zbW9zMXdjNTl6ZXU3MmNjdnp5ZWR6ZGE1N3pzcXh2eXZ2Y3poaHBhdDI4"
},
{
"key": "cmVjaXBpZW50",
"value": "Y29zbW9zMTJ4OTNmY3V2azg3M3o1ejZnejRlNTl2dnlxcXp1eDdzdDcwNWd5"
}
]
},
"hash": "784314784503582AC885BD6FB0D2A5B79FF703A7",
"height": "5"
}
}
```
@ -656,7 +763,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te
"chain_id": "string",
"account_number": 0,
"sequence": 0,
"gas": 0
"gas": "simulate"
},
"depositer": "string",
"amount": 0,
@ -759,7 +866,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te
"chain_id": "string",
"account_number": 0,
"sequence": 0,
"gas": 0
"gas": "simulate"
},
// A cosmos address
"voter": "string",

View File

@ -1,46 +0,0 @@
# Building an App
::: tip
Lotion requires __node v7.6.0__ or higher, and a mac or linux machine.
:::
## Installation
```
$ npm install lotion
```
## Simple App
`app.js`:
```js
let lotion = require('lotion')
let app = lotion({
initialState: {
count: 0
}
})
app.use(function (state, tx) {
if(state.count === tx.nonce) {
state.count++
}
})
app.listen(3000)
```
run `node app.js`, then:
```bash
$ curl http://localhost:3000/state
# { "count": 0 }
$ curl http://localhost:3000/txs -d '{ "nonce": 0 }'
# { "ok": true }
$ curl http://localhost:3000/state
# { "count": 1 }
```
## Learn More
You can learn more about Lotion JS by visiting Lotion on [Github](https://github.com/keppel/lotion).

View File

@ -1,5 +1,54 @@
# Lotion JS Overview
# Overview
Lotion is a new way to create blockchain apps in JavaScript, which aims to make writing new blockchains fast and fun. It builds on top of Tendermint using the ABCI protocol. Lotion lets you write secure, scalable applications that can easily interoperate with other blockchains on the Cosmos Network using IBC.
Lotion is an alternative to the Cosmos SDK and allows you to create blockchain apps in JavaScript. It aims to make writing new blockchain apps fast and easy by using the ABCI protocol to build on top of Tendermint. Lotion lets you write secure, scalable applications that can easily interoperate with other blockchains on the Cosmos Network using IBC.
Lotion itself is a tiny framework; its true power comes from the network of small, focused modules built upon it. Adding a fully-featured cryptocurrency to your blockchain, for example, takes only a few lines of code.
For more information see the [website](https://lotionjs.com) and [GitHub repo](https://github.com/keppel/lotion), for complete documentation which expands on the following example.
## Building an App
### Installation
::: tip
Lotion requires __node v7.6.0__ or higher, and a mac or linux machine.
:::
```
$ npm install lotion
```
### Simple App
`app.js`:
```js
let lotion = require('lotion')
let app = lotion({
initialState: {
count: 0
}
})
app.use(function (state, tx) {
if(state.count === tx.nonce) {
state.count++
}
})
app.listen(3000)
```
run `node app.js`, then:
```bash
$ curl http://localhost:3000/state
# { "count": 0 }
$ curl http://localhost:3000/txs -d '{ "nonce": 0 }'
# { "ok": true }
$ curl http://localhost:3000/state
# { "count": 1 }
```

View File

@ -22,17 +22,17 @@ There are three types of key representations that are used:
- Derived from account keys generated by `gaiacli keys add`
- Used to receive funds
- e.g. `cosmos15h6vd5f0wqps26zjlwrc6chah08ryu4hzzdwhc`
* `cosmosval`
* `cosmosvaloper`
* Used to associate a validator to it's operator
* Used to invoke staking commands
* e.g. `cosmosval1carzvgq3e6y3z5kz5y6gxp3wpy3qdrv928vyah`
* e.g. `cosmosvaloper1carzvgq3e6y3z5kz5y6gxp3wpy3qdrv928vyah`
- `cosmospub`
- Derived from account keys generated by `gaiacli keys add`
- e.g. `cosmospub1zcjduc3q7fu03jnlu2xpl75s2nkt7krm6grh4cc5aqth73v0zwmea25wj2hsqhlqzm`
- `cosmosconspub`
- `cosmosvalconspub`
- Generated when the node is created with `gaiad init`.
- Get this value with `gaiad tendermint show-validator`
- e.g. `cosmosconspub1zcjduepq0ms2738680y72v44tfyqm3c9ppduku8fs6sr73fx7m666sjztznqzp2emf`
- e.g. `cosmosvalconspub1zcjduepq0ms2738680y72v44tfyqm3c9ppduku8fs6sr73fx7m666sjztznqzp2emf`
#### Generate Keys
@ -111,7 +111,7 @@ The `--amount` flag accepts the format `--amount=<value|coin_name>`.
::: tip Note
You may want to cap the maximum gas that can be consumed by the transaction via the `--gas` flag.
If set to 0, the gas limit will be automatically estimated.
If you pass `--gas=simulate`, the gas limit will be automatically estimated.
Gas estimate might be inaccurate as state changes could occur in between the end of the simulation and the actual execution of a transaction, thus an adjustment is applied on top of the original estimate in order to ensure the transaction is broadcasted successfully. The adjustment can be controlled via the `--gas-adjustment` flag, whose default value is 1.0.
:::
@ -139,6 +139,32 @@ gaiacli send \
--dry-run
```
Furthermore, you can build a transaction and print its JSON format to STDOUT by appending `--generate-only` to the list of the command line arguments:
```bash
gaiacli send \
--amount=10faucetToken \
--chain-id=<chain_id> \
--name=<key_name> \
--to=<destination_cosmosaccaddr> \
--generate-only > unsignedSendTx.json
```
You can now sign the transaction file generated through the `--generate-only` flag by providing your key to the following command:
```bash
gaiacli sign \
--chain-id=<chain_id> \
--name=<key_name>
unsignedSendTx.json > signedSendTx.json
```
You can broadcast the signed transaction to a node by providing the JSON file to the following command:
```
gaiacli broadcast --node=<node> signedSendTx.json
```
### Staking
#### Set up a Validator

View File

@ -285,7 +285,7 @@ it can't increment sequence numbers, change PubKeys, or otherwise.
A `bank.Keeper` is easily instantiated from an `AccountMapper`:
```go
coinKeeper = bank.NewKeeper(accountMapper)
bankKeeper = bank.NewBaseKeeper(accountMapper)
```
We can then use it within a handler, instead of working directly with the
@ -295,7 +295,7 @@ We can then use it within a handler, instead of working directly with the
// Finds account with addr in AccountMapper.
// Adds coins to account's coin array.
// Sets updated account in AccountMapper
app.coinKeeper.AddCoins(ctx, addr, coins)
app.bankKeeper.AddCoins(ctx, addr, coins)
```
See the [bank.Keeper API
@ -336,7 +336,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Set various mappers/keepers to interact easily with underlying stores
accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount)
coinKeeper := bank.NewKeeper(accountMapper)
bankKeeper := bank.NewBaseKeeper(accountMapper)
feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees)
app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper))
@ -344,7 +344,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Register message routes.
// Note the handler gets access to
app.Router().
AddRoute("send", bank.NewHandler(coinKeeper))
AddRoute("send", bank.NewHandler(bankKeeper))
// Mount stores and load the latest state.
app.MountStoresIAVL(keyAccount, keyFees)

View File

@ -31,7 +31,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Set various mappers/keepers to interact easily with underlying stores
accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount)
coinKeeper := bank.NewKeeper(accountMapper)
bankKeeper := bank.NewBaseKeeper(accountMapper)
feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees)
app.SetAnteHandler(auth.NewAnteHandler(accountMapper, feeKeeper))
@ -39,7 +39,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Register message routes.
// Note the handler gets access to
app.Router().
AddRoute("bank", bank.NewHandler(coinKeeper))
AddRoute("bank", bank.NewHandler(bankKeeper))
// Mount stores and load the latest state.
app.MountStoresIAVL(keyAccount, keyFees)

View File

@ -29,7 +29,7 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Set various mappers/keepers to interact easily with underlying stores
accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount)
coinKeeper := bank.NewKeeper(accountMapper)
bankKeeper := bank.NewBaseKeeper(accountMapper)
// TODO
keyFees := sdk.NewKVStoreKey("fee")
@ -43,7 +43,7 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Register message routes.
// Note the handler gets access to the account store.
app.Router().
AddRoute("bank", bank.NewHandler(coinKeeper))
AddRoute("bank", bank.NewHandler(bankKeeper))
// Mount stores and load the latest state.
app.MountStoresIAVL(keyAccount, keyFees)

View File

@ -33,16 +33,16 @@ var cdc = MakeCodec()
- Instantiate the keepers. Note that keepers generally need access to other module's keepers. In this case, make sure you only pass an instance of the keeper for the functionality that is needed. If a keeper only needs to read in another module's store, a read-only keeper should be passed to it.
```go
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.coinKeeper,app.RegisterCodespace(simplestake.DefaultCodespace))
app.simpleGovKeeper = simpleGov.NewKeeper(app.capKeySimpleGovStore, app.coinKeeper, app.stakeKeeper, app.RegisterCodespace(simpleGov.DefaultCodespace))
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper,app.RegisterCodespace(simplestake.DefaultCodespace))
app.simpleGovKeeper = simpleGov.NewKeeper(app.capKeySimpleGovStore, app.bankKeeper, app.stakeKeeper, app.RegisterCodespace(simpleGov.DefaultCodespace))
```
- Declare the handlers.
```go
app.Router().
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("simplestake", simplestake.NewHandler(app.stakeKeeper)).
AddRoute("simpleGov", simpleGov.NewHandler(app.simpleGovKeeper))
```

View File

@ -38,7 +38,7 @@ type SimpleGovApp struct {
// keepers
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper
bankKeeper bank.Keeper
stakeKeeper simplestake.Keeper
simpleGovKeeper simpleGov.Keeper

View File

@ -1,12 +1,12 @@
# End Block
At each endblock, the fees received are sorted to the proposer, community fund,
At each endblock, the fees received are allocated to the proposer, community fund,
and global pool. When the validator is the proposer of the round, that
validator (and their delegators) receives between 1% and 5% of fee rewards, the
reserve tax is then charged, then the remainder is distributed proportionally
by voting power to all bonded validators independent of whether they voted
(social distribution). Note the social distribution is applied to proposer
validator in addition to the proposer reward.
reserve community tax is then charged, then the remainder is distributed
proportionally by voting power to all bonded validators independent of whether
they voted (social distribution). Note the social distribution is applied to
proposer validator in addition to the proposer reward.
The amount of proposer reward is calculated from pre-commits Tendermint
messages in order to incentivize validators to wait and include additional
@ -15,13 +15,17 @@ pool which validator holds individually
(`ValidatorDistribution.ProvisionsRewardPool`).
```
func SortFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
sumPowerPrecommitValidators, totalBondedTokens, communityTax sdk.Dec)
func AllocateFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
sumPowerPrecommitValidators, totalBondedTokens, communityTax,
proposerCommissionRate sdk.Dec)
feesCollectedDec = MakeDecCoins(feesCollected)
proposerReward = feesCollectedDec * (0.01 + 0.04
* sumPowerPrecommitValidators / totalBondedTokens)
proposer.ProposerPool += proposerReward
commission = proposerReward * proposerCommissionRate
proposer.PoolCommission += commission
proposer.Pool += proposerReward - commission
communityFunding = feesCollectedDec * communityTax
global.CommunityFund += communityFunding

View File

@ -0,0 +1,26 @@
# Hooks
## Create or modify delegation distribution
- triggered-by: `stake.TxDelegate`, `stake.TxBeginRedelegate`, `stake.TxBeginUnbonding`
The pool of a new delegator bond will be 0 for the height at which the bond was
added, or the withdrawal has taken place. This is achieved by setting
`DelegatorDistInfo.WithdrawalHeight` to the height of the triggering transaction.
## Commission rate change
- triggered-by: `stake.TxEditValidator`
If a validator changes its commission rate, all commission on fees must be
simultaneously withdrawn using the transaction `TxWithdrawValidator`.
Additionally the change and associated height must be recorded in a
`ValidatorUpdate` state record.
## Change in Validator State
- triggered-by: `stake.Slash`, `stake.UpdateValidator`
Whenever a validator is slashed or enters/leaves the validator group all of the
validator entitled reward tokens must be simultaneously withdrawn from
`Global.Pool` and added to `ValidatorDistInfo.Pool`.

View File

@ -2,53 +2,71 @@
## Overview
Collected fees are pooled globally and divided out passively to validators and
delegators. Each validator has the opportunity to charge commission to the
delegators on the fees collected on behalf of the delegators by the validators.
Fees are paid directly into a global fee pool, and validator proposer-reward
pool. Due to the nature of passive accounting whenever changes to parameters
which affect the rate of fee distribution occurs, withdrawal of fees must also
occur when:
- withdrawing one must withdrawal the maximum amount they are entitled
too, leaving nothing in the pool,
- bonding, unbonding, or re-delegating tokens to an existing account a
full withdrawal of the fees must occur (as the rules for lazy accounting
change),
- a validator chooses to change the commission on fees, all accumulated
commission fees must be simultaneously withdrawn.
This _simple_ distribution mechanism describes a functional way to passively
distribute rewards between validator and delegators. Note that this mechanism does
not distribute funds in as precisely as active reward distribution and will therefore
be upgraded in the future.
The above scenarios are covered in `triggers.md`.
The mechanism operates as follows. Collected rewards are pooled globally and
divided out passively to validators and delegators. Each validator has the
opportunity to charge commission to the delegators on the rewards collected on
behalf of the delegators by the validators. Fees are paid directly into a
global reward pool, and validator proposer-reward pool. Due to the nature of
passive accounting, whenever changes to parameters which affect the rate of reward
distribution occurs, withdrawal of rewards must also occur.
- Whenever withdrawing, one must withdraw the maximum amount they are entitled
too, leaving nothing in the pool.
- Whenever bonding, unbonding, or re-delegating tokens to an existing account, a
full withdrawal of the rewards must occur (as the rules for lazy accounting
change).
- Whenever a validator chooses to change the commission on rewards, all accumulated
commission rewards must be simultaneously withdrawn.
The above scenarios are covered in `hooks.md`.
The distribution mechanism outlines herein is used to lazily distribute the
following between validators and associated delegators:
following rewards between validators and associated delegators:
- multi-token fees to be socially distributed,
- proposer reward pool,
- inflated atom provisions, and
- validator commission on all rewards earned by their delegators stake
Fees are pooled within a global pool, as well as validator specific
proposer-reward pools. The mechanisms used allow for validators and delegators
to independently and lazily withdrawn their rewards. As a part of the lazy
computations adjustment factors must be maintained for each validator and
delegator to determine the true proportion of fees in each pool which they are
entitled too. Adjustment factors are updated every time a validator or
delegator's voting power changes. Validators and delegators must withdraw all
fees they are entitled too before they can change their portion of bonded
Atoms.
proposer-reward pools. The mechanisms used allow for validators and delegators
to independently and lazily withdraw their rewards.
## Shortcomings
As a part of the lazy computations, each delegator holds an accumulation term
specific to each validator which is used to estimate what their approximate
fair portion of tokens held in the global pool is owed to them.
```
entitlement = delegator-accumulation / all-delegators-accumulation
```
Under the circumstance that there were constant and equal flow of incoming
reward tokens every block, this distribution mechanism would be equal to the
active distribution (distribute individually to all delegators each block).
However this is unrealistic so deviations from the active distribution will
occur based on fluctuations of incoming reward tokens as well as timing of
reward withdrawal by other delegators.
If you happen to know that incoming rewards are about significantly move up,
you are incentivized to not withdraw until after this event, increasing the
worth of your existing _accum_.
## Affect on Staking
Charging commission on Atom provisions while also allowing for Atom-provisions
to be auto-bonded (distributed directly to the validators bonded stake) is
problematic within DPoS. Fundamentally these two mechnisms are mutually
exclusive. If there are atoms commissions and auto-bonding Atoms, the portion
of Atoms the fee distribution calculation would become very large as the Atom
portion for each delegator would change each block making a withdrawal of fees
problematic within DPoS. Fundamentally these two mechanisms are mutually
exclusive. If there are Atom commissions and auto-bonding Atoms, the portion
of Atoms the reward distribution calculation would become very large as the Atom
portion for each delegator would change each block making a withdrawal of rewards
for a delegator require a calculation for every single block since the last
withdrawal. In conclusion we can only have atom commission and unbonded atoms
provisions, or bonded atom provisions with no Atom commission, and we elect to
withdrawal. In conclusion, we can only have Atom commission and unbonded atoms
provisions or bonded atom provisions with no Atom commission, and we elect to
implement the former. Stakeholders wishing to rebond their provisions may elect
to set up a script to periodically withdraw and rebond fees.
to set up a script to periodically withdraw and rebond rewards.

View File

@ -23,78 +23,46 @@ type DecCoin struct {
}
type Global struct {
PrevBondedTokens sdk.Dec // bonded token amount for the global pool on the previous block
Adjustment sdk.Dec // global adjustment factor for lazy calculations
Pool DecCoins // funds for all validators which have yet to be withdrawn
PrevReceivedPool DecCoins // funds added to the pool on the previous block
EverReceivedPool DecCoins // total funds ever added to the pool
CommunityFund DecCoins // pool for community funds yet to be spent
TotalValAccumUpdateHeight int64 // last height which the total validator accum was updated
TotalValAccum sdk.Dec // total valdator accum held by validators
Pool DecCoins // funds for all validators which have yet to be withdrawn
CommunityPool DecCoins // pool for community funds yet to be spent
}
```
### Validator Distribution
Validator distribution information for the relevant validator is updated each time:
1. delegation amount to a validator are updated,
1. delegation amount to a validator is updated,
2. a validator successfully proposes a block and receives a reward,
3. any delegator withdraws from a validator, or
4. the validator withdraws it's commission.
- ValidatorDistribution: `0x02 | ValOwnerAddr -> amino(validatorDistribution)`
- ValidatorDistInfo: `0x02 | ValOperatorAddr -> amino(validatorDistribution)`
```golang
type ValidatorDistribution struct {
CommissionWithdrawalHeight int64 // last time this validator withdrew commission
Adjustment sdk.Dec // global pool adjustment factor
ProposerAdjustment DecCoins // proposer pool adjustment factor
ProposerPool DecCoins // reward pool collected from being the proposer
EverReceivedProposerReward DecCoins // all rewards ever collected from being the proposer
PrevReceivedProposerReward DecCoins // previous rewards collected from being the proposer
PrevBondedTokens sdk.Dec // bonded token amount on the previous block
PrevDelegatorShares sdk.Dec // amount of delegator shares for the validator on the previous block
type ValidatorDistInfo struct {
GlobalWithdrawalHeight int64 // last height this validator withdrew from the global pool
Pool DecCoins // rewards owed to delegators, commission has already been charged (includes proposer reward)
PoolCommission DecCoins // commission collected by this validator (pending withdrawal)
TotalDelAccumUpdateHeight int64 // last height which the total delegator accum was updated
TotalDelAccum sdk.Dec // total proposer pool accumulation factor held by delegators
}
```
### Delegation Distribution
Each delegation holds multiple adjustment factors to specify its entitlement to
the rewards from a validator. `AdjustmentPool` is used to passively calculate
each bonds entitled fees from the `RewardPool`. `AdjustmentPool` is used to
passively calculate each bonds entitled fees from
`ValidatorDistribution.ProposerRewardPool`
Each delegation distribution only needs to record the height at which it last
withdrew fees. Because a delegation must withdraw fees each time it's
properties change (aka bonded tokens etc.) its properties will remain constant
and the delegator's _accumulation_ factor can be calculated passively knowing
only the height of the last withdrawal and its current properties.
- DelegatorDistribution: ` 0x02 | DelegatorAddr | ValOwnerAddr -> amino(delegatorDist)`
- DelegatorDistInfo: ` 0x02 | DelegatorAddr | ValOperatorAddr -> amino(delegatorDist)`
```golang
type DelegatorDist struct {
WithdrawalHeight int64 // last time this delegation withdrew rewards
Adjustment sdk.Dec // fee provisioning adjustment factor
AdjustmentProposer DecCoins // proposers pool adjustment factor
PrevTokens sdk.Dec // bonded tokens held by the delegation on the previous block
PrevShares sdk.Dec // delegator shares held by the delegation on the previous block
}
```
### Power Change
Every instance that the voting power changes, information about the state of
the validator set during the change must be recorded as a `PowerChange` for
other validators to run through. Each power change is indexed by its block
height.
- PowerChange: `0x03 | amino(Height) -> amino(validatorDist)`
```golang
type PowerChange struct {
Height int64 // block height at change
ValidatorBondedTokens sdk.Dec // following used to create distribution scenarios
ValidatorDelegatorShares sdk.Dec
ValidatorDelegatorShareExRate sdk.Dec
ValidatorCommission sdk.Dec
PoolBondedTokens sdk.Dec
Global Global
ValDistr ValidatorDistribution
DelegationShares sdk.Dec
DelDistr DelegatorDistribution
type DelegatorDistInfo struct {
WithdrawalHeight int64 // last time this delegation withdrew rewards
}
```

View File

@ -1,399 +1,213 @@
# Transactions
## TxWithdrawDelegation
## TxWithdrawDelegationRewardsAll
When a delegator wishes to withdraw their transaction fees it must send
`TxWithdrawDelegation`. Note that parts of this transaction logic are also
When a delegator wishes to withdraw their rewards it must send
`TxWithdrawDelegationRewardsAll`. Note that parts of this transaction logic are also
triggered each with any change in individual delegations, such as an unbond,
redelegation, or delegation of additional tokens to a specific validator.
Each time a withdrawal is made by a recipient the adjustment term must be
modified for each block with a change in distributors shares since the time of
last withdrawal. This is accomplished by iterating over all relevant
`PowerChange`'s stored in distribution state.
```golang
type TxWithdrawDelegation struct {
type TxWithdrawDelegationRewardsAll struct {
delegatorAddr sdk.AccAddress
withdrawAddr sdk.AccAddress // address to make the withdrawal to
}
func WithdrawDelegator(delegatorAddr, withdrawAddr sdk.AccAddress)
entitlement = GetDelegatorEntitlement(delegatorAddr)
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
func WithdrawDelegationRewardsAll(delegatorAddr, withdrawAddr sdk.AccAddress)
height = GetHeight()
withdraw = GetDelegatorRewardsAll(delegatorAddr, height)
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
func GetDelegatorEntitlement(delegatorAddr sdk.AccAddress) DecCoins
func GetDelegatorRewardsAll(delegatorAddr sdk.AccAddress, height int64) DecCoins
// compile all the distribution scenarios
// get all distribution scenarios
delegations = GetDelegations(delegatorAddr)
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
delegation.ValidatorAddr)
pcs = GetPowerChanges(DelDistr.WithdrawalHeight)
// update all adjustment factors for each delegation since last withdrawal
for pc = range pcs
for delegation = range delegations
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
delegation.ValidatorAddr)
pc.ProcessPowerChangeDelegation(delegation, DelDistr)
// collect all entitled fees
entitlement = 0
// collect all entitled rewards
withdraw = 0
pool = stake.GetPool()
global = GetGlobal()
for delegation = range delegations
global = GetGlobal()
pool = GetPool()
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
delInfo = GetDelegationDistInfo(delegation.DelegatorAddr,
delegation.ValidatorAddr)
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
valInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
validator = GetValidator(delegation.ValidatorAddr)
scenerio1 = NewDelegationFromGlobalPool(delegation, validator,
pool, global, ValDistr, DelDistr)
scenerio2 = NewDelegationFromProvisionPool(delegation, validator,
ValDistr, DelDistr)
entitlement += scenerio1.WithdrawalEntitlement()
entitlement += scenerio2.WithdrawalEntitlement()
return entitlement
global, diWithdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
validator.Tokens, validator.DelegatorShares, validator.Commission)
withdraw += diWithdraw
func (pc PowerChange) ProcessPowerChangeDelegation(delegation sdk.Delegation,
DelDistr DelegationDistribution)
// get the historical scenarios
scenario1 = pc.DelegationFromGlobalPool(delegation, DelDistr)
scenario2 = pc.DelegationFromProvisionPool(delegation, DelDistr)
// process the adjustment factors
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
SetGlobal(global)
return withdraw
```
## TxWithdrawValidator
## TxWithdrawDelegationReward
When a validator wishes to withdraw their transaction fees it must send
`TxWithdrawDelegation`. Note that parts of this transaction logic is also
triggered each with any change in individual delegations, such as an unbond,
redelegation, or delegation of additional tokens to a specific validator. This
transaction withdraws the validators commission rewards, as well as any rewards
earning on their self-delegation.
under special circumstances a delegator may wish to withdraw rewards from only
a single validator.
```golang
type TxWithdrawValidator struct {
ownerAddr sdk.AccAddress // validator address to withdraw from
type TxWithdrawDelegationReward struct {
delegatorAddr sdk.AccAddress
validatorAddr sdk.AccAddress
withdrawAddr sdk.AccAddress // address to make the withdrawal to
}
func WithdrawDelegationReward(delegatorAddr, validatorAddr, withdrawAddr sdk.AccAddress)
height = GetHeight()
// get all distribution scenarios
pool = stake.GetPool()
global = GetGlobal()
delInfo = GetDelegationDistInfo(delegatorAddr,
validatorAddr)
valInfo = GetValidatorDistInfo(validatorAddr)
validator = GetValidator(validatorAddr)
global, withdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
validator.Tokens, validator.DelegatorShares, validator.Commission)
SetGlobal(global)
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
```
## TxWithdrawValidatorRewardsAll
When a validator wishes to withdraw their rewards it must send
`TxWithdrawValidatorRewardsAll`. Note that parts of this transaction logic are also
triggered each with any change in individual delegations, such as an unbond,
redelegation, or delegation of additional tokens to a specific validator. This
transaction withdraws the validators commission fee, as well as any rewards
earning on their self-delegation.
```
type TxWithdrawValidatorRewardsAll struct {
operatorAddr sdk.AccAddress // validator address to withdraw from
withdrawAddr sdk.AccAddress // address to make the withdrawal to
}
func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress)
func WithdrawValidatorRewardsAll(operatorAddr, withdrawAddr sdk.AccAddress)
// update the delegator adjustment factors and also withdrawal delegation fees
entitlement = GetDelegatorEntitlement(ownerAddr)
// update the validator adjustment factors for commission
ValDistr = GetValidatorDistribution(ownerAddr.ValidatorAddr)
pcs = GetPowerChanges(ValDistr.CommissionWithdrawalHeight)
for pc = range pcs
pc.ProcessPowerChangeCommission()
// withdrawal validator commission rewards
height = GetHeight()
global = GetGlobal()
pool = GetPool()
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
ValInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
validator = GetValidator(delegation.ValidatorAddr)
scenerio1 = NewCommissionFromGlobalPool(validator,
pool, global, ValDistr)
scenerio2 = CommissionFromProposerPool(validator, ValDistr)
entitlement += scenerio1.WithdrawalEntitlement()
entitlement += scenerio2.WithdrawalEntitlement()
// withdraw self-delegation
withdraw = GetDelegatorRewardsAll(validator.OperatorAddr, height)
// withdrawal validator commission rewards
global, commission = valInfo.WithdrawCommission(global, valInfo, height, pool.BondedTokens,
validator.Tokens, validator.Commission)
withdraw += commission
SetGlobal(global)
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
```
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
## Common calculations
func (pc PowerChange) ProcessPowerChangeCommission()
### Update total validator accum
// get the historical scenarios
scenario1 = pc.CommissionFromGlobalPool()
scenario2 = pc.CommissionFromProposerPool()
The total amount of validator accum must be calculated in order to determine
the amount of pool tokens which a validator is entitled to at a particular
block. The accum is always additive to the existing accum. This term is to be
updated each time rewards are withdrawn from the system.
// process the adjustment factors
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
```
func (g Global) UpdateTotalValAccum(height int64, totalBondedTokens Dec) Global
blocks = height - g.TotalValAccumUpdateHeight
g.TotalValAccum += totalDelShares * blocks
g.TotalValAccumUpdateHeight = height
return g
```
## Common Calculations
### Update validator's accums
### Distribution scenario
The total amount of delegator accum must be updated in order to determine the
amount of pool tokens which each delegator is entitled to, relative to the
other delegators for that validator. The accum is always additive to
the existing accum. This term is to be updated each time a
withdrawal is made from a validator.
A common form of abstracted calculations exists between validators and
delegations attempting to withdrawal their rewards, either from `Global.Pool`
or from `ValidatorDistribution.ProposerPool`. With the following interface
fulfilled the entitled fees for the various scenarios can be calculated.
```golang
type DistributionScenario interface {
DistributorTokens() DecCoins // current tokens from distributor
DistributorCumulativeTokens() DecCoins // total tokens ever received
DistributorPrevReceivedTokens() DecCoins // last value of tokens received
DistributorShares() sdk.Dec // current shares
DistributorPrevShares() sdk.Dec // shares last block
RecipientAdjustment() sdk.Dec
RecipientShares() sdk.Dec // current shares
RecipientPrevShares() sdk.Dec // shares last block
ModifyAdjustments(withdrawal sdk.Dec) // proceedure to modify adjustment factors
}
```
func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares Dec) ValidatorDistInfo
blocks = height - vi.TotalDelAccumUpdateHeight
vi.TotalDelAccum += totalDelShares * blocks
vi.TotalDelAccumUpdateHeight = height
return vi
```
#### Entitled reward from distribution scenario
### Global pool to validator pool
The entitlement to the distributor's tokens held can be accounted for lazily.
To begin this calculation we must determine the recipient's _simple pool_ and
_projected pool_. The simple pool represents a lazy accounting of what a
recipient's entitlement to the distributor's tokens would be if all recipients
for that distributor had static shares (equal to the current shares), and no
recipients had ever withdrawn their entitled rewards. The projected pool
represents the anticipated recipient's entitlement to the distributors tokens
based on the current blocks token input (for example fees reward received) to
the distributor, and the distributor's tokens and shares of the previous block
assuming that neither had changed in the current block. Using the simple and
projected pools we can determine all cumulative changes which have taken place
outside of the recipient and adjust the recipient's _adjustment factor_ to
account for these changes and ultimately keep track of the correct entitlement
to the distributors tokens.
Every time a validator or delegator executes a withdrawal or the validator is
the proposer and receives new tokens, the relevant validator must move tokens
from the passive global pool to their own pool. It is at this point that the
commission is withdrawn
```
func (d DistributionScenario) RecipientCount(height int64) sdk.Dec
return v.RecipientShares() * height
```
func (vi ValidatorDistInfo) TakeAccum(g Global, height int64, totalBonded, vdTokens, commissionRate Dec) (
vi ValidatorDistInfo, g Global)
func (d DistributionScenario) GlobalCount(height int64) sdk.Dec
return d.DistributorShares() * height
func (d DistributionScenario) SimplePool() DecCoins
return d.RecipientCount() / d.GlobalCount() * d.DistributorCumulativeTokens
func (d DistributionScenario) ProjectedPool(height int64) DecCoins
return d.RecipientPrevShares() * (height-1)
/ (d.DistributorPrevShares() * (height-1))
* d.DistributorCumulativeTokens
+ d.RecipientShares() / d.DistributorShares()
* d.DistributorPrevReceivedTokens()
```
The `DistributionScenario` _adjustment_ terms account for changes in
recipient/distributor shares and recipient withdrawals. The adjustment factor
must be modified whenever the recipient withdraws from the distributor or the
distributor's/recipient's shares are changed.
- When the shares of the recipient is changed the adjustment factor is
increased/decreased by the difference between the _simple_ and _projected_
pools. In other words, the cumulative difference in the shares if the shares
has been the new shares as opposed to the old shares for the entire duration of
the blockchain up the previous block.
- When a recipient makes a withdrawal the adjustment factor is increased by the
withdrawal amount.
```
func (d DistributionScenario) UpdateAdjustmentForPowerChange(height int64)
simplePool = d.SimplePool()
projectedPool = d.ProjectedPool(height)
AdjustmentChange = simplePool - projectedPool
if AdjustmentChange > 0
d.ModifyAdjustments(AdjustmentChange)
func (d DistributionScenario) WithdrawalEntitlement() DecCoins
entitlement = d.SimplePool() - d.RecipientAdjustment()
d.ModifyAdjustments(entitlement)
return entitlement
```
### Distribution scenarios
Note that the distribution scenario structures are found in `state.md`.
#### Delegation's entitlement to Global.Pool
For delegations (including validator's self-delegation) all fees from fee pool
are subject to commission rate from the owner of the validator. The global
shares should be taken as true number of global bonded shares. The recipients
shares should be taken as the bonded tokens less the validator's commission.
```
type DelegationFromGlobalPool struct {
DelegationShares sdk.Dec
ValidatorCommission sdk.Dec
ValidatorBondedTokens sdk.Dec
ValidatorDelegatorShareExRate sdk.Dec
PoolBondedTokens sdk.Dec
Global Global
ValDistr ValidatorDistribution
DelDistr DelegatorDistribution
}
func (d DelegationFromGlobalPool) DistributorTokens() DecCoins
return d.Global.Pool
func (d DelegationFromGlobalPool) DistributorCumulativeTokens() DecCoins
return d.Global.EverReceivedPool
func (d DelegationFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
return d.Global.PrevReceivedPool
g.UpdateTotalValAccum(height, totalBondedShares)
func (d DelegationFromGlobalPool) DistributorShares() sdk.Dec
return d.PoolBondedTokens
func (d DelegationFromGlobalPool) DistributorPrevShares() sdk.Dec
return d.Global.PrevBondedTokens
func (d DelegationFromGlobalPool) RecipientShares() sdk.Dec
return d.DelegationShares * d.ValidatorDelegatorShareExRate() *
d.ValidatorBondedTokens() * (1 - d.ValidatorCommission)
func (d DelegationFromGlobalPool) RecipientPrevShares() sdk.Dec
return d.DelDistr.PrevTokens
func (d DelegationFromGlobalPool) RecipientAdjustment() sdk.Dec
return d.DelDistr.Adjustment
func (d DelegationFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
d.ValDistr.Adjustment += withdrawal
d.DelDistr.Adjustment += withdrawal
d.global.Adjustment += withdrawal
SetValidatorDistribution(d.ValDistr)
SetDelegatorDistribution(d.DelDistr)
SetGlobal(d.Global)
```
#### Delegation's entitlement to ValidatorDistribution.ProposerPool
Delegations (including validator's self-delegation) are still subject
commission on the rewards gained from the proposer pool. Global shares in this
context is actually the validators total delegations shares. The recipient's
shares is taken as the effective delegation shares less the validator's
commission.
```
type DelegationFromProposerPool struct {
DelegationShares sdk.Dec
ValidatorCommission sdk.Dec
ValidatorDelegatorShares sdk.Dec
ValDistr ValidatorDistribution
DelDistr DelegatorDistribution
}
func (d DelegationFromProposerPool) DistributorTokens() DecCoins
return d.ValDistr.ProposerPool
func (d DelegationFromProposerPool) DistributorCumulativeTokens() DecCoins
return d.ValDistr.EverReceivedProposerReward
func (d DelegationFromProposerPool) DistributorPrevReceivedTokens() DecCoins
return d.ValDistr.PrevReceivedProposerReward
func (d DelegationFromProposerPool) DistributorShares() sdk.Dec
return d.ValidatorDelegatorShares
func (d DelegationFromProposerPool) DistributorPrevShares() sdk.Dec
return d.ValDistr.PrevDelegatorShares
func (d DelegationFromProposerPool) RecipientShares() sdk.Dec
return d.DelegationShares * (1 - d.ValidatorCommission)
func (d DelegationFromProposerPool) RecipientPrevShares() sdk.Dec
return d.DelDistr.PrevShares
func (d DelegationFromProposerPool) RecipientAdjustment() sdk.Dec
return d.DelDistr.AdjustmentProposer
func (d DelegationFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
d.ValDistr.AdjustmentProposer += withdrawal
d.DelDistr.AdjustmentProposer += withdrawal
SetValidatorDistribution(d.ValDistr)
SetDelegatorDistribution(d.DelDistr)
```
#### Validators's commission entitlement to Global.Pool
Similar to a delegator's entitlement, but with recipient shares based on the
commission portion of bonded tokens.
```
type CommissionFromGlobalPool struct {
ValidatorBondedTokens sdk.Dec
ValidatorCommission sdk.Dec
PoolBondedTokens sdk.Dec
Global Global
ValDistr ValidatorDistribution
}
func (c CommissionFromGlobalPool) DistributorTokens() DecCoins
return c.Global.Pool
func (c CommissionFromGlobalPool) DistributorCumulativeTokens() DecCoins
return c.Global.EverReceivedPool
func (c CommissionFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
return c.Global.PrevReceivedPool
// update the validators pool
blocks = height - vi.GlobalWithdrawalHeight
vi.GlobalWithdrawalHeight = height
accum = blocks * vdTokens
withdrawalTokens := g.Pool * accum / g.TotalValAccum
commission := withdrawalTokens * commissionRate
func (c CommissionFromGlobalPool) DistributorShares() sdk.Dec
return c.PoolBondedTokens
g.TotalValAccum -= accumm
vi.PoolCommission += commission
vi.PoolCommissionFree += withdrawalTokens - commission
g.Pool -= withdrawalTokens
func (c CommissionFromGlobalPool) DistributorPrevShares() sdk.Dec
return c.Global.PrevBondedTokens
func (c CommissionFromGlobalPool) RecipientShares() sdk.Dec
return c.ValidatorBondedTokens() * c.ValidatorCommission
func (c CommissionFromGlobalPool) RecipientPrevShares() sdk.Dec
return c.ValDistr.PrevBondedTokens * c.ValidatorCommission
func (c CommissionFromGlobalPool) RecipientAdjustment() sdk.Dec
return c.ValDistr.Adjustment
func (c CommissionFromGlobalPool) ModifyAdjustments(withdrawal sdk.Dec)
c.ValDistr.Adjustment += withdrawal
c.Global.Adjustment += withdrawal
SetValidatorDistribution(c.ValDistr)
SetGlobal(c.Global)
return vi, g
```
#### Validators's commission entitlement to ValidatorDistribution.ProposerPool
Similar to a delegators entitlement to the proposer pool, but with recipient
shares based on the commission portion of the total delegator shares.
### Delegation reward withdrawal
For delegations (including validator's self-delegation) all rewards from reward
pool have already had the validator's commission taken away.
```
type CommissionFromProposerPool struct {
ValidatorDelegatorShares sdk.Dec
ValidatorCommission sdk.Dec
ValDistr ValidatorDistribution
}
func (di DelegatorDistInfo) WithdrawRewards(g Global, vi ValidatorDistInfo,
height int64, totalBonded, vdTokens, totalDelShares, commissionRate Dec) (
di DelegatorDistInfo, g Global, withdrawn DecCoins)
func (c CommissionFromProposerPool) DistributorTokens() DecCoins
return c.ValDistr.ProposerPool
vi.UpdateTotalDelAccum(height, totalDelShares)
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
blocks = height - di.WithdrawalHeight
di.WithdrawalHeight = height
accum = delegatorShares * blocks
withdrawalTokens := vi.Pool * accum / vi.TotalDelAccum
vi.TotalDelAccum -= accum
func (c CommissionFromProposerPool) DistributorCumulativeTokens() DecCoins
return c.ValDistr.EverReceivedProposerReward
vi.Pool -= withdrawalTokens
vi.TotalDelAccum -= accum
return di, g, withdrawalTokens
func (c CommissionFromProposerPool) DistributorPrevReceivedTokens() DecCoins
return c.ValDistr.PrevReceivedProposerReward
func (c CommissionFromProposerPool) DistributorShares() sdk.Dec
return c.ValidatorDelegatorShares
func (c CommissionFromProposerPool) DistributorPrevShares() sdk.Dec
return c.ValDistr.PrevDelegatorShares
func (c CommissionFromProposerPool) RecipientShares() sdk.Dec
return c.ValidatorDelegatorShares * (c.ValidatorCommission)
func (c CommissionFromProposerPool) RecipientPrevShares() sdk.Dec
return c.ValDistr.PrevDelegatorShares * (c.ValidatorCommission)
func (c CommissionFromProposerPool) RecipientAdjustment() sdk.Dec
return c.ValDistr.AdjustmentProposer
func (c CommissionFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
c.ValDistr.AdjustmentProposer += withdrawal
SetValidatorDistribution(c.ValDistr)
```
### Validator commission withdrawal
Commission is calculated each time rewards enter into the validator.
```
func (vi ValidatorDistInfo) WithdrawCommission(g Global, height int64,
totalBonded, vdTokens, commissionRate Dec) (
vi ValidatorDistInfo, g Global, withdrawn DecCoins)
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
withdrawalTokens := vi.PoolCommission
vi.PoolCommission = 0
return vi, g, withdrawalTokens
```

View File

@ -6,14 +6,14 @@ In the Cosmos network, keys and addresses may refer to a number of different rol
## HRP table
| HRP | Definition |
|---------------|--------------------------------------|
| cosmos | Cosmos Account Address |
| cosmospub | Cosmos Account Public Key |
| cosmoscons | Cosmos Consensus Address |
| cosmosconspub | Cosmos Consensus Public Key |
| cosmosval | Cosmos Validator Operator Address |
| cosmosvalpub | Cosmos Validator Operator Public Key |
| HRP | Definition |
|-------------------|---------------------------------------|
| cosmos | Cosmos Account Address |
| cosmospub | Cosmos Account Public Key |
| cosmosvalcons | Cosmos Validator Consensus Address |
| cosmosvalconspub | Cosmos Validator Consensus Public Key |
| cosmosvaloper | Cosmos Validator Operator Address |
| cosmosvaloperpub | Cosmos Validator Operator Public Key |
## Encoding

View File

@ -12,7 +12,7 @@ the changes cleared
```golang
EndBlock() ValidatorSetChanges
vsc = GetTendermintUpdates()
vsc = GetValidTendermintUpdates()
ClearTendermintUpdates()
return vsc
```

View File

@ -14,7 +14,7 @@ type Pool struct {
BondedTokens int64 // reserve of bonded tokens
InflationLastTime int64 // block which the last inflation was processed // TODO make time
Inflation sdk.Dec // current annual inflation rate
DateLastCommissionReset int64 // unix timestamp for last commission accounting reset (daily)
}
```
@ -29,41 +29,40 @@ overall functioning of the stake module.
```golang
type Params struct {
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
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
MaxValidators uint16 // maximum number of validators
BondDenom string // bondable coin denomination
}
```
### Validator
Validators are identified according to the `ValOwnerAddr`,
an SDK account address for the owner of the validator.
Validators are identified according to the `OperatorAddr`, an SDK validator
address for the operator of the validator.
Validators also have a `ValTendermintAddr`, the address
of the public key of the validator.
Validators also have a `ConsPubKey`, the public key of the validator.
Validators are indexed in the store using the following maps:
- Validators: `0x02 | ValOwnerAddr -> amino(validator)`
- ValidatorsByPubKey: `0x03 | ValTendermintAddr -> ValOwnerAddr`
- ValidatorsByPower: `0x05 | power | blockHeight | blockTx -> ValOwnerAddr`
- Validators: `0x02 | OperatorAddr -> amino(validator)`
- ValidatorsByPubKey: `0x03 | ConsPubKey -> OperatorAddr`
- ValidatorsByPower: `0x05 | power | blockHeight | blockTx -> OperatorAddr`
`Validators` is the primary index - it ensures that each owner can have only one
associated validator, where the public key of that validator can change in the
future. Delegators can refer to the immutable owner of the validator, without
concern for the changing public key.
`Validators` is the primary index - it ensures that each operator can have only one
associated validator, where the public key of that validator can change in the
future. Delegators can refer to the immutable operator of the validator, without
concern for the changing public key.
`ValidatorsByPubKey` is a secondary index that enables lookups for slashing.
When Tendermint reports evidence, it provides the validator address, so this
map is needed to find the owner.
`ValidatorsByPubKey` is a secondary index that enables lookups for slashing.
When Tendermint reports evidence, it provides the validator address, so this
map is needed to find the operator.
`ValidatorsByPower` is a secondary index that provides a sorted list of
potential validators to quickly determine the current active set. For instance,
the first 100 validators in this list can be returned with every EndBlock.
`ValidatorsByPower` is a secondary index that provides a sorted list of
potential validators to quickly determine the current active set. For instance,
the first 100 validators in this list can be returned with every EndBlock.
The `Validator` holds the current state and some historical actions of the
validator.
@ -72,18 +71,18 @@ validator.
type Validator struct {
ConsensusPubKey crypto.PubKey // Tendermint consensus pubkey of validator
Jailed bool // has the validator been jailed?
Status sdk.BondStatus // validator status (bonded/unbonding/unbonded)
Tokens sdk.Dec // delegated tokens (incl. self-delegation)
Status sdk.BondStatus // validator status (bonded/unbonding/unbonded)
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
// Needed for ordering vals in the by-power key
BondHeight int64 // earliest height as a bonded validator
BondIntraTxCounter int16 // block-local tx index of validator change
CommissionInfo CommissionInfo // info about the validator's commission
}
@ -96,42 +95,41 @@ type CommissionInfo struct {
}
type Description struct {
Moniker string // name
Identity string // optional identity signature (ex. UPort or Keybase)
Website string // optional website link
Details string // optional details
Moniker string // name
Identity string // optional identity signature (ex. UPort or Keybase)
Website string // optional website link
Details string // optional details
}
```
### Delegation
Delegations are identified by combining `DelegatorAddr` (the address of the delegator) with the ValOwnerAddr
Delegators are indexed in the store as follows:
Delegations are identified by combining `DelegatorAddr` (the address of the delegator)
with the `OperatorAddr` Delegators are indexed in the store as follows:
- Delegation: ` 0x0A | DelegatorAddr | ValOwnerAddr -> amino(delegation)`
- Delegation: ` 0x0A | DelegatorAddr | OperatorAddr -> amino(delegation)`
Atom holders may delegate coins to validators; under this circumstance their
funds are held in a `Delegation` data structure. It is owned by one
delegator, and is associated with the shares for one validator. The sender of
funds are held in a `Delegation` data structure. It is owned by one
delegator, and is associated with the shares for one validator. The sender of
the transaction is the owner of the bond.
```golang
type Delegation struct {
Shares sdk.Dec // delegation shares recieved
Height int64 // last height bond updated
Shares sdk.Dec // delegation shares received
Height int64 // last height bond updated
}
```
### UnbondingDelegation
Shares in a `Delegation` can be unbonded, but they must for some time exist as an `UnbondingDelegation`,
where shares can be reduced if Byzantine behaviour is detected.
Shares in a `Delegation` can be unbonded, but they must for some time exist as an `UnbondingDelegation`, where shares can be reduced if Byzantine behavior is detected.
`UnbondingDelegation` are indexed in the store as:
- UnbondingDelegationByDelegator: ` 0x0B | DelegatorAddr | ValOwnerAddr ->
- UnbondingDelegationByDelegator: ` 0x0B | DelegatorAddr | OperatorAddr ->
amino(unbondingDelegation)`
- UnbondingDelegationByValOwner: ` 0x0C | ValOwnerAddr | DelegatorAddr | ValOwnerAddr ->
- UnbondingDelegationByValOwner: ` 0x0C | OperatorAddr | DelegatorAddr | OperatorAddr ->
nil`
The first map here is used in queries, to lookup all unbonding delegations for
@ -148,26 +146,26 @@ type UnbondingDelegation struct {
Tokens sdk.Coins // the value in Atoms of the amount of shares which are unbonding
CompleteTime int64 // unix time to complete redelegation
}
```
```
### Redelegation
Shares in a `Delegation` can be rebonded to a different validator, but they must for some time exist as a `Redelegation`,
where shares can be reduced if Byzantine behaviour is detected. This is tracked
as moving a delegation from a `FromValOwnerAddr` to a `ToValOwnerAddr`.
Shares in a `Delegation` can be rebonded to a different validator, but they must
for some time exist as a `Redelegation`, where shares can be reduced if Byzantine
behavior is detected. This is tracked as moving a delegation from a `FromOperatorAddr`
to a `ToOperatorAddr`.
`Redelegation` are indexed in the store as:
- Redelegations: `0x0D | DelegatorAddr | FromValOwnerAddr | ToValOwnerAddr ->
- Redelegations: `0x0D | DelegatorAddr | FromOperatorAddr | ToOperatorAddr ->
amino(redelegation)`
- RedelegationsBySrc: `0x0E | FromValOwnerAddr | ToValOwnerAddr |
- RedelegationsBySrc: `0x0E | FromOperatorAddr | ToOperatorAddr |
DelegatorAddr -> nil`
- RedelegationsByDst: `0x0F | ToValOwnerAddr | FromValOwnerAddr | DelegatorAddr
- RedelegationsByDst: `0x0F | ToOperatorAddr | FromOperatorAddr | DelegatorAddr
-> nil`
The first map here is used for queries, to lookup all redelegations for a given
delegator. The second map is used for slashing based on the FromValOwnerAddr,
delegator. The second map is used for slashing based on the `FromOperatorAddr`,
while the third map is for slashing based on the ToValOwnerAddr.
A redelegation object is created every time a redelegation occurs. The

View File

@ -77,14 +77,14 @@ We view testnet participation as a great way to signal to the community that you
In short, there are two types of keys:
* **Tendermint Key**: This is a unique key used to sign block hashes. It is associated with a public key `cosmosconspub`.
* **Tendermint Key**: This is a unique key used to sign block hashes. It is associated with a public key `cosmosvalconspub`.
* Generated when the node is created with gaiad init.
* Get this value with `gaiad tendermint show-validator`
e.g. `cosmosconspub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c`
e.g. `cosmosvalconspub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c`
* **Application keys**: These keys are created from the application and used to sign transactions. As a validator, you will probably use one key to sign staking-related transactions, and another key to sign governance-related transactions. Application keys are associated with a public key `cosmospub` and an address `cosmos`. Both are derived from account keys generated by `gaiacli keys add`.
* Note: A validator's operator key is directly tied to an application key, but
uses reserved prefixes solely for this purpose: `cosmosval` and `cosmosvalpub`
uses reserved prefixes solely for this purpose: `cosmosvaloper` and `cosmosvaloperpub`
### What are the different states a validator can be in?

View File

@ -16,7 +16,7 @@ If you want to become a validator for the Hub's `mainnet`, you should [research
### Create Your Validator
Your `cosmosconspub` can be used to create a new validator by staking tokens. You can find your validator pubkey by running:
Your `cosmosvalconspub` can be used to create a new validator by staking tokens. You can find your validator pubkey by running:
```bash
gaiad tendermint show-validator

View File

@ -253,7 +253,7 @@ first time.
Accounts are serialized and stored in a Merkle tree under the key
``base/a/<address>``, where ``<address>`` is the address of the account.
Typically, the address of the account is the 20-byte ``RIPEMD160`` hash
Typically, the address of the account is the first 20-bytes of the ``sha256`` hash
of the public key, but other formats are acceptable as well, as defined
in the `Tendermint crypto
library <https://github.com/tendermint/tendermint/tree/master/crypto>`__. The Merkle tree

View File

@ -37,7 +37,7 @@ type BasecoinApp struct {
// manage getting and setting accounts
accountMapper auth.AccountMapper
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper
bankKeeper bank.Keeper
ibcMapper ibc.Mapper
}
@ -67,13 +67,13 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.Ba
return &types.AppAccount{}
},
)
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
// register message routes
app.Router().
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper))
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.bankKeeper))
// perform initialization logic
app.SetInitChainer(app.initChainer)

View File

@ -41,7 +41,7 @@ type DemocoinApp struct {
// keepers
feeCollectionKeeper auth.FeeCollectionKeeper
coinKeeper bank.Keeper
bankKeeper bank.Keeper
coolKeeper cool.Keeper
powKeeper pow.Keeper
ibcMapper ibc.Mapper
@ -75,17 +75,17 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
)
// Add handlers.
app.coinKeeper = bank.NewKeeper(app.accountMapper)
app.coolKeeper = cool.NewKeeper(app.capKeyMainStore, app.coinKeeper, app.RegisterCodespace(cool.DefaultCodespace))
app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), app.coinKeeper, app.RegisterCodespace(pow.DefaultCodespace))
app.bankKeeper = bank.NewBaseKeeper(app.accountMapper)
app.coolKeeper = cool.NewKeeper(app.capKeyMainStore, app.bankKeeper, app.RegisterCodespace(cool.DefaultCodespace))
app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), app.bankKeeper, app.RegisterCodespace(pow.DefaultCodespace))
app.ibcMapper = ibc.NewMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace))
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.coinKeeper, app.RegisterCodespace(simplestake.DefaultCodespace))
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper, app.RegisterCodespace(simplestake.DefaultCodespace))
app.Router().
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute("cool", cool.NewHandler(app.coolKeeper)).
AddRoute("pow", app.powKeeper.Handler).
AddRoute("sketchy", sketchy.NewHandler()).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.bankKeeper)).
AddRoute("simplestake", simplestake.NewHandler(app.stakeKeeper))
// Initialize BaseApp.

View File

@ -62,6 +62,7 @@ func GetAssocKey(base sdk.ValAddress, assoc sdk.ValAddress) []byte {
}
// Associate associates new address with validator address
// nolint: unparam
func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
return false
@ -76,6 +77,7 @@ func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc
}
// Dissociate removes association between addresses
// nolint: unparam
func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
return false
@ -90,6 +92,7 @@ func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.ValAddress, asso
}
// Associations returns all associated addresses with a validator
// nolint: unparam
func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.ValAddress) (res []sdk.ValAddress) {
res = make([]sdk.ValAddress, valset.maxAssoc)
iter := sdk.KVStorePrefixIterator(valset.store, GetAssocPrefix(base))

View File

@ -49,13 +49,13 @@ func getMockApp(t *testing.T) *mock.App {
RegisterWire(mapp.Cdc)
keyCool := sdk.NewKVStoreKey("cool")
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
keeper := NewKeeper(keyCool, coinKeeper, mapp.RegisterCodespace(DefaultCodespace))
bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper)
keeper := NewKeeper(keyCool, bankKeeper, mapp.RegisterCodespace(DefaultCodespace))
mapp.Router().AddRoute("cool", NewHandler(keeper))
mapp.SetInitChainer(getInitChainer(mapp, keeper, "ice-cold"))
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyCool}))
require.NoError(t, mapp.CompleteSetup(keyCool))
return mapp
}

View File

@ -11,7 +11,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
// QuizTxCmd invokes the coolness quiz transaction.
@ -21,7 +21,7 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command {
Short: "What's cooler than being cool?",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
@ -34,7 +34,7 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command {
msg := cool.NewMsgQuiz(from, args[0])
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}
@ -46,7 +46,7 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command {
Short: "You're so cool, tell us what is cool!",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
@ -59,7 +59,7 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command {
msg := cool.NewMsgSetTrend(from, args[0])
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}

View File

@ -31,7 +31,7 @@ func TestCoolKeeper(t *testing.T) {
am := auth.NewAccountMapper(cdc, capKey, auth.ProtoBaseAccount)
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
ck := bank.NewKeeper(am)
ck := bank.NewBaseKeeper(am)
keeper := NewKeeper(capKey, ck, DefaultCodespace)
err := InitGenesis(ctx, keeper, Genesis{"icy"})

View File

@ -25,14 +25,14 @@ func getMockApp(t *testing.T) *mock.App {
RegisterWire(mapp.Cdc)
keyPOW := sdk.NewKVStoreKey("pow")
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
bankKeeper := bank.NewBaseKeeper(mapp.AccountMapper)
config := Config{"pow", 1}
keeper := NewKeeper(keyPOW, config, coinKeeper, mapp.RegisterCodespace(DefaultCodespace))
keeper := NewKeeper(keyPOW, config, bankKeeper, mapp.RegisterCodespace(DefaultCodespace))
mapp.Router().AddRoute("pow", keeper.Handler)
mapp.SetInitChainer(getInitChainer(mapp, keeper))
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyPOW}))
require.NoError(t, mapp.CompleteSetup(keyPOW))
mapp.Seal()

View File

@ -10,7 +10,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/spf13/cobra"
)
@ -22,7 +22,7 @@ func MineCmd(cdc *wire.Codec) *cobra.Command {
Short: "Mine some coins with proof-of-work!",
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
@ -53,7 +53,7 @@ func MineCmd(cdc *wire.Codec) *cobra.Command {
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}

View File

@ -22,7 +22,7 @@ func TestPowHandler(t *testing.T) {
am := auth.NewAccountMapper(cdc, capKey, auth.ProtoBaseAccount)
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger())
config := NewConfig("pow", int64(1))
ck := bank.NewKeeper(am)
ck := bank.NewBaseKeeper(am)
keeper := NewKeeper(capKey, config, ck, DefaultCodespace)
handler := keeper.Handler

View File

@ -35,7 +35,7 @@ func TestPowKeeperGetSet(t *testing.T) {
am := auth.NewAccountMapper(cdc, capKey, auth.ProtoBaseAccount)
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger())
config := NewConfig("pow", int64(1))
ck := bank.NewKeeper(am)
ck := bank.NewBaseKeeper(am)
keeper := NewKeeper(capKey, config, ck, DefaultCodespace)
err := InitGenesis(ctx, keeper, Genesis{uint64(1), uint64(0)})

View File

@ -11,7 +11,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -30,7 +30,7 @@ func BondTxCmd(cdc *wire.Codec) *cobra.Command {
Use: "bond",
Short: "Bond to a validator",
RunE: func(cmd *cobra.Command, args []string) error {
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
@ -68,7 +68,7 @@ func BondTxCmd(cdc *wire.Codec) *cobra.Command {
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -84,7 +84,7 @@ func UnbondTxCmd(cdc *wire.Codec) *cobra.Command {
Use: "unbond",
Short: "Unbond from a validator",
RunE: func(cmd *cobra.Command, args []string) error {
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout)
@ -98,7 +98,7 @@ func UnbondTxCmd(cdc *wire.Codec) *cobra.Command {
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
},
}

View File

@ -21,13 +21,13 @@ type Keeper struct {
codespace sdk.CodespaceType
}
func NewKeeper(key sdk.StoreKey, coinKeeper bank.Keeper, codespace sdk.CodespaceType) Keeper {
func NewKeeper(key sdk.StoreKey, bankKeeper bank.Keeper, codespace sdk.CodespaceType) Keeper {
cdc := wire.NewCodec()
wire.RegisterCrypto(cdc)
return Keeper{
key: key,
cdc: cdc,
ck: coinKeeper,
ck: bankKeeper,
codespace: codespace,
}
}

View File

@ -36,7 +36,7 @@ func TestKeeperGetSet(t *testing.T) {
auth.RegisterBaseAccount(cdc)
accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount)
stakeKeeper := NewKeeper(capKey, bank.NewKeeper(accountMapper), DefaultCodespace)
stakeKeeper := NewKeeper(capKey, bank.NewBaseKeeper(accountMapper), DefaultCodespace)
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger())
addr := sdk.AccAddress([]byte("some-address"))
@ -66,8 +66,8 @@ func TestBonding(t *testing.T) {
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger())
accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount)
coinKeeper := bank.NewKeeper(accountMapper)
stakeKeeper := NewKeeper(capKey, coinKeeper, DefaultCodespace)
bankKeeper := bank.NewBaseKeeper(accountMapper)
stakeKeeper := NewKeeper(capKey, bankKeeper, DefaultCodespace)
addr := sdk.AccAddress([]byte("some-address"))
privKey := ed25519.GenPrivKey()
pubKey := privKey.PubKey()

View File

@ -0,0 +1,13 @@
import fileinput
import re
# This script goes through the provided file, and replaces any " \#<number>",
# with the valid mark down formatted link to it. e.g.
# " [\#number](https://github.com/cosmos/cosmos-sdk/issues/<number>)
# Note that if the number is for a PR, github will auto-redirect you when you click the link.
# It is safe to run the script multiple times in succession.
#
# Example usage $ python3 linkify_changelog.py ../PENDING.md
for line in fileinput.input(inplace=1):
line = re.sub(r"\s\\#([0-9]*)", r" [\\#\1](https://github.com/cosmos/cosmos-sdk/issues/\1)", line.rstrip())
print(line)

View File

@ -344,6 +344,7 @@ func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
// writeGenesisFile creates and writes the genesis configuration to disk. An
// error is returned if building or writing the configuration to file fails.
// nolint: unparam
func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error {
genDoc := tmtypes.GenesisDoc{
ChainID: chainID,

View File

@ -84,6 +84,7 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error {
return nil
}
// nolint: unparam
func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) {
cfg := ctx.Config
home := cfg.RootDir

View File

@ -18,9 +18,11 @@ import (
)
var (
nodeDirPrefix = "node-dir-prefix"
nValidators = "v"
outputDir = "output-dir"
nodeDirPrefix = "node-dir-prefix"
nValidators = "v"
outputDir = "output-dir"
nodeDaemonHome = "node-daemon-home"
nodeCliHome = "node-cli-home"
startingIPAddress = "starting-ip-address"
)
@ -39,7 +41,7 @@ Note, strict routability for addresses is turned off in the config file.
Example:
gaiad testnet --v 4 --output-dir ./output --starting-ip-address 192.168.10.2
gaiad testnet --v 4 --o ./output --starting-ip-address 192.168.10.2
`,
RunE: func(_ *cobra.Command, _ []string) error {
config := ctx.Config
@ -53,6 +55,10 @@ Example:
"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, ...)")
cmd.Flags().String(nodeDaemonHome, "gaiad",
"Home directory of the node's daemon configuration")
cmd.Flags().String(nodeCliHome, "gaiacli",
"Home directory of the node's cli configuration")
cmd.Flags().String(startingIPAddress, "192.168.0.1",
"Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
@ -66,8 +72,10 @@ func testnetWithConfig(config *cfg.Config, cdc *wire.Codec, appInit AppInit) err
// Generate private key, node ID, initial transaction
for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
nodeDir := filepath.Join(outDir, nodeDirName, "gaiad")
clientDir := filepath.Join(outDir, nodeDirName, "gaiacli")
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
nodeCliHomeName := viper.GetString(nodeCliHome)
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
clientDir := filepath.Join(outDir, nodeDirName, nodeCliHomeName)
gentxsDir := filepath.Join(outDir, "gentxs")
config.SetRoot(nodeDir)
@ -122,7 +130,8 @@ func testnetWithConfig(config *cfg.Config, cdc *wire.Codec, appInit AppInit) err
for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
nodeDir := filepath.Join(outDir, nodeDirName, "gaiad")
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
gentxsDir := filepath.Join(outDir, "gentxs")
initConfig := InitConfig{
chainID,

View File

@ -51,6 +51,10 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error
if err != nil {
return err
}
err = validateConfig(config)
if err != nil {
return err
}
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger, err = tmflags.ParseLogLevel(config.LogLevel, logger, cfg.DefaultLogLevel())
if err != nil {
@ -96,6 +100,14 @@ func interceptLoadConfig() (conf *cfg.Config, err error) {
return
}
// validate the config with the sdk's requirements.
func validateConfig(conf *cfg.Config) error {
if conf.Consensus.CreateEmptyBlocks == false {
return errors.New("config option CreateEmptyBlocks = false is currently unsupported")
}
return nil
}
// add server commands
func AddCommands(
ctx *Context, cdc *wire.Codec,

View File

@ -20,7 +20,7 @@ const (
// load the iavl store
func LoadIAVLStore(db dbm.DB, id CommitID, pruning sdk.PruningStrategy) (CommitStore, error) {
tree := iavl.NewVersionedTree(db, defaultIAVLCacheSize)
tree := iavl.NewMutableTree(db, defaultIAVLCacheSize)
_, err := tree.LoadVersion(id.Version)
if err != nil {
return nil, err
@ -40,7 +40,7 @@ var _ Queryable = (*iavlStore)(nil)
type iavlStore struct {
// The underlying tree.
tree *iavl.VersionedTree
tree *iavl.MutableTree
// How many old versions we hold onto.
// A value of 0 means keep no recent states.
@ -56,7 +56,8 @@ type iavlStore struct {
}
// CONTRACT: tree should be fully loaded.
func newIAVLStore(tree *iavl.VersionedTree, numRecent int64, storeEvery int64) *iavlStore {
// nolint: unparam
func newIAVLStore(tree *iavl.MutableTree, numRecent int64, storeEvery int64) *iavlStore {
st := &iavlStore{
tree: tree,
numRecent: numRecent,
@ -95,7 +96,7 @@ func (st *iavlStore) Commit() CommitID {
// Implements Committer.
func (st *iavlStore) LastCommitID() CommitID {
return CommitID{
Version: st.tree.Version64(),
Version: st.tree.Version(),
Hash: st.tree.Hash(),
}
}
@ -167,19 +168,19 @@ func (st *iavlStore) Gas(meter GasMeter, config GasConfig) KVStore {
// Implements KVStore.
func (st *iavlStore) Iterator(start, end []byte) Iterator {
return newIAVLIterator(st.tree.Tree(), start, end, true)
return newIAVLIterator(st.tree.ImmutableTree, start, end, true)
}
// Implements KVStore.
func (st *iavlStore) ReverseIterator(start, end []byte) Iterator {
return newIAVLIterator(st.tree.Tree(), start, end, false)
return newIAVLIterator(st.tree.ImmutableTree, start, end, false)
}
// Handle gatest the latest height, if height is 0
func getHeight(tree *iavl.VersionedTree, req abci.RequestQuery) int64 {
func getHeight(tree *iavl.MutableTree, req abci.RequestQuery) int64 {
height := req.Height
if height == 0 {
latest := tree.Version64()
latest := tree.Version()
if tree.VersionExists(latest - 1) {
height = latest - 1
} else {
@ -255,7 +256,7 @@ func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
// Implements Iterator.
type iavlIterator struct {
// Underlying store
tree *iavl.Tree
tree *iavl.ImmutableTree
// Domain
start, end []byte
@ -286,7 +287,7 @@ var _ Iterator = (*iavlIterator)(nil)
// newIAVLIterator will create a new iavlIterator.
// CONTRACT: Caller must release the iavlIterator, as each one creates a new
// goroutine.
func newIAVLIterator(tree *iavl.Tree, start, end []byte, ascending bool) *iavlIterator {
func newIAVLIterator(tree *iavl.ImmutableTree, start, end []byte, ascending bool) *iavlIterator {
iter := &iavlIterator{
tree: tree,
start: cp(start),

View File

@ -29,8 +29,8 @@ var (
)
// make a tree and save it
func newTree(t *testing.T, db dbm.DB) (*iavl.VersionedTree, CommitID) {
tree := iavl.NewVersionedTree(db, cacheSize)
func newTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, CommitID) {
tree := iavl.NewMutableTree(db, cacheSize)
for k, v := range treeData {
tree.Set([]byte(k), []byte(v))
}
@ -325,7 +325,7 @@ type pruneState struct {
func testPruning(t *testing.T, numRecent int64, storeEvery int64, states []pruneState) {
db := dbm.NewMemDB()
tree := iavl.NewVersionedTree(db, cacheSize)
tree := iavl.NewMutableTree(db, cacheSize)
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
for step, state := range states {
for _, ver := range state.stored {
@ -344,7 +344,7 @@ func testPruning(t *testing.T, numRecent int64, storeEvery int64, states []prune
func TestIAVLNoPrune(t *testing.T) {
db := dbm.NewMemDB()
tree := iavl.NewVersionedTree(db, cacheSize)
tree := iavl.NewMutableTree(db, cacheSize)
iavlStore := newIAVLStore(tree, numRecent, int64(1))
nextVersion(iavlStore)
for i := 1; i < 100; i++ {
@ -359,7 +359,7 @@ func TestIAVLNoPrune(t *testing.T) {
func TestIAVLPruneEverything(t *testing.T) {
db := dbm.NewMemDB()
tree := iavl.NewVersionedTree(db, cacheSize)
tree := iavl.NewMutableTree(db, cacheSize)
iavlStore := newIAVLStore(tree, int64(0), int64(0))
nextVersion(iavlStore)
for i := 1; i < 100; i++ {
@ -377,7 +377,7 @@ func TestIAVLPruneEverything(t *testing.T) {
func TestIAVLStoreQuery(t *testing.T) {
db := dbm.NewMemDB()
tree := iavl.NewVersionedTree(db, cacheSize)
tree := iavl.NewMutableTree(db, cacheSize)
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
k1, v1 := []byte("key1"), []byte("val1")
@ -468,7 +468,7 @@ func TestIAVLStoreQuery(t *testing.T) {
func BenchmarkIAVLIteratorNext(b *testing.B) {
db := dbm.NewMemDB()
treeSize := 1000
tree := iavl.NewVersionedTree(db, cacheSize)
tree := iavl.NewMutableTree(db, cacheSize)
for i := 0; i < treeSize; i++ {
key := cmn.RandBytes(4)
value := cmn.RandBytes(50)

View File

@ -2,6 +2,7 @@ package store
import (
"bytes"
"github.com/pkg/errors"
"github.com/tendermint/iavl"
cmn "github.com/tendermint/tendermint/libs/common"
@ -47,7 +48,6 @@ func VerifyMultiStoreCommitInfo(storeName string, storeInfos []storeInfo, appHas
Version: height,
StoreInfos: storeInfos,
}
if !bytes.Equal(appHash, ci.Hash()) {
return nil, cmn.NewError("the merkle root of multiStoreCommitInfo doesn't equal to appHash")
}

View File

@ -2,14 +2,17 @@ package store
import (
"encoding/hex"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/iavl"
cmn "github.com/tendermint/tendermint/libs/common"
"testing"
"github.com/tendermint/tendermint/libs/db"
)
func TestVerifyMultiStoreCommitInfo(t *testing.T) {
appHash, _ := hex.DecodeString("ebf3c1fb724d3458023c8fefef7b33add2fc1e84")
appHash, _ := hex.DecodeString("69959B1B4E68E0F7BD3551A50C8F849B81801AF2")
substoreRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828")
storeName := "acc"
@ -81,17 +84,17 @@ func TestVerifyMultiStoreCommitInfo(t *testing.T) {
})
commitHash, err := VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash)
assert.Nil(t, err)
assert.Equal(t, commitHash, substoreRootHash)
require.Nil(t, err)
require.Equal(t, commitHash, substoreRootHash)
appHash, _ = hex.DecodeString("29de216bf5e2531c688de36caaf024cd3bb09ee3")
_, err = VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash)
assert.Error(t, err, "appHash doesn't match to the merkle root of multiStoreCommitInfo")
require.Error(t, err, "appHash doesn't match to the merkle root of multiStoreCommitInfo")
}
func TestVerifyRangeProof(t *testing.T) {
tree := iavl.NewTree(nil, 0)
tree := iavl.NewMutableTree(db.NewMemDB(), 0)
rand := cmn.NewRand()
rand.Seed(0) // for determinism
@ -100,7 +103,7 @@ func TestVerifyRangeProof(t *testing.T) {
tree.Set(key, []byte(rand.Str(8)))
}
root := tree.Hash()
root := tree.WorkingHash()
key := []byte{0x32}
val, proof, err := tree.GetWithProof(key)

View File

@ -66,7 +66,7 @@ func testPrefixStore(t *testing.T, baseStore KVStore, prefix []byte) {
func TestIAVLStorePrefix(t *testing.T) {
db := dbm.NewMemDB()
tree := iavl.NewVersionedTree(db, cacheSize)
tree := iavl.NewMutableTree(db, cacheSize)
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
testPrefixStore(t, iavlStore, []byte("test"))

View File

@ -5,10 +5,9 @@ import (
"io"
"strings"
"golang.org/x/crypto/ripemd160"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/crypto/tmhash"
dbm "github.com/tendermint/tendermint/libs/db"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -424,7 +423,7 @@ func (si storeInfo) Hash() []byte {
// Doesn't write Name, since merkle.SimpleHashFromMap() will
// include them via the keys.
bz, _ := cdc.MarshalBinary(si.Core) // Does not error
hasher := ripemd160.New()
hasher := tmhash.New()
_, err := hasher.Write(bz)
if err != nil {
// TODO: Handle with #870

View File

@ -179,6 +179,7 @@ func (tkv *TraceKVStore) CacheWrapWithTrace(_ io.Writer, _ TraceContext) CacheWr
// writeOperation writes a KVStore operation to the underlying io.Writer as
// JSON-encoded data where the key/value pair is base64 encoded.
// nolint: errcheck
func writeOperation(w io.Writer, op operation, tc TraceContext, key, value []byte) {
traceOp := traceOperation{
Operation: op,

View File

@ -156,8 +156,8 @@ func TestTestTraceKVStoreIterator(t *testing.T) {
iterator := store.Iterator(nil, nil)
s, e := iterator.Domain()
require.Equal(t, []uint8([]byte(nil)), s)
require.Equal(t, []uint8([]byte(nil)), e)
require.Equal(t, []byte(nil), s)
require.Equal(t, []byte(nil), e)
testCases := []struct {
expectedKey []byte
@ -212,8 +212,8 @@ func TestTestTraceKVStoreReverseIterator(t *testing.T) {
iterator := store.ReverseIterator(nil, nil)
s, e := iterator.Domain()
require.Equal(t, []uint8([]byte(nil)), s)
require.Equal(t, []uint8([]byte(nil)), e)
require.Equal(t, []byte(nil), s)
require.Equal(t, []byte(nil), e)
testCases := []struct {
expectedKey []byte

View File

@ -1,6 +1,7 @@
package store
import (
sdk "github.com/cosmos/cosmos-sdk/types"
dbm "github.com/tendermint/tendermint/libs/db"
)
@ -41,3 +42,8 @@ func (ts *transientStore) Prefix(prefix []byte) KVStore {
func (ts *transientStore) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, ts)
}
// Implements Store.
func (ts *transientStore) GetStoreType() StoreType {
return sdk.StoreTypeTransient
}

View File

@ -13,6 +13,7 @@ import (
// ExecuteT executes the command, pipes any input to STDIN and return STDOUT,
// logging STDOUT/STDERR to t.
// nolint: errcheck
func ExecuteT(t *testing.T, cmd, input string) (out string) {
t.Log("Running", cmn.Cyan(cmd))

View File

@ -23,9 +23,10 @@ INEFFASSIGN_CHECK := $(shell command -v ineffassign 2> /dev/null)
MISSPELL_CHECK := $(shell command -v misspell 2> /dev/null)
ERRCHECK_CHECK := $(shell command -v errcheck 2> /dev/null)
UNPARAM_CHECK := $(shell command -v unparam 2> /dev/null)
GOCYCLO_CHECK := $(shell command -v gocyclo 2> /dev/null)
# GOCYCLO_CHECK := $(shell command -v gocyclo 2> /dev/null)
STATIK_CHECK := $(shell command -v statik 2> /dev/null)
check_tools:
ifndef DEP_CHECK
@echo "No dep in path. Install with 'make get_tools'."
@ -139,12 +140,12 @@ else
@echo "Installing unparam"
go get -v $(UNPARAM)
endif
ifdef GOCYCLO_CHECK
@echo "gocyclo is already installed. Run 'make update_tools' to update."
else
@echo "Installing gocyclo"
go get -v $(GOCYCLO)
endif
# ifdef GOCYCLO_CHECK
# @echo "gocyclo is already installed. Run 'make update_tools' to update."
# else
# @echo "Installing gocyclo"
# go get -v $(GOCYCLO)
# endif
ifdef STATIK_CHECK
@echo "statik is already installed. Run 'make update_tools' to update."
else
@ -172,8 +173,8 @@ update_dev_tools:
go get -u -v $(ERRCHECK)
@echo "Updating unparam"
go get -u -v $(UNPARAM)
@echo "Updating goyclo"
go get -u -v $(GOCYCLO)
# @echo "Updating goyclo"
# go get -u -v $(GOCYCLO)
@echo "Updating statik"
go get -u -v $(STATIK)

View File

@ -2,7 +2,7 @@
"Linters": {
"vet": "go tool vet -composites=false :PATH:LINE:MESSAGE"
},
"Enable": ["golint", "vet", "ineffassign", "unparam", "unconvert", "misspell", "gocyclo"],
"Enable": ["golint", "vet", "ineffassign", "unparam", "unconvert", "misspell"],
"Deadline": "500s",
"Vendor": true,
"Cyclo": 11

View File

@ -22,13 +22,13 @@ const (
// Bech32PrefixAccPub defines the Bech32 prefix of an account's public key
Bech32PrefixAccPub = "cosmospub"
// Bech32PrefixValAddr defines the Bech32 prefix of a validator's operator address
Bech32PrefixValAddr = "cosmosval"
Bech32PrefixValAddr = "cosmosvaloper"
// Bech32PrefixValPub defines the Bech32 prefix of a validator's operator public key
Bech32PrefixValPub = "cosmosvalpub"
Bech32PrefixValPub = "cosmosvaloperpub"
// Bech32PrefixConsAddr defines the Bech32 prefix of a consensus node address
Bech32PrefixConsAddr = "cosmoscons"
Bech32PrefixConsAddr = "cosmosvalcons"
// Bech32PrefixConsPub defines the Bech32 prefix of a consensus node public key
Bech32PrefixConsPub = "cosmosconspub"
Bech32PrefixConsPub = "cosmosvalconspub"
)
// ----------------------------------------------------------------------------
@ -133,6 +133,7 @@ func (aa AccAddress) String() string {
}
// Format implements the fmt.Formatter interface.
// nolint: errcheck
func (aa AccAddress) Format(s fmt.State, verb rune) {
switch verb {
case 's':
@ -145,7 +146,7 @@ func (aa AccAddress) Format(s fmt.State, verb rune) {
}
// ----------------------------------------------------------------------------
// validator owner
// validator operator
// ----------------------------------------------------------------------------
// ValAddress defines a wrapper around bytes meant to present a validator's
@ -247,6 +248,7 @@ func (va ValAddress) String() string {
}
// Format implements the fmt.Formatter interface.
// nolint: errcheck
func (va ValAddress) Format(s fmt.State, verb rune) {
switch verb {
case 's':
@ -361,6 +363,7 @@ func (ca ConsAddress) String() string {
}
// Format implements the fmt.Formatter interface.
// nolint: errcheck
func (ca ConsAddress) Format(s fmt.State, verb rune) {
switch verb {
case 's':

View File

@ -30,6 +30,7 @@ type Context struct {
}
// create a new context
// nolint: unparam
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Logger) Context {
c := Context{
Context: context.Background(),

View File

@ -219,6 +219,7 @@ func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error {
}
// Implements ABCIError.
// nolint: errcheck
func (err *sdkError) TraceSDK(format string, args ...interface{}) Error {
err.Trace(1, format, args...)
return err

View File

@ -40,7 +40,7 @@ type Validator interface {
GetJailed() bool // whether the validator is jailed
GetMoniker() string // moniker of the validator
GetStatus() BondStatus // status of the validator
GetOperator() ValAddress // owner address to receive/return validators coins
GetOperator() ValAddress // operator address to receive/return validators coins
GetPubKey() crypto.PubKey // validation pubkey
GetPower() Dec // validation power
GetTokens() Dec // validation tokens
@ -59,11 +59,11 @@ func ABCIValidator(v Validator) abci.Validator {
// properties for the set of all validators
type ValidatorSet interface {
// iterate through validator by owner-AccAddress, execute func for each validator
// iterate through validators by operator address, execute func for each validator
IterateValidators(Context,
func(index int64, validator Validator) (stop bool))
// iterate through bonded validator by pubkey-AccAddress, execute func for each validator
// iterate through bonded validators by operator address, execute func for each validator
IterateValidatorsBonded(Context,
func(index int64, validator Validator) (stop bool))

View File

@ -2,6 +2,7 @@ package auth
import (
"bytes"
"encoding/hex"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -190,6 +191,13 @@ func processSig(
return
}
var dummySecp256k1Pubkey secp256k1.PubKeySecp256k1
func init() {
bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A")
copy(dummySecp256k1Pubkey[:], bz)
}
func processPubKey(acc Account, sig StdSignature, simulate bool) (crypto.PubKey, sdk.Result) {
// If pubkey is not known for account,
// set it from the StdSignature.
@ -200,7 +208,7 @@ func processPubKey(acc Account, sig StdSignature, simulate bool) (crypto.PubKey,
// and gasKVStore.Set() shall consume the largest amount, i.e.
// it takes more gas to verifiy secp256k1 keys than ed25519 ones.
if pubKey == nil {
return secp256k1.GenPrivKey().PubKey(), sdk.Result{}
return dummySecp256k1Pubkey, sdk.Result{}
}
return pubKey, sdk.Result{}
}

View File

@ -30,6 +30,7 @@ func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder {
// GetAccountCmd returns a query account that will display the state of the
// account at a given address.
// nolint: unparam
func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder) *cobra.Command {
return &cobra.Command{
Use: "account [address]",

91
x/auth/client/cli/sign.go Normal file
View File

@ -0,0 +1,91 @@
package cli
import (
"fmt"
"io/ioutil"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/spf13/cobra"
amino "github.com/tendermint/go-amino"
)
const (
flagAppend = "append"
flagPrintSigs = "print-sigs"
)
// GetSignCommand returns the sign command
func GetSignCommand(codec *amino.Codec, decoder auth.AccountDecoder) *cobra.Command {
cmd := &cobra.Command{
Use: "sign <file>",
Short: "Sign transactions",
Long: `Sign transactions created with the --generate-only flag.
Read a transaction from <file>, sign it, and print its JSON encoding.`,
RunE: makeSignCmd(codec, decoder),
Args: cobra.ExactArgs(1),
}
cmd.Flags().String(client.FlagName, "", "Name of private key with which to sign")
cmd.Flags().Bool(flagAppend, true, "Append the signature to the existing ones. If disabled, old signatures would be overwritten")
cmd.Flags().Bool(flagPrintSigs, false, "Print the addresses that must sign the transaction and those who have already signed it, then exit")
return cmd
}
func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) (err error) {
stdTx, err := readAndUnmarshalStdTx(cdc, args[0])
if err != nil {
return
}
if viper.GetBool(flagPrintSigs) {
printSignatures(stdTx)
return nil
}
name := viper.GetString(client.FlagName)
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(decoder)
txBldr := authtxb.NewTxBuilderFromCLI()
newTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, viper.GetBool(flagAppend))
if err != nil {
return err
}
json, err := cdc.MarshalJSON(newTx)
if err != nil {
return err
}
fmt.Printf("%s\n", json)
return
}
}
func printSignatures(stdTx auth.StdTx) {
fmt.Println("Signers:")
for i, signer := range stdTx.GetSigners() {
fmt.Printf(" %v: %v\n", i, signer.String())
}
fmt.Println("")
fmt.Println("Signatures:")
for i, sig := range stdTx.GetSignatures() {
fmt.Printf(" %v: %v\n", i, sdk.AccAddress(sig.Address()).String())
}
return
}
func readAndUnmarshalStdTx(cdc *amino.Codec, filename string) (stdTx auth.StdTx, err error) {
var bytes []byte
if bytes, err = ioutil.ReadFile(filename); err != nil {
return
}
if err = cdc.UnmarshalJSON(bytes, &stdTx); err != nil {
return
}
return
}

View File

@ -1,179 +0,0 @@
package context
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/pkg/errors"
"github.com/spf13/viper"
)
// TxContext implements a transaction context created in SDK modules.
type TxContext struct {
Codec *wire.Codec
AccountNumber int64
Sequence int64
Gas int64
ChainID string
Memo string
Fee string
}
// NewTxContextFromCLI returns a new initialized TxContext with parameters from
// the command line using Viper.
func NewTxContextFromCLI() TxContext {
// if chain ID is not specified manually, read default chain ID
chainID := viper.GetString(client.FlagChainID)
if chainID == "" {
defaultChainID, err := defaultChainID()
if err != nil {
chainID = defaultChainID
}
}
return TxContext{
ChainID: chainID,
Gas: viper.GetInt64(client.FlagGas),
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
Sequence: viper.GetInt64(client.FlagSequence),
Fee: viper.GetString(client.FlagFee),
Memo: viper.GetString(client.FlagMemo),
}
}
// WithCodec returns a copy of the context with an updated codec.
func (ctx TxContext) WithCodec(cdc *wire.Codec) TxContext {
ctx.Codec = cdc
return ctx
}
// WithChainID returns a copy of the context with an updated chainID.
func (ctx TxContext) WithChainID(chainID string) TxContext {
ctx.ChainID = chainID
return ctx
}
// WithGas returns a copy of the context with an updated gas.
func (ctx TxContext) WithGas(gas int64) TxContext {
ctx.Gas = gas
return ctx
}
// WithFee returns a copy of the context with an updated fee.
func (ctx TxContext) WithFee(fee string) TxContext {
ctx.Fee = fee
return ctx
}
// WithSequence returns a copy of the context with an updated sequence number.
func (ctx TxContext) WithSequence(sequence int64) TxContext {
ctx.Sequence = sequence
return ctx
}
// WithMemo returns a copy of the context with an updated memo.
func (ctx TxContext) WithMemo(memo string) TxContext {
ctx.Memo = memo
return ctx
}
// WithAccountNumber returns a copy of the context with an account number.
func (ctx TxContext) WithAccountNumber(accnum int64) TxContext {
ctx.AccountNumber = accnum
return ctx
}
// Build builds a single message to be signed from a TxContext given a set of
// messages. It returns an error if a fee is supplied but cannot be parsed.
func (ctx TxContext) Build(msgs []sdk.Msg) (auth.StdSignMsg, error) {
chainID := ctx.ChainID
if chainID == "" {
return auth.StdSignMsg{}, errors.Errorf("chain ID required but not specified")
}
fee := sdk.Coin{}
if ctx.Fee != "" {
parsedFee, err := sdk.ParseCoin(ctx.Fee)
if err != nil {
return auth.StdSignMsg{}, err
}
fee = parsedFee
}
return auth.StdSignMsg{
ChainID: ctx.ChainID,
AccountNumber: ctx.AccountNumber,
Sequence: ctx.Sequence,
Memo: ctx.Memo,
Msgs: msgs,
Fee: auth.NewStdFee(ctx.Gas, fee),
}, nil
}
// Sign signs a transaction given a name, passphrase, and a single message to
// signed. An error is returned if signing fails.
func (ctx TxContext) Sign(name, passphrase string, msg auth.StdSignMsg) ([]byte, error) {
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
sig, pubkey, err := keybase.Sign(name, passphrase, msg.Bytes())
if err != nil {
return nil, err
}
sigs := []auth.StdSignature{{
AccountNumber: msg.AccountNumber,
Sequence: msg.Sequence,
PubKey: pubkey,
Signature: sig,
}}
return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
}
// BuildAndSign builds a single message to be signed, and signs a transaction
// with the built message given a name, passphrase, and a set of
// messages.
func (ctx TxContext) BuildAndSign(name, passphrase string, msgs []sdk.Msg) ([]byte, error) {
msg, err := ctx.Build(msgs)
if err != nil {
return nil, err
}
return ctx.Sign(name, passphrase, msg)
}
// BuildWithPubKey builds a single message to be signed from a TxContext given a set of
// messages and attach the public key associated to the given name.
// It returns an error if a fee is supplied but cannot be parsed or the key cannot be
// retrieved.
func (ctx TxContext) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, error) {
msg, err := ctx.Build(msgs)
if err != nil {
return nil, err
}
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
info, err := keybase.Get(name)
if err != nil {
return nil, err
}
sigs := []auth.StdSignature{{
AccountNumber: msg.AccountNumber,
Sequence: msg.Sequence,
PubKey: info.GetPubKey(),
}}
return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
}

View File

@ -20,6 +20,10 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, s
"/auth/accounts/{address}",
QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), cliCtx),
).Methods("GET")
r.HandleFunc(
"/tx/sign",
SignTxRequestHandlerFn(cdc, cliCtx),
).Methods("POST")
}
// query accountREST Handler

View File

@ -0,0 +1,61 @@
package rest
import (
"io/ioutil"
"net/http"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
// SignBody defines the properties of a sign request's body.
type SignBody struct {
Tx auth.StdTx `json:"tx"`
LocalAccountName string `json:"name"`
Password string `json:"password"`
ChainID string `json:"chain_id"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
AppendSig bool `json:"append_sig"`
}
// sign tx REST handler
func SignTxRequestHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var m SignBody
body, err := ioutil.ReadAll(r.Body)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
err = cdc.UnmarshalJSON(body, &m)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
txBldr := authtxb.TxBuilder{
ChainID: m.ChainID,
AccountNumber: m.AccountNumber,
Sequence: m.Sequence,
}
signedTx, err := txBldr.SignStdTx(m.LocalAccountName, m.Password, m.Tx, m.AppendSig)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := wire.MarshalJSONIndent(cdc, signedTx)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
}
}

View File

@ -0,0 +1,213 @@
package context
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/pkg/errors"
"github.com/spf13/viper"
)
// TxBuilder implements a transaction context created in SDK modules.
type TxBuilder struct {
Codec *wire.Codec
AccountNumber int64
Sequence int64
Gas int64 // TODO: should this turn into uint64? requires further discussion - see #2173
GasAdjustment float64
SimulateGas bool
ChainID string
Memo string
Fee string
}
// NewTxBuilderFromCLI returns a new initialized TxBuilder with parameters from
// the command line using Viper.
func NewTxBuilderFromCLI() TxBuilder {
// if chain ID is not specified manually, read default chain ID
chainID := viper.GetString(client.FlagChainID)
if chainID == "" {
defaultChainID, err := defaultChainID()
if err != nil {
chainID = defaultChainID
}
}
return TxBuilder{
ChainID: chainID,
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
Gas: client.GasFlagVar.Gas,
GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment),
Sequence: viper.GetInt64(client.FlagSequence),
SimulateGas: client.GasFlagVar.Simulate,
Fee: viper.GetString(client.FlagFee),
Memo: viper.GetString(client.FlagMemo),
}
}
// WithCodec returns a copy of the context with an updated codec.
func (bldr TxBuilder) WithCodec(cdc *wire.Codec) TxBuilder {
bldr.Codec = cdc
return bldr
}
// WithChainID returns a copy of the context with an updated chainID.
func (bldr TxBuilder) WithChainID(chainID string) TxBuilder {
bldr.ChainID = chainID
return bldr
}
// WithGas returns a copy of the context with an updated gas.
func (bldr TxBuilder) WithGas(gas int64) TxBuilder {
bldr.Gas = gas
return bldr
}
// WithFee returns a copy of the context with an updated fee.
func (bldr TxBuilder) WithFee(fee string) TxBuilder {
bldr.Fee = fee
return bldr
}
// WithSequence returns a copy of the context with an updated sequence number.
func (bldr TxBuilder) WithSequence(sequence int64) TxBuilder {
bldr.Sequence = sequence
return bldr
}
// WithMemo returns a copy of the context with an updated memo.
func (bldr TxBuilder) WithMemo(memo string) TxBuilder {
bldr.Memo = memo
return bldr
}
// WithAccountNumber returns a copy of the context with an account number.
func (bldr TxBuilder) WithAccountNumber(accnum int64) TxBuilder {
bldr.AccountNumber = accnum
return bldr
}
// Build builds a single message to be signed from a TxBuilder given a set of
// messages. It returns an error if a fee is supplied but cannot be parsed.
func (bldr TxBuilder) Build(msgs []sdk.Msg) (auth.StdSignMsg, error) {
chainID := bldr.ChainID
if chainID == "" {
return auth.StdSignMsg{}, errors.Errorf("chain ID required but not specified")
}
fee := sdk.Coin{}
if bldr.Fee != "" {
parsedFee, err := sdk.ParseCoin(bldr.Fee)
if err != nil {
return auth.StdSignMsg{}, err
}
fee = parsedFee
}
return auth.StdSignMsg{
ChainID: bldr.ChainID,
AccountNumber: bldr.AccountNumber,
Sequence: bldr.Sequence,
Memo: bldr.Memo,
Msgs: msgs,
Fee: auth.NewStdFee(bldr.Gas, fee),
}, nil
}
// Sign signs a transaction given a name, passphrase, and a single message to
// signed. An error is returned if signing fails.
func (bldr TxBuilder) Sign(name, passphrase string, msg auth.StdSignMsg) ([]byte, error) {
sig, err := MakeSignature(name, passphrase, msg)
if err != nil {
return nil, err
}
return bldr.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, []auth.StdSignature{sig}, msg.Memo))
}
// BuildAndSign builds a single message to be signed, and signs a transaction
// with the built message given a name, passphrase, and a set of
// messages.
func (bldr TxBuilder) BuildAndSign(name, passphrase string, msgs []sdk.Msg) ([]byte, error) {
msg, err := bldr.Build(msgs)
if err != nil {
return nil, err
}
return bldr.Sign(name, passphrase, msg)
}
// BuildWithPubKey builds a single message to be signed from a TxBuilder given a set of
// messages and attach the public key associated to the given name.
// It returns an error if a fee is supplied but cannot be parsed or the key cannot be
// retrieved.
func (bldr TxBuilder) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, error) {
msg, err := bldr.Build(msgs)
if err != nil {
return nil, err
}
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
info, err := keybase.Get(name)
if err != nil {
return nil, err
}
sigs := []auth.StdSignature{{
AccountNumber: msg.AccountNumber,
Sequence: msg.Sequence,
PubKey: info.GetPubKey(),
}}
return bldr.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
}
// SignStdTx appends a signature to a StdTx and returns a copy of a it. If append
// is false, it replaces the signatures already attached with the new signature.
func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx auth.StdTx, appendSig bool) (signedStdTx auth.StdTx, err error) {
stdSignature, err := MakeSignature(name, passphrase, auth.StdSignMsg{
ChainID: bldr.ChainID,
AccountNumber: bldr.AccountNumber,
Sequence: bldr.Sequence,
Fee: stdTx.Fee,
Msgs: stdTx.GetMsgs(),
Memo: stdTx.GetMemo(),
})
if err != nil {
return
}
sigs := stdTx.GetSignatures()
if len(sigs) == 0 || !appendSig {
sigs = []auth.StdSignature{stdSignature}
} else {
sigs = append(sigs, stdSignature)
}
signedStdTx = auth.NewStdTx(stdTx.GetMsgs(), stdTx.Fee, sigs, stdTx.GetMemo())
return
}
// MakeSignature builds a StdSignature given key name, passphrase, and a StdSignMsg.
func MakeSignature(name, passphrase string, msg auth.StdSignMsg) (sig auth.StdSignature, err error) {
keybase, err := keys.GetKeyBase()
if err != nil {
return
}
sigBytes, pubkey, err := keybase.Sign(name, passphrase, msg.Bytes())
if err != nil {
return
}
return auth.StdSignature{
AccountNumber: msg.AccountNumber,
Sequence: msg.Sequence,
PubKey: pubkey,
Signature: sigBytes,
}, nil
}

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