Merge branch 'develop' into sunny/gov-bft-time
This commit is contained in:
commit
72b3a45778
|
@ -415,12 +415,12 @@
|
||||||
version = "v0.12.0-rc0"
|
version = "v0.12.0-rc0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:d4a15d404afbf591e8be16fcda7f5ac87948d5c7531f9d909fd84cc730ab16e2"
|
digest = "1:e99ef92d64f2391efbbfb15310df635f96247532bbac2676ea43e466d706401d"
|
||||||
name = "github.com/tendermint/iavl"
|
name = "github.com/tendermint/iavl"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "35f66e53d9b01e83b30de68b931f54b2477a94c9"
|
revision = "e5726c0066ccdd299a2ec9262f93c7896cdfcd87"
|
||||||
version = "v0.9.2"
|
version = "v0.10.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:4f15e95fe3888cc75dd34f407d6394cbc7fd3ff24920851b92b295f6a8b556e6"
|
digest = "1:4f15e95fe3888cc75dd34f407d6394cbc7fd3ff24920851b92b295f6a8b556e6"
|
||||||
|
@ -552,7 +552,7 @@
|
||||||
"unix",
|
"unix",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "11551d06cbcc94edc80a0facaccbda56473c19c1"
|
revision = "4ea2f632f6e912459fe60b26b1749377f0d889d5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
|
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/tendermint/iavl"
|
name = "github.com/tendermint/iavl"
|
||||||
version = "=v0.9.2"
|
version = "=v0.10.0"
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/tendermint/tendermint"
|
name = "github.com/tendermint/tendermint"
|
||||||
|
|
13
Makefile
13
Makefile
|
@ -157,12 +157,23 @@ test_sim_gaia_nondeterminism:
|
||||||
|
|
||||||
test_sim_gaia_fast:
|
test_sim_gaia_fast:
|
||||||
@echo "Running quick Gaia simulation. This may take several minutes..."
|
@echo "Running quick Gaia simulation. This may take several minutes..."
|
||||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=50 -v -timeout 24h
|
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=150 -v -timeout 24h
|
||||||
|
|
||||||
test_sim_gaia_slow:
|
test_sim_gaia_slow:
|
||||||
@echo "Running full Gaia simulation. This may take awhile!"
|
@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 -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:
|
test_cover:
|
||||||
@bash tests/test_cover.sh
|
@bash tests/test_cover.sh
|
||||||
|
|
||||||
|
|
57
PENDING.md
57
PENDING.md
|
@ -8,34 +8,36 @@ BREAKING CHANGES
|
||||||
* Gaia CLI (`gaiacli`)
|
* Gaia CLI (`gaiacli`)
|
||||||
* [x/stake] Validator.Owner renamed to Validator.Operator
|
* [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] 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](https://github.com/cosmos/cosmos-sdk/issues/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] [\#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 changed proposalID in governance REST endpoints to proposal-id
|
* [cli] [\#2061](https://github.com/cosmos/cosmos-sdk/issues/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] [\#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)
|
* [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
|
* [cli] [\#2190](https://github.com/cosmos/cosmos-sdk/issues/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
|
* [\#2040](https://github.com/cosmos/cosmos-sdk/issues/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
|
bech32 prefix, `cosmosval`. A validator's Tendermint signing key and address
|
||||||
now use a new bech32 prefix, `cosmoscons`.
|
now use a new bech32 prefix, `cosmoscons`.
|
||||||
|
|
||||||
* Gaia
|
* Gaia
|
||||||
* Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013)
|
* 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
|
* [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, 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] [#1676] Revoked and jailed validators put into the unbonding state
|
||||||
* [x/stake] [#1877] Redelegations/unbonding-delegation from unbonding validator have reduced time
|
* [x/stake] [#1877] Redelegations/unbonding-delegation from unbonding validator have reduced time
|
||||||
* [x/stake] \#2040 Validator operator type has now changed to `sdk.ValAddress`
|
* [x/stake] [\#2040](https://github.com/cosmos/cosmos-sdk/issues/2040) Validator operator type has now changed to `sdk.ValAddress`
|
||||||
* A new bech32 prefix has been introduced for Tendermint signing keys and
|
* A new bech32 prefix has been introduced for Tendermint signing keys and
|
||||||
addresses, `cosmosconspub` and `cosmoscons` respectively.
|
addresses, `cosmosconspub` and `cosmoscons` respectively.
|
||||||
* [x/gov] \#2195 Made governance use BFT Time instead of Block Heights for deposit and voting periods.
|
* [x/gov] \#2195 Made governance use BFT Time instead of Block Heights for deposit and voting periods.
|
||||||
|
|
||||||
* SDK
|
* SDK
|
||||||
* [core] \#1807 Switch from use of rational to decimal
|
* [core] [\#1807](https://github.com/cosmos/cosmos-sdk/issues/1807) Switch from use of rational to decimal
|
||||||
* [types] \#1901 Validator interface's GetOwner() renamed to GetOperator()
|
* [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
|
* [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] Rename TestAndRunTx to Operation [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
||||||
|
* [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)
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
|
|
||||||
|
@ -44,23 +46,26 @@ FEATURES
|
||||||
|
|
||||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||||
* [lcd] Endpoints to query staking pool and params
|
* [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
|
* [lcd] [\#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
|
||||||
|
* [lcd] [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add support for `generate_only=true` query argument to generate offline unsigned transactions
|
||||||
|
|
||||||
* Gaia CLI (`gaiacli`)
|
* Gaia CLI (`gaiacli`)
|
||||||
* [cli] Cmds to query staking pool and params
|
* [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
|
* [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
|
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](https://github.com/cosmos/cosmos-sdk/issues/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] [\#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=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] [\#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] [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add --generate-only flag to build an unsigned transaction and write it to STDOUT.
|
||||||
|
|
||||||
* Gaia
|
* Gaia
|
||||||
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
|
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
|
||||||
|
|
||||||
* SDK
|
* SDK
|
||||||
* [querier] added custom querier functionality, so ABCI query requests can be handled by keepers
|
* [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
|
* Tendermint
|
||||||
|
|
||||||
|
@ -70,7 +75,7 @@ IMPROVEMENTS
|
||||||
* [tools] Added ansible script to enable process core dumps
|
* [tools] Added ansible script to enable process core dumps
|
||||||
|
|
||||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
* 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`)
|
* Gaia CLI (`gaiacli`)
|
||||||
* [cli] #2060 removed `--select` from `block` command
|
* [cli] #2060 removed `--select` from `block` command
|
||||||
|
@ -80,11 +85,13 @@ 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/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/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] [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)
|
||||||
* SDK
|
* SDK
|
||||||
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.
|
* [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] Speedup IAVL iteration, and consequently everything that requires IAVL iteration. [#2143](https://github.com/cosmos/cosmos-sdk/issues/2143)
|
||||||
|
* [store] \#1952 Update IAVL dependency to v0.10.0
|
||||||
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
* [simulation] Make timestamps randomized [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
|
@ -94,15 +101,15 @@ BUG FIXES
|
||||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||||
|
|
||||||
* Gaia CLI (`gaiacli`)
|
* 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.
|
||||||
|
|
||||||
* Gaia
|
* Gaia
|
||||||
|
|
||||||
* SDK
|
* SDK
|
||||||
* \#1988 Make us compile on OpenBSD (disable ledger) [#1988] (https://github.com/cosmos/cosmos-sdk/issues/1988)
|
* [\#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 Fix DB Iterator leak, which may leak a go routine.
|
* [\#2105](https://github.com/cosmos/cosmos-sdk/issues/2105) Fix DB Iterator leak, which may leak a go routine.
|
||||||
* [ledger] \#2064 Fix inability to sign and send transactions via the LCD by
|
* [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.
|
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`
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
|
|
|
@ -345,6 +345,7 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) (res a
|
||||||
return queryable.Query(req)
|
return queryable.Query(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func handleQueryP2P(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) {
|
func handleQueryP2P(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) {
|
||||||
// "/p2p" prefix for p2p queries
|
// "/p2p" prefix for p2p queries
|
||||||
if len(path) >= 4 {
|
if len(path) >= 4 {
|
||||||
|
|
|
@ -626,12 +626,12 @@ func TestSimulateTx(t *testing.T) {
|
||||||
// simulate a message, check gas reported
|
// simulate a message, check gas reported
|
||||||
result := app.Simulate(tx)
|
result := app.Simulate(tx)
|
||||||
require.True(t, result.IsOK(), result.Log)
|
require.True(t, result.IsOK(), result.Log)
|
||||||
require.Equal(t, int64(gasConsumed), result.GasUsed)
|
require.Equal(t, gasConsumed, result.GasUsed)
|
||||||
|
|
||||||
// simulate again, same result
|
// simulate again, same result
|
||||||
result = app.Simulate(tx)
|
result = app.Simulate(tx)
|
||||||
require.True(t, result.IsOK(), result.Log)
|
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
|
// simulate by calling Query with encoded tx
|
||||||
txBytes, err := codec.MarshalBinary(tx)
|
txBytes, err := codec.MarshalBinary(tx)
|
||||||
|
|
|
@ -26,12 +26,6 @@ func (app *BaseApp) SetCMS(cms store.CommitMultiStore) {
|
||||||
}
|
}
|
||||||
app.cms = cms
|
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) {
|
func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) {
|
||||||
if app.sealed {
|
if app.sealed {
|
||||||
panic("SetInitChainer() on sealed BaseApp")
|
panic("SetInitChainer() on sealed BaseApp")
|
||||||
|
|
|
@ -3,10 +3,11 @@ package context
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ type CLIContext struct {
|
||||||
PrintResponse bool
|
PrintResponse bool
|
||||||
Certifier tmlite.Certifier
|
Certifier tmlite.Certifier
|
||||||
DryRun bool
|
DryRun bool
|
||||||
|
GenerateOnly bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCLIContext returns a new initialized CLIContext with parameters from the
|
// NewCLIContext returns a new initialized CLIContext with parameters from the
|
||||||
|
@ -65,6 +67,7 @@ func NewCLIContext() CLIContext {
|
||||||
PrintResponse: viper.GetBool(client.FlagPrintResponse),
|
PrintResponse: viper.GetBool(client.FlagPrintResponse),
|
||||||
Certifier: createCertifier(),
|
Certifier: createCertifier(),
|
||||||
DryRun: viper.GetBool(client.FlagDryRun),
|
DryRun: viper.GetBool(client.FlagDryRun),
|
||||||
|
GenerateOnly: viper.GetBool(client.FlagGenerateOnly),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/store"
|
"github.com/cosmos/cosmos-sdk/store"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
@ -17,7 +19,6 @@ import (
|
||||||
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
|
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetNode returns an RPC client. If the context's client is not defined, an
|
// GetNode returns an RPC client. If the context's client is not defined, an
|
||||||
|
@ -323,6 +324,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyProof perform response proof verification
|
// verifyProof perform response proof verification
|
||||||
|
// nolint: unparam
|
||||||
func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
|
func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
|
||||||
|
|
||||||
if ctx.Certifier == nil {
|
if ctx.Certifier == nil {
|
||||||
|
|
|
@ -27,6 +27,7 @@ const (
|
||||||
FlagJson = "json"
|
FlagJson = "json"
|
||||||
FlagPrintResponse = "print-response"
|
FlagPrintResponse = "print-response"
|
||||||
FlagDryRun = "dry-run"
|
FlagDryRun = "dry-run"
|
||||||
|
FlagGenerateOnly = "generate-only"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LineBreak can be included in a command list to provide a blank line
|
// LineBreak can be included in a command list to provide a blank line
|
||||||
|
@ -64,6 +65,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
|
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
|
||||||
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for query responses")
|
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(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")
|
||||||
}
|
}
|
||||||
return cmds
|
return cmds
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,6 +313,22 @@ func TestIBCTransfer(t *testing.T) {
|
||||||
// TODO: query ibc egress packet state
|
// TODO: query ibc egress packet state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCoinSendGenerateOnly(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()
|
||||||
|
// create TX
|
||||||
|
res, body, _ := doSendWithGas(t, port, seed, name, password, addr, 0, 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))
|
||||||
|
}
|
||||||
|
|
||||||
func TestTxs(t *testing.T) {
|
func TestTxs(t *testing.T) {
|
||||||
name, password := "test", "1234567890"
|
name, password := "test", "1234567890"
|
||||||
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
|
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
|
||||||
|
|
|
@ -3,11 +3,17 @@ package utils
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
auth "github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
queryArgDryRun = "simulate"
|
queryArgDryRun = "simulate"
|
||||||
|
queryArgGenerateOnly = "generate_only"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteErrorResponse prepares and writes a HTTP error
|
// 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
|
// HasDryRunArg returns true if the request's URL query contains
|
||||||
// the dry run argument and its value is set to "true".
|
// the dry run argument and its value is set to "true".
|
||||||
func HasDryRunArg(r *http.Request) bool {
|
func HasDryRunArg(r *http.Request) bool { return urlQueryHasArg(r.URL, queryArgDryRun) }
|
||||||
return r.URL.Query().Get(queryArgDryRun) == "true"
|
|
||||||
}
|
// 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
|
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a default
|
||||||
// value if the string is empty. Write
|
// value if the string is empty. Write
|
||||||
|
@ -43,3 +50,21 @@ func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEm
|
||||||
}
|
}
|
||||||
return n, true
|
return n, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteGenerateStdTxResponse writes response for the generate_only mode.
|
||||||
|
func WriteGenerateStdTxResponse(w http.ResponseWriter, txCtx authctx.TxContext, msgs []sdk.Msg) {
|
||||||
|
stdMsg, err := txCtx.Build(msgs)
|
||||||
|
if err != nil {
|
||||||
|
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
output, err := txCtx.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" }
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
auth "github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
|
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
|
||||||
amino "github.com/tendermint/go-amino"
|
amino "github.com/tendermint/go-amino"
|
||||||
"github.com/tendermint/tendermint/libs/common"
|
"github.com/tendermint/tendermint/libs/common"
|
||||||
|
@ -28,7 +29,7 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stdout, "estimated gas = %v\n", txCtx.Gas)
|
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txCtx.Gas)
|
||||||
}
|
}
|
||||||
if cliCtx.DryRun {
|
if cliCtx.DryRun {
|
||||||
return nil
|
return nil
|
||||||
|
@ -85,6 +86,19 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
|
||||||
|
func PrintUnsignedStdTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) (err error) {
|
||||||
|
stdTx, err := buildUnsignedStdTx(txCtx, cliCtx, msgs)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
json, err := txCtx.Codec.MarshalJSON(stdTx)
|
||||||
|
if err == nil {
|
||||||
|
fmt.Printf("%s\n", json)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func adjustGasEstimate(estimate int64, adjustment float64) int64 {
|
func adjustGasEstimate(estimate int64, adjustment float64) int64 {
|
||||||
return int64(adjustment * float64(estimate))
|
return int64(adjustment * float64(estimate))
|
||||||
}
|
}
|
||||||
|
@ -128,3 +142,24 @@ func prepareTxContext(txCtx authctx.TxContext, cliCtx context.CLIContext) (authc
|
||||||
}
|
}
|
||||||
return txCtx, nil
|
return txCtx, 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(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) {
|
||||||
|
txCtx, err = prepareTxContext(txCtx, cliCtx)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if txCtx.Gas == 0 {
|
||||||
|
txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, msgs)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txCtx.Gas)
|
||||||
|
}
|
||||||
|
stdSignMsg, err := txCtx.Build(msgs)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return auth.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil
|
||||||
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ func resolveProjectPath(remoteProjectPath string) string {
|
||||||
return gopath + string(os.PathSeparator) + "src" + string(os.PathSeparator) + remoteProjectPath
|
return gopath + string(os.PathSeparator) + "src" + string(os.PathSeparator) + remoteProjectPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam, errcheck
|
||||||
func copyBasecoinTemplate(projectName string, projectPath string, remoteProjectPath string) {
|
func copyBasecoinTemplate(projectName string, projectPath string, remoteProjectPath string) {
|
||||||
basecoinProjectPath := resolveProjectPath(remoteBasecoinPath)
|
basecoinProjectPath := resolveProjectPath(remoteBasecoinPath)
|
||||||
filepath.Walk(basecoinProjectPath, func(path string, f os.FileInfo, err error) error {
|
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) {
|
func createGopkg(projectPath string) {
|
||||||
// Create gopkg.toml file
|
// Create gopkg.toml file
|
||||||
dependencies := map[string]string{
|
dependencies := map[string]string{
|
||||||
|
@ -111,6 +113,7 @@ func createGopkg(projectPath string) {
|
||||||
ioutil.WriteFile(projectPath+"/Gopkg.toml", []byte(contents), os.ModePerm)
|
ioutil.WriteFile(projectPath+"/Gopkg.toml", []byte(contents), os.ModePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
func createMakefile(projectPath string) {
|
func createMakefile(projectPath string) {
|
||||||
// Create makefile
|
// Create makefile
|
||||||
// TODO: Should we use tools/ directory as in Cosmos-SDK to get tools for linting etc.
|
// TODO: Should we use tools/ directory as in Cosmos-SDK to get tools for linting etc.
|
||||||
|
|
|
@ -3,7 +3,9 @@ package app
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -15,6 +17,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
|
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"
|
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||||
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
||||||
|
@ -28,6 +31,7 @@ var (
|
||||||
blockSize int
|
blockSize int
|
||||||
enabled bool
|
enabled bool
|
||||||
verbose bool
|
verbose bool
|
||||||
|
commit bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -36,6 +40,7 @@ func init() {
|
||||||
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "Operations per block")
|
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "Operations per block")
|
||||||
flag.BoolVar(&enabled, "SimulationEnabled", false, "Enable the simulation")
|
flag.BoolVar(&enabled, "SimulationEnabled", false, "Enable the simulation")
|
||||||
flag.BoolVar(&verbose, "SimulationVerbose", false, "Verbose log output")
|
flag.BoolVar(&verbose, "SimulationVerbose", false, "Verbose log output")
|
||||||
|
flag.BoolVar(&commit, "SimulationCommit", false, "Have the simulation commit")
|
||||||
}
|
}
|
||||||
|
|
||||||
func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
|
func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage {
|
||||||
|
@ -49,7 +54,7 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
|
||||||
Coins: coins,
|
Coins: coins,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
govGenesis := gov.DefaultGenesisState()
|
||||||
// Default genesis state
|
// Default genesis state
|
||||||
stakeGenesis := stake.DefaultGenesisState()
|
stakeGenesis := stake.DefaultGenesisState()
|
||||||
var validators []stake.Validator
|
var validators []stake.Validator
|
||||||
|
@ -73,6 +78,7 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
|
||||||
genesis := GenesisState{
|
genesis := GenesisState{
|
||||||
Accounts: genesisAccounts,
|
Accounts: genesisAccounts,
|
||||||
StakeData: stakeGenesis,
|
StakeData: stakeGenesis,
|
||||||
|
GovData: govGenesis,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshal genesis
|
// Marshal genesis
|
||||||
|
@ -112,6 +118,39 @@ func invariants(app *GaiaApp) []simulation.Invariant {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
simulation.SimulateFromSeed(
|
||||||
|
b, app.BaseApp, appStateFn, seed,
|
||||||
|
testAndRunTxs(app),
|
||||||
|
[]simulation.RandSetup{},
|
||||||
|
invariants(app), // these shouldn't get ran
|
||||||
|
numBlocks,
|
||||||
|
blockSize,
|
||||||
|
commit,
|
||||||
|
)
|
||||||
|
if commit {
|
||||||
|
fmt.Println("GoLevelDB Stats")
|
||||||
|
fmt.Println(db.Stats()["leveldb.stats"])
|
||||||
|
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFullGaiaSimulation(t *testing.T) {
|
func TestFullGaiaSimulation(t *testing.T) {
|
||||||
if !enabled {
|
if !enabled {
|
||||||
t.Skip("Skipping Gaia simulation")
|
t.Skip("Skipping Gaia simulation")
|
||||||
|
@ -136,9 +175,11 @@ func TestFullGaiaSimulation(t *testing.T) {
|
||||||
invariants(app),
|
invariants(app),
|
||||||
numBlocks,
|
numBlocks,
|
||||||
blockSize,
|
blockSize,
|
||||||
false,
|
commit,
|
||||||
)
|
)
|
||||||
|
if commit {
|
||||||
|
fmt.Println("Database Size", db.Stats()["database.size"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make another test for the fuzzer itself, which just has noOp txs
|
// TODO: Make another test for the fuzzer itself, which just has noOp txs
|
||||||
|
@ -148,7 +189,7 @@ func TestAppStateDeterminism(t *testing.T) {
|
||||||
t.Skip("Skipping Gaia simulation")
|
t.Skip("Skipping Gaia simulation")
|
||||||
}
|
}
|
||||||
|
|
||||||
numSeeds := 5
|
numSeeds := 3
|
||||||
numTimesToRunPerSeed := 5
|
numTimesToRunPerSeed := 5
|
||||||
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
|
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
|
||||||
|
|
||||||
|
@ -165,10 +206,11 @@ func TestAppStateDeterminism(t *testing.T) {
|
||||||
testAndRunTxs(app),
|
testAndRunTxs(app),
|
||||||
[]simulation.RandSetup{},
|
[]simulation.RandSetup{},
|
||||||
[]simulation.Invariant{},
|
[]simulation.Invariant{},
|
||||||
20,
|
50,
|
||||||
20,
|
100,
|
||||||
true,
|
false,
|
||||||
)
|
)
|
||||||
|
app.Commit()
|
||||||
appHash := app.LastCommitID().Hash
|
appHash := app.LastCommitID().Hash
|
||||||
appHashList[j] = appHash
|
appHashList[j] = appHash
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
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/client/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
|
@ -155,8 +156,18 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
||||||
|
|
||||||
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(1))
|
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
|
// Test --dry-run
|
||||||
success := executeWrite(t, cvStr+" --dry-run", app.DefaultKeyPass)
|
success = executeWrite(t, cvStr+" --dry-run", app.DefaultKeyPass)
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
|
|
||||||
executeWrite(t, cvStr, app.DefaultKeyPass)
|
executeWrite(t, cvStr, app.DefaultKeyPass)
|
||||||
|
@ -222,8 +233,18 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
spStr += fmt.Sprintf(" --title=%s", "Test")
|
spStr += fmt.Sprintf(" --title=%s", "Test")
|
||||||
spStr += fmt.Sprintf(" --description=%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
|
// Test --dry-run
|
||||||
success := executeWrite(t, spStr+" --dry-run", app.DefaultKeyPass)
|
success = executeWrite(t, spStr+" --dry-run", app.DefaultKeyPass)
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
|
|
||||||
executeWrite(t, spStr, app.DefaultKeyPass)
|
executeWrite(t, spStr, app.DefaultKeyPass)
|
||||||
|
@ -244,6 +265,16 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
depositStr += fmt.Sprintf(" --deposit=%s", "10steak")
|
depositStr += fmt.Sprintf(" --deposit=%s", "10steak")
|
||||||
depositStr += fmt.Sprintf(" --proposal-id=%s", "1")
|
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)
|
executeWrite(t, depositStr, app.DefaultKeyPass)
|
||||||
tests.WaitForNextNBlocksTM(2, port)
|
tests.WaitForNextNBlocksTM(2, port)
|
||||||
|
|
||||||
|
@ -258,6 +289,16 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
voteStr += fmt.Sprintf(" --proposal-id=%s", "1")
|
voteStr += fmt.Sprintf(" --proposal-id=%s", "1")
|
||||||
voteStr += fmt.Sprintf(" --option=%s", "Yes")
|
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)
|
executeWrite(t, voteStr, app.DefaultKeyPass)
|
||||||
tests.WaitForNextNBlocksTM(2, port)
|
tests.WaitForNextNBlocksTM(2, port)
|
||||||
|
|
||||||
|
@ -291,6 +332,52 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
require.Equal(t, " 2 - Apples", proposalsQuery)
|
require.Equal(t, " 2 - Apples", proposalsQuery)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGaiaCLISendGenerateOnly(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)
|
||||||
|
|
||||||
|
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, estimate gas
|
||||||
|
success, stdout, stderr = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||||
|
"gaiacli send %v --amount=10steak --to=%s --from=foo --gas=0 --generate-only",
|
||||||
|
flags, barAddr), []string{}...)
|
||||||
|
require.True(t, success)
|
||||||
|
require.NotEmpty(t, stderr)
|
||||||
|
msg = unmarshalStdTx(t, stdout)
|
||||||
|
require.NotZero(t, msg.Fee.Gas)
|
||||||
|
require.Equal(t, len(msg.Msgs), 1)
|
||||||
|
|
||||||
|
// 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()))
|
||||||
|
}
|
||||||
|
|
||||||
//___________________________________________________________________________________
|
//___________________________________________________________________________________
|
||||||
// helper methods
|
// helper methods
|
||||||
|
|
||||||
|
@ -315,6 +402,12 @@ func initializeFixtures(t *testing.T) (chainID, servAddr, port string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unmarshalStdTx(t *testing.T, s string) (stdTx auth.StdTx) {
|
||||||
|
cdc := app.MakeCodec()
|
||||||
|
require.Nil(t, cdc.UnmarshalJSON([]byte(s), &stdTx))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//___________________________________________________________________________________
|
//___________________________________________________________________________________
|
||||||
// executors
|
// executors
|
||||||
|
|
||||||
|
|
|
@ -224,9 +224,9 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t
|
||||||
}
|
}
|
||||||
case offlineInfo:
|
case offlineInfo:
|
||||||
linfo := info.(offlineInfo)
|
linfo := info.(offlineInfo)
|
||||||
fmt.Printf("Bytes to sign:\n%s", msg)
|
fmt.Fprintf(os.Stderr, "Bytes to sign:\n%s", msg)
|
||||||
buf := bufio.NewReader(os.Stdin)
|
buf := bufio.NewReader(os.Stdin)
|
||||||
fmt.Printf("\nEnter Amino-encoded signature:\n")
|
fmt.Fprintf(os.Stderr, "\nEnter Amino-encoded signature:\n")
|
||||||
// Will block until user inputs the signature
|
// Will block until user inputs the signature
|
||||||
signed, err := buf.ReadString('\n')
|
signed, err := buf.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -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.
|
|
@ -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)
|
||||||
|
```
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
```
|
|
@ -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 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
|
||||||
|
|
||||||
|
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)
|
||||||
|
```
|
||||||
|
|
|
@ -139,6 +139,17 @@ gaiacli send \
|
||||||
--dry-run
|
--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
|
||||||
|
```
|
||||||
|
|
||||||
### Staking
|
### Staking
|
||||||
|
|
||||||
#### Set up a Validator
|
#### Set up a Validator
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# End Block
|
# 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
|
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
|
validator (and their delegators) receives between 1% and 5% of fee rewards, the
|
||||||
reserve tax is then charged, then the remainder is distributed proportionally
|
reserve community tax is then charged, then the remainder is distributed
|
||||||
by voting power to all bonded validators independent of whether they voted
|
proportionally by voting power to all bonded validators independent of whether
|
||||||
(social distribution). Note the social distribution is applied to proposer
|
they voted (social distribution). Note the social distribution is applied to
|
||||||
validator in addition to the proposer reward.
|
proposer validator in addition to the proposer reward.
|
||||||
|
|
||||||
The amount of proposer reward is calculated from pre-commits Tendermint
|
The amount of proposer reward is calculated from pre-commits Tendermint
|
||||||
messages in order to incentivize validators to wait and include additional
|
messages in order to incentivize validators to wait and include additional
|
||||||
|
@ -15,13 +15,17 @@ pool which validator holds individually
|
||||||
(`ValidatorDistribution.ProvisionsRewardPool`).
|
(`ValidatorDistribution.ProvisionsRewardPool`).
|
||||||
|
|
||||||
```
|
```
|
||||||
func SortFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
func AllocateFees(feesCollected sdk.Coins, global Global, proposer ValidatorDistribution,
|
||||||
sumPowerPrecommitValidators, totalBondedTokens, communityTax sdk.Dec)
|
sumPowerPrecommitValidators, totalBondedTokens, communityTax,
|
||||||
|
proposerCommissionRate sdk.Dec)
|
||||||
|
|
||||||
feesCollectedDec = MakeDecCoins(feesCollected)
|
feesCollectedDec = MakeDecCoins(feesCollected)
|
||||||
proposerReward = feesCollectedDec * (0.01 + 0.04
|
proposerReward = feesCollectedDec * (0.01 + 0.04
|
||||||
* sumPowerPrecommitValidators / totalBondedTokens)
|
* sumPowerPrecommitValidators / totalBondedTokens)
|
||||||
proposer.ProposerPool += proposerReward
|
|
||||||
|
commission = proposerReward * proposerCommissionRate
|
||||||
|
proposer.PoolCommission += commission
|
||||||
|
proposer.Pool += proposerReward - commission
|
||||||
|
|
||||||
communityFunding = feesCollectedDec * communityTax
|
communityFunding = feesCollectedDec * communityTax
|
||||||
global.CommunityFund += communityFunding
|
global.CommunityFund += communityFunding
|
||||||
|
|
|
@ -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`.
|
|
@ -2,26 +2,31 @@
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Collected fees are pooled globally and divided out passively to validators and
|
This _simple_ distribution mechanism describes a functional way to passively
|
||||||
delegators. Each validator has the opportunity to charge commission to the
|
distribute rewards between validator and delegators. Note that this mechanism does
|
||||||
delegators on the fees collected on behalf of the delegators by the validators.
|
not distribute funds in as precisely as active reward distribution and will therefore
|
||||||
Fees are paid directly into a global fee pool, and validator proposer-reward
|
be upgraded in the future.
|
||||||
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
|
The mechanism operates as follows. Collected rewards are pooled globally and
|
||||||
too, leaving nothing in the pool,
|
divided out passively to validators and delegators. Each validator has the
|
||||||
- bonding, unbonding, or re-delegating tokens to an existing account a
|
opportunity to charge commission to the delegators on the rewards collected on
|
||||||
full withdrawal of the fees must occur (as the rules for lazy accounting
|
behalf of the delegators by the validators. Fees are paid directly into a
|
||||||
change),
|
global reward pool, and validator proposer-reward pool. Due to the nature of
|
||||||
- a validator chooses to change the commission on fees, all accumulated
|
passive accounting, whenever changes to parameters which affect the rate of reward
|
||||||
commission fees must be simultaneously withdrawn.
|
distribution occurs, withdrawal of rewards must also occur.
|
||||||
|
|
||||||
The above scenarios are covered in `triggers.md`.
|
- 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
|
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,
|
- multi-token fees to be socially distributed,
|
||||||
- proposer reward pool,
|
- proposer reward pool,
|
||||||
- inflated atom provisions, and
|
- inflated atom provisions, and
|
||||||
|
@ -29,26 +34,39 @@ following between validators and associated delegators:
|
||||||
|
|
||||||
Fees are pooled within a global pool, as well as validator specific
|
Fees are pooled within a global pool, as well as validator specific
|
||||||
proposer-reward pools. The mechanisms used allow for validators and delegators
|
proposer-reward pools. The mechanisms used allow for validators and delegators
|
||||||
to independently and lazily withdrawn their rewards. As a part of the lazy
|
to independently and lazily withdraw their rewards.
|
||||||
computations adjustment factors must be maintained for each validator and
|
|
||||||
delegator to determine the true proportion of fees in each pool which they are
|
## Shortcomings
|
||||||
entitled too. Adjustment factors are updated every time a validator or
|
|
||||||
delegator's voting power changes. Validators and delegators must withdraw all
|
As a part of the lazy computations, each delegator holds an accumulation term
|
||||||
fees they are entitled too before they can change their portion of bonded
|
specific to each validator which is used to estimate what their approximate
|
||||||
Atoms.
|
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
|
## Affect on Staking
|
||||||
|
|
||||||
|
|
||||||
Charging commission on Atom provisions while also allowing for Atom-provisions
|
Charging commission on Atom provisions while also allowing for Atom-provisions
|
||||||
to be auto-bonded (distributed directly to the validators bonded stake) is
|
to be auto-bonded (distributed directly to the validators bonded stake) is
|
||||||
problematic within DPoS. Fundamentally these two mechnisms are mutually
|
problematic within DPoS. Fundamentally these two mechanisms are mutually
|
||||||
exclusive. If there are atoms commissions and auto-bonding Atoms, the portion
|
exclusive. If there are Atom commissions and auto-bonding Atoms, the portion
|
||||||
of Atoms the fee distribution calculation would become very large as the Atom
|
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 fees
|
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
|
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
|
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
|
provisions or bonded atom provisions with no Atom commission, and we elect to
|
||||||
implement the former. Stakeholders wishing to rebond their provisions may elect
|
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.
|
||||||
|
|
||||||
|
|
|
@ -23,78 +23,46 @@ type DecCoin struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Global struct {
|
type Global struct {
|
||||||
PrevBondedTokens sdk.Dec // bonded token amount for the global pool on the previous block
|
TotalValAccumUpdateHeight int64 // last height which the total validator accum was updated
|
||||||
Adjustment sdk.Dec // global adjustment factor for lazy calculations
|
TotalValAccum sdk.Dec // total valdator accum held by validators
|
||||||
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
Pool DecCoins // funds for all validators which have yet to be withdrawn
|
||||||
PrevReceivedPool DecCoins // funds added to the pool on the previous block
|
CommunityPool DecCoins // pool for community funds yet to be spent
|
||||||
EverReceivedPool DecCoins // total funds ever added to the pool
|
|
||||||
CommunityFund DecCoins // pool for community funds yet to be spent
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Validator Distribution
|
### Validator Distribution
|
||||||
|
|
||||||
Validator distribution information for the relevant validator is updated each time:
|
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,
|
2. a validator successfully proposes a block and receives a reward,
|
||||||
3. any delegator withdraws from a validator, or
|
3. any delegator withdraws from a validator, or
|
||||||
4. the validator withdraws it's commission.
|
4. the validator withdraws it's commission.
|
||||||
|
|
||||||
- ValidatorDistribution: `0x02 | ValOwnerAddr -> amino(validatorDistribution)`
|
- ValidatorDistInfo: `0x02 | ValOperatorAddr -> amino(validatorDistribution)`
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type ValidatorDistribution struct {
|
type ValidatorDistInfo struct {
|
||||||
CommissionWithdrawalHeight int64 // last time this validator withdrew commission
|
GlobalWithdrawalHeight int64 // last height this validator withdrew from the global pool
|
||||||
Adjustment sdk.Dec // global pool adjustment factor
|
Pool DecCoins // rewards owed to delegators, commission has already been charged (includes proposer reward)
|
||||||
ProposerAdjustment DecCoins // proposer pool adjustment factor
|
PoolCommission DecCoins // commission collected by this validator (pending withdrawal)
|
||||||
ProposerPool DecCoins // reward pool collected from being the proposer
|
|
||||||
EverReceivedProposerReward DecCoins // all rewards ever collected from being the proposer
|
TotalDelAccumUpdateHeight int64 // last height which the total delegator accum was updated
|
||||||
PrevReceivedProposerReward DecCoins // previous rewards collected from being the proposer
|
TotalDelAccum sdk.Dec // total proposer pool accumulation factor held by delegators
|
||||||
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
|
### Delegation Distribution
|
||||||
|
|
||||||
Each delegation holds multiple adjustment factors to specify its entitlement to
|
Each delegation distribution only needs to record the height at which it last
|
||||||
the rewards from a validator. `AdjustmentPool` is used to passively calculate
|
withdrew fees. Because a delegation must withdraw fees each time it's
|
||||||
each bonds entitled fees from the `RewardPool`. `AdjustmentPool` is used to
|
properties change (aka bonded tokens etc.) its properties will remain constant
|
||||||
passively calculate each bonds entitled fees from
|
and the delegator's _accumulation_ factor can be calculated passively knowing
|
||||||
`ValidatorDistribution.ProposerRewardPool`
|
only the height of the last withdrawal and its current properties.
|
||||||
|
|
||||||
- DelegatorDistribution: ` 0x02 | DelegatorAddr | ValOwnerAddr -> amino(delegatorDist)`
|
- DelegatorDistInfo: ` 0x02 | DelegatorAddr | ValOperatorAddr -> amino(delegatorDist)`
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type DelegatorDist struct {
|
type DelegatorDistInfo struct {
|
||||||
WithdrawalHeight int64 // last time this delegation withdrew rewards
|
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
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,399 +1,213 @@
|
||||||
# Transactions
|
# Transactions
|
||||||
|
|
||||||
## TxWithdrawDelegation
|
## TxWithdrawDelegationRewardsAll
|
||||||
|
|
||||||
When a delegator wishes to withdraw their transaction fees it must send
|
When a delegator wishes to withdraw their rewards it must send
|
||||||
`TxWithdrawDelegation`. Note that parts of this transaction logic are also
|
`TxWithdrawDelegationRewardsAll`. Note that parts of this transaction logic are also
|
||||||
triggered each with any change in individual delegations, such as an unbond,
|
triggered each with any change in individual delegations, such as an unbond,
|
||||||
redelegation, or delegation of additional tokens to a specific validator.
|
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
|
```golang
|
||||||
type TxWithdrawDelegation struct {
|
type TxWithdrawDelegationRewardsAll struct {
|
||||||
delegatorAddr sdk.AccAddress
|
delegatorAddr sdk.AccAddress
|
||||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithdrawDelegator(delegatorAddr, withdrawAddr sdk.AccAddress)
|
func WithdrawDelegationRewardsAll(delegatorAddr, withdrawAddr sdk.AccAddress)
|
||||||
entitlement = GetDelegatorEntitlement(delegatorAddr)
|
height = GetHeight()
|
||||||
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
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)
|
delegations = GetDelegations(delegatorAddr)
|
||||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
|
||||||
delegation.ValidatorAddr)
|
|
||||||
pcs = GetPowerChanges(DelDistr.WithdrawalHeight)
|
|
||||||
|
|
||||||
// update all adjustment factors for each delegation since last withdrawal
|
// collect all entitled rewards
|
||||||
for pc = range pcs
|
withdraw = 0
|
||||||
for delegation = range delegations
|
pool = stake.GetPool()
|
||||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
|
||||||
delegation.ValidatorAddr)
|
|
||||||
pc.ProcessPowerChangeDelegation(delegation, DelDistr)
|
|
||||||
|
|
||||||
// collect all entitled fees
|
|
||||||
entitlement = 0
|
|
||||||
for delegation = range delegations
|
|
||||||
global = GetGlobal()
|
global = GetGlobal()
|
||||||
pool = GetPool()
|
for delegation = range delegations
|
||||||
DelDistr = GetDelegationDistribution(delegation.DelegatorAddr,
|
delInfo = GetDelegationDistInfo(delegation.DelegatorAddr,
|
||||||
delegation.ValidatorAddr)
|
delegation.ValidatorAddr)
|
||||||
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
valInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
|
||||||
validator = GetValidator(delegation.ValidatorAddr)
|
validator = GetValidator(delegation.ValidatorAddr)
|
||||||
|
|
||||||
scenerio1 = NewDelegationFromGlobalPool(delegation, validator,
|
global, diWithdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
|
||||||
pool, global, ValDistr, DelDistr)
|
validator.Tokens, validator.DelegatorShares, validator.Commission)
|
||||||
scenerio2 = NewDelegationFromProvisionPool(delegation, validator,
|
withdraw += diWithdraw
|
||||||
ValDistr, DelDistr)
|
|
||||||
entitlement += scenerio1.WithdrawalEntitlement()
|
|
||||||
entitlement += scenerio2.WithdrawalEntitlement()
|
|
||||||
|
|
||||||
return entitlement
|
SetGlobal(global)
|
||||||
|
return withdraw
|
||||||
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
|
## TxWithdrawDelegationReward
|
||||||
|
|
||||||
When a validator wishes to withdraw their transaction fees it must send
|
under special circumstances a delegator may wish to withdraw rewards from only
|
||||||
`TxWithdrawDelegation`. Note that parts of this transaction logic is also
|
a single validator.
|
||||||
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
|
```golang
|
||||||
type TxWithdrawValidator struct {
|
type TxWithdrawDelegationReward struct {
|
||||||
ownerAddr sdk.AccAddress // validator address to withdraw from
|
delegatorAddr sdk.AccAddress
|
||||||
|
validatorAddr sdk.AccAddress
|
||||||
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
withdrawAddr sdk.AccAddress // address to make the withdrawal to
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress)
|
func WithdrawDelegationReward(delegatorAddr, validatorAddr, withdrawAddr sdk.AccAddress)
|
||||||
|
height = GetHeight()
|
||||||
|
|
||||||
// update the delegator adjustment factors and also withdrawal delegation fees
|
// get all distribution scenarios
|
||||||
entitlement = GetDelegatorEntitlement(ownerAddr)
|
pool = stake.GetPool()
|
||||||
|
global = GetGlobal()
|
||||||
|
delInfo = GetDelegationDistInfo(delegatorAddr,
|
||||||
|
validatorAddr)
|
||||||
|
valInfo = GetValidatorDistInfo(validatorAddr)
|
||||||
|
validator = GetValidator(validatorAddr)
|
||||||
|
|
||||||
// update the validator adjustment factors for commission
|
global, withdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
|
||||||
ValDistr = GetValidatorDistribution(ownerAddr.ValidatorAddr)
|
validator.Tokens, validator.DelegatorShares, validator.Commission)
|
||||||
pcs = GetPowerChanges(ValDistr.CommissionWithdrawalHeight)
|
|
||||||
for pc = range pcs
|
|
||||||
pc.ProcessPowerChangeCommission()
|
|
||||||
|
|
||||||
// withdrawal validator commission rewards
|
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 WithdrawValidatorRewardsAll(operatorAddr, withdrawAddr sdk.AccAddress)
|
||||||
|
|
||||||
|
height = GetHeight()
|
||||||
global = GetGlobal()
|
global = GetGlobal()
|
||||||
pool = GetPool()
|
pool = GetPool()
|
||||||
ValDistr = GetValidatorDistribution(delegation.ValidatorAddr)
|
ValInfo = GetValidatorDistInfo(delegation.ValidatorAddr)
|
||||||
validator = GetValidator(delegation.ValidatorAddr)
|
validator = GetValidator(delegation.ValidatorAddr)
|
||||||
|
|
||||||
scenerio1 = NewCommissionFromGlobalPool(validator,
|
// withdraw self-delegation
|
||||||
pool, global, ValDistr)
|
withdraw = GetDelegatorRewardsAll(validator.OperatorAddr, height)
|
||||||
scenerio2 = CommissionFromProposerPool(validator, ValDistr)
|
|
||||||
entitlement += scenerio1.WithdrawalEntitlement()
|
|
||||||
entitlement += scenerio2.WithdrawalEntitlement()
|
|
||||||
|
|
||||||
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal())
|
// withdrawal validator commission rewards
|
||||||
|
global, commission = valInfo.WithdrawCommission(global, valInfo, height, pool.BondedTokens,
|
||||||
|
validator.Tokens, validator.Commission)
|
||||||
|
withdraw += commission
|
||||||
|
SetGlobal(global)
|
||||||
|
|
||||||
func (pc PowerChange) ProcessPowerChangeCommission()
|
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
|
||||||
|
|
||||||
// get the historical scenarios
|
|
||||||
scenario1 = pc.CommissionFromGlobalPool()
|
|
||||||
scenario2 = pc.CommissionFromProposerPool()
|
|
||||||
|
|
||||||
// process the adjustment factors
|
|
||||||
scenario1.UpdateAdjustmentForPowerChange(pc.Height)
|
|
||||||
scenario2.UpdateAdjustmentForPowerChange(pc.Height)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Common Calculations
|
## Common calculations
|
||||||
|
|
||||||
### Distribution scenario
|
### Update total validator accum
|
||||||
|
|
||||||
A common form of abstracted calculations exists between validators and
|
The total amount of validator accum must be calculated in order to determine
|
||||||
delegations attempting to withdrawal their rewards, either from `Global.Pool`
|
the amount of pool tokens which a validator is entitled to at a particular
|
||||||
or from `ValidatorDistribution.ProposerPool`. With the following interface
|
block. The accum is always additive to the existing accum. This term is to be
|
||||||
fulfilled the entitled fees for the various scenarios can be calculated.
|
updated each time rewards are withdrawn from the system.
|
||||||
|
|
||||||
```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
|
func (g Global) UpdateTotalValAccum(height int64, totalBondedTokens Dec) Global
|
||||||
return v.RecipientShares() * height
|
blocks = height - g.TotalValAccumUpdateHeight
|
||||||
|
g.TotalValAccum += totalDelShares * blocks
|
||||||
func (d DistributionScenario) GlobalCount(height int64) sdk.Dec
|
g.TotalValAccumUpdateHeight = height
|
||||||
return d.DistributorShares() * height
|
return g
|
||||||
|
|
||||||
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
|
### Update validator's accums
|
||||||
recipient/distributor shares and recipient withdrawals. The adjustment factor
|
|
||||||
must be modified whenever the recipient withdraws from the distributor or the
|
The total amount of delegator accum must be updated in order to determine the
|
||||||
distributor's/recipient's shares are changed.
|
amount of pool tokens which each delegator is entitled to, relative to the
|
||||||
- When the shares of the recipient is changed the adjustment factor is
|
other delegators for that validator. The accum is always additive to
|
||||||
increased/decreased by the difference between the _simple_ and _projected_
|
the existing accum. This term is to be updated each time a
|
||||||
pools. In other words, the cumulative difference in the shares if the shares
|
withdrawal is made from a validator.
|
||||||
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)
|
func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares Dec) ValidatorDistInfo
|
||||||
simplePool = d.SimplePool()
|
blocks = height - vi.TotalDelAccumUpdateHeight
|
||||||
projectedPool = d.ProjectedPool(height)
|
vi.TotalDelAccum += totalDelShares * blocks
|
||||||
AdjustmentChange = simplePool - projectedPool
|
vi.TotalDelAccumUpdateHeight = height
|
||||||
if AdjustmentChange > 0
|
return vi
|
||||||
d.ModifyAdjustments(AdjustmentChange)
|
|
||||||
|
|
||||||
func (d DistributionScenario) WithdrawalEntitlement() DecCoins
|
|
||||||
entitlement = d.SimplePool() - d.RecipientAdjustment()
|
|
||||||
d.ModifyAdjustments(entitlement)
|
|
||||||
return entitlement
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Distribution scenarios
|
### Global pool to validator pool
|
||||||
|
|
||||||
Note that the distribution scenario structures are found in `state.md`.
|
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
|
||||||
#### Delegation's entitlement to Global.Pool
|
from the passive global pool to their own pool. It is at this point that the
|
||||||
|
commission is withdrawn
|
||||||
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 {
|
func (vi ValidatorDistInfo) TakeAccum(g Global, height int64, totalBonded, vdTokens, commissionRate Dec) (
|
||||||
DelegationShares sdk.Dec
|
vi ValidatorDistInfo, g Global)
|
||||||
ValidatorCommission sdk.Dec
|
|
||||||
ValidatorBondedTokens sdk.Dec
|
|
||||||
ValidatorDelegatorShareExRate sdk.Dec
|
|
||||||
PoolBondedTokens sdk.Dec
|
|
||||||
Global Global
|
|
||||||
ValDistr ValidatorDistribution
|
|
||||||
DelDistr DelegatorDistribution
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) DistributorTokens() DecCoins
|
g.UpdateTotalValAccum(height, totalBondedShares)
|
||||||
return d.Global.Pool
|
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) DistributorCumulativeTokens() DecCoins
|
// update the validators pool
|
||||||
return d.Global.EverReceivedPool
|
blocks = height - vi.GlobalWithdrawalHeight
|
||||||
|
vi.GlobalWithdrawalHeight = height
|
||||||
|
accum = blocks * vdTokens
|
||||||
|
withdrawalTokens := g.Pool * accum / g.TotalValAccum
|
||||||
|
commission := withdrawalTokens * commissionRate
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) DistributorPrevReceivedTokens() DecCoins
|
g.TotalValAccum -= accumm
|
||||||
return d.Global.PrevReceivedPool
|
vi.PoolCommission += commission
|
||||||
|
vi.PoolCommissionFree += withdrawalTokens - commission
|
||||||
|
g.Pool -= withdrawalTokens
|
||||||
|
|
||||||
func (d DelegationFromGlobalPool) DistributorShares() sdk.Dec
|
return vi, g
|
||||||
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
|
### Delegation reward withdrawal
|
||||||
commission on the rewards gained from the proposer pool. Global shares in this
|
|
||||||
context is actually the validators total delegations shares. The recipient's
|
For delegations (including validator's self-delegation) all rewards from reward
|
||||||
shares is taken as the effective delegation shares less the validator's
|
pool have already had the validator's commission taken away.
|
||||||
commission.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
type DelegationFromProposerPool struct {
|
func (di DelegatorDistInfo) WithdrawRewards(g Global, vi ValidatorDistInfo,
|
||||||
DelegationShares sdk.Dec
|
height int64, totalBonded, vdTokens, totalDelShares, commissionRate Dec) (
|
||||||
ValidatorCommission sdk.Dec
|
di DelegatorDistInfo, g Global, withdrawn DecCoins)
|
||||||
ValidatorDelegatorShares sdk.Dec
|
|
||||||
ValDistr ValidatorDistribution
|
|
||||||
DelDistr DelegatorDistribution
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) DistributorTokens() DecCoins
|
vi.UpdateTotalDelAccum(height, totalDelShares)
|
||||||
return d.ValDistr.ProposerPool
|
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) DistributorCumulativeTokens() DecCoins
|
blocks = height - di.WithdrawalHeight
|
||||||
return d.ValDistr.EverReceivedProposerReward
|
di.WithdrawalHeight = height
|
||||||
|
accum = delegatorShares * blocks
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) DistributorPrevReceivedTokens() DecCoins
|
withdrawalTokens := vi.Pool * accum / vi.TotalDelAccum
|
||||||
return d.ValDistr.PrevReceivedProposerReward
|
vi.TotalDelAccum -= accum
|
||||||
|
|
||||||
func (d DelegationFromProposerPool) DistributorShares() sdk.Dec
|
vi.Pool -= withdrawalTokens
|
||||||
return d.ValidatorDelegatorShares
|
vi.TotalDelAccum -= accum
|
||||||
|
return di, g, withdrawalTokens
|
||||||
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
|
### Validator commission withdrawal
|
||||||
return c.Global.Pool
|
|
||||||
|
|
||||||
func (c CommissionFromGlobalPool) DistributorCumulativeTokens() DecCoins
|
Commission is calculated each time rewards enter into the validator.
|
||||||
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 {
|
func (vi ValidatorDistInfo) WithdrawCommission(g Global, height int64,
|
||||||
ValidatorDelegatorShares sdk.Dec
|
totalBonded, vdTokens, commissionRate Dec) (
|
||||||
ValidatorCommission sdk.Dec
|
vi ValidatorDistInfo, g Global, withdrawn DecCoins)
|
||||||
ValDistr ValidatorDistribution
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) DistributorTokens() DecCoins
|
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
|
||||||
return c.ValDistr.ProposerPool
|
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) DistributorCumulativeTokens() DecCoins
|
withdrawalTokens := vi.PoolCommission
|
||||||
return c.ValDistr.EverReceivedProposerReward
|
vi.PoolCommission = 0
|
||||||
|
|
||||||
func (c CommissionFromProposerPool) DistributorPrevReceivedTokens() DecCoins
|
return vi, g, withdrawalTokens
|
||||||
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)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ func GetAssocKey(base sdk.ValAddress, assoc sdk.ValAddress) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Associate associates new address with validator address
|
// Associate associates new address with validator address
|
||||||
|
// nolint: unparam
|
||||||
func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
|
func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
|
||||||
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
|
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
|
||||||
return false
|
return false
|
||||||
|
@ -76,6 +77,7 @@ func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dissociate removes association between addresses
|
// Dissociate removes association between addresses
|
||||||
|
// nolint: unparam
|
||||||
func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
|
func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
|
||||||
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
|
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
|
||||||
return false
|
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
|
// Associations returns all associated addresses with a validator
|
||||||
|
// nolint: unparam
|
||||||
func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.ValAddress) (res []sdk.ValAddress) {
|
func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.ValAddress) (res []sdk.ValAddress) {
|
||||||
res = make([]sdk.ValAddress, valset.maxAssoc)
|
res = make([]sdk.ValAddress, valset.maxAssoc)
|
||||||
iter := sdk.KVStorePrefixIterator(valset.store, GetAssocPrefix(base))
|
iter := sdk.KVStorePrefixIterator(valset.store, GetAssocPrefix(base))
|
||||||
|
|
|
@ -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)
|
|
@ -344,6 +344,7 @@ func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
|
||||||
|
|
||||||
// writeGenesisFile creates and writes the genesis configuration to disk. An
|
// writeGenesisFile creates and writes the genesis configuration to disk. An
|
||||||
// error is returned if building or writing the configuration to file fails.
|
// 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 {
|
func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error {
|
||||||
genDoc := tmtypes.GenesisDoc{
|
genDoc := tmtypes.GenesisDoc{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
|
|
|
@ -84,6 +84,7 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) {
|
func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) {
|
||||||
cfg := ctx.Config
|
cfg := ctx.Config
|
||||||
home := cfg.RootDir
|
home := cfg.RootDir
|
||||||
|
|
|
@ -20,7 +20,7 @@ const (
|
||||||
|
|
||||||
// load the iavl store
|
// load the iavl store
|
||||||
func LoadIAVLStore(db dbm.DB, id CommitID, pruning sdk.PruningStrategy) (CommitStore, error) {
|
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)
|
_, err := tree.LoadVersion(id.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -40,7 +40,7 @@ var _ Queryable = (*iavlStore)(nil)
|
||||||
type iavlStore struct {
|
type iavlStore struct {
|
||||||
|
|
||||||
// The underlying tree.
|
// The underlying tree.
|
||||||
tree *iavl.VersionedTree
|
tree *iavl.MutableTree
|
||||||
|
|
||||||
// How many old versions we hold onto.
|
// How many old versions we hold onto.
|
||||||
// A value of 0 means keep no recent states.
|
// A value of 0 means keep no recent states.
|
||||||
|
@ -56,7 +56,8 @@ type iavlStore struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONTRACT: tree should be fully loaded.
|
// 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{
|
st := &iavlStore{
|
||||||
tree: tree,
|
tree: tree,
|
||||||
numRecent: numRecent,
|
numRecent: numRecent,
|
||||||
|
@ -167,16 +168,16 @@ func (st *iavlStore) Gas(meter GasMeter, config GasConfig) KVStore {
|
||||||
|
|
||||||
// Implements KVStore.
|
// Implements KVStore.
|
||||||
func (st *iavlStore) Iterator(start, end []byte) Iterator {
|
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.
|
// Implements KVStore.
|
||||||
func (st *iavlStore) ReverseIterator(start, end []byte) Iterator {
|
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
|
// 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
|
height := req.Height
|
||||||
if height == 0 {
|
if height == 0 {
|
||||||
latest := tree.Version64()
|
latest := tree.Version64()
|
||||||
|
@ -255,7 +256,7 @@ func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
|
||||||
// Implements Iterator.
|
// Implements Iterator.
|
||||||
type iavlIterator struct {
|
type iavlIterator struct {
|
||||||
// Underlying store
|
// Underlying store
|
||||||
tree *iavl.Tree
|
tree *iavl.ImmutableTree
|
||||||
|
|
||||||
// Domain
|
// Domain
|
||||||
start, end []byte
|
start, end []byte
|
||||||
|
@ -286,7 +287,7 @@ var _ Iterator = (*iavlIterator)(nil)
|
||||||
// newIAVLIterator will create a new iavlIterator.
|
// newIAVLIterator will create a new iavlIterator.
|
||||||
// CONTRACT: Caller must release the iavlIterator, as each one creates a new
|
// CONTRACT: Caller must release the iavlIterator, as each one creates a new
|
||||||
// goroutine.
|
// 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{
|
iter := &iavlIterator{
|
||||||
tree: tree,
|
tree: tree,
|
||||||
start: cp(start),
|
start: cp(start),
|
||||||
|
|
|
@ -29,8 +29,8 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// make a tree and save it
|
// make a tree and save it
|
||||||
func newTree(t *testing.T, db dbm.DB) (*iavl.VersionedTree, CommitID) {
|
func newTree(t *testing.T, db dbm.DB) (*iavl.MutableTree, CommitID) {
|
||||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
tree := iavl.NewMutableTree(db, cacheSize)
|
||||||
for k, v := range treeData {
|
for k, v := range treeData {
|
||||||
tree.Set([]byte(k), []byte(v))
|
tree.Set([]byte(k), []byte(v))
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ type pruneState struct {
|
||||||
|
|
||||||
func testPruning(t *testing.T, numRecent int64, storeEvery int64, states []pruneState) {
|
func testPruning(t *testing.T, numRecent int64, storeEvery int64, states []pruneState) {
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
tree := iavl.NewMutableTree(db, cacheSize)
|
||||||
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
|
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
|
||||||
for step, state := range states {
|
for step, state := range states {
|
||||||
for _, ver := range state.stored {
|
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) {
|
func TestIAVLNoPrune(t *testing.T) {
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
tree := iavl.NewMutableTree(db, cacheSize)
|
||||||
iavlStore := newIAVLStore(tree, numRecent, int64(1))
|
iavlStore := newIAVLStore(tree, numRecent, int64(1))
|
||||||
nextVersion(iavlStore)
|
nextVersion(iavlStore)
|
||||||
for i := 1; i < 100; i++ {
|
for i := 1; i < 100; i++ {
|
||||||
|
@ -359,7 +359,7 @@ func TestIAVLNoPrune(t *testing.T) {
|
||||||
|
|
||||||
func TestIAVLPruneEverything(t *testing.T) {
|
func TestIAVLPruneEverything(t *testing.T) {
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
tree := iavl.NewMutableTree(db, cacheSize)
|
||||||
iavlStore := newIAVLStore(tree, int64(0), int64(0))
|
iavlStore := newIAVLStore(tree, int64(0), int64(0))
|
||||||
nextVersion(iavlStore)
|
nextVersion(iavlStore)
|
||||||
for i := 1; i < 100; i++ {
|
for i := 1; i < 100; i++ {
|
||||||
|
@ -377,7 +377,7 @@ func TestIAVLPruneEverything(t *testing.T) {
|
||||||
|
|
||||||
func TestIAVLStoreQuery(t *testing.T) {
|
func TestIAVLStoreQuery(t *testing.T) {
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
tree := iavl.NewMutableTree(db, cacheSize)
|
||||||
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
|
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
|
||||||
|
|
||||||
k1, v1 := []byte("key1"), []byte("val1")
|
k1, v1 := []byte("key1"), []byte("val1")
|
||||||
|
@ -468,7 +468,7 @@ func TestIAVLStoreQuery(t *testing.T) {
|
||||||
func BenchmarkIAVLIteratorNext(b *testing.B) {
|
func BenchmarkIAVLIteratorNext(b *testing.B) {
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
treeSize := 1000
|
treeSize := 1000
|
||||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
tree := iavl.NewMutableTree(db, cacheSize)
|
||||||
for i := 0; i < treeSize; i++ {
|
for i := 0; i < treeSize; i++ {
|
||||||
key := cmn.RandBytes(4)
|
key := cmn.RandBytes(4)
|
||||||
value := cmn.RandBytes(50)
|
value := cmn.RandBytes(50)
|
||||||
|
|
|
@ -2,10 +2,12 @@ package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/tendermint/iavl"
|
"github.com/tendermint/iavl"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
"testing"
|
"github.com/tendermint/tendermint/libs/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVerifyMultiStoreCommitInfo(t *testing.T) {
|
func TestVerifyMultiStoreCommitInfo(t *testing.T) {
|
||||||
|
@ -91,7 +93,7 @@ func TestVerifyMultiStoreCommitInfo(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVerifyRangeProof(t *testing.T) {
|
func TestVerifyRangeProof(t *testing.T) {
|
||||||
tree := iavl.NewTree(nil, 0)
|
tree := iavl.NewMutableTree(db.NewMemDB(), 0)
|
||||||
|
|
||||||
rand := cmn.NewRand()
|
rand := cmn.NewRand()
|
||||||
rand.Seed(0) // for determinism
|
rand.Seed(0) // for determinism
|
||||||
|
@ -100,7 +102,7 @@ func TestVerifyRangeProof(t *testing.T) {
|
||||||
tree.Set(key, []byte(rand.Str(8)))
|
tree.Set(key, []byte(rand.Str(8)))
|
||||||
}
|
}
|
||||||
|
|
||||||
root := tree.Hash()
|
root := tree.WorkingHash()
|
||||||
|
|
||||||
key := []byte{0x32}
|
key := []byte{0x32}
|
||||||
val, proof, err := tree.GetWithProof(key)
|
val, proof, err := tree.GetWithProof(key)
|
||||||
|
|
|
@ -66,7 +66,7 @@ func testPrefixStore(t *testing.T, baseStore KVStore, prefix []byte) {
|
||||||
|
|
||||||
func TestIAVLStorePrefix(t *testing.T) {
|
func TestIAVLStorePrefix(t *testing.T) {
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
tree := iavl.NewVersionedTree(db, cacheSize)
|
tree := iavl.NewMutableTree(db, cacheSize)
|
||||||
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
|
iavlStore := newIAVLStore(tree, numRecent, storeEvery)
|
||||||
|
|
||||||
testPrefixStore(t, iavlStore, []byte("test"))
|
testPrefixStore(t, iavlStore, []byte("test"))
|
||||||
|
|
|
@ -179,6 +179,7 @@ func (tkv *TraceKVStore) CacheWrapWithTrace(_ io.Writer, _ TraceContext) CacheWr
|
||||||
|
|
||||||
// writeOperation writes a KVStore operation to the underlying io.Writer as
|
// writeOperation writes a KVStore operation to the underlying io.Writer as
|
||||||
// JSON-encoded data where the key/value pair is base64 encoded.
|
// 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) {
|
func writeOperation(w io.Writer, op operation, tc TraceContext, key, value []byte) {
|
||||||
traceOp := traceOperation{
|
traceOp := traceOperation{
|
||||||
Operation: op,
|
Operation: op,
|
||||||
|
|
|
@ -156,8 +156,8 @@ func TestTestTraceKVStoreIterator(t *testing.T) {
|
||||||
iterator := store.Iterator(nil, nil)
|
iterator := store.Iterator(nil, nil)
|
||||||
|
|
||||||
s, e := iterator.Domain()
|
s, e := iterator.Domain()
|
||||||
require.Equal(t, []uint8([]byte(nil)), s)
|
require.Equal(t, []byte(nil), s)
|
||||||
require.Equal(t, []uint8([]byte(nil)), e)
|
require.Equal(t, []byte(nil), e)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
expectedKey []byte
|
expectedKey []byte
|
||||||
|
@ -212,8 +212,8 @@ func TestTestTraceKVStoreReverseIterator(t *testing.T) {
|
||||||
iterator := store.ReverseIterator(nil, nil)
|
iterator := store.ReverseIterator(nil, nil)
|
||||||
|
|
||||||
s, e := iterator.Domain()
|
s, e := iterator.Domain()
|
||||||
require.Equal(t, []uint8([]byte(nil)), s)
|
require.Equal(t, []byte(nil), s)
|
||||||
require.Equal(t, []uint8([]byte(nil)), e)
|
require.Equal(t, []byte(nil), e)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
expectedKey []byte
|
expectedKey []byte
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
// ExecuteT executes the command, pipes any input to STDIN and return STDOUT,
|
// ExecuteT executes the command, pipes any input to STDIN and return STDOUT,
|
||||||
// logging STDOUT/STDERR to t.
|
// logging STDOUT/STDERR to t.
|
||||||
|
// nolint: errcheck
|
||||||
func ExecuteT(t *testing.T, cmd, input string) (out string) {
|
func ExecuteT(t *testing.T, cmd, input string) (out string) {
|
||||||
t.Log("Running", cmn.Cyan(cmd))
|
t.Log("Running", cmn.Cyan(cmd))
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ INEFFASSIGN_CHECK := $(shell command -v ineffassign 2> /dev/null)
|
||||||
MISSPELL_CHECK := $(shell command -v misspell 2> /dev/null)
|
MISSPELL_CHECK := $(shell command -v misspell 2> /dev/null)
|
||||||
ERRCHECK_CHECK := $(shell command -v errcheck 2> /dev/null)
|
ERRCHECK_CHECK := $(shell command -v errcheck 2> /dev/null)
|
||||||
UNPARAM_CHECK := $(shell command -v unparam 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)
|
||||||
|
|
||||||
check_tools:
|
check_tools:
|
||||||
ifndef DEP_CHECK
|
ifndef DEP_CHECK
|
||||||
|
@ -126,12 +126,12 @@ else
|
||||||
@echo "Installing unparam"
|
@echo "Installing unparam"
|
||||||
go get -v $(UNPARAM)
|
go get -v $(UNPARAM)
|
||||||
endif
|
endif
|
||||||
ifdef GOCYCLO_CHECK
|
# ifdef GOCYCLO_CHECK
|
||||||
@echo "gocyclo is already installed. Run 'make update_tools' to update."
|
# @echo "gocyclo is already installed. Run 'make update_tools' to update."
|
||||||
else
|
# else
|
||||||
@echo "Installing gocyclo"
|
# @echo "Installing gocyclo"
|
||||||
go get -v $(GOCYCLO)
|
# go get -v $(GOCYCLO)
|
||||||
endif
|
# endif
|
||||||
|
|
||||||
update_tools:
|
update_tools:
|
||||||
@echo "Updating dep"
|
@echo "Updating dep"
|
||||||
|
@ -153,8 +153,8 @@ update_dev_tools:
|
||||||
go get -u -v $(ERRCHECK)
|
go get -u -v $(ERRCHECK)
|
||||||
@echo "Updating unparam"
|
@echo "Updating unparam"
|
||||||
go get -u -v $(UNPARAM)
|
go get -u -v $(UNPARAM)
|
||||||
@echo "Updating goyclo"
|
# @echo "Updating goyclo"
|
||||||
go get -u -v $(GOCYCLO)
|
# go get -u -v $(GOCYCLO)
|
||||||
|
|
||||||
# To avoid unintended conflicts with file names, always add to .PHONY
|
# To avoid unintended conflicts with file names, always add to .PHONY
|
||||||
# unless there is a reason not to.
|
# unless there is a reason not to.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"Linters": {
|
"Linters": {
|
||||||
"vet": "go tool vet -composites=false :PATH:LINE:MESSAGE"
|
"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",
|
"Deadline": "500s",
|
||||||
"Vendor": true,
|
"Vendor": true,
|
||||||
"Cyclo": 11
|
"Cyclo": 11
|
||||||
|
|
|
@ -133,6 +133,7 @@ func (aa AccAddress) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format implements the fmt.Formatter interface.
|
// Format implements the fmt.Formatter interface.
|
||||||
|
// nolint: errcheck
|
||||||
func (aa AccAddress) Format(s fmt.State, verb rune) {
|
func (aa AccAddress) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 's':
|
case 's':
|
||||||
|
@ -247,6 +248,7 @@ func (va ValAddress) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format implements the fmt.Formatter interface.
|
// Format implements the fmt.Formatter interface.
|
||||||
|
// nolint: errcheck
|
||||||
func (va ValAddress) Format(s fmt.State, verb rune) {
|
func (va ValAddress) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 's':
|
case 's':
|
||||||
|
@ -361,6 +363,7 @@ func (ca ConsAddress) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format implements the fmt.Formatter interface.
|
// Format implements the fmt.Formatter interface.
|
||||||
|
// nolint: errcheck
|
||||||
func (ca ConsAddress) Format(s fmt.State, verb rune) {
|
func (ca ConsAddress) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 's':
|
case 's':
|
||||||
|
|
|
@ -30,6 +30,7 @@ type Context struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a new context
|
// create a new context
|
||||||
|
// nolint: unparam
|
||||||
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Logger) Context {
|
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Logger) Context {
|
||||||
c := Context{
|
c := Context{
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
|
|
|
@ -219,6 +219,7 @@ func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements ABCIError.
|
// Implements ABCIError.
|
||||||
|
// nolint: errcheck
|
||||||
func (err *sdkError) TraceSDK(format string, args ...interface{}) Error {
|
func (err *sdkError) TraceSDK(format string, args ...interface{}) Error {
|
||||||
err.Trace(1, format, args...)
|
err.Trace(1, format, args...)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -30,6 +30,7 @@ func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder {
|
||||||
|
|
||||||
// GetAccountCmd returns a query account that will display the state of the
|
// GetAccountCmd returns a query account that will display the state of the
|
||||||
// account at a given address.
|
// account at a given address.
|
||||||
|
// nolint: unparam
|
||||||
func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder) *cobra.Command {
|
func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder) *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "account [address]",
|
Use: "account [address]",
|
||||||
|
|
|
@ -143,12 +143,12 @@ func StdSignBytes(chainID string, accnum int64, sequence int64, fee StdFee, msgs
|
||||||
// a Msg with the other requirements for a StdSignDoc before
|
// a Msg with the other requirements for a StdSignDoc before
|
||||||
// it is signed. For use in the CLI.
|
// it is signed. For use in the CLI.
|
||||||
type StdSignMsg struct {
|
type StdSignMsg struct {
|
||||||
ChainID string
|
ChainID string `json:"chain_id"`
|
||||||
AccountNumber int64
|
AccountNumber int64 `json:"account_number"`
|
||||||
Sequence int64
|
Sequence int64 `json:"sequence"`
|
||||||
Fee StdFee
|
Fee StdFee `json:"fee"`
|
||||||
Msgs []sdk.Msg
|
Msgs []sdk.Msg `json:"msgs"`
|
||||||
Memo string
|
Memo string `json:"memo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// get message bytes
|
// get message bytes
|
||||||
|
|
|
@ -68,6 +68,9 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||||
|
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
msg := client.BuildMsg(from, to, coins)
|
msg := client.BuildMsg(from, to, coins)
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
|
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
|
|
|
@ -107,6 +107,11 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo
|
||||||
txCtx = newCtx
|
txCtx = newCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if utils.HasGenerateOnlyArg(r) {
|
||||||
|
utils.WriteGenerateStdTxResponse(w, txCtx, []sdk.Msg{msg})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
// SimulateSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both
|
// SimulateSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both
|
||||||
// accounts already exist.
|
// accounts already exist.
|
||||||
func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation {
|
func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation {
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
|
||||||
fromKey := simulation.RandomKey(r, keys)
|
fromKey := simulation.RandomKey(r, keys)
|
||||||
fromAddr := sdk.AccAddress(fromKey.PubKey().Address())
|
fromAddr := sdk.AccAddress(fromKey.PubKey().Address())
|
||||||
toKey := simulation.RandomKey(r, keys)
|
toKey := simulation.RandomKey(r, keys)
|
||||||
|
@ -58,7 +58,7 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation
|
||||||
Inputs: []bank.Input{bank.NewInput(fromAddr, coins)},
|
Inputs: []bank.Input{bank.NewInput(fromAddr, coins)},
|
||||||
Outputs: []bank.Output{bank.NewOutput(toAddr, coins)},
|
Outputs: []bank.Output{bank.NewOutput(toAddr, coins)},
|
||||||
}
|
}
|
||||||
sendAndVerifyMsgSend(t, app, mapper, msg, ctx, log, []crypto.PrivKey{fromKey})
|
sendAndVerifyMsgSend(tb, app, mapper, msg, ctx, log, []crypto.PrivKey{fromKey})
|
||||||
event("bank/sendAndVerifyMsgSend/ok")
|
event("bank/sendAndVerifyMsgSend/ok")
|
||||||
|
|
||||||
return action, nil, nil
|
return action, nil, nil
|
||||||
|
@ -66,7 +66,7 @@ func SimulateSingleInputMsgSend(mapper auth.AccountMapper) simulation.Operation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends and verifies the transition of a msg send. This fails if there are repeated inputs or outputs
|
// Sends and verifies the transition of a msg send. This fails if there are repeated inputs or outputs
|
||||||
func sendAndVerifyMsgSend(t *testing.T, app *baseapp.BaseApp, mapper auth.AccountMapper, msg bank.MsgSend, ctx sdk.Context, log string, privkeys []crypto.PrivKey) {
|
func sendAndVerifyMsgSend(tb testing.TB, app *baseapp.BaseApp, mapper auth.AccountMapper, msg bank.MsgSend, ctx sdk.Context, log string, privkeys []crypto.PrivKey) {
|
||||||
initialInputAddrCoins := make([]sdk.Coins, len(msg.Inputs))
|
initialInputAddrCoins := make([]sdk.Coins, len(msg.Inputs))
|
||||||
initialOutputAddrCoins := make([]sdk.Coins, len(msg.Outputs))
|
initialOutputAddrCoins := make([]sdk.Coins, len(msg.Outputs))
|
||||||
AccountNumbers := make([]int64, len(msg.Inputs))
|
AccountNumbers := make([]int64, len(msg.Inputs))
|
||||||
|
@ -91,12 +91,12 @@ func sendAndVerifyMsgSend(t *testing.T, app *baseapp.BaseApp, mapper auth.Accoun
|
||||||
// TODO: Do this in a more 'canonical' way
|
// TODO: Do this in a more 'canonical' way
|
||||||
fmt.Println(res)
|
fmt.Println(res)
|
||||||
fmt.Println(log)
|
fmt.Println(log)
|
||||||
t.FailNow()
|
tb.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(msg.Inputs); i++ {
|
for i := 0; i < len(msg.Inputs); i++ {
|
||||||
terminalInputCoins := mapper.GetAccount(ctx, msg.Inputs[i].Address).GetCoins()
|
terminalInputCoins := mapper.GetAccount(ctx, msg.Inputs[i].Address).GetCoins()
|
||||||
require.Equal(t,
|
require.Equal(tb,
|
||||||
initialInputAddrCoins[i].Minus(msg.Inputs[i].Coins),
|
initialInputAddrCoins[i].Minus(msg.Inputs[i].Coins),
|
||||||
terminalInputCoins,
|
terminalInputCoins,
|
||||||
fmt.Sprintf("Input #%d had an incorrect amount of coins\n%s", i, log),
|
fmt.Sprintf("Input #%d had an incorrect amount of coins\n%s", i, log),
|
||||||
|
@ -104,11 +104,9 @@ func sendAndVerifyMsgSend(t *testing.T, app *baseapp.BaseApp, mapper auth.Accoun
|
||||||
}
|
}
|
||||||
for i := 0; i < len(msg.Outputs); i++ {
|
for i := 0; i < len(msg.Outputs); i++ {
|
||||||
terminalOutputCoins := mapper.GetAccount(ctx, msg.Outputs[i].Address).GetCoins()
|
terminalOutputCoins := mapper.GetAccount(ctx, msg.Outputs[i].Address).GetCoins()
|
||||||
require.Equal(t,
|
if !terminalOutputCoins.IsEqual(initialOutputAddrCoins[i].Plus(msg.Outputs[i].Coins)) {
|
||||||
initialOutputAddrCoins[i].Plus(msg.Outputs[i].Coins),
|
tb.Fatalf("Output #%d had an incorrect amount of coins\n%s", i, log)
|
||||||
terminalOutputCoins,
|
}
|
||||||
fmt.Sprintf("Output #%d had an incorrect amount of coins\n%s", i, log),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,12 +99,15 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := gov.NewMsgSubmitProposal(proposal.Title, proposal.Description, proposalType, fromAddr, amount)
|
msg := gov.NewMsgSubmitProposal(proposal.Title, proposal.Description, proposalType, fromAddr, amount)
|
||||||
|
|
||||||
err = msg.ValidateBasic()
|
err = msg.ValidateBasic()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
|
|
||||||
// Build and sign the transaction, then broadcast to Tendermint
|
// Build and sign the transaction, then broadcast to Tendermint
|
||||||
// proposalID must be returned, and it is a part of response.
|
// proposalID must be returned, and it is a part of response.
|
||||||
cliCtx.PrintResponse = true
|
cliCtx.PrintResponse = true
|
||||||
|
@ -177,12 +180,15 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := gov.NewMsgDeposit(depositerAddr, proposalID, amount)
|
msg := gov.NewMsgDeposit(depositerAddr, proposalID, amount)
|
||||||
|
|
||||||
err = msg.ValidateBasic()
|
err = msg.ValidateBasic()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
|
|
||||||
// Build and sign the transaction, then broadcast to a Tendermint
|
// Build and sign the transaction, then broadcast to a Tendermint
|
||||||
// node.
|
// node.
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
@ -221,12 +227,15 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := gov.NewMsgVote(voterAddr, proposalID, byteVoteOption)
|
msg := gov.NewMsgVote(voterAddr, proposalID, byteVoteOption)
|
||||||
|
|
||||||
err = msg.ValidateBasic()
|
err = msg.ValidateBasic()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]",
|
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]",
|
||||||
voterAddr.String(), msg.ProposalID, msg.Option.String(),
|
voterAddr.String(), msg.ProposalID, msg.Option.String(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -96,6 +96,12 @@ func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLICont
|
||||||
}
|
}
|
||||||
txCtx = newCtx
|
txCtx = newCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if utils.HasGenerateOnlyArg(r) {
|
||||||
|
utils.WriteGenerateStdTxResponse(w, txCtx, []sdk.Msg{msg})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
txBytes, err := txCtx.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg})
|
txBytes, err := txCtx.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||||
|
|
|
@ -132,6 +132,7 @@ func (vo VoteOption) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Printf / Sprintf, returns bech32 when using %s
|
// For Printf / Sprintf, returns bech32 when using %s
|
||||||
|
// nolint: errcheck
|
||||||
func (vo VoteOption) Format(s fmt.State, verb rune) {
|
func (vo VoteOption) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 's':
|
case 's':
|
||||||
|
|
|
@ -209,6 +209,7 @@ func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
|
||||||
// Procedures
|
// Procedures
|
||||||
|
|
||||||
// Returns the current Deposit Procedure from the global param store
|
// Returns the current Deposit Procedure from the global param store
|
||||||
|
// nolint: errcheck
|
||||||
func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
|
func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
|
||||||
var depositProcedure DepositProcedure
|
var depositProcedure DepositProcedure
|
||||||
keeper.ps.Get(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
|
keeper.ps.Get(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
|
||||||
|
@ -216,6 +217,7 @@ func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the current Voting Procedure from the global param store
|
// Returns the current Voting Procedure from the global param store
|
||||||
|
// nolint: errcheck
|
||||||
func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
|
func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
|
||||||
var votingProcedure VotingProcedure
|
var votingProcedure VotingProcedure
|
||||||
keeper.ps.Get(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
|
keeper.ps.Get(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
|
||||||
|
@ -223,20 +225,24 @@ func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the current Tallying Procedure from the global param store
|
// Returns the current Tallying Procedure from the global param store
|
||||||
|
// nolint: errcheck
|
||||||
func (keeper Keeper) GetTallyingProcedure(ctx sdk.Context) TallyingProcedure {
|
func (keeper Keeper) GetTallyingProcedure(ctx sdk.Context) TallyingProcedure {
|
||||||
var tallyingProcedure TallyingProcedure
|
var tallyingProcedure TallyingProcedure
|
||||||
keeper.ps.Get(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
keeper.ps.Get(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
||||||
return tallyingProcedure
|
return tallyingProcedure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
func (keeper Keeper) setDepositProcedure(ctx sdk.Context, depositProcedure DepositProcedure) {
|
func (keeper Keeper) setDepositProcedure(ctx sdk.Context, depositProcedure DepositProcedure) {
|
||||||
keeper.ps.Set(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
|
keeper.ps.Set(ctx, ParamStoreKeyDepositProcedure, &depositProcedure)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
func (keeper Keeper) setVotingProcedure(ctx sdk.Context, votingProcedure VotingProcedure) {
|
func (keeper Keeper) setVotingProcedure(ctx sdk.Context, votingProcedure VotingProcedure) {
|
||||||
keeper.ps.Set(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
|
keeper.ps.Set(ctx, ParamStoreKeyVotingProcedure, &votingProcedure)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
func (keeper Keeper) setTallyingProcedure(ctx sdk.Context, tallyingProcedure TallyingProcedure) {
|
func (keeper Keeper) setTallyingProcedure(ctx sdk.Context, tallyingProcedure TallyingProcedure) {
|
||||||
keeper.ps.Set(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
keeper.ps.Set(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@ const MsgType = "gov"
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
// MsgSubmitProposal
|
// MsgSubmitProposal
|
||||||
type MsgSubmitProposal struct {
|
type MsgSubmitProposal struct {
|
||||||
Title string // Title of the proposal
|
Title string `json:"title"` // Title of the proposal
|
||||||
Description string // Description of the proposal
|
Description string `json:"description"` // Description of the proposal
|
||||||
ProposalType ProposalKind // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
||||||
Proposer sdk.AccAddress // Address of the proposer
|
Proposer sdk.AccAddress `json:"proposer"` // Address of the proposer
|
||||||
InitialDeposit sdk.Coins // Initial deposit paid by sender. Must be strictly positive.
|
InitialDeposit sdk.Coins `json:"initial_deposit"` // Initial deposit paid by sender. Must be strictly positive.
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMsgSubmitProposal(title string, description string, proposalType ProposalKind, proposer sdk.AccAddress, initialDeposit sdk.Coins) MsgSubmitProposal {
|
func NewMsgSubmitProposal(title string, description string, proposalType ProposalKind, proposer sdk.AccAddress, initialDeposit sdk.Coins) MsgSubmitProposal {
|
||||||
|
|
|
@ -188,6 +188,7 @@ func (pt ProposalKind) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Printf / Sprintf, returns bech32 when using %s
|
// For Printf / Sprintf, returns bech32 when using %s
|
||||||
|
// nolint: errcheck
|
||||||
func (pt ProposalKind) Format(s fmt.State, verb rune) {
|
func (pt ProposalKind) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 's':
|
case 's':
|
||||||
|
@ -290,6 +291,7 @@ func (status ProposalStatus) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Printf / Sprintf, returns bech32 when using %s
|
// For Printf / Sprintf, returns bech32 when using %s
|
||||||
|
// nolint: errcheck
|
||||||
func (status ProposalStatus) Format(s fmt.State, verb rune) {
|
func (status ProposalStatus) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 's':
|
case 's':
|
||||||
|
|
|
@ -36,6 +36,7 @@ type QueryProposalParams struct {
|
||||||
ProposalID int64
|
ProposalID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||||
var params QueryProposalParams
|
var params QueryProposalParams
|
||||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||||
|
@ -61,6 +62,7 @@ type QueryDepositParams struct {
|
||||||
Depositer sdk.AccAddress
|
Depositer sdk.AccAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||||
var params QueryDepositParams
|
var params QueryDepositParams
|
||||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||||
|
@ -82,6 +84,7 @@ type QueryVoteParams struct {
|
||||||
Voter sdk.AccAddress
|
Voter sdk.AccAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||||
var params QueryVoteParams
|
var params QueryVoteParams
|
||||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||||
|
@ -102,6 +105,7 @@ type QueryDepositsParams struct {
|
||||||
ProposalID int64
|
ProposalID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||||
var params QueryDepositParams
|
var params QueryDepositParams
|
||||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||||
|
@ -129,6 +133,7 @@ type QueryVotesParams struct {
|
||||||
ProposalID int64
|
ProposalID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||||
var params QueryVotesParams
|
var params QueryVotesParams
|
||||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||||
|
@ -160,6 +165,7 @@ type QueryProposalsParams struct {
|
||||||
NumLatestProposals int64
|
NumLatestProposals int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func queryProposals(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
func queryProposals(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||||
var params QueryProposalsParams
|
var params QueryProposalsParams
|
||||||
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
err2 := keeper.cdc.UnmarshalJSON(req.Data, ¶ms)
|
||||||
|
@ -181,6 +187,7 @@ type QueryTallyParams struct {
|
||||||
ProposalID int64
|
ProposalID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
|
||||||
// TODO: Dependant on #1914
|
// TODO: Dependant on #1914
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
|
@ -23,7 +21,25 @@ const (
|
||||||
// SimulateMsgSubmitProposal simulates a msg Submit Proposal
|
// SimulateMsgSubmitProposal simulates a msg Submit Proposal
|
||||||
// Note: Currently doesn't ensure that the proposal txt is in JSON form
|
// Note: Currently doesn't ensure that the proposal txt is in JSON form
|
||||||
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
|
handler := gov.NewHandler(k)
|
||||||
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOps []simulation.FutureOperation, err sdk.Error) {
|
||||||
|
msg := simulationCreateMsgSubmitProposal(tb, r, keys, log)
|
||||||
|
ctx, write := ctx.CacheContext()
|
||||||
|
result := handler(ctx, msg)
|
||||||
|
if result.IsOK() {
|
||||||
|
// Update pool to keep invariants
|
||||||
|
pool := sk.GetPool(ctx)
|
||||||
|
pool.LooseTokens = pool.LooseTokens.Sub(sdk.NewDecFromInt(msg.InitialDeposit.AmountOf(denom)))
|
||||||
|
sk.SetPool(ctx, pool)
|
||||||
|
write()
|
||||||
|
}
|
||||||
|
event(fmt.Sprintf("gov/MsgSubmitProposal/%v", result.IsOK()))
|
||||||
|
action = fmt.Sprintf("TestMsgSubmitProposal: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
|
||||||
|
return action, nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func simulationCreateMsgSubmitProposal(tb testing.TB, r *rand.Rand, keys []crypto.PrivKey, log string) gov.MsgSubmitProposal {
|
||||||
key := simulation.RandomKey(r, keys)
|
key := simulation.RandomKey(r, keys)
|
||||||
addr := sdk.AccAddress(key.PubKey().Address())
|
addr := sdk.AccAddress(key.PubKey().Address())
|
||||||
deposit := randomDeposit(r)
|
deposit := randomDeposit(r)
|
||||||
|
@ -34,25 +50,15 @@ func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operati
|
||||||
addr,
|
addr,
|
||||||
deposit,
|
deposit,
|
||||||
)
|
)
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
ctx, write := ctx.CacheContext()
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
result := gov.NewHandler(k)(ctx, msg)
|
|
||||||
if result.IsOK() {
|
|
||||||
// Update pool to keep invariants
|
|
||||||
pool := sk.GetPool(ctx)
|
|
||||||
pool.LooseTokens = pool.LooseTokens.Sub(sdk.NewDecFromInt(deposit.AmountOf(denom)))
|
|
||||||
sk.SetPool(ctx, pool)
|
|
||||||
write()
|
|
||||||
}
|
|
||||||
event(fmt.Sprintf("gov/MsgSubmitProposal/%v", result.IsOK()))
|
|
||||||
action = fmt.Sprintf("TestMsgSubmitProposal: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
|
|
||||||
return action, nil, nil
|
|
||||||
}
|
}
|
||||||
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateMsgDeposit
|
// SimulateMsgDeposit
|
||||||
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
key := simulation.RandomKey(r, keys)
|
key := simulation.RandomKey(r, keys)
|
||||||
addr := sdk.AccAddress(key.PubKey().Address())
|
addr := sdk.AccAddress(key.PubKey().Address())
|
||||||
proposalID, ok := randomProposalID(r, k, ctx)
|
proposalID, ok := randomProposalID(r, k, ctx)
|
||||||
|
@ -61,7 +67,9 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
}
|
}
|
||||||
deposit := randomDeposit(r)
|
deposit := randomDeposit(r)
|
||||||
msg := gov.NewMsgDeposit(addr, proposalID, deposit)
|
msg := gov.NewMsgDeposit(addr, proposalID, deposit)
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := gov.NewHandler(k)(ctx, msg)
|
result := gov.NewHandler(k)(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
|
@ -78,8 +86,9 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateMsgVote
|
// SimulateMsgVote
|
||||||
|
// nolint: unparam
|
||||||
func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
key := simulation.RandomKey(r, keys)
|
key := simulation.RandomKey(r, keys)
|
||||||
addr := sdk.AccAddress(key.PubKey().Address())
|
addr := sdk.AccAddress(key.PubKey().Address())
|
||||||
proposalID, ok := randomProposalID(r, k, ctx)
|
proposalID, ok := randomProposalID(r, k, ctx)
|
||||||
|
@ -88,7 +97,9 @@ func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
|
||||||
}
|
}
|
||||||
option := randomVotingOption(r)
|
option := randomVotingOption(r)
|
||||||
msg := gov.NewMsgVote(addr, proposalID, option)
|
msg := gov.NewMsgVote(addr, proposalID, option)
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := gov.NewHandler(k)(ctx, msg)
|
result := gov.NewHandler(k)(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
|
|
|
@ -43,6 +43,9 @@ func IBCTransferCmd(cdc *wire.Codec) *cobra.Command {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
|
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
|
|
|
@ -163,6 +163,7 @@ func query(node string, key []byte, storeName string) (res []byte, err error) {
|
||||||
return context.NewCLIContext().WithNodeURI(node).QueryStore(key, storeName)
|
return context.NewCLIContext().WithNodeURI(node).QueryStore(key, storeName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func (c relayCommander) broadcastTx(seq int64, node string, tx []byte) error {
|
func (c relayCommander) broadcastTx(seq int64, node string, tx []byte) error {
|
||||||
_, err := context.NewCLIContext().WithNodeURI(node).BroadcastTx(tx)
|
_, err := context.NewCLIContext().WithNodeURI(node).BroadcastTx(tx)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -98,6 +98,11 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C
|
||||||
txCtx = newCtx
|
txCtx = newCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if utils.HasGenerateOnlyArg(r) {
|
||||||
|
utils.WriteGenerateStdTxResponse(w, txCtx, []sdk.Msg{msg})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||||
|
|
|
@ -22,11 +22,11 @@ func init() {
|
||||||
// IBCPacket defines a piece of data that can be send between two separate
|
// IBCPacket defines a piece of data that can be send between two separate
|
||||||
// blockchains.
|
// blockchains.
|
||||||
type IBCPacket struct {
|
type IBCPacket struct {
|
||||||
SrcAddr sdk.AccAddress
|
SrcAddr sdk.AccAddress `json:"src_addr"`
|
||||||
DestAddr sdk.AccAddress
|
DestAddr sdk.AccAddress `json:"dest_addr"`
|
||||||
Coins sdk.Coins
|
Coins sdk.Coins `json:"coins"`
|
||||||
SrcChain string
|
SrcChain string `json:"src_chain"`
|
||||||
DestChain string
|
DestChain string `json:"dest_chain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIBCPacket(srcAddr sdk.AccAddress, destAddr sdk.AccAddress, coins sdk.Coins,
|
func NewIBCPacket(srcAddr sdk.AccAddress, destAddr sdk.AccAddress, coins sdk.Coins,
|
||||||
|
|
|
@ -86,6 +86,7 @@ func (app *App) CompleteSetup(newKeys []*sdk.KVStoreKey) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitChainer performs custom logic for initialization.
|
// InitChainer performs custom logic for initialization.
|
||||||
|
// nolint: errcheck
|
||||||
func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain {
|
func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain {
|
||||||
// Load the genesis accounts
|
// Load the genesis accounts
|
||||||
for _, genacc := range app.GenesisAccounts {
|
for _, genacc := range app.GenesisAccounts {
|
||||||
|
@ -207,6 +208,7 @@ func GeneratePrivKeyAddressPairsFromRand(rand *rand.Rand, n int) (keys []crypto.
|
||||||
|
|
||||||
// RandomSetGenesis set genesis accounts with random coin values using the
|
// RandomSetGenesis set genesis accounts with random coin values using the
|
||||||
// provided addresses and coin denominations.
|
// provided addresses and coin denominations.
|
||||||
|
// nolint: errcheck
|
||||||
func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) {
|
func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) {
|
||||||
accts := make([]auth.Account, len(addrs), len(addrs))
|
accts := make([]auth.Account, len(addrs), len(addrs))
|
||||||
randCoinIntervals := []BigInterval{
|
randCoinIntervals := []BigInterval{
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -16,7 +17,6 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Simulate tests application by sending random messages.
|
// Simulate tests application by sending random messages.
|
||||||
|
@ -28,34 +28,10 @@ func Simulate(
|
||||||
SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit)
|
SimulateFromSeed(t, app, appStateFn, time, ops, setups, invariants, numBlocks, blockSize, commit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateFromSeed tests an application by running the provided
|
func initChain(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress, setups []RandSetup, app *baseapp.BaseApp,
|
||||||
// operations, testing the provided invariants, but using the provided seed.
|
appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage) (validators map[string]mockValidator) {
|
||||||
func SimulateFromSeed(
|
|
||||||
t *testing.T, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []Operation, setups []RandSetup,
|
|
||||||
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
|
||||||
) {
|
|
||||||
log := fmt.Sprintf("Starting SimulateFromSeed with randomness created with seed %d", int(seed))
|
|
||||||
r := rand.New(rand.NewSource(seed))
|
|
||||||
|
|
||||||
unixTime := r.Int63n(int64(math.Pow(2, 40)))
|
|
||||||
|
|
||||||
// Set the timestamp for simulation
|
|
||||||
timestamp := time.Unix(unixTime, 0)
|
|
||||||
log = fmt.Sprintf("%s\nStarting the simulation from time %v, unixtime %v", log, timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
|
|
||||||
fmt.Printf("%s\n", log)
|
|
||||||
timeDiff := maxTimePerBlock - minTimePerBlock
|
|
||||||
|
|
||||||
keys, accs := mock.GeneratePrivKeyAddressPairsFromRand(r, numKeys)
|
|
||||||
|
|
||||||
// Setup event stats
|
|
||||||
events := make(map[string]uint)
|
|
||||||
event := func(what string) {
|
|
||||||
log += "\nevent - " + what
|
|
||||||
events[what]++
|
|
||||||
}
|
|
||||||
|
|
||||||
res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, keys, accs)})
|
res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, keys, accs)})
|
||||||
validators := make(map[string]mockValidator)
|
validators = make(map[string]mockValidator)
|
||||||
for _, validator := range res.Validators {
|
for _, validator := range res.Validators {
|
||||||
validators[string(validator.Address)] = mockValidator{validator, GetMemberOfInitialState(r, initialLivenessWeightings)}
|
validators[string(validator.Address)] = mockValidator{validator, GetMemberOfInitialState(r, initialLivenessWeightings)}
|
||||||
}
|
}
|
||||||
|
@ -64,85 +40,161 @@ func SimulateFromSeed(
|
||||||
setups[i](r, keys)
|
setups[i](r, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func randTimestamp(r *rand.Rand) time.Time {
|
||||||
|
unixTime := r.Int63n(int64(math.Pow(2, 40)))
|
||||||
|
return time.Unix(unixTime, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateFromSeed tests an application by running the provided
|
||||||
|
// operations, testing the provided invariants, but using the provided seed.
|
||||||
|
func SimulateFromSeed(
|
||||||
|
tb testing.TB, app *baseapp.BaseApp, appStateFn func(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json.RawMessage, seed int64, ops []Operation, setups []RandSetup,
|
||||||
|
invariants []Invariant, numBlocks int, blockSize int, commit bool,
|
||||||
|
) {
|
||||||
|
testingMode, t, b := getTestingMode(tb)
|
||||||
|
log := fmt.Sprintf("Starting SimulateFromSeed with randomness created with seed %d", int(seed))
|
||||||
|
r := rand.New(rand.NewSource(seed))
|
||||||
|
timestamp := randTimestamp(r)
|
||||||
|
log = updateLog(testingMode, log, "Starting the simulation from time %v, unixtime %v", timestamp.UTC().Format(time.UnixDate), timestamp.Unix())
|
||||||
|
fmt.Printf("%s\n", log)
|
||||||
|
timeDiff := maxTimePerBlock - minTimePerBlock
|
||||||
|
|
||||||
|
keys, accs := mock.GeneratePrivKeyAddressPairsFromRand(r, numKeys)
|
||||||
|
|
||||||
|
// Setup event stats
|
||||||
|
events := make(map[string]uint)
|
||||||
|
event := func(what string) {
|
||||||
|
log = updateLog(testingMode, log, "event - %s", what)
|
||||||
|
events[what]++
|
||||||
|
}
|
||||||
|
|
||||||
|
validators := initChain(r, keys, accs, setups, app, appStateFn)
|
||||||
|
|
||||||
header := abci.Header{Height: 0, Time: timestamp}
|
header := abci.Header{Height: 0, Time: timestamp}
|
||||||
opCount := 0
|
opCount := 0
|
||||||
|
|
||||||
var pastTimes []time.Time
|
var pastTimes []time.Time
|
||||||
var pastSigningValidators [][]abci.SigningValidator
|
var pastSigningValidators [][]abci.SigningValidator
|
||||||
|
|
||||||
request := RandomRequestBeginBlock(t, r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log)
|
request := RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log)
|
||||||
// These are operations which have been queued by previous operations
|
// These are operations which have been queued by previous operations
|
||||||
operationQueue := make(map[int][]Operation)
|
operationQueue := make(map[int][]Operation)
|
||||||
|
|
||||||
for i := 0; i < numBlocks; i++ {
|
if !testingMode {
|
||||||
|
b.ResetTimer()
|
||||||
|
}
|
||||||
|
blockSimulator := createBlockSimulator(testingMode, tb, t, event, invariants, ops, operationQueue, numBlocks)
|
||||||
|
|
||||||
|
for i := 0; i < numBlocks; i++ {
|
||||||
// Log the header time for future lookup
|
// Log the header time for future lookup
|
||||||
pastTimes = append(pastTimes, header.Time)
|
pastTimes = append(pastTimes, header.Time)
|
||||||
pastSigningValidators = append(pastSigningValidators, request.LastCommitInfo.Validators)
|
pastSigningValidators = append(pastSigningValidators, request.LastCommitInfo.Validators)
|
||||||
|
|
||||||
// Run the BeginBlock handler
|
// Run the BeginBlock handler
|
||||||
app.BeginBlock(request)
|
app.BeginBlock(request)
|
||||||
|
log = updateLog(testingMode, log, "BeginBlock")
|
||||||
|
|
||||||
log += "\nBeginBlock"
|
if testingMode {
|
||||||
|
|
||||||
// Make sure invariants hold at beginning of block
|
// Make sure invariants hold at beginning of block
|
||||||
AssertAllInvariants(t, app, invariants, log)
|
AssertAllInvariants(t, app, invariants, log)
|
||||||
|
}
|
||||||
|
|
||||||
ctx := app.NewContext(false, header)
|
ctx := app.NewContext(false, header)
|
||||||
|
thisBlockSize := getBlockSize(r, blockSize)
|
||||||
|
|
||||||
var thisBlockSize int
|
|
||||||
load := r.Float64()
|
|
||||||
switch {
|
|
||||||
case load < 0.33:
|
|
||||||
thisBlockSize = 0
|
|
||||||
case load < 0.66:
|
|
||||||
thisBlockSize = r.Intn(blockSize * 2)
|
|
||||||
default:
|
|
||||||
thisBlockSize = r.Intn(blockSize * 4)
|
|
||||||
}
|
|
||||||
// Run queued operations. Ignores blocksize if blocksize is too small
|
// Run queued operations. Ignores blocksize if blocksize is too small
|
||||||
log, numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), t, r, app, ctx, keys, log, event)
|
log, numQueuedOpsRan := runQueuedOperations(operationQueue, int(header.Height), tb, r, app, ctx, keys, log, event)
|
||||||
opCount += numQueuedOpsRan
|
opCount += numQueuedOpsRan
|
||||||
thisBlockSize -= numQueuedOpsRan
|
thisBlockSize -= numQueuedOpsRan
|
||||||
for j := 0; j < thisBlockSize; j++ {
|
log, operations := blockSimulator(thisBlockSize, r, app, ctx, keys, log, header)
|
||||||
logUpdate, futureOps, err := ops[r.Intn(len(ops))](t, r, app, ctx, keys, log, event)
|
opCount += operations
|
||||||
log += "\n" + logUpdate
|
|
||||||
queueOperations(operationQueue, futureOps)
|
|
||||||
|
|
||||||
require.Nil(t, err, log)
|
|
||||||
if onOperation {
|
|
||||||
AssertAllInvariants(t, app, invariants, log)
|
|
||||||
}
|
|
||||||
if opCount%200 == 0 {
|
|
||||||
fmt.Printf("\rSimulating... block %d/%d, operation %d.", header.Height, numBlocks, opCount)
|
|
||||||
}
|
|
||||||
opCount++
|
|
||||||
}
|
|
||||||
|
|
||||||
res := app.EndBlock(abci.RequestEndBlock{})
|
res := app.EndBlock(abci.RequestEndBlock{})
|
||||||
header.Height++
|
header.Height++
|
||||||
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
|
header.Time = header.Time.Add(time.Duration(minTimePerBlock) * time.Second).Add(time.Duration(int64(r.Intn(int(timeDiff)))) * time.Second)
|
||||||
|
log = updateLog(testingMode, log, "EndBlock")
|
||||||
|
|
||||||
log += "\nEndBlock"
|
if testingMode {
|
||||||
|
|
||||||
// Make sure invariants hold at end of block
|
// Make sure invariants hold at end of block
|
||||||
AssertAllInvariants(t, app, invariants, log)
|
AssertAllInvariants(t, app, invariants, log)
|
||||||
|
}
|
||||||
if commit {
|
if commit {
|
||||||
app.Commit()
|
app.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a random RequestBeginBlock with the current validator set for the next block
|
// Generate a random RequestBeginBlock with the current validator set for the next block
|
||||||
request = RandomRequestBeginBlock(t, r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log)
|
request = RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log)
|
||||||
|
|
||||||
// Update the validator set
|
// Update the validator set
|
||||||
validators = updateValidators(t, r, validators, res.ValidatorUpdates, event)
|
validators = updateValidators(tb, r, validators, res.ValidatorUpdates, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\nSimulation complete. Final height (blocks): %d, final time (seconds): %v\n", header.Height, header.Time)
|
fmt.Printf("\nSimulation complete. Final height (blocks): %d, final time (seconds), : %v, operations ran %d\n", header.Height, header.Time, opCount)
|
||||||
DisplayEvents(events)
|
DisplayEvents(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a function to simulate blocks. Written like this to avoid constant parameters being passed everytime, to minimize
|
||||||
|
// memory overhead
|
||||||
|
func createBlockSimulator(testingMode bool, tb testing.TB, t *testing.T, event func(string), invariants []Invariant, ops []Operation, operationQueue map[int][]Operation, totalNumBlocks int) func(
|
||||||
|
blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, privKeys []crypto.PrivKey, log string, header abci.Header) (updatedLog string, opCount int) {
|
||||||
|
return func(blocksize int, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
|
keys []crypto.PrivKey, log string, header abci.Header) (updatedLog string, opCount int) {
|
||||||
|
for j := 0; j < blocksize; j++ {
|
||||||
|
logUpdate, futureOps, err := ops[r.Intn(len(ops))](tb, r, app, ctx, keys, log, event)
|
||||||
|
log = updateLog(testingMode, log, logUpdate)
|
||||||
|
if err != nil {
|
||||||
|
tb.Fatalf("error on operation %d within block %d, %v, log %s", header.Height, opCount, err, log)
|
||||||
|
}
|
||||||
|
|
||||||
|
queueOperations(operationQueue, futureOps)
|
||||||
|
if testingMode {
|
||||||
|
if onOperation {
|
||||||
|
AssertAllInvariants(t, app, invariants, log)
|
||||||
|
}
|
||||||
|
if opCount%50 == 0 {
|
||||||
|
fmt.Printf("\rSimulating... block %d/%d, operation %d/%d. ", header.Height, totalNumBlocks, opCount, blocksize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opCount++
|
||||||
|
}
|
||||||
|
return log, opCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestingMode(tb testing.TB) (testingMode bool, t *testing.T, b *testing.B) {
|
||||||
|
testingMode = false
|
||||||
|
if _t, ok := tb.(*testing.T); ok {
|
||||||
|
t = _t
|
||||||
|
testingMode = true
|
||||||
|
} else {
|
||||||
|
b = tb.(*testing.B)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLog(testingMode bool, log string, update string, args ...interface{}) (updatedLog string) {
|
||||||
|
if testingMode {
|
||||||
|
update = fmt.Sprintf(update, args...)
|
||||||
|
return fmt.Sprintf("%s\n%s", log, update)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBlockSize(r *rand.Rand, blockSize int) int {
|
||||||
|
load := r.Float64()
|
||||||
|
switch {
|
||||||
|
case load < 0.33:
|
||||||
|
return 0
|
||||||
|
case load < 0.66:
|
||||||
|
return r.Intn(blockSize * 2)
|
||||||
|
default:
|
||||||
|
return r.Intn(blockSize * 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// adds all future operations into the operation queue.
|
// adds all future operations into the operation queue.
|
||||||
func queueOperations(queuedOperations map[int][]Operation, futureOperations []FutureOperation) {
|
func queueOperations(queuedOperations map[int][]Operation, futureOperations []FutureOperation) {
|
||||||
if futureOperations == nil {
|
if futureOperations == nil {
|
||||||
|
@ -157,7 +209,8 @@ func queueOperations(queuedOperations map[int][]Operation, futureOperations []Fu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runQueuedOperations(queueOperations map[int][]Operation, height int, t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
// nolint: errcheck
|
||||||
|
func runQueuedOperations(queueOperations map[int][]Operation, height int, tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
privKeys []crypto.PrivKey, log string, event func(string)) (updatedLog string, numOpsRan int) {
|
privKeys []crypto.PrivKey, log string, event func(string)) (updatedLog string, numOpsRan int) {
|
||||||
updatedLog = log
|
updatedLog = log
|
||||||
if queuedOps, ok := queueOperations[height]; ok {
|
if queuedOps, ok := queueOperations[height]; ok {
|
||||||
|
@ -166,9 +219,12 @@ func runQueuedOperations(queueOperations map[int][]Operation, height int, t *tes
|
||||||
// For now, queued operations cannot queue more operations.
|
// For now, queued operations cannot queue more operations.
|
||||||
// If a need arises for us to support queued messages to queue more messages, this can
|
// If a need arises for us to support queued messages to queue more messages, this can
|
||||||
// be changed.
|
// be changed.
|
||||||
logUpdate, _, err := queuedOps[i](t, r, app, ctx, privKeys, updatedLog, event)
|
logUpdate, _, err := queuedOps[i](tb, r, app, ctx, privKeys, updatedLog, event)
|
||||||
updatedLog += "\n" + logUpdate
|
updatedLog = fmt.Sprintf("%s\n%s", updatedLog, logUpdate)
|
||||||
require.Nil(t, err, updatedLog)
|
if err != nil {
|
||||||
|
fmt.Fprint(os.Stderr, updatedLog)
|
||||||
|
tb.FailNow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete(queueOperations, height)
|
delete(queueOperations, height)
|
||||||
return updatedLog, numOps
|
return updatedLog, numOps
|
||||||
|
@ -188,7 +244,8 @@ func getKeys(validators map[string]mockValidator) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction
|
// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction
|
||||||
func RandomRequestBeginBlock(t *testing.T, r *rand.Rand, validators map[string]mockValidator, livenessTransitions TransitionMatrix, evidenceFraction float64,
|
// nolint: unparam
|
||||||
|
func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator, livenessTransitions TransitionMatrix, evidenceFraction float64,
|
||||||
pastTimes []time.Time, pastSigningValidators [][]abci.SigningValidator, event func(string), header abci.Header, log string) abci.RequestBeginBlock {
|
pastTimes []time.Time, pastSigningValidators [][]abci.SigningValidator, event func(string), header abci.Header, log string) abci.RequestBeginBlock {
|
||||||
if len(validators) == 0 {
|
if len(validators) == 0 {
|
||||||
return abci.RequestBeginBlock{Header: header}
|
return abci.RequestBeginBlock{Header: header}
|
||||||
|
@ -220,6 +277,7 @@ func RandomRequestBeginBlock(t *testing.T, r *rand.Rand, validators map[string]m
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
// TODO: Determine capacity before allocation
|
||||||
evidence := make([]abci.Evidence, 0)
|
evidence := make([]abci.Evidence, 0)
|
||||||
// Anything but the first block
|
// Anything but the first block
|
||||||
if len(pastTimes) > 0 {
|
if len(pastTimes) > 0 {
|
||||||
|
@ -264,11 +322,20 @@ func AssertAllInvariants(t *testing.T, app *baseapp.BaseApp, tests []Invariant,
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateValidators mimicks Tendermint's update logic
|
// updateValidators mimicks Tendermint's update logic
|
||||||
func updateValidators(t *testing.T, r *rand.Rand, current map[string]mockValidator, updates []abci.Validator, event func(string)) map[string]mockValidator {
|
// nolint: unparam
|
||||||
|
func updateValidators(tb testing.TB, r *rand.Rand, current map[string]mockValidator, updates []abci.Validator, event func(string)) map[string]mockValidator {
|
||||||
for _, update := range updates {
|
for _, update := range updates {
|
||||||
switch {
|
switch {
|
||||||
case update.Power == 0:
|
case update.Power == 0:
|
||||||
require.NotNil(t, current[string(update.PubKey.Data)], "tried to delete a nonexistent validator")
|
// // TEMPORARY DEBUG CODE TO PROVE THAT THE OLD METHOD WAS BROKEN
|
||||||
|
// // (i.e. didn't catch in the event of problem)
|
||||||
|
// if val, ok := tb.(*testing.T); ok {
|
||||||
|
// require.NotNil(val, current[string(update.PubKey.Data)])
|
||||||
|
// }
|
||||||
|
// // CORRECT CHECK
|
||||||
|
// if _, ok := current[string(update.PubKey.Data)]; !ok {
|
||||||
|
// tb.Fatalf("tried to delete a nonexistent validator")
|
||||||
|
// }
|
||||||
event("endblock/validatorupdates/kicked")
|
event("endblock/validatorupdates/kicked")
|
||||||
delete(current, string(update.PubKey.Data))
|
delete(current, string(update.PubKey.Data))
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -23,7 +23,7 @@ type (
|
||||||
// Operations can optionally provide a list of "FutureOperations" to run later
|
// Operations can optionally provide a list of "FutureOperations" to run later
|
||||||
// These will be ran at the beginning of the corresponding block.
|
// These will be ran at the beginning of the corresponding block.
|
||||||
Operation func(
|
Operation func(
|
||||||
t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
privKeys []crypto.PrivKey, log string, event func(string),
|
privKeys []crypto.PrivKey, log string, event func(string),
|
||||||
) (action string, futureOperations []FutureOperation, err sdk.Error)
|
) (action string, futureOperations []FutureOperation, err sdk.Error)
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ func NewKeeper(cdc *wire.Codec, key sdk.StoreKey) Keeper {
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitKeeper constructs a new Keeper with initial parameters
|
// InitKeeper constructs a new Keeper with initial parameters
|
||||||
|
// nolint: errcheck
|
||||||
func InitKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, params ...interface{}) Keeper {
|
func InitKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, params ...interface{}) Keeper {
|
||||||
if len(params)%2 != 0 {
|
if len(params)%2 != 0 {
|
||||||
panic("Odd params list length for InitKeeper")
|
panic("Odd params list length for InitKeeper")
|
||||||
|
|
|
@ -15,6 +15,7 @@ func ActivatedParamKey(ty string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitGenesis stores activated type to param store
|
// InitGenesis stores activated type to param store
|
||||||
|
// nolint: errcheck
|
||||||
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
||||||
for _, ty := range data.ActivatedTypes {
|
for _, ty := range data.ActivatedTypes {
|
||||||
k.set(ctx, ActivatedParamKey(ty), true)
|
k.set(ctx, ActivatedParamKey(ty), true)
|
||||||
|
|
|
@ -33,7 +33,9 @@ func GetCmdUnjail(cdc *wire.Codec) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := slashing.NewMsgUnjail(sdk.ValAddress(valAddr))
|
msg := slashing.NewMsgUnjail(sdk.ValAddress(valAddr))
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Cod
|
||||||
}
|
}
|
||||||
|
|
||||||
// http request handler to query signing info
|
// http request handler to query signing info
|
||||||
|
// nolint: unparam
|
||||||
func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
|
func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
|
|
@ -99,6 +99,11 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI
|
||||||
txCtx = newCtx
|
txCtx = newCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if utils.HasGenerateOnlyArg(r) {
|
||||||
|
utils.WriteGenerateStdTxResponse(w, txCtx, []sdk.Msg{msg})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own validator address")
|
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own validator address")
|
||||||
|
|
|
@ -16,15 +16,15 @@ func TestCannotUnjailUnlessJailed(t *testing.T) {
|
||||||
slh := NewHandler(keeper)
|
slh := NewHandler(keeper)
|
||||||
amtInt := int64(100)
|
amtInt := int64(100)
|
||||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||||
msg := newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt)
|
msg := newTestMsgCreateValidator(addr, val, amt)
|
||||||
got := stake.NewHandler(sk)(ctx, msg)
|
got := stake.NewHandler(sk)(ctx, msg)
|
||||||
require.True(t, got.IsOK())
|
require.True(t, got.IsOK())
|
||||||
stake.EndBlocker(ctx, sk)
|
stake.EndBlocker(ctx, sk)
|
||||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||||
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()))
|
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
|
||||||
|
|
||||||
// assert non-jailed validator can't be unjailed
|
// assert non-jailed validator can't be unjailed
|
||||||
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
|
got = slh(ctx, NewMsgUnjail(addr))
|
||||||
require.False(t, got.IsOK(), "allowed unjail of non-jailed validator")
|
require.False(t, got.IsOK(), "allowed unjail of non-jailed validator")
|
||||||
require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), got.Code)
|
require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), got.Code)
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ func TestJailedValidatorDelegations(t *testing.T) {
|
||||||
// create a validator
|
// create a validator
|
||||||
amount := int64(10)
|
amount := int64(10)
|
||||||
valPubKey, bondAmount := pks[0], sdk.NewInt(amount)
|
valPubKey, bondAmount := pks[0], sdk.NewInt(amount)
|
||||||
valAddr, consAddr := sdk.ValAddress(addrs[1]), sdk.ConsAddress(addrs[0])
|
valAddr, consAddr := addrs[1], sdk.ConsAddress(addrs[0])
|
||||||
|
|
||||||
msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount)
|
msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount)
|
||||||
got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal)
|
got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal)
|
||||||
|
|
|
@ -27,12 +27,12 @@ func TestHandleDoubleSign(t *testing.T) {
|
||||||
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
|
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
|
||||||
amtInt := int64(100)
|
amtInt := int64(100)
|
||||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||||
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt))
|
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||||
require.True(t, got.IsOK())
|
require.True(t, got.IsOK())
|
||||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||||
keeper.AddValidators(ctx, validatorUpdates)
|
keeper.AddValidators(ctx, validatorUpdates)
|
||||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||||
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()))
|
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
|
||||||
|
|
||||||
// handle a signature to set signing info
|
// handle a signature to set signing info
|
||||||
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true)
|
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true)
|
||||||
|
@ -41,13 +41,13 @@ func TestHandleDoubleSign(t *testing.T) {
|
||||||
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
|
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
|
||||||
|
|
||||||
// should be jailed
|
// should be jailed
|
||||||
require.True(t, sk.Validator(ctx, sdk.ValAddress(addr)).GetJailed())
|
require.True(t, sk.Validator(ctx, addr).GetJailed())
|
||||||
// unjail to measure power
|
// unjail to measure power
|
||||||
sk.Unjail(ctx, val)
|
sk.Unjail(ctx, val)
|
||||||
// power should be reduced
|
// power should be reduced
|
||||||
require.Equal(
|
require.Equal(
|
||||||
t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))),
|
t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))),
|
||||||
sk.Validator(ctx, sdk.ValAddress(addr)).GetPower(),
|
sk.Validator(ctx, addr).GetPower(),
|
||||||
)
|
)
|
||||||
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.MaxEvidenceAge(ctx))})
|
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.MaxEvidenceAge(ctx))})
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ func TestHandleDoubleSign(t *testing.T) {
|
||||||
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
|
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
|
||||||
require.Equal(
|
require.Equal(
|
||||||
t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))),
|
t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))),
|
||||||
sk.Validator(ctx, sdk.ValAddress(addr)).GetPower(),
|
sk.Validator(ctx, addr).GetPower(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,12 +125,12 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||||
sh := stake.NewHandler(sk)
|
sh := stake.NewHandler(sk)
|
||||||
slh := NewHandler(keeper)
|
slh := NewHandler(keeper)
|
||||||
got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt))
|
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||||
require.True(t, got.IsOK())
|
require.True(t, got.IsOK())
|
||||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||||
keeper.AddValidators(ctx, validatorUpdates)
|
keeper.AddValidators(ctx, validatorUpdates)
|
||||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||||
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()))
|
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
|
||||||
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
||||||
require.False(t, found)
|
require.False(t, found)
|
||||||
require.Equal(t, int64(0), info.StartHeight)
|
require.Equal(t, int64(0), info.StartHeight)
|
||||||
|
@ -165,7 +165,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||||
validator, _ := sk.GetValidatorByPubKey(ctx, val)
|
validator, _ := sk.GetValidatorByPubKey(ctx, val)
|
||||||
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||||
pool := sk.GetPool(ctx)
|
pool := sk.GetPool(ctx)
|
||||||
require.Equal(t, int64(amtInt), pool.BondedTokens.RoundInt64())
|
require.Equal(t, amtInt, pool.BondedTokens.RoundInt64())
|
||||||
|
|
||||||
// 501st block missed
|
// 501st block missed
|
||||||
ctx = ctx.WithBlockHeight(height)
|
ctx = ctx.WithBlockHeight(height)
|
||||||
|
@ -180,12 +180,12 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||||
|
|
||||||
// unrevocation should fail prior to jail expiration
|
// unrevocation should fail prior to jail expiration
|
||||||
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
|
got = slh(ctx, NewMsgUnjail(addr))
|
||||||
require.False(t, got.IsOK())
|
require.False(t, got.IsOK())
|
||||||
|
|
||||||
// unrevocation should succeed after jail expiration
|
// unrevocation should succeed after jail expiration
|
||||||
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeUnbondDuration(ctx))})
|
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeUnbondDuration(ctx))})
|
||||||
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
|
got = slh(ctx, NewMsgUnjail(addr))
|
||||||
require.True(t, got.IsOK())
|
require.True(t, got.IsOK())
|
||||||
|
|
||||||
// validator should be rebonded now
|
// validator should be rebonded now
|
||||||
|
@ -195,7 +195,7 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||||
// validator should have been slashed
|
// validator should have been slashed
|
||||||
pool = sk.GetPool(ctx)
|
pool = sk.GetPool(ctx)
|
||||||
slashAmt := sdk.NewDec(amtInt).Mul(keeper.SlashFractionDowntime(ctx)).RoundInt64()
|
slashAmt := sdk.NewDec(amtInt).Mul(keeper.SlashFractionDowntime(ctx)).RoundInt64()
|
||||||
require.Equal(t, int64(amtInt)-slashAmt, pool.BondedTokens.RoundInt64())
|
require.Equal(t, amtInt-slashAmt, pool.BondedTokens.RoundInt64())
|
||||||
|
|
||||||
// validator start height should have been changed
|
// validator start height should have been changed
|
||||||
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
||||||
|
@ -235,12 +235,12 @@ func TestHandleNewValidator(t *testing.T) {
|
||||||
ctx, ck, sk, _, keeper := createTestInput(t)
|
ctx, ck, sk, _, keeper := createTestInput(t)
|
||||||
addr, val, amt := addrs[0], pks[0], int64(100)
|
addr, val, amt := addrs[0], pks[0], int64(100)
|
||||||
sh := stake.NewHandler(sk)
|
sh := stake.NewHandler(sk)
|
||||||
got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, sdk.NewInt(amt)))
|
got := sh(ctx, newTestMsgCreateValidator(addr, val, sdk.NewInt(amt)))
|
||||||
require.True(t, got.IsOK())
|
require.True(t, got.IsOK())
|
||||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||||
keeper.AddValidators(ctx, validatorUpdates)
|
keeper.AddValidators(ctx, validatorUpdates)
|
||||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}})
|
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}})
|
||||||
require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())
|
require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower())
|
||||||
|
|
||||||
// 1000 first blocks not a validator
|
// 1000 first blocks not a validator
|
||||||
ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1)
|
ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1)
|
||||||
|
@ -252,7 +252,7 @@ func TestHandleNewValidator(t *testing.T) {
|
||||||
|
|
||||||
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
require.Equal(t, int64(keeper.SignedBlocksWindow(ctx)+1), info.StartHeight)
|
require.Equal(t, keeper.SignedBlocksWindow(ctx)+1, info.StartHeight)
|
||||||
require.Equal(t, int64(2), info.IndexOffset)
|
require.Equal(t, int64(2), info.IndexOffset)
|
||||||
require.Equal(t, int64(1), info.SignedBlocksCounter)
|
require.Equal(t, int64(1), info.SignedBlocksCounter)
|
||||||
require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
|
require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
|
||||||
|
@ -273,7 +273,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
||||||
amtInt := int64(100)
|
amtInt := int64(100)
|
||||||
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
|
||||||
sh := stake.NewHandler(sk)
|
sh := stake.NewHandler(sk)
|
||||||
got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt))
|
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||||
require.True(t, got.IsOK())
|
require.True(t, got.IsOK())
|
||||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||||
keeper.AddValidators(ctx, validatorUpdates)
|
keeper.AddValidators(ctx, validatorUpdates)
|
||||||
|
@ -296,7 +296,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
||||||
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
require.Equal(t, sdk.Unbonding, validator.GetStatus())
|
||||||
|
|
||||||
// validator should have been slashed
|
// validator should have been slashed
|
||||||
require.Equal(t, int64(amtInt-1), validator.GetTokens().RoundInt64())
|
require.Equal(t, amtInt-1, validator.GetTokens().RoundInt64())
|
||||||
|
|
||||||
// another block missed
|
// another block missed
|
||||||
ctx = ctx.WithBlockHeight(height)
|
ctx = ctx.WithBlockHeight(height)
|
||||||
|
@ -304,6 +304,6 @@ func TestHandleAlreadyJailed(t *testing.T) {
|
||||||
|
|
||||||
// validator should not have been slashed twice
|
// validator should not have been slashed twice
|
||||||
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||||
require.Equal(t, int64(amtInt-1), validator.GetTokens().RoundInt64())
|
require.Equal(t, amtInt-1, validator.GetTokens().RoundInt64())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
|
@ -17,11 +15,13 @@ import (
|
||||||
|
|
||||||
// SimulateMsgUnjail
|
// SimulateMsgUnjail
|
||||||
func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation {
|
func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation {
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
key := simulation.RandomKey(r, keys)
|
key := simulation.RandomKey(r, keys)
|
||||||
address := sdk.ValAddress(key.PubKey().Address())
|
address := sdk.ValAddress(key.PubKey().Address())
|
||||||
msg := slashing.NewMsgUnjail(address)
|
msg := slashing.NewMsgUnjail(address)
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := slashing.NewHandler(k)(ctx, msg)
|
result := slashing.NewHandler(k)(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
|
|
|
@ -17,12 +17,12 @@ func TestBeginBlocker(t *testing.T) {
|
||||||
addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100)
|
addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100)
|
||||||
|
|
||||||
// bond the validator
|
// bond the validator
|
||||||
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), pk, amt))
|
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, pk, amt))
|
||||||
require.True(t, got.IsOK())
|
require.True(t, got.IsOK())
|
||||||
validatorUpdates := stake.EndBlocker(ctx, sk)
|
validatorUpdates := stake.EndBlocker(ctx, sk)
|
||||||
keeper.AddValidators(ctx, validatorUpdates)
|
keeper.AddValidators(ctx, validatorUpdates)
|
||||||
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||||
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()))
|
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
|
||||||
|
|
||||||
val := abci.Validator{
|
val := abci.Validator{
|
||||||
Address: pk.Address(),
|
Address: pk.Address(),
|
||||||
|
|
|
@ -77,7 +77,9 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
|
||||||
} else {
|
} else {
|
||||||
msg = stake.NewMsgCreateValidator(sdk.ValAddress(valAddr), pk, amount, description)
|
msg = stake.NewMsgCreateValidator(sdk.ValAddress(valAddr), pk, amount, description)
|
||||||
}
|
}
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
|
@ -117,6 +119,9 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
|
||||||
|
|
||||||
msg := stake.NewMsgEditValidator(sdk.ValAddress(valAddr), description)
|
msg := stake.NewMsgEditValidator(sdk.ValAddress(valAddr), description)
|
||||||
|
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
|
@ -156,6 +161,9 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
||||||
|
|
||||||
msg := stake.NewMsgDelegate(delAddr, valAddr, amount)
|
msg := stake.NewMsgDelegate(delAddr, valAddr, amount)
|
||||||
|
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
|
@ -225,6 +233,9 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
|
|
||||||
msg := stake.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, sharesAmount)
|
msg := stake.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, sharesAmount)
|
||||||
|
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
|
@ -313,6 +324,9 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command {
|
||||||
|
|
||||||
msg := stake.NewMsgCompleteRedelegate(delAddr, valSrcAddr, valDstAddr)
|
msg := stake.NewMsgCompleteRedelegate(delAddr, valSrcAddr, valDstAddr)
|
||||||
|
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
|
@ -374,6 +388,9 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
|
|
||||||
msg := stake.NewMsgBeginUnbonding(delAddr, valAddr, sharesAmount)
|
msg := stake.NewMsgBeginUnbonding(delAddr, valAddr, sharesAmount)
|
||||||
|
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
|
@ -409,6 +426,9 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command {
|
||||||
|
|
||||||
msg := stake.NewMsgCompleteUnbonding(delAddr, valAddr)
|
msg := stake.NewMsgCompleteUnbonding(delAddr, valAddr)
|
||||||
|
|
||||||
|
if cliCtx.GenerateOnly {
|
||||||
|
return utils.PrintUnsignedStdTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
|
}
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
|
||||||
},
|
},
|
||||||
|
|
|
@ -297,6 +297,11 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
||||||
txCtx = newCtx
|
txCtx = newCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if utils.HasGenerateOnlyArg(r) {
|
||||||
|
utils.WriteGenerateStdTxResponse(w, txCtx, []sdk.Msg{msg})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||||
|
|
|
@ -163,6 +163,7 @@ func getValidators(validatorKVs []sdk.KVPair, cdc *wire.Codec) ([]types.BechVali
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets all Bech32 validators from a key
|
// gets all Bech32 validators from a key
|
||||||
|
// nolint: unparam
|
||||||
func getBech32Validators(storeName string, cliCtx context.CLIContext, cdc *wire.Codec) (
|
func getBech32Validators(storeName string, cliCtx context.CLIContext, cdc *wire.Codec) (
|
||||||
validators []types.BechValidator, httpStatusCode int, errMsg string, err error) {
|
validators []types.BechValidator, httpStatusCode int, errMsg string, err error) {
|
||||||
|
|
||||||
|
|
|
@ -430,7 +430,7 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
||||||
initBond,
|
initBond,
|
||||||
}
|
}
|
||||||
for _, c := range errorCases {
|
for _, c := range errorCases {
|
||||||
unbondShares := sdk.NewDec(int64(c))
|
unbondShares := sdk.NewDec(c)
|
||||||
msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares)
|
msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares)
|
||||||
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
|
||||||
require.False(t, got.IsOK(), "expected unbond msg to fail")
|
require.False(t, got.IsOK(), "expected unbond msg to fail")
|
||||||
|
|
|
@ -68,6 +68,7 @@ func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []
|
||||||
|
|
||||||
// get the power ranking of a validator
|
// get the power ranking of a validator
|
||||||
// NOTE the larger values are of higher value
|
// NOTE the larger values are of higher value
|
||||||
|
// nolint: unparam
|
||||||
func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
|
func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
|
||||||
|
|
||||||
potentialPower := validator.Tokens
|
potentialPower := validator.Tokens
|
||||||
|
|
|
@ -203,6 +203,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty
|
||||||
// the unbonding delegation had enough stake to slash
|
// the unbonding delegation had enough stake to slash
|
||||||
// (the amount actually slashed may be less if there's
|
// (the amount actually slashed may be less if there's
|
||||||
// insufficient stake remaining)
|
// insufficient stake remaining)
|
||||||
|
// nolint: unparam
|
||||||
func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation,
|
func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation,
|
||||||
infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Dec) {
|
infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Dec) {
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package keeper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"container/list"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
@ -11,6 +12,19 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Cache the amino decoding of validators, as it can be the case that repeated slashing calls
|
||||||
|
// cause many calls to GetValidator, which were shown to throttle the state machine in our
|
||||||
|
// simulation. Note this is quite biased though, as the simulator does more slashes than a
|
||||||
|
// live chain should, however we require the slashing to be fast as noone pays gas for it.
|
||||||
|
type cachedValidator struct {
|
||||||
|
val types.Validator
|
||||||
|
marshalled string // marshalled amino bytes for the validator object (not operator address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// validatorCache-key: validator amino bytes
|
||||||
|
var validatorCache = make(map[string]cachedValidator, 500)
|
||||||
|
var validatorCacheList = list.New()
|
||||||
|
|
||||||
// get a single validator
|
// get a single validator
|
||||||
func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator types.Validator, found bool) {
|
func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator types.Validator, found bool) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
@ -18,6 +32,28 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator ty
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return validator, false
|
return validator, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If these amino encoded bytes are in the cache, return the cached validator
|
||||||
|
strValue := string(value)
|
||||||
|
if val, ok := validatorCache[strValue]; ok {
|
||||||
|
valToReturn := val.val
|
||||||
|
// Doesn't mutate the cache's value
|
||||||
|
valToReturn.Operator = addr
|
||||||
|
return valToReturn, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// amino bytes weren't found in cache, so amino unmarshal and add it to the cache
|
||||||
|
validator = types.MustUnmarshalValidator(k.cdc, addr, value)
|
||||||
|
cachedVal := cachedValidator{validator, strValue}
|
||||||
|
validatorCache[strValue] = cachedValidator{validator, strValue}
|
||||||
|
validatorCacheList.PushBack(cachedVal)
|
||||||
|
|
||||||
|
// if the cache is too big, pop off the last element from it
|
||||||
|
if validatorCacheList.Len() > 500 {
|
||||||
|
valToRemove := validatorCacheList.Remove(validatorCacheList.Front()).(cachedValidator)
|
||||||
|
delete(validatorCache, valToRemove.marshalled)
|
||||||
|
}
|
||||||
|
|
||||||
validator = types.MustUnmarshalValidator(k.cdc, addr, value)
|
validator = types.MustUnmarshalValidator(k.cdc, addr, value)
|
||||||
return validator, true
|
return validator, true
|
||||||
}
|
}
|
||||||
|
@ -336,6 +372,7 @@ func (k Keeper) updateForJailing(ctx sdk.Context, oldFound bool, oldValidator, n
|
||||||
return newValidator
|
return newValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: unparam
|
||||||
func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool {
|
func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool {
|
||||||
if oldFound && oldValidator.BondedTokens().LT(newValidator.BondedTokens()) {
|
if oldFound && oldValidator.BondedTokens().LT(newValidator.BondedTokens()) {
|
||||||
return true
|
return true
|
||||||
|
@ -344,6 +381,7 @@ func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator,
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the bond height and incremented intra-tx counter
|
// get the bond height and incremented intra-tx counter
|
||||||
|
// nolint: unparam
|
||||||
func (k Keeper) bondIncrement(ctx sdk.Context, oldFound bool, oldValidator,
|
func (k Keeper) bondIncrement(ctx sdk.Context, oldFound bool, oldValidator,
|
||||||
newValidator types.Validator) (height int64, intraTxCounter int16) {
|
newValidator types.Validator) (height int64, intraTxCounter int16) {
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ func AllInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simula
|
||||||
}
|
}
|
||||||
|
|
||||||
// SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations
|
// SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations
|
||||||
|
// nolint: unparam
|
||||||
func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simulation.Invariant {
|
func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) simulation.Invariant {
|
||||||
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
return func(t *testing.T, app *baseapp.BaseApp, log string) {
|
||||||
ctx := app.NewContext(false, abci.Header{})
|
ctx := app.NewContext(false, abci.Header{})
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
@ -19,9 +17,8 @@ import (
|
||||||
|
|
||||||
// SimulateMsgCreateValidator
|
// SimulateMsgCreateValidator
|
||||||
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||||
|
handler := stake.NewHandler(k)
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
|
||||||
|
|
||||||
denom := k.GetParams(ctx).BondDenom
|
denom := k.GetParams(ctx).BondDenom
|
||||||
description := stake.Description{
|
description := stake.Description{
|
||||||
|
@ -44,9 +41,11 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
PubKey: pubkey,
|
PubKey: pubkey,
|
||||||
Delegation: sdk.NewCoin(denom, amount),
|
Delegation: sdk.NewCoin(denom, amount),
|
||||||
}
|
}
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := stake.NewHandler(k)(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
write()
|
write()
|
||||||
}
|
}
|
||||||
|
@ -59,9 +58,8 @@ func SimulateMsgCreateValidator(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
|
|
||||||
// SimulateMsgEditValidator
|
// SimulateMsgEditValidator
|
||||||
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||||
|
handler := stake.NewHandler(k)
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
|
||||||
|
|
||||||
description := stake.Description{
|
description := stake.Description{
|
||||||
Moniker: simulation.RandStringOfLength(r, 10),
|
Moniker: simulation.RandStringOfLength(r, 10),
|
||||||
|
@ -76,9 +74,11 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||||
Description: description,
|
Description: description,
|
||||||
ValidatorAddr: address,
|
ValidatorAddr: address,
|
||||||
}
|
}
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := stake.NewHandler(k)(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
write()
|
write()
|
||||||
}
|
}
|
||||||
|
@ -90,9 +90,8 @@ func SimulateMsgEditValidator(k stake.Keeper) simulation.Operation {
|
||||||
|
|
||||||
// SimulateMsgDelegate
|
// SimulateMsgDelegate
|
||||||
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||||
|
handler := stake.NewHandler(k)
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
|
||||||
|
|
||||||
denom := k.GetParams(ctx).BondDenom
|
denom := k.GetParams(ctx).BondDenom
|
||||||
validatorKey := simulation.RandomKey(r, keys)
|
validatorKey := simulation.RandomKey(r, keys)
|
||||||
|
@ -111,9 +110,11 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
|
||||||
ValidatorAddr: validatorAddress,
|
ValidatorAddr: validatorAddress,
|
||||||
Delegation: sdk.NewCoin(denom, amount),
|
Delegation: sdk.NewCoin(denom, amount),
|
||||||
}
|
}
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := stake.NewHandler(k)(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
write()
|
write()
|
||||||
}
|
}
|
||||||
|
@ -125,9 +126,8 @@ func SimulateMsgDelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operat
|
||||||
|
|
||||||
// SimulateMsgBeginUnbonding
|
// SimulateMsgBeginUnbonding
|
||||||
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||||
|
handler := stake.NewHandler(k)
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
|
||||||
|
|
||||||
denom := k.GetParams(ctx).BondDenom
|
denom := k.GetParams(ctx).BondDenom
|
||||||
validatorKey := simulation.RandomKey(r, keys)
|
validatorKey := simulation.RandomKey(r, keys)
|
||||||
|
@ -146,9 +146,11 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
||||||
ValidatorAddr: validatorAddress,
|
ValidatorAddr: validatorAddress,
|
||||||
SharesAmount: sdk.NewDecFromInt(amount),
|
SharesAmount: sdk.NewDecFromInt(amount),
|
||||||
}
|
}
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := stake.NewHandler(k)(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
write()
|
write()
|
||||||
}
|
}
|
||||||
|
@ -160,9 +162,8 @@ func SimulateMsgBeginUnbonding(m auth.AccountMapper, k stake.Keeper) simulation.
|
||||||
|
|
||||||
// SimulateMsgCompleteUnbonding
|
// SimulateMsgCompleteUnbonding
|
||||||
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||||
|
handler := stake.NewHandler(k)
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
|
||||||
|
|
||||||
validatorKey := simulation.RandomKey(r, keys)
|
validatorKey := simulation.RandomKey(r, keys)
|
||||||
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
validatorAddress := sdk.ValAddress(validatorKey.PubKey().Address())
|
||||||
|
@ -172,9 +173,11 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||||
DelegatorAddr: delegatorAddress,
|
DelegatorAddr: delegatorAddress,
|
||||||
ValidatorAddr: validatorAddress,
|
ValidatorAddr: validatorAddress,
|
||||||
}
|
}
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := stake.NewHandler(k)(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
write()
|
write()
|
||||||
}
|
}
|
||||||
|
@ -186,9 +189,8 @@ func SimulateMsgCompleteUnbonding(k stake.Keeper) simulation.Operation {
|
||||||
|
|
||||||
// SimulateMsgBeginRedelegate
|
// SimulateMsgBeginRedelegate
|
||||||
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation.Operation {
|
||||||
|
handler := stake.NewHandler(k)
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
|
||||||
|
|
||||||
denom := k.GetParams(ctx).BondDenom
|
denom := k.GetParams(ctx).BondDenom
|
||||||
sourceValidatorKey := simulation.RandomKey(r, keys)
|
sourceValidatorKey := simulation.RandomKey(r, keys)
|
||||||
|
@ -211,9 +213,11 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
ValidatorDstAddr: destValidatorAddress,
|
ValidatorDstAddr: destValidatorAddress,
|
||||||
SharesAmount: sdk.NewDecFromInt(amount),
|
SharesAmount: sdk.NewDecFromInt(amount),
|
||||||
}
|
}
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := stake.NewHandler(k)(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
write()
|
write()
|
||||||
}
|
}
|
||||||
|
@ -225,9 +229,8 @@ func SimulateMsgBeginRedelegate(m auth.AccountMapper, k stake.Keeper) simulation
|
||||||
|
|
||||||
// SimulateMsgCompleteRedelegate
|
// SimulateMsgCompleteRedelegate
|
||||||
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
||||||
|
handler := stake.NewHandler(k)
|
||||||
return func(t *testing.T, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
||||||
keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
|
|
||||||
|
|
||||||
validatorSrcKey := simulation.RandomKey(r, keys)
|
validatorSrcKey := simulation.RandomKey(r, keys)
|
||||||
validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address())
|
validatorSrcAddress := sdk.ValAddress(validatorSrcKey.PubKey().Address())
|
||||||
|
@ -240,9 +243,11 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
||||||
ValidatorSrcAddr: validatorSrcAddress,
|
ValidatorSrcAddr: validatorSrcAddress,
|
||||||
ValidatorDstAddr: validatorDstAddress,
|
ValidatorDstAddr: validatorDstAddress,
|
||||||
}
|
}
|
||||||
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
|
if msg.ValidateBasic() != nil {
|
||||||
|
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
|
||||||
|
}
|
||||||
ctx, write := ctx.CacheContext()
|
ctx, write := ctx.CacheContext()
|
||||||
result := stake.NewHandler(k)(ctx, msg)
|
result := handler(ctx, msg)
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
write()
|
write()
|
||||||
}
|
}
|
||||||
|
@ -253,6 +258,7 @@ func SimulateMsgCompleteRedelegate(k stake.Keeper) simulation.Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
|
// nolint: errcheck
|
||||||
func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup {
|
func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup {
|
||||||
return func(r *rand.Rand, privKeys []crypto.PrivKey) {
|
return func(r *rand.Rand, privKeys []crypto.PrivKey) {
|
||||||
ctx := mapp.NewContext(false, abci.Header{})
|
ctx := mapp.NewContext(false, abci.Header{})
|
||||||
|
|
|
@ -23,7 +23,7 @@ func TestDelegationEqual(t *testing.T) {
|
||||||
ok := d1.Equal(d2)
|
ok := d1.Equal(d2)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
d2.ValidatorAddr = sdk.ValAddress(addr3)
|
d2.ValidatorAddr = addr3
|
||||||
d2.Shares = sdk.NewDec(200)
|
d2.Shares = sdk.NewDec(200)
|
||||||
|
|
||||||
ok = d1.Equal(d2)
|
ok = d1.Equal(d2)
|
||||||
|
@ -57,7 +57,7 @@ func TestUnbondingDelegationEqual(t *testing.T) {
|
||||||
ok := ud1.Equal(ud2)
|
ok := ud1.Equal(ud2)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
ud2.ValidatorAddr = sdk.ValAddress(addr3)
|
ud2.ValidatorAddr = addr3
|
||||||
|
|
||||||
ud2.MinTime = time.Unix(20*20*2, 0)
|
ud2.MinTime = time.Unix(20*20*2, 0)
|
||||||
ok = ud1.Equal(ud2)
|
ok = ud1.Equal(ud2)
|
||||||
|
|
Loading…
Reference in New Issue