Merge branch 'develop' into sunny/gov-bft-time

This commit is contained in:
Christopher Goes 2018-09-07 07:47:14 +02:00 committed by GitHub
commit 72b3a45778
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
86 changed files with 1622 additions and 718 deletions

8
Gopkg.lock generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,53 +2,71 @@
## Overview ## 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
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 mechanism operates as follows. Collected rewards are pooled globally and
divided out passively to validators and delegators. Each validator has the
opportunity to charge commission to the delegators on the rewards collected on
behalf of the delegators by the validators. Fees are paid directly into a
global reward pool, and validator proposer-reward pool. Due to the nature of
passive accounting, whenever changes to parameters which affect the rate of reward
distribution occurs, withdrawal of rewards must also occur.
- Whenever withdrawing, one must withdraw the maximum amount they are entitled
too, leaving nothing in the pool.
- Whenever bonding, unbonding, or re-delegating tokens to an existing account, a
full withdrawal of the rewards must occur (as the rules for lazy accounting
change).
- Whenever a validator chooses to change the commission on rewards, all accumulated
commission rewards must be simultaneously withdrawn.
The above scenarios are covered in `hooks.md`.
The distribution mechanism outlines herein is used to lazily distribute the 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
- validator commission on all rewards earned by their delegators stake - validator commission on all rewards earned by their delegators stake
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.

View File

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

View File

@ -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, global = GetGlobal()
delegation.ValidatorAddr)
pc.ProcessPowerChangeDelegation(delegation, DelDistr)
// collect all entitled fees
entitlement = 0
for delegation = range delegations for delegation = range delegations
global = GetGlobal() delInfo = GetDelegationDistInfo(delegation.DelegatorAddr,
pool = GetPool()
DelDistr = GetDelegationDistribution(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
func (pc PowerChange) ProcessPowerChangeDelegation(delegation sdk.Delegation, SetGlobal(global)
DelDistr DelegationDistribution) return withdraw
// 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
}
func WithdrawDelegationReward(delegatorAddr, validatorAddr, withdrawAddr sdk.AccAddress)
height = GetHeight()
// get all distribution scenarios
pool = stake.GetPool()
global = GetGlobal()
delInfo = GetDelegationDistInfo(delegatorAddr,
validatorAddr)
valInfo = GetValidatorDistInfo(validatorAddr)
validator = GetValidator(validatorAddr)
global, withdraw = delInfo.WithdrawRewards(global, valInfo, height, pool.BondedTokens,
validator.Tokens, validator.DelegatorShares, validator.Commission)
SetGlobal(global)
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
```
## TxWithdrawValidatorRewardsAll
When a validator wishes to withdraw their rewards it must send
`TxWithdrawValidatorRewardsAll`. Note that parts of this transaction logic are also
triggered each with any change in individual delegations, such as an unbond,
redelegation, or delegation of additional tokens to a specific validator. This
transaction withdraws the validators commission fee, as well as any rewards
earning on their self-delegation.
```
type TxWithdrawValidatorRewardsAll struct {
operatorAddr sdk.AccAddress // validator address to withdraw from
withdrawAddr sdk.AccAddress // address to make the withdrawal to withdrawAddr sdk.AccAddress // address to make the withdrawal to
} }
func WithdrawalValidator(ownerAddr, withdrawAddr sdk.AccAddress) func WithdrawValidatorRewardsAll(operatorAddr, withdrawAddr sdk.AccAddress)
// update the delegator adjustment factors and also withdrawal delegation fees height = GetHeight()
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() 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() // withdrawal validator commission rewards
entitlement += scenerio2.WithdrawalEntitlement() global, commission = valInfo.WithdrawCommission(global, valInfo, height, pool.BondedTokens,
validator.Tokens, validator.Commission)
withdraw += commission
SetGlobal(global)
AddCoins(withdrawAddr, withdraw.TruncateDecimal())
```
AddCoins(withdrawAddr, totalEntitlment.TruncateDecimal()) ## Common calculations
func (pc PowerChange) ProcessPowerChangeCommission() ### Update total validator accum
// get the historical scenarios The total amount of validator accum must be calculated in order to determine
scenario1 = pc.CommissionFromGlobalPool() the amount of pool tokens which a validator is entitled to at a particular
scenario2 = pc.CommissionFromProposerPool() block. The accum is always additive to the existing accum. This term is to be
updated each time rewards are withdrawn from the system.
// process the adjustment factors ```
scenario1.UpdateAdjustmentForPowerChange(pc.Height) func (g Global) UpdateTotalValAccum(height int64, totalBondedTokens Dec) Global
scenario2.UpdateAdjustmentForPowerChange(pc.Height) blocks = height - g.TotalValAccumUpdateHeight
g.TotalValAccum += totalDelShares * blocks
g.TotalValAccumUpdateHeight = height
return g
``` ```
## Common Calculations ### Update validator's accums
### Distribution scenario The total amount of delegator accum must be updated in order to determine the
amount of pool tokens which each delegator is entitled to, relative to the
other delegators for that validator. The accum is always additive to
the existing accum. This term is to be updated each time a
withdrawal is made from a validator.
A common form of abstracted calculations exists between validators and ```
delegations attempting to withdrawal their rewards, either from `Global.Pool` func (vi ValidatorDistInfo) UpdateTotalDelAccum(height int64, totalDelShares Dec) ValidatorDistInfo
or from `ValidatorDistribution.ProposerPool`. With the following interface blocks = height - vi.TotalDelAccumUpdateHeight
fulfilled the entitled fees for the various scenarios can be calculated. vi.TotalDelAccum += totalDelShares * blocks
vi.TotalDelAccumUpdateHeight = height
```golang return vi
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 ### Global pool to validator pool
The entitlement to the distributor's tokens held can be accounted for lazily. Every time a validator or delegator executes a withdrawal or the validator is
To begin this calculation we must determine the recipient's _simple pool_ and the proposer and receives new tokens, the relevant validator must move tokens
_projected pool_. The simple pool represents a lazy accounting of what a from the passive global pool to their own pool. It is at this point that the
recipient's entitlement to the distributor's tokens would be if all recipients commission is withdrawn
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 (vi ValidatorDistInfo) TakeAccum(g Global, height int64, totalBonded, vdTokens, commissionRate Dec) (
return v.RecipientShares() * height vi ValidatorDistInfo, g Global)
func (d DistributionScenario) GlobalCount(height int64) sdk.Dec g.UpdateTotalValAccum(height, totalBondedShares)
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 // update the validators pool
return d.PoolBondedTokens blocks = height - vi.GlobalWithdrawalHeight
vi.GlobalWithdrawalHeight = height
func (d DelegationFromGlobalPool) DistributorPrevShares() sdk.Dec accum = blocks * vdTokens
return d.Global.PrevBondedTokens withdrawalTokens := g.Pool * accum / g.TotalValAccum
commission := withdrawalTokens * commissionRate
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 g.TotalValAccum -= accumm
return c.PoolBondedTokens vi.PoolCommission += commission
vi.PoolCommissionFree += withdrawalTokens - commission
g.Pool -= withdrawalTokens
func (c CommissionFromGlobalPool) DistributorPrevShares() sdk.Dec return vi, g
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 ### Delegation reward withdrawal
shares based on the commission portion of the total delegator shares.
For delegations (including validator's self-delegation) all rewards from reward
pool have already had the validator's commission taken away.
``` ```
type CommissionFromProposerPool struct { func (di DelegatorDistInfo) WithdrawRewards(g Global, vi ValidatorDistInfo,
ValidatorDelegatorShares sdk.Dec height int64, totalBonded, vdTokens, totalDelShares, commissionRate Dec) (
ValidatorCommission sdk.Dec di DelegatorDistInfo, g Global, withdrawn DecCoins)
ValDistr ValidatorDistribution
}
func (c CommissionFromProposerPool) DistributorTokens() DecCoins vi.UpdateTotalDelAccum(height, totalDelShares)
return c.ValDistr.ProposerPool g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
blocks = height - di.WithdrawalHeight
di.WithdrawalHeight = height
accum = delegatorShares * blocks
withdrawalTokens := vi.Pool * accum / vi.TotalDelAccum
vi.TotalDelAccum -= accum
func (c CommissionFromProposerPool) DistributorCumulativeTokens() DecCoins vi.Pool -= withdrawalTokens
return c.ValDistr.EverReceivedProposerReward vi.TotalDelAccum -= accum
return di, g, withdrawalTokens
func (c CommissionFromProposerPool) DistributorPrevReceivedTokens() DecCoins
return c.ValDistr.PrevReceivedProposerReward
func (c CommissionFromProposerPool) DistributorShares() sdk.Dec
return c.ValidatorDelegatorShares
func (c CommissionFromProposerPool) DistributorPrevShares() sdk.Dec
return c.ValDistr.PrevDelegatorShares
func (c CommissionFromProposerPool) RecipientShares() sdk.Dec
return c.ValidatorDelegatorShares * (c.ValidatorCommission)
func (c CommissionFromProposerPool) RecipientPrevShares() sdk.Dec
return c.ValDistr.PrevDelegatorShares * (c.ValidatorCommission)
func (c CommissionFromProposerPool) RecipientAdjustment() sdk.Dec
return c.ValDistr.AdjustmentProposer
func (c CommissionFromProposerPool) ModifyAdjustments(withdrawal sdk.Dec)
c.ValDistr.AdjustmentProposer += withdrawal
SetValidatorDistribution(c.ValDistr)
``` ```
### Validator commission withdrawal
Commission is calculated each time rewards enter into the validator.
```
func (vi ValidatorDistInfo) WithdrawCommission(g Global, height int64,
totalBonded, vdTokens, commissionRate Dec) (
vi ValidatorDistInfo, g Global, withdrawn DecCoins)
g = vi.TakeAccum(g, height, totalBonded, vdTokens, commissionRate)
withdrawalTokens := vi.PoolCommission
vi.PoolCommission = 0
return vi, g, withdrawalTokens
```

View File

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

View File

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

View File

@ -344,6 +344,7 @@ func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
// writeGenesisFile creates and writes the genesis configuration to disk. An // 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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -179,6 +179,7 @@ func (tkv *TraceKVStore) CacheWrapWithTrace(_ io.Writer, _ TraceContext) CacheWr
// writeOperation writes a KVStore operation to the underlying io.Writer as // 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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,6 +30,7 @@ func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder {
// GetAccountCmd returns a query account that will display the state of the // 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]",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, &params) err2 := keeper.cdc.UnmarshalJSON(req.Data, &params)
@ -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, &params) err2 := keeper.cdc.UnmarshalJSON(req.Data, &params)
@ -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, &params) err2 := keeper.cdc.UnmarshalJSON(req.Data, &params)
@ -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, &params) err2 := keeper.cdc.UnmarshalJSON(req.Data, &params)
@ -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, &params) err2 := keeper.cdc.UnmarshalJSON(req.Data, &params)
@ -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, &params) err2 := keeper.cdc.UnmarshalJSON(req.Data, &params)
@ -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

View File

@ -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,24 +21,15 @@ 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)
key := simulation.RandomKey(r, keys) 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) {
addr := sdk.AccAddress(key.PubKey().Address()) msg := simulationCreateMsgSubmitProposal(tb, r, keys, log)
deposit := randomDeposit(r)
msg := gov.NewMsgSubmitProposal(
simulation.RandStringOfLength(r, 5),
simulation.RandStringOfLength(r, 5),
gov.ProposalTypeText,
addr,
deposit,
)
require.Nil(t, msg.ValidateBasic(), "expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
ctx, write := ctx.CacheContext() ctx, write := ctx.CacheContext()
result := gov.NewHandler(k)(ctx, msg) result := handler(ctx, msg)
if result.IsOK() { if result.IsOK() {
// Update pool to keep invariants // Update pool to keep invariants
pool := sk.GetPool(ctx) pool := sk.GetPool(ctx)
pool.LooseTokens = pool.LooseTokens.Sub(sdk.NewDecFromInt(deposit.AmountOf(denom))) pool.LooseTokens = pool.LooseTokens.Sub(sdk.NewDecFromInt(msg.InitialDeposit.AmountOf(denom)))
sk.SetPool(ctx, pool) sk.SetPool(ctx, pool)
write() write()
} }
@ -50,9 +39,26 @@ func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operati
} }
} }
func simulationCreateMsgSubmitProposal(tb testing.TB, r *rand.Rand, keys []crypto.PrivKey, log string) gov.MsgSubmitProposal {
key := simulation.RandomKey(r, keys)
addr := sdk.AccAddress(key.PubKey().Address())
deposit := randomDeposit(r)
msg := gov.NewMsgSubmitProposal(
simulation.RandStringOfLength(r, 5),
simulation.RandStringOfLength(r, 5),
gov.ProposalTypeText,
addr,
deposit,
)
if msg.ValidateBasic() != nil {
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)
}
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() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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